Network Deployment (Distributed operating systems), v8.0 > Develop and deploying applications > Develop Messaging resources > Program to use asynchronous messaging > Program to use JMS and messaging directly
Design an enterprise application to use JMS
There are many things to consider when designing an enterprise application to use the JMS APIs directly for asynchronous messaging.
Procedure
- 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 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.
The point-to-point and publish/subscribe versions of JMS common interfaces. The first column of this table lists the JMS common interfaces, the second column lists the corresponding point-to-point interfaces, and the third column lists the corresponding publish/subscribe interfaces.
JMS common interfaces Point-to-point interfaces Publish/subscribe interfaces ConnectionFactory QueueConnectionFactory TopicConnectionFactory Connection QueueConnection TopicConnection Destination Queue Topic Session QueueSession, TopicSession, MessageProducer QueueSender TopicPublisher MessageConsumer QueueReceiver,
QueueBrowserTopicSubscriber For more information about using these JMS interfaces, see the Java Message Service Documentation and the Use Java section of the WebSphere MQ information center.
The section "JMS (JMS) Requirements" of the 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 setClientIDThis method restriction is enforced in WAS by throwing a javax.jms.IllegalStateException exception.
- Applications refer to JMS resources that are predefined, as administered objects, to WAS.
Details of JMS resources that are used by enterprise applications are defined to WAS 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.
JMS resources for point-to-point and publish/subscribe messaging. The left hand column of this table lists the JMS resources for point-to-point messaging, and the right hand column lists the JMS resources for publish/subscribe.
Point-to-point Publish/subscribe ConnectionFactory (or QueueConnectionFactory)
QueueConnectionFactory (or TopicConnectionFactory)
TopicA connection factory is used to create connections from the JMS provider to the messaging system, and encapsulates the configuration parameters needed to create connections.
- To improve performance, the application server pools connections and sessions with the JMS provider. You have to configure the connection and session pool properties appropriately for your applications, otherwise you might not get the connection and session behavior that you want.
- Applications must not cache JMS connections, sessions, producers or consumers. WAS closes these objects when a bean or servlet completes, and so any attempt to use a cached object will fail with a javax.jms.IllegalStateException exception.
To improve performance, applications can cache JMS objects that have been looked up from JNDI. For example, an EJB or servlet needs to look up a JMS ConnectionFactory only once, but it must call the createConnection method on each instantiation. Because of the effect of pooling on connections and sessions with the JMS provider, there should be no performance impact.
- 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.
- Use durable subscriptions with the default messaging provider. A durable subscription on a JMS topic enables a subscriber to receive a copy of all messages published to topic, even after periods of time when the subscriber is not connected to the server. Therefore, subscriber applications can operate disconnected from the server for long periods of time, and then reconnect to the server and process messages that were published during their absence. If an application creates a durable subscription, it is added to the runtime list that administrators can display and act on through the administrative console.
Each durable subscription is given a unique identifier, clientID##subName where:
- clientID
- The client identifier used to associate a connection and its objects with the messages maintained for applications (as clients of the JMS provider). You should use a naming convention that helps you identify the applications, in case we have to relate durable subscriptions to the associated applications for runtime administration.
- subName
- The subscription name used to uniquely identify a durable subscription within a given client identifier.
For durable subscriptions created by message-driven beans, these values are set on the JMS activation specification. For other durable subscriptions, the client identifier is set on the JMS connection factory, and the subscription name is set by the application on the createDurableSubscriber operation.
To create a durable subscription to a topic, an application uses the createDurableSubscriber operation defined in the JMS API:
public TopicSubscriber createDurableSubscriber(Topic topic, java.lang.String subName, java.lang.String messageSelector, boolean noLocal) throws JMSException
- topic
- The name of the JMS topic to subscribe to. This is the name of an object supporting the javax.jms.Topic interfaces, such as found by looking up a suitable JNDI entry.
- subName
- The name used to identify this subscription.
- messageSelector
- Only messages with properties matching the message selector expression are delivered to consumers. A value of null or an empty string indicates that all messages should be delivered.
- noLocal
- If set to true, this parameter prevents the delivery of messages published on the same connection as the durable subscriber.
Applications can use a two argument form of the createDurableSubscriber operation that takes only topic and subName parameters. This alternative call directly invokes the four argument version shown above, but sets messageSelector to null (so all messages are delivered) and sets noLocal to false (so messages published on the connection are delivered). For example, to create a durable subscription to the topic called myTopic, with the subscription name of mySubscription:
session.createDurableSubscriber(myTopic,"mySubscription");If the createDurableSubscription operation fails, it throws a JMS exception that provides a message and linked exception to give more detail about the cause of the problem.
To delete a durable subscription, an application uses the unsubscribe operation defined in the JMS API
In normal operation there can be at most one active (connected) subscriber for a durable subscription at a time. However, the subscriber application can be running in a cloned application server, for failover and load balancing purposes. In this case the "one active subscriber" restriction is lifted to provide a shared durable subscription that can have multiple simultaneous consumers.
For more information about application use of durable subscriptions, see the section "Using Durable Subscriptions" in the JMS specification.
- 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.
- 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, 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();- JMS applications using the default messaging provider can access, without any restrictions, the content of messages that have been received from WAS v5 embedded messaging or WebSphere MQ.
- JMS applications can access the full set of JMS_IBM* properties. These properties are of value to JMS applications that use resources provided by the default messaging provider, the V5 default messaging provider, or the WebSphere MQ provider.
For messages handled by WebSphere MQ, the JMS_IBM* properties are mapped to equivalent WebSphere MQ Message Descriptor (MQMD) fields. For more information about the JMS_IBM* properties and MQMD fields, see the Use Java section of the WebSphere MQ information center.
- JMS applications can use report messages as a form of managed request/response processing, to give remote feedback to producers on the outcome of their send operations and the fate of their messages. JMS applications can request a full range of report options using JMS_IBM_Report_Xxxx message properties. For more information about using JMS report messages, see JMS report messages.
- JMS applications can use the JMS_IBM_Report_Discard_Msg property to control how a request message is disposed of if it cannot be delivered to the destination queue.
- MQRO_Dead_Letter_Queue
- This is the default. The request message should be written to the dead letter queue.
- MQRO_Discard
- The request message should be discarded. This is usually used in conjunction with MQRO_Exception_With_Full_Data to return an undeliverable request message to its sender.
- Use a listener to receive messages asynchronously. In a client, not in a servlet or enterprise bean, 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 ... } }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 Java Message Service Documentation.
An alternative to developing your own JMS listener class, you can use a message-driven bean, as described in Program with message-driven beans.
- To use authentication with WebSphere MQ or the v5 Embedded Messaging support, 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.
- 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 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 if it is not committed or rolled back by the application.
- Clients cannot use 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.
- If you want the application to use WebSphere MQ as an external JMS provider, then send messages within a container-managed transaction.
When you use WebSphere MQ as an external JMS provider, messages sent within a user-managed transaction can arrive before the transaction commits. This occurs only when you use WebSphere MQ as an external JMS provider, and you send messages to a WebSphere MQ queue within a user-managed transaction. The message arrives on the destination queue before the transaction commits.
The cause of this problem is that the WebSphere MQ resource manager has not been enlisted in the user-managed transaction.
The solution is to use a container-managed transaction.
Related
JMS report messages
JMS interfaces - explicit polling for messages
Develop an enterprise application to use JMS
Develop a JMS client
Deploy an enterprise application to use JMS
Program to use JMS and messaging directly
Related
JMS interfaces
WebSphere MQ library