Overview  Developing EAServer messaging service applications

Chapter 31: Using the Message Service

Developing JMS applications

You can create a JMS application using either the point-to-point or the publish/subscribe messaging model. Both models support applications that are capable of:

You can download a copy of the JMS 1.0.2 API documentation from the Java Web site.


Creating a JMS InitialContext object

A JMS client application must instantiate a JMS InitialContext object and set these properties:

When instantiating a JMS InitialContext from a base client, specify the user name with the SECURITY_PRINCIPAL property, and specify the password with the SECURITY_CREDENTIALS property. The default for both properties is an empty string.

This example runs the JMS client application JMSClientClass and sets the InitialContext factory, URL, user name, and password properties at runtime:

java -D java.naming.factory.initial=com.sybase.jms.InitialContextFactory 
-Djava.naming.provider.url=iiop://stack:9000 
-DSECURITY_PRINCIPAL=”jagadmin” -DSECURITY_CREDENTIALS=”sybase”
JMSClientClass

Looking up a ConnectionFactory object

A connection factory allows you to create JMS connections and specify a set of configuration properties that define the connections. EAServer provides two types of connection factories, one to create queue connections and one to create topic connections. Queue connections allow you to send and receive messages using the PTP messaging model. Topic connections allow you to publish and receive messages using the Pub/Sub messaging model. EAServer provides two preconfigured connection factories that you can use javax.jms.QueueConnectionFactory and javax.jms.TopicConnectionFactory. To create connection factories, use EAServer Manager—see Chapter 8, “Setting up the Message Service,” in the EAServer System Administration Guide for details. Once you have created a connection factory, client applications must look up a ConnectionFactory object using JNDI, as in this example:

// Look up a queue connection factory

QueueConnectionFactory queueCF =
 (QueueConnectionFactory) ctx.lookup(“MyTestQueueCF”);

// Look up a topic connection factory

TopicConnectionFactory topicCF =
 (TopicConnectionFactory) ctx.lookup(“MyTestTopicCF”);

If the connection factory cannot be found, EAServer throws a javax.naming.NamingException.


Creating permanent destinations

Permanent destinations are message queues or topics whose configuration properties are stored in a database. You can create permanent destinations two ways. The recommended way is to use EAServer Manager to create and configure message queues and topics. See Chapter 8, “Setting up the Message Service,” in the EAServer System Administration Guide for information on how to do this. You can also create permanent destinations using the JMS APIs createQueue and createTopic. Sybase suggests that you use this option only when client applications need the ability to dynamically change the provider-specific destination name; applications using this technique are not portable.

When you create message queues and topics using EAServer Manager, client applications can use their InitialContext object to look up the destinations; for example:

// Look up a message queue

javax.jms.Queue queue = 
   (javax.jms.Queue) ctx.lookup(“MyQueue”);

// Look up a topic

javax.jms.Topic topic =
   (javax.jms.Topic) ctx.lookup(“MyTopic”);

To create permanent destinations using the JMS APIs, you must first create a session; see “Creating sessions” for details. Once you have access to a session object, use this syntax to create a destination:

javax.jms.Queue queue =
   queueSession.createQueue(“MyQueue”);

javax.jms.Topic topic =
   topicSession.createTopic(“MyTopic”);

Temporary destinations

You can also create temporary destination objects that are active only during the lifetime of a session. When the session is closed, temporary destination objects and their associated messages are discarded. These two lines illustrate how to create temporary message queue and topic destinations:

// Create a temporary queue

javax.jms.Queue queue =
   queueSession.createTemporaryQueue();

// Create a temporary topic

javax.jms.Topic topic =    topicSession.createTemporaryTopic();

By default, temporary message queues time out after 60 seconds of inactivity. To increase this value, you can do one of two things:

Chapter 8, “Setting up the Message Service,” in the EAServer System Administration Guide describes these settings in detail.


Creating connections

JMS provides two types of connections, one for message queues and one for topics. To create a connection from a JMS client application to EAServer, you must have access to a ConnectionFactory object. See “Looking up a ConnectionFactory object”. Once you have created a connection, you must explicitly start it before EAServer can deliver messages on the connection. To avoid message delivery before a client has finished setting up, you may want to delay starting the connection. This code fragment creates a QueueConnection object and starts the connection:

QueueConnection queueConn =
   queueCF.createQueueConnection();

// other setup procedures

queueConn.start();

This sample creates a connection object for a topic and starts the connection:

TopicConnection topicConn = 
   topicCF.createTopicConnection();

// other setup procedures

topicConn.start();

You can also stop delivery of messages using the QueueConnection.stop method, then use start to resume delivery. While a connection is stopped, receive calls do not return with a message, and messages are not delivered to message listeners. Any calls to receive or message listeners that are in progress when stop is called, complete before the stop method returns.

With a single connection to EAServer, the message service can send and receive multiple messages. Therefore, a JMS client usually only needs one connection.

Setting the client ID

A connection for a durable topic subscriber must have a client ID associated with it so that EAServer can uniquely identify a client if it disconnects and later reconnects. You can use EAServer Manager to set the client ID when you create the topic connection factory; see Chapter 8, “Setting up the Message Service,” in the EAServer System Administration Guide. If you do not set the client ID in the connection factory, you must set it immediately after creating the connection and before performing any other action on the connection. After this point, attempting to set the client ID throws an IllegalStateException. This code fragment illustrates how to set a topic connection’s client ID:

topicConn.setClientID(“Client ID String”);

For more information about topic subscribers, see “Creating message consumers”.

ExceptionListener

To enable EAServer to asynchronously notify clients of serious connection problems, create and register an ExceptionListener. The javax.jms.ExceptionListener must implement this method:

void onException(JMSException exception);

To register a listener, call the Connection::setExceptionListener method, for example:

queueConn.setExceptionListener(MyExceptionListener);

If an exception occurs and a listener has been registered, EAServer calls the onException method and passes the JMSException, which describes the problem.


Creating sessions

Once a client has established a connection with EAServer, it needs to create one or more sessions. A session serves as a factory for creating message producers, message consumers, and temporary destinations. JMS provides two types of session objects, one for queue connections and one for topic connections. To create a QueueSession object, use a previously created QueueConnection object as follows:

QueueSession queueSession =   queueConn.createQueueSession(true,
                            Session.AUTO_ACKNOWLEDGE);

To create a TopicSession object, use a previously created TopicConnection object as follows:

TopicSession topicSession =   topicConn.createTopicSession(true,
                            Session.AUTO_ACKNOWLEDGE);

When you create a session, set the first parameter to true if you want a transacted session. When you publish or send a message in a transacted session, the transaction begins automatically. Once a transacted session starts, all messages published or sent in the session become part of the transaction until the transaction is committed or rolled back. When a transaction is committed, all published or sent messages are delivered. If a transaction is rolled back, any messages produced in the session are destroyed, and any consumed messages are recovered. When a transacted session is committed or rolled back, the current transaction ends and the next transaction begins. See Chapter 2, “Understanding Transactions and Component Lifecycles” for more information about transactions.

Set the first parameter to false when you do not want a transacted session. If a client has an active transaction context, it can still determine transactional behavior, even if it does not create a transacted session.

The second parameter indicates whether the message producer or the consumer will acknowledge messages. This parameter is valid only for nontransacted sessions. In transacted sessions, acknowledgment is determined by the outcome of the transaction.

Acknowledgment mode

Description

AUTO_ACKNOWLEDGE

The session automatically acknowledges messages.

CLIENT_ACKNOWLEDGE

The client explicitly acknowledges a message, which automatically acknowledges all messages delivered in the session.

DUPS_OK_ACKNOWLEDGE

EAServer implements this the same as AUTO_ACKNOWLEDGE.

Session::recover

To stop message delivery within a session and redeliver all the unacknowledged messages, you can use the Session.recover method. When you call recover for a session, the message service:

The method can be called only by a non-transacted session; it throws an IllegalStateException if it is called by a transacted session.


Creating message producers

Create message producers for sending and publishing messages. JMS defines two message producer objects, a QueueSender, used to send messages, and a TopicPublisher, used to publish messages. To create a QueueSender object, use a previously created QueueSession object and this syntax:

javax.jms.QueueSender sender = queueSession.createSender(queue);

To create a TopicPublisher object, use a previously created TopicSession object and this syntax:

javax.jms.TopicPublisher publisher = topicSession.createPublisher(topic)

Creating message consumers

Message consumers can be either QueueReceiver or TopicSubscriber objects. Create a QueueReceiver to retrieve messages that are sent using the PTP messaging model. Use previously created Queue and QueueSession objects, as follows:

javax.jms.QueueReceiver receiver =
   queueSession.createReceiver(queue);

