Messenger Introduction

Messenger is a JMS (Java Message Service) framework which makes it very easy to use JMS in Web Service and Web Application environments.

Messenger implements session pooling (which can be quite hard to do with JMS) which makes JMS very easy to work with. Also Messenger hides much of the complexity of JMS behind a simple facade API, the Messenger interface.

In addition Messenger provides an XML deployment configuration file to avoid having to litter your code with complex deployment configuration details in your application code.

Messenger also provides a Messagelet Engine which is a JMS based container that can be deployed in any Servlet Engine to process JMS messages via MessageListeners, Message Driven Objects, Servlets or JSP.

Example Config

Here is an example Messenger.xml deployment configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<manager>

  <!-- this example Messenger XML config file should work with J2EE SDK -->

  <messenger name="topic">
    <jndi lookupName="TopicConnectionFactory">
      <property>
        <name>com.sun.jms.internal.java.naming.factory.initial</name>
        <value>com.sun.enterprise.naming.SerialInitContextFactory</value>
      </property>          
    </jndi>
  </messenger>

  <messenger name="queue">
    <jndi lookupName="QueueConnectionFactory">
      <property>
        <name>com.sun.jms.internal.java.naming.factory.initial</name>
        <value>com.sun.enterprise.naming.SerialInitContextFactory</value>
      </property>          
    </jndi>
  </messenger>

</manager>

It should work with the J2EE SDK to make 2 standard Messengers called topic and queue respectively.

So how would we use these 2 Messengers from Java code?

Example Code

Here's some example code to send a message on a topic.


// get a Messenger and Destination
Messenger messenger = MessengerManager.get( "topic" );
Destination destination = messenger.getDestination( "CHAT.NEWBIES" );

// now lets send a message
TextMessage message = messenger.createTextMessage( "this is some text" );
messenger.send( destination, message );

Here's some code to receive a message on a queue, blocking until the message arrives.


// get a Messenger and Destination
Messenger messenger = MessengerManager.get( "queue" );
Destination destination = messenger.getDestination( "REQUEST.BUILD" );

// now lets receive a message
Message message = messenger.receive( destination );

Notice how the construction of individual Messenger objects can be hidden behind the MessengerManager in a similar way to tools like log4j.

Also notice that the Messenger API is a simple facade, no need for Topic and Queue specific coding as well as the use of MessageConsumer, MessageProducer, TopicPublisher, TopicSubscriber, QueueSender, QueueReceiver and the plethora of Connection and Session objects.

Configuration

By default, Messenger will look for an XML document called Messenger.xml on the CLASSPATH as soon as a Messenger instance is looked up via the following code.


Messenger messenger = MessengerManager.get( "customer.orders" );

An alternative approach is to define the system property org.apache.commons.messenger to point to a URL of a Messenger deployment configuration document. For example


  $ java -Dorg.apache.commons.messenger=http://localhost/config/Messenger.xml MyApplication

In servlet environments its often a good idea to explicitly configure the singleton MessengerManager in a Servlet initialisation method using servlet initialisation parameters. Here's an example


public class MyServlet extends HttpServlet {
    
    public void init() throws ServletException {
        // initialise the Messenger connections
        String url = getInitParameter( "messenger" );
        if ( url != null ) {
            MessengerManager.configure( url );
        }
    }
}  

Messagelets

The Messenger project provides a Messagelet Engine which is a JMS based Container which runs in any Servlet Engine such as Tomcat 4.0. The Messagelet Engine provides a simple framework for processing JMS messages in a variety of ways using either regular JMS MessageListeners, Message Driven Objects, Servlets or even JSP.

To deploy a Messagelet Container you need to add the ManagerServlet in a web application giving it an XML configuration file describing all the various JMS connections and an XML configuration file describing all the subscriptions.

Here are example connections and subscriptions XML configuration files. There now follows the section you need to add to your web.xml configuration file to deploy the Messagelet Manager Servlet.


  <servlet>
    <servlet-name>managerServlet</servlet-name>
    <servlet-class>org.apache.commons.messagelet.ManagerServlet</servlet-class>
    <init-param>
      <param-name>connections</param-name>
      <param-value>/WEB-INF/Messenger.xml</param-value>
    </init-param> 
    <init-param>
      <param-name>subscriptions</param-name>
      <param-value>/WEB-INF/subscriptions.xml</param-value>
    </init-param> 
    <load-on-startup>1</load-on-startup> 
  </servlet>

Once you've done the above and the web application is started the Messagelet engine will subscribe to the various JMS subscriptions and then dispatch JMS messages to the various MessageListener objects, Servlets or JSP pages.

There are a variety of ways in which you can process JMS messages depending on your requirements.

  • A MessageListener is a standard JMS listener of messages.
  • A MessageDrivenObject is-a JMS MessageListener which has extra servlet-based lifecycle methods just like a Servlet. This allows an MDO to know when its being initialised and when its being destroryed and so do some resource management (such as creating or closing database connections etc). Also on initialisation the MDO gets access to the ServletContext so that it can read some initialization parameters from the web application or perform web-app level logging and so on.
  • A MessengerMDO is-a MessageDrivenObject but also provides a number of helper methods such as access to the Messenger to which its listening, so that responses can be sent back to the originator of the message, as well as access to the ServletContext and some logging helper methods.
  • A Servlet can be any GenericServlet or HttpServlet. If the JMS message that is being dispatched is a TextMessage then the body of the message is available via the ServletRequest.getReader() method, in the normal Servlet way. Any output written to the ServletResponse.getWriter() will be converted into a TextMessage and sent back to the originator. All servlets and JSP pages have access to the originating JMS message and Messenger objects via the "message" and "messenger" request attributes respectively.
  • A Messagelet is a JMS specific Servlet, just like a HttpServlet is a HTTP specific Servlet. It provides access to a Messagelet specific MessageletRequest and MessageletResponse to allow access to the JMS Message and the Messenger for sending replies.
  • A JSP page can be any piece of JSP, for example the standard JSP tag library can be used to perform JavaScript, XPath, XSLT or SQL operations on the incoming message. The request scope "message" and "messenger" attributes can be used to access the originating JMS Message and Messenger objects.

There are some examples of an MDO, Servlet and Messagelet here or you can see example JSP here

Bridging JMS providers

In addition the Messagelet engine provides a Bridge mechanism which allows messages to be consumed from one destination and connection and sent to another destination, possibly using a different JMS connection and provider. This allows, for example, messages to be consumed on SpiritWave and sent to MQSeries, possibly applying some custom transformation along the way.

The Bridge mechanism is provided via the BridgeMDO and using the <bridge> element inside a subscription deployment descriptor.