Enterprise Messaging in a Heterogeneous Environment

Introduction

I work for a small company that long ago decided to standardize its core application on the .NET platform. The resulting system was entirely proprietary, developed in house and based on Microsoft technology (for example, MSMQ, IIS, and SQL Server). As the business grew, new business processes were introduced and it made sense to seek the “help” of third-party applications to carry out steps within them. In particular, one of the crucial steps involved large document transformation. After a series of inquiries and trials, a powerful, dependable, and speedy Java-based transformation engine was purchased. In solving one problem, another is created: the integration of a Java application into a homogeneous, .NET-based SOA.

Integration can be accomplished when both .NET and Java messaging systems operate under the same message transportation standards, message structures are interoperable, and a platform neutral protocol is used to relay messages from one system to the other.

The following discusses how to use enterprise messaging to integrate Java and .NET applications into a single logical Enterprise Messaging Bus.

Transportation

Central to success with enterprise messaging is the establishment of how messages will be sent and how they will be received: “the transportation layer.” When using queuing systems such as MSMQ for message transport, it’s common that a sender, or “producer,” of a message be required to know or discover which queue the receiver, or “consumer,” of the message is connected to. If the producer expects a response from the consumer, the producer provides the location or alias of the queue it itself is connected to in the request message. The consumer then dynamically connects to the producer’s queue and sends the reply. This type of architecture has two main problems:

  1. Security: Access must be configured for each producer/consumer interaction (one producer may communicate with “n” number of consumers). This can be a nightmare for any infrastructure/operations team to support.
  2. Coupling: Message producers are responsible for locating and connecting to one to many consumer queues. They are also responsible for message delivery to those queues. This has a tendency to further couple, rather than decouple, services. The goal of an SOA is for services to be loosely coupled.

A queuing architecture implemented as described above (often called “Point-to-Point”) results in “spaghetification”—a web of integration points that must be maintained in a given environment. SOAs based on Web services also tend to follow this Point-to-Point pattern (until WS-Notification is generally accepted, that is).

Enter publish/subscribe. The basic premise of this idea is that a producer can send a message and know nothing about the location of the consumer. In fact, multiple consumers can receive and do work on the same message. Consumers, or “subscribers,” profess their interest in a message and are notified when a message they have asked to receive is sent. Messages, in turn, must be filterable so the messaging system can properly deliver them. This filterable attribute is akin to the Label property of a System.Messaging.Message object in .NET or the Topic for a JMS message in Java. But, the generic term I’d like to use is TIBCO’s word for the concept, “subject.”

In a publish/subscribe architecture, subject naming conventions are paramount. Generally speaking, a good naming convention is arranged from domain downward. For example, suppose the following was the convention:

WORLD.CONTINENT.COUNTRY.STATE.COUNTY.CITY

In this example, a subscriber could feasibly listen for any messages destined for earth by subscribing to messages with the subject “EARTH.*” (note the wildcard character “*”). Alternatively, if a subscriber were more interested in messages destined for a specific continent on earth, it could apply a subject filter such as “EARTH.AUSTRALIA.*.” In this example, all messages destined for the Australian continent on planet Earth would be received by the subscriber (this type of wildcard subscription is useful when creating diagnostic or message routing applications). The analogy continues to the very lowest level, where you can subscribe to messages destined only for a particular city (and breaks down once you realize not all countries have states or the concept of counties).

For practical purposes, the following convention can be employed:

COMPANY.DIVISION.ROLE.ENTITY.Action:ACME.TELECOM.PROVISIONING.DSL.Activate

Queuing systems such as MSMQ can be modified to simulate publish/subscribe through the introduction of a custom message “router.” At startup, each subscriber registers its interest in one to many subjects. Registration includes the subscriber’s local queue address. It is then the router’s responsibility to deliver messages to registered subscriber queues. The following diagram illustrates how the router maintains correlation between subjects and queues:

In this model, all publishers send messages to a single central queue. Each message sent to this queue is filtered by the router based on subject and forwarded to the subscribers interested in the message.

