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.
A JMS client application must instantiate a JMS InitialContext object and set these properties:
InitialContext factory – set java.naming.factory.initial
to “com.sybase.jms.InitialContextFactory”
.
URL – set java.naming.provider.url
to
the location where the client can connect to EAServer.
User name – valid for a connection with EAServer.
Password – valid for the user name.
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
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.
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”);
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:
Set the connection factory’s CONFIG_QUEUE property to the name of a message queue with a reasonably high timeout value. Subsequently, each temporary message queue you create that uses this connection factory inherits the properties of the queue assigned to CONFIG_QUEUE.
Set the value at the global level so all temporary
message queues use the same timeout value. To do this, edit the MessageServiceConfig.props file, located
in the EAServer /Repository/Component/CtsComponents directory,
and set the session.timeout
property
to the appropriate number of seconds.
Chapter 8, “Setting up the Message Service,” in the EAServer System Administration Guide describes these settings in detail.
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.
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”.
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.
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. |
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:
Stops message delivery within the session.
Marks all unacknowledged messages “redelivered”, including those that have been delivered.
Restarts sending all unacknowledged messages, beginning with the oldest message.
The method can be called only by a non-transacted session; it throws an IllegalStateException if it is called by a transacted session.
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)
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”);
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.
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());
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)
Installing
and configuring an MDB
Create a new EJB component, as described in Chapter 7, “Creating Enterprise JavaBeans Components.”
You do not need to define remote or local interfaces.
On the General tab, supply these values:
Description – summarize the bean’s purpose.
Component Type – select EJB - Message Driven Bean from the drop-down list.
EJB Version – choose 2.0.
MDB Class – enter the name of the Java class that implements the MDB; for example com.sybase.jaguar.myPkg.MyBeanImpl.
On the MDB Type tab, enter:
Destination Type – choose either Queue or Topic.
Name – enter the name of the destination queue or topic.
Listener – enter the package and component
name for the MDB listener; for example, MyPkg/MyBeanImpl
.
To specify a thread pool, append the thread pool name in square
brackets, for example, MyPkg/MyBeanImpl[MyThreadPool]
.
You can create thread pools in EAServer Manager as described in Chapter 8, “Setting up the Message Service,” in the EAServer System Administration Guide. The thread pool must have one or more worker threads. A thread pool with multiple worker threads enables the message listener to process multiple messages at the same time. If you do not specify the name of a thread pool, the message listener uses the <system> default thread pool, which has a single worker thread.
Acknowledge Mode – choose either Auto or Dups-ok. For an explanation of the acknowledgment modes, see “Creating sessions”.
Message Selector – if the destination type is a queue, enter a message selector to filter incoming messages; for example, to receive all published messages with the topic “StockPrice.SY”, enter:
topic = ‘StockPrice.SY’
Subscription/Durability – if the destination type is a topic, select either Durable or Non-durable. For a description of these options, see “Creating message consumers”.
On the Transactions tab:
Select one of Not Supported, Required, or Bean Managed.
Optionally, select Automatic Failover.
“Component properties: Transactions” describes the options on this tab.
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.”
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:
Enable the Automatic Failover option on the Transactions tab.
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.
Similar to other EJBs, you can enter information on these tabs, but it is not required. For more information, see:
Tab |
Description link |
---|---|
Instances |
|
Resources |
|
EJB References |
|
EJB Local References |
|
Environment |
|
Resource References |
|
Resource Environment References |
|
Role References |
|
Java Classes |
|
Additional Files |
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.
For information about Enterprise JavaBeans, see these chapters:
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.
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.
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); }
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);
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”.
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();
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);
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:
QueueConnection.close
TopicConnection.close
QueueSession.close
TopicSession.close
QueueReceiver.close
TopicSubscriber.close
QueueSender.close
TopicPublisher.close
EAServer does not support these JMS interface methods:
JMS interface |
Method |
---|---|
javax.jms.Session |
|
javax.jms.QueueConnection |
|
javax.jms.TopicConnection |
|
In addition, EAServer does not support these JMS interfaces:
javax.jms.XAQueueConnection
javax.jms.XATopicConnection
javax.jms.XAQueueConnectionFactory
javax.jms.XATopicConnectionFactory
javax.jms.XASession
javax.jms.XAQueueSession
javax.jms.XATopicSession
javax.jms.XAConnection
javax.jms.XAConnectionFactory
javax.jms.ServerSession
javax.jms.ServerSessionPool
javax.jms.ConnectionConsumer
EAServer 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. |
![]() |