A TopicSubscriber object receives published messages and can be either durable or nondurable. A nondurable subscriber can only receive published messages while it is connected to EAServer. If you want guaranteed message delivery, make the subscriber durable. For example, if you create a durable subscription on a topic, EAServer saves all published messages for the topic in a database. If a durable subscriber is temporarily disconnected from EAServer, its messages will be delivered when the subscriber is reconnected. The messages are deleted from the database only after they are delivered to the durable subscriber.

This example illustrates how to create both durable and nondurable topic subscribers. In both cases, you need to reference previously created Topic and TopicSession objects:

// Create a durable subscriber

javax.jms.TopicSubscriber subscriber = 
   topicSession.createDurableSubscriber(topic,
                                   “subscriptionName”)

// Create a non-durable subscriber

javax.jms.TopicScuscriber subscriber =
   topicSession.createSubscriber(topic);

To remove a durable topic subscription, call the TopicSession.unsubscribe method, and pass in the subscription name; for example:

topicSession.unsubscribe(“subscriptionName”);

Filtering messages using selectors

You can use selectors to specify which messages you want delivered to a message queue. Once you add a selector to a queue, the message service delivers only those messages whose message topic matches the selector. You can create message selectors using EAServer Manager—see Chapter 8, “Setting up the Message Service,” in the EAServer System Administration Guide. You can also create message selectors programmatically. This example illustrates how to create a message selector and use it when you are creating a new QueueReceiver:

// Create a selector to receive only Text messages
// whose value property equals 100.

String selector = “value = 100 and Type = TextMessage”;

// Create a queue receiver using the selector.

QueueReceiver receiver =
   queueSession.createReceiver(queue, selector);

This code sample sends two messages to the message queue we just created. The properties of the first message match those of the message queue’s selector. The properties of the second message do not.

// Create and send a message whose properties match 
// the message queue selector.

TextMessage textMsg =
   queueSession.createTextMessage(“Text Message”);
textMsg.setIntProperty(“Value”, 100);
textMsg.setStringProperty(“Type”, “TextMessage”);
sender.send(textMsg);

// Create and send a Bytes message, whose value 
// property equals 200.

BytesMessage bytesMsg =
   queueSession.createBytesMessage();
bytesMsg.setIntProperty(“Value”, 200);
bytesMsg.setStringProperty(“Type”, “BytesMessage”);
sender.send(bytesMsg);

When we retrieve messages from the message queue, the Text message will be returned but the Bytes message will not.


Implementing and installing message listeners

Message listeners allow you to receive messages asynchronously. Once you have implemented a listener, install it on a message consumer. When a message is delivered to the message consumer, the listener can send the message to other consumers or notify one or more components.

JMS message listeners implement the javax.jms.MessageLintener interface and can be either client-side listener objects or EJB 2.0 message-driven beans (MDB). The MessageListener interface contains only the onMessage method. This example illustrates the skeleton code for a message listener:

class QueueMessageListener implements MessageListener
{
   public void onMessage(javax.jms.Message msg)
   {
      // process message, notify component
   }
}

You can use EAServer Manager to install a message listener on a message queue or topic—see “Installing and configuring an MDB”. You can also install a message listener within your application. First create a message consumer, see “Creating message consumers”, then install the listener, using this syntax:

receiver.setMessageListener(new QueueMessageListener());

Message-driven beans

An MDB is a type of Enterprise JavaBean (EJB) specifically designed as a JMS message consumer. You can install an MDB as a message listener on a message queue or topic.

When an MDB is installed as a listener on a message consumer and a JMS message arrives, EAServer instantiates the MDB to process the message. An MDB must implement the MessageDrivenBean interface, which consists of these methods:

Method name

Description

ejbCreate

Creates an instance of an MDB.

setMessageDrivenContext

Associates an MDB instance with its context, which EAServer maintains. This provides the MDB instance access to the MessageDrivenContext interface.

ejbRemove

Notifies the MDB instance that it is being removed and should release its resources.

An MDB instance with container-managed transactions can call these MessageDrivenContext interface methods:

Method name

Description

setRollbackOnly

To specify that the current transaction must be rolled back.

getRollbackOnly

To test whether the current transaction has been marked to roll back.

getUserTransaction

Returns the javax.transaction.UserTransaction interface, with which the MDB can set and obtain transaction status.

Unlike other EJBs, message-driven Beans do not have a home or remote interface, and clients cannot directly access an MDB. EAServer calls the onMessage method of the javax.jms.MessageListener interface to notify an MDB that a message has been delivered to the queue or topic on which it is installed. To prevent client access to the onMessage method, this component property is set automatically when you install and configure an MDB:

com.sybase.jaguar.component.roles = onMessage(security-roles=ServiceControl)

StepsInstalling and configuring an MDB

  1. Create a new EJB component, as described in Chapter 7, “Creating Enterprise JavaBeans Components.”

    NoteYou do not need to define remote or local interfaces.

  2. On the General tab, supply these values:

  3. On the MDB Type tab, enter:

  4. On the Transactions tab:

    “Component properties: Transactions” describes the options on this tab.

  5. On the Run-As Mode tab, define the identity properties used for intercomponent calls. “Component properties: Run-As Mode” describes this tab in detail. If you do not specify a Run As Mode, the default value for an MDB is “System.”

  6. Optionally specify a retry timeout. If your MDB throws an exception while processing a message, EAServer can retry delivery for the time period you specify. By default, EAServer does not retry delivery. To configure this setting:

    1. Enable the Automatic Failover option on the Transactions tab.

    2. On the Advanced tab, set the property com.sybase.jaguar.component.retry.timeout to the number of seconds that EAServer should retry delivery. EAServer retries at intervals that increase by about one second after each failure; that is, after one second, again after 3 seconds, again after 6 seconds, and so forth.

  7. Similar to other EJBs, you can enter information on these tabs, but it is not required. For more information, see:

    Tab

    Description link

    Instances

    “Component properties: Instances”

    Resources

    “Component properties: Resources”

    EJB References

    “EJB references”

    EJB Local References

    “EJB local references”

    Environment

    “Environment properties”

    Resource References

    “Resource references”

    Resource Environment References

    “Resource environment references”

    Role References

    “Configuring role references and method permissions”

    Java Classes

    Chapter 30, “Configuring Custom Java Class Lists”

    Additional Files

    “Component properties: Additional Files”

Running the sample JMS client and MDB

EAServer includes a sample JMS client and MDB listener. For more information, see “Using message-driven beans and JMS” in Chapter 5, “Using the EAServer Samples,” in the EAServer Cookbook.

Related chapters

For information about Enterprise JavaBeans, see these chapters:


Creating messages

To create a message, you must first create an instance of either a queue or topic session. See “Creating sessions” for details. To create a text message, use this syntax:

// Create a text message using a QueueSession

javax.jms.TextMessage queueTextMsg =
   queueSession.createTextMessage(“Text message”);

// Create a text message using a TopicSession

javax.jms.TextMessage topicTextMsg = 
   topicSession.createTextMessage(“Text message”);

EAServer supports six message types that a message producer can send or publish. Table 31-1 describes the message types and the javax.jms.Session interface APIs used to create instances of each.

Table 31-1: JMS message types

Message type

Create message API

Comments

Plain

Session.createMessage

Creates a message without a message body.

Text

Session.createTextMessage

Creates a message that can contain a string in the message body.

Object

Session.createObjectMessage

Creates a message that can contain a serializable Java object in the message body.

Stream

Session.createStreamMessage

Creates a message that can contain a stream of Java primitives in the message body. Fill and read the message sequentially.

Map

Session.createMapMessage

Creates a message whose body can contain a set of name-value pairs where names are Strings and values are Java primitive types.

Bytes

Session.createBytesMessage

Creates a message that can contain a stream of uninterpreted bytes in the message body.

To improve interoperability with non-Java clients or components and to improve message receivers’ ability to filter messages, Sybase recommends that you use either plain messages or text messages. Selectors allow you to filter messages based on the text in the message properties. You cannot filter messages based on the text in the message body. Therefore, message text in the message properties, instead of the message body, enables the message receivers to filter messages more efficiently.

For more information about the message types, see the JMS API documentation.


Sending messages

To send a message, you must specify the destination message queue. The message service notifies listeners that are registered for the queue and the message remains in the queue until it is received and acknowledged.

Figure 31-1: Send message flow

Figure 31-1illustrates the message flow that occurs when a client or component sends a message.

This example notifies a client of a completed order; it creates a new message, constructs the message text, and sends the message to the client’s queue:

public void notifyOrder(QueueSession qSession,
                        Queue queue, 
                        int orderNo, 
                        String product)
{
   String time = new java.util.Date().toString();
   String text = "Order " + orderNo + " for product " + product + 
      " was completed at " + time;

   javax.jms.QueueSender sender = qSession.createSender(queue);
   javax.jms.TextMessage textMsg = qSession.createTextMessage(text);

   textMsg.setStringProperty(“ProductDescription”, product);
   textMsg.setIntProperty(“OrderNumber”, orderNo);

   sender.send(textMsg);
}

Publishing messages

When you publish a message, a copy is sent to all topic subscribers that have a message selector registered with the specified topic. Figure 31-2 illustrates the message flow when a client or component publishes a message.

Figure 31-2: Publish message flow

This example publishes a message that notifies clients of changes in a stock value; it creates the message text, creates a TopicPublisher and the message using the TopicSession object, and publishes the message:

public void notifyStockValue(TopicSession tSession, 
                             Topic topic, 
                             String stock, 
                             double value)
{
   String time = new java.util.Date().toString();
   String text = time + ": The stock " + stock + " has value " + value;

   // Create the publisher and message objects.

   javax.jms.TopicPublisher publisher = tSession.createPublisher(topic);
   javax.jms.TextMessage textMsg = tSession.createTextMessage(text);

   
   // Publish a non-persistent message with a priority of 9 and a 
   // lifetime of 5000 milliseconds (5 seconds)

   publisher.publish(textMsg, DeliveryMode.NON_PERSISTENT, 9, 5000);
}

To publish a persistent message using the default priority (4) and timeout (never expires) values, use this syntax:

publisher.publish(textMsg);

Receiving messages

You can receive messages either synchronously or asynchronously. To receive messages synchronously (get all the messages at one time), call the receive method for the message consumer. The following code samples illustrate how to receive all the messages from a queue, using three different timeout options:

// Get all the messages from the queue. If none exists,
// wait until a message arrives.

javax.jms.TextMessage queueTextMsg =
   (javax.jms.TextMessage) receiver.receive();

// Get all the messages from the queue. If none exists,
// wait 5000 milliseconds (5 seconds) or until a message
// arrives, whichever comes first.

javax.jms.TextMessage queueTextMsg =
   (javax.jms.TextMessage) receiver.receive(5000);

// Get all the messages from the queue. If none exists,
// return NULL.

javax.jms.TextMessage queueTextMsg =
   (javax.jms.TextMessage) receiver.receiveNoWait();

To receive messages asynchronously, implement a message listener and install it on the message consumer, either a topic or a queue. See “Implementing and installing message listeners”.

For information about creating message queues and topics, see “Creating message consumers”.


Browsing messages

You can look at messages in a queue without removing them using the QueueBrowser interface. You can browse through all the messages in a queue, or through a subset of the messages. To browse through a queue’s messages, create an instance of a QueueBrowser object using a previously created QueueSession object. To create a browser for viewing all the messages in a queue, call createBrowser and pass the message queue:

javax.jms.QueueBrowser qbrowser =
   queueSession.createBrowser(queue);

To create a browser for viewing a subset of the messages in a queue, call createBrowser and pass the message queue and a message selector string:

javax.jms.QueueBrowser qbrowser =
   queueSession.createBrowser(queue, selector);

For information about message selectors, see “Filtering messages using selectors”.

Once you have access to the QueueBrowser object, call getEnumeration, which returns an Enumeration that allows you to view the messages in the order that they would be received:

java.util.Enumeration enum = qbrowser.getEnumeration();

Enabling JMS tracing

To help debug your JMS client application, you can enable tracing by setting the com.sybase.jms.debug property to true in the InitialContext object. When you enable tracing, diagnostic messages are printed in the console window. By default, tracing is disabled. This code sample illustrates how to set the tracing property:

Properties prop = new Properties();

prop.put(“com.sybase.jms.debug”, “true”);
javax.naming.Context ctx = 
   new javax.naming.InitialContext(prop);

Closing connections, sessions, consumers, and producers

The JMS server allocates resources for each of these objects: connections, sessions, message consumers, and message producers. When you no longer need one of these objects, you should close it to release its resources and help the application run more efficiently. To release each object’s resources, EAServer provides these methods:


JMS interfaces not supported

EAServer does not support these JMS interface methods:

JMS interface

Method

javax.jms.Session

  • run

  • setMessageListener

  • getMessageListener

javax.jms.QueueConnection

  • createConnectionConsumer

javax.jms.TopicConnection

  • createConnectionConsumer

  • createDurableConnectionConsumer

In addition, EAServer does not support these JMS interfaces:

NoteEAServer supports the XA interfaces that are required to support two-phase commit and the XA transaction coordinator for JMS clients and components.





Copyright © 2005. Sybase Inc. All rights reserved. Developing EAServer messaging service applications