The advantages to this model are the following:

  1. The router is the only component requiring access to consumer queues.
  2. Queues can be redeployed and configured with little or no impact to other services.
  3. The architecture is scalable and loosely coupled—message producers need only connect to and send messages to one queue. The messaging infrastructure is responsible for delivering messages to consumers.

The problem with this model, however, is that the router becomes a bottleneck for the messaging architecture because all messages funnel through it. To overcome this, multiple instances of the router should run concurrently to distribute the workload.

Once services on the .NET side of the house are operating under a pseudo publish/subscribe messaging paradigm, it’s easy to extend the metaphor to Java-based messaging systems such as JMS, which support publish/subscribe out of the box.

Subscribing to Messages

MSMQ and JMS both provide mechanisms for event-based notification. That is, consumers can be notified when messages are sent to them by the messaging infrastructure.

In C#, the PeekCompleted event is fired for the first message in the queue (and is continuously fired until the message is removed or its lifespan expires). The following code sample wires an event handler to the PeekCompleted event and interrogates the message’s Label property to determine whether it matches the subject name the consumer is interested in.

private MessageQueue
   m_messageQueue;

private string
   m_subject;

public Subscriber(string queueName, string subject)
{
   m_subject                          = subject;
   m_messageQueue                     = new MessageQueue(queueName);
   MessageQueue.EnableConnectionCache = false;

   m_messageQueue.PeekCompleted       += new
      PeekCompletedEventHandler(OnPeekCompleted);
}

protected void OnPeekCompleted(object sender,
                               PeekCompletedEventArgs asyncResult)
{
   try
   {
      //end the peek and get the message
      using(Message message = m_messageQueue.EndPeek(asyncResult))
      {
         //filter on label. If we are doing a wildcard subscription,
         //check if the message label is a partial match to the
         //subject; otherwise, check for an absolute match.

         if(m_subject.IndexOf("*") > -1)
         {
            //We're doing a wildcard subscription here
            if(message.Label.IndexOf(m_subject.Replace("*",null)) > -1)
            {
               //Pull the message off the queue
               m_messageQueue.ReceiveById(message.Id);
            }
            else return;
         }
         else if(m_subject.Equals(message.Label))
         {
            //Pull the message off the queue
            m_messageQueue.ReceiveById(message.Id);
         }
         else return;

         //Execute business logic
         ...
      }
   }
   finally
   {
      //Resume listening for messages
      m_messageQueue.BeginPeek();
   }
}

In Java, a subscriber must implement the javax.jms.MessageListener interface and define a method called onMessage(). The JMS subscriber connects to the JMS Provider that automatically performs the subject filtering that has to be done explicitly by the C# subscriber. onMessage() is invoked, then, only when a message is published on the subject the subscriber is interested in. JMS also has out-of-the-box support for wildcard subscription (“*”).

private TopicConnection
   m_connection;

private TopicSession
   m_session;

private TopicConnectionFactory
   m_factory;

public Subscriber(String subject, String broker, String connectID,
                  String userID, String password)
                 throws javax.jms.JMSException{

   try{

      //Initialize the session and connection with the JMS Provider
      Hashtable props = new Hashtable();
      props.put(Context.INITIAL_CONTEXT_FACTORY,
                org.exolab.jms.jndi.rmi.
                RmiJndiInitialContextFactory.class.getName());
      props.put(Context.PROVIDER_URL, broker);
      Context context = new InitialContext(props);

      m_factory = ((TopicConnectionFactory)
                  context.lookup("JmsTopicConnectionFactory"));

      if(null == m_factory)
      {
         throw new RuntimeException("Failed to locate connection
                                     factory");
      }

      m_connection = m_factory.createTopicConnection(userID, password);
      m_session    = m_connection.createTopicSession(false,Session.
                                                     AUTO_ACKNOWLEDGE);

      //Set up a subscriber
      m_session.createSubscriber(m_session.createTopic(m_subject)).
         setMessageListener(this);
      m_connection.start();
   }
   catch(javax.naming.NamingException nfe){

      throw new RuntimeException(nfe.getMessage());
   }
}

public void onMessage(javax.jms.Message message){

   try{

      //Business Logic
      ...
   }
   catch(javax.jms.JMSException jme){

      //Handle the exception
      ...
   }
}

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read