Designing an enterprise application to use JMS

This topic describes things to consider when designing an enterprise application to use the JMS API directly for asynchronous messaging.

Why and when to perform this task

This topic describes things to consider when designing an enterprise application to use the JMS API directly for asynchronous messaging.

  1. The application refers to JMS resources that are predefined, as administered objects, to WebSphere Application Server.

    Details of JMS resources that are used by enterprise applications are defined to WebSphere Application Server and bound into the JNDI namespace by the WebSphere administrative support. An enterprise application can retrieve these objects from the JNDI namespace and use them without needing to know anything about their implementation. This enables the underlying messaging architecture defined by the JMS resources to be changed without requiring changes to the enterprise application. When designing an enterprise application, you need to identify the details of the following types of JMS resources:

    Point-to-Point Publish/Subscribe
    QueueConnectionFactory
    Queue
    TopicConnectionFactory
    Topic


    A connection factory is used to create connections with the JMS provider for a specific JMS queue or topic destination. Each connection factory encapsulates the configuration parameters needed to create a connection to a JMS destination.

    For more information about the properties of these JMS resources, see Configuring JMS provider resources.

  2. The application server pools connections and sessions with the JMS provider to improve performance. This is independent from any WebSphere MQ connection pooling. You need to configure the connection and session pool properties appropriately for your applications, otherwise you may not get the connection and session behavior that you want.
  3. Applications can cache JMS connections, sessions, and producers or consumers. Due to the pooling mentioned above this may not give as much of a performance improvement as you might expect.

    You must not cache session handles in stateless session beans that operate in transactions started by a client of the bean. Caching handles in this way causes the bean to be returned to the pool while the session is still involved in the transaction. Also, you should not cache non-durable subscribers due to the restriction mentioned above.

  4. A non-durable subscriber can only be used in the same transactional context (for example, a global transaction or an unspecified transaction context) that existed when the subscriber was created. For more information about this context restriction, see The effect of transaction context on non-durable subscribers.
  5. You should not use a large number of subscriptions on a queue that is supported by the message broker of the embedded JMS provider, because the message broker can fail to recover them when restarting. The maximum number of subscriptions on a queue that is supported by the message broker of the embedded JMS provider is [on AIX] 15000 and [on other platforms] 30000 subscriptions.
  6. If you want to use authentication with embedded WebSphere messaging, you cannot have user IDs longer than 12 characters. For example, the default Windows NT user ID, administrator, is not valid for use with WebSphere internal messaging, because it contains 13 characters.
  7. For messaging operations, you should write application programs that use only references to the interfaces defined in Sun's javax.jms package.

    JMS defines a generic view of a messaging that maps onto the underlying transport. An enterprise application that uses JMS, makes use of the following interfaces that are defined in Sun's javax.jms package:

    Connection
    Provides access to the underlying transport, and is used to create Sessions.
    Session
    Provides a context for producing and consuming messages, including the methods used to create MessageProducers and MessageConsumers.
    MessageProducer
    Used to send messages.
    MessageConsumer
    Used to receive messages.

    The generic JMS interfaces are subclassed into the following more specific versions for Point-to-Point and Publish/Subscribe behavior:

    Point-to-Point Publish/Subscribe
    QueueConnection
    QueueSession,
    QueueSender
    QueueReceiver
    TopicConnection
    TopicSession,
    TopicSender
    TopicReceiver


    The section "J2EE.6.7 Java Message Service (JMS) 1.0 Requirements" of the Target can be accessed only when this topic is linked to the World Wide Web   J2EE specification gives a list of methods that must not be called in Web and EJB containers:

          javax.jms.Session method setMessageListener
          javax.jms.Session method getMessageListener
          javax.jms.Session method run
          javax.jms.QueueConnection method createConnectionConsumer
          javax.jms.TopicConnection method createConnectionConsumer
          javax.jms.TopicConnection method createDurableConnectionConsumer
          javax.jms.MessageConsumer method getMessageListener
          javax.jms.MessageConsumer method setMessageListener
          javax.jms.Connection setExceptionListener
          javax.jms.Connection stop
          javax.jms.Connection setClientID
    

    This method restriction is enforced in IBM WebSphere Application Server by throwing a javax.jms.IllegalStateException.

  8. The following points, as defined in the EJB specification, apply to the use of flags on createxxxSession calls:
    • The transacted flag passed on createxxxSession is ignored inside a global transaction and all work is performed as part of the transaction. Outside of a transaction the transacted flag is not used and, if set to true, the application should use session.commit() and session.rollback() to control the completion of the work. In an EJB2.0 module, if the transacted flag is set to true and outside of an XA transaction, then the session is involved in the WebSphere local transaction and the unresolved action attribute of the method applies to the JMS work.
    • Clients cannot use using Message.acknowledge() to acknowledge messages. If a value of CLIENT_ACKNOWLEDGE is passed on the createxxxSession call, then messages are automatically acknowledged by the application server and Message.acknowledge() is not used.
  9. Decide what message selectors are needed.

    You can use the JMS message selector mechanism to select a subset of the messages on a queue so that this subset is returned by a receive call. The selector can refer to fields in the JMS message header and fields in the message properties.

  10. Acting on messages received.

    When a message is received, you can act on it as needed by the business logic of the application. Some general JMS actions are to check that the message is of the correct type and extract the content of the message. To extract the content from the body of the message, you need to cast from the generic Message class (which is the declared return type of the receive methods) to the more specific subclass, such as TextMessage. It is good practice always to test the message class before casting, so that unexpected errors can be handled gracefully.

    In this example, the instanceof operator is used to check that the message received is of the TextMessage type. The message content is then extracted by casting to the TextMessage subclass.

           if ( inMessage instanceof TextMessage )
    
    ...
               String replyString = ((TextMessage) inMessage).getText();
    
  11. Using a listener to receive messages asynchronously.

    An alternative to making calls to QueueReceiver.receive() is to register a method that is called automatically when a suitable message is available; for example:

    ...
    MyClass listener =new MyClass();
    queueReceiver.setMessageListener(listener);
    //application continues with other application-specific behavior.
    ...

    When a message is available, it is retrieved by the onMessage() method on the listener object.

    import javax.jms.*;
    public class MyClass implements MessageListener
    {
    public void onMessage(Message message)
    {
    System.out.println("message is "+message);
    //application specific processing here
    ...
    
    }
    }

    Note: A MessageListener can only be used in the client container. (The J2EE specification forbids the use of the JMS MessageListener mechanism for the asynchronous receipt of messages in the EJB and Web containers.)

    For asynchronous message delivery, the application code cannot catch exceptions raised by failures to receive messages. This is because the application code does not make explicit calls to receive() methods. To cope with this situation, you can register an ExceptionListener, which is an instance of a class that implements the onException()method. When an error occurs, this method is called with the JMSException passed as its only parameter.

    For more details about using listeners to receive messages asynchronously, see the Target can be accessed only when this topic is linked to the World Wide Web   Java Message Service Documentation .

    Note: An alternative to developing your own JMS listener class, you can use a message-driven bean, as described in Using message-driven beans in applications.

  12. Warning when receiving messages within a server-side application component.

    Take care when performing a JMS receive() from a server-side application component if that receive() invocation is waiting on a message produced by another application component that is deployed in the same server. Such a JMS receive() is synchronous, so blocks until the response message is received.

    This type of application design can lead to the consumer/producer problem where the entire set of work threads can be exhausted by the receiving component, which has been blocked waiting for responses, leaving no available worker thread for which to dispatch the application component that would generate the response JMS message.

    To illustrate this problem, picture a servlet and a message-driven bean deployed in the same server. When this servlet dispatches a request it sends a message to a queue which is serviced by the message-driven bean (that is, messages produced by the servlet are consumed by the message-driven bean's onMessage() method). The servlet subsequently issues a receive(), waiting for a reply on a temporary ReplyTo queue. The message-driven bean's onMessage() method performs a database query and sends back a reply to the servlet on the temporary queue. If a large number of servlet requests occur at once (relative to the number of server worker threads), then it is likely that all available server worker threads will be used to dispatch a servlet request, send a message, and wait for a reply. The application server enters a deadly-embrace condition whereby no threads remain to process any of the message-driven beans that are now pending. Since the servlets are waiting in blocking recieves, the server hangs, likely leading to application failure.

    Possible solutions are:

    1. Ensure that the number of worker threads (# of threads per server region * # of server regions per server) exceeds the number of concurrent dispatches of the application component doing the receive() so that there is always a worker thread available to dispatch the message producing component.
    2. Use an application topology that places the receiver application component in a separate server than the producer application component. While worker thread usage can still need to be carefully considered under such a deployment scenario, this separation ensures that there are always be threads that cannot be blocked by the message receiving component. There can be other interactions to consider, such as an application server that has multiple applications installed.
    3. Refactor your application to do the message receives from a client component, which will not compete with the producer component for worker threads. Furthermore, the client component can do asynchronous (non-blocking) receives, which are prohibited from J2EE servers. So, for example, the example application above could be refactored to have a client sending messages to a queue and then waiting for a response from the MDB.

Related concepts
An overview of WebSphere asynchronous messaging using JMS
Related tasks
Developing a J2EE application to use JMS
Deploying a J2EE application to use JMS
Using JMS and messaging in applications
Related reference
The effect of transaction context on non-durable subscribers



Searchable topic ID:   tmj_desap
Last updated: Jun 21, 2007 9:56:50 PM CDT    WebSphere Application Server for z/OS, Version 5.0.2
http://publib.boulder.ibm.com/infocenter/wasinfo/index.jsp?topic=/com.ibm.websphere.zseries.doc/info/zseries/ae/tmj_desap.html

Library | Support | Terms of Use | Feedback