Using WebLogic JMS
I. IntroductionWebLogic JMS overviewJava Message Service (JMS) allows Java programs to exchange messages with other Java programs sharing a messaging system. A messaging system accepts messages from "producer" clients and delivers them to "consumer" clients. Messaging systems, sometimes called Message-Oriented Middleware (MOM) products, enable Java clients to use their services by supplying a Java layer called a JMS Provider, which implements JMS for the specific product. WebLogic JMS implements the JavaSoft JMS specification version 1.0.1. WebLogic JMS includes a full-featured messaging system, which can be configured by setting properties in the weblogic.properties file, from the WebLogic Console, or programmatically, using the JMS interfaces. Configuration properties are described in the Configuring WebLogic JMS section of this document. You can use WebLogic JMS with the other WebLogic Server APIs and facilities, such as Enterprise Java Beans (EJBeans), JDBC connection pools, Servlets, and RMI. JMS operations can participate in transactions with other Java APIs that use the Java Transaction API. WebLogic JMS has some similarities to WebLogic Events, a proprietary publish/subscribe (pub/sub) messaging system implemented prior to the release of the JMS specification. Below is a summary of the main areas in which these systems differ. Refer to the appropriate Developer Guide for more information on these features.
JMS messaging modelsJMS supports two messaging models: point-to-point (PTP) and publish/subscribe. The terms "message producer" and "message consumer" describe clients that send and receive messages in either of the models, although each model has its own specific terms for producers and consumers.
The PTP and pub/sub messaging models are very similar. They are implemented with classes that extend common root classes. For example, the PTP javax.jms.Queue class and the pub/sub javax.jms.Topic class each extend a common javax.jms.Destination class. Messages can be NON-PERSISTENT or PERSISTENT. NON-PERSISTENT messages are not stored in a database, and may be lost during a failure. JMS specifies that a NON-PERSISTENT message will be delivered at most once. A PERSISTENT message is not considered sent until it has been stored in the database. JMS guarantees that PERSISTENT messages are delivered at least once. WebLogic JMS writes PERSISTENT messages to database via a JDBC connection pool assigned to JMS in the weblogic.properties file. JMS objectsYou use the javax.jms client APIs in your JMS client applications. You retrieve the initial JMS object, a ConnectionFactory, using WebLogic JNDI. The Topics and Queues your application uses are also retrieved through JNDI. An administrator defines ConnectionFactories, Topics, and Queues in the weblogic.properties file, and the WebLogic Server adds them to the JNDI space during startup. WebLogic JMS provides default connection factories, so it is not necessary to define connection factories for most applications. See Configuring WebLogic JMS for information about defining JMS objects in the weblogic.properties file. The steps for setting up a JMS client are presented in Implementing with WebLogic JMS. The next sections describe the behaviors and features of the main JMS objects. ConnectionsA Connection represents an open connection to the messaging system. It creates the associated server-side and client-side objects that manage the state of the JMS connection. It also creates Sessions, objects that manage the active exchange of messages between the client and the messaging system. Connections are created by a ConnectionFactory obtained with a JNDI lookup. The ConnectionFactory and Connection classes for the two JMS messaging models extend ConnectionFactory and Connection:
In the WebLogic Server, JMS traffic is multiplexed with the other WebLogic services on the client connection to the server. No additional TCP/IP connections are created for JMS. Servlets and other server-side objects may also obtain JMS Connections. A Connection may contain a client identifier that is used for clients with durable subscriptions. Durable subscriptions are a feature unique to the pub/sub messaging model, so client IDs are only of consequence with TopicConnections; QueueConnections also contain Client IDs, but JMS does not use them. The client ID can be supplied in two ways:
Note that the JMS client ID is not equivalent to the WebLogic Server username used to authenticate a user in the WebLogic security realm. You can, of course, use the WebLogic username for the JMS client ID if it is appropriate for your JMS application.
A newly created Connection is stopped -- no messages are received
until the Connection is started. Typically, the other JMS objects are
set up to handle messages before the Connection is started.
Messages may be produced on a stopped Connection, but cannot be
delivered to a stopped connection.
A JMS Session is a context for producing and consuming messages. A Session creates MessageProducers and MessageConsumers, the objects that transmit and receive messages. A Session can also create a temporary Queue or Topic, which exists only for the duration of the session. Sessions are created by the JMS Connection. QueueConnections create QueueSessions and TopicConnections create TopicSessions. Sessions can be transacted. A transacted Session has one active transaction at a time. Messages sent or received during a transaction are treated as an atomic unit. If the client rolls back the transaction, the messages it received during the transaction are not acknowledged and messages it sent are discarded. When a client commits a transaction, all of the messages received during the transaction are acknowledged by the messaging system and messages it sent are accepted for delivery. JMS can participate in distributed transactions with other Java services that use the Java Transaction Service (JTS), such as EJB. The javadocs for JTS are on the JavaSoft website. To guarantee that messages are delivered, Sessions retain received messages until the receiving client acknowledges them. When a Session is transacted, the acknowledgement is automatic -- a side effect of committing the transaction. In non-transacted Sessions, the client creating the Session selects one of three acknowledgement modes. The most efficient in terms of resource usage is DUPS_OK_ACKNOWLEDGE, which allows the session to "lazily" acknowledge receipt on behalf of the client. This mode can result in duplicate messages if there is a failure and you should avoid it if your application is not able to handle duplicates. If you create a Session with AUTO_ACKNOWLEDGE, the Session acknowledges receipt of a message when the client method that receives the message has returned from processing it. A Session created with CLIENT_ACKNOWLEDGE relies on the client to call an acknowledge method on a received message. Once this method is called, the Session acknowledges all messages received since the last acknowledgement. This allows the client to receive and process a batch of messages and then acknowledge them all with one call. Destinations -- Queues and TopicsJMS Queues and Topics extend javax.jms.Destination. Queues manage messages for the point-to-point messaging model and Topics manage messages for the publish/subscribe model. Client programs retrieve Queues and Topics with JNDI. Like ConnectionFactories, Queues and Topics can be configured in the weblogic.properties file, in the WebLogic Console, or programmatically by using JMS interfaces. As part of their configuration in the weblogic.properties file and in the WebLogic Console, Queues and Topics are automatically bound to JNDI names. If configured programmatically, the message destinations must be bound explicitly using the appropriate JNDI interface. Clients can also create temporary Queues and Topics that exist only for the duration of the JMS connection in which they are created. On the client side, Queue and Topic objects are handles to the object on the server. Their only methods simply return their names. To access them for messaging, you create message producers and consumers that attach to them. MessageProducers and MessageConsumersThe Session object creates message senders and receivers attached to Queues and Topics. The message sender/receiver objects are subclassed from the MessageProducer and MessageConsumer classes. A MessageProducer sends messages to a Queue or Topic. A MessageConsumer receives messages from a Queue or Topic. The point-to-point and pub/sub messaging models have different names for these objects, as this table shows:
The QueueReceiver and TopicSubscriber objects can be created with a message selector that specifies which messages are to be delivered to the client. The selector is a String patterned after the WHERE clause of an SQL SELECT statement. The selector filters messages based on values of properties that are set in the message. Selectors are discussed in Using message selectors. The client can request that messages be delivered synchronously or asynchronously. If synchronous, the client calls a receive() method on the QueueReceiver or TopicSubscriber and blocks until a message arrives. If asynchronous, the client provides an implementation of the JMS MessageListener interface. When a message arrives, the onMessage() method of that implementation is called to receive the message. With the point-to-point model, clients have the option of browsing queues by creating a QueueBrowser object in their QueueSession. This object produces an enumeration of the messages in the queue at the time the QueueBrowser is created -- a snapshot. The client can view the messages in the queue, but the messages are not considered "read" or removed from the queue. There can be multiple Sessions with QueueReceivers for the same Queue. However, a message can only be delivered to one QueueReceiver. JMS does not specify which QueueReceiver will receive a message when there are multiple candidates. With the publish/subscribe model, messages are delivered to multiple TopicSubscribers. TopicSubscribers can be non-durable or durable. With non-durable TopicSubscribers, messages are only delivered to clients with an active Session. Messages sent to a Topic while a client is not listening are never seen by that client. With a durable subscription, WebLogic JMS stores messages in a database until the message has been delivered to all durable subscribers or has expired. The subscriptions, too, are stored in the database. The client can modify a durable subscription by creating a new one with the same client ID. To delete a durable subscription, the TopicSession has an unsubscribe() method. Another particular feature of the publish/subscribe model is that a client can have a JMS connection in which it both publishes to and subscribes to the same Topic. Since Topic messages are delivered to all subscribers, the client can receive messages it has published itself. A JMS client can set a NoLocal attribute on the TopicSubscriber to prevent WebLogic JMS from delivering messages sent from its own connection. Messages
A JMS message (javax.jms.Message) contains a set of standard header
fields, application-specific properties, and a message body.
JMS Messages contain a standard set of headers that are always transmitted with the message. They are available to message consumers that receive messages and some fields can be set by the message producers that send messages.
Message property fieldsThe property fields section of a Message contains additional header fields added by the sending client. The properties are standard Java name/value pairs. The values can be boolean, byte, short, int, long, float, double, and String data types.
Although message property fields may be used for application-specific
purposes, JMS provides them primarily for use in message
selectors. Message selectors allow clients to choose the messages they
want to receive by providing a simple query string. The sending
client can set message property fields to describe or classify a
message in a standardized way so that interested receivers can choose
it with their message selector. Since message selectors cannot
reference the contents (body) of a message, some
fields from the message contents may be duplicated as message property
fields.
The Message body contains the message content. JMS defines six message types:
Configuring WebLogic JMSThe WebLogic Server has built-in defaults for JMS, so you can use some JMS features without any special configuration. To use persistent messages or durable subscriptions, or to set up custom JMS applications the WebLogic administrator can perform any of these configuration tasks:
Once these steps are completed, JMS clients can begin sending and receiving messages through the JMS API. You can use the WebLogic Console to perform most of this work. The Console lists JMS objects that have been created, allows you to create factories, Topics, and Queues. You can also initialize a database for JMS, which creates the JMS system tables. The weblogic.properties file included in the WebLogic distribution has a section for WebLogic JMS properties, including properties you need to execute the JMS examples. Before you start the WebLogic Server, search the properties file for "WEBLOGIC JMS" and uncomment the properties for the examples you want to try. Also, you need a JDBC connection pool for some examples. Search for "DEMO CONNECTION POOL" to find the properties that define a connection pool on a Cloudscape database that is initialized for JMS.
Create a JMS databaseJMS stores persistent messages in a database, accessed through a JDBC connection pool, which you define in the weblogic.properties file. If you do not use persistent messages, you do not need to assign a connection pool for JMS. The JMS connection pool can use any database that you can access through a JDBC driver. WebLogic provides JDBC drivers for Oracle, Microsoft SQL Server, and Informix Dynamic Server. If the database can store Java objects directly (Cloudscape, for example) then JMS stores messages in the database as Java objects. Otherwise, Message objects are serialized and stored in a blob (or database vendor equivalent type) column. Important: If you combine JMS and EJBs in an application, and require operations on both within the same transaction, both must use the same database connection pool. See Using transactions with JMS for more information about developing JMS applications that use transactions. The JMS examples are set up to work with the Cloudscape Java database. An evaluation version of Cloudscape is included in your WebLogic distribution and a "demo" database containing the JMS system tables is provided. The JMS database contains five system tables, used internally by JMS. You can create the tables using the WebLogic Console or using the utils.Schema utility. The utils.Schema utility is a Java program that takes command line arguments to specify the JDBC driver, database connection information and the name of a file containing the semicolon-terminated SQL Data Definition Language (DDL) commands that create the database tables. By convention, the DDL file has a .ddl extension. We have included DDL files for Cloudscape, MSSQL Server, IBM DB2, and Oracle databases. To execute utils.Schema, your CLASSPATH must contain the weblogic/classes directory. Here is the syntax for the utils.Schema command: java utils.Schema url JDBC_driver [options] DDL_file
Here is a utils.Schema command to create the JMS tables in an Oracle server named DEMO, with the username "scott" and password "tiger": java utils.Schema jdbc:weblogic:oracle:DEMO \ weblogic.jdbc.oci.Driver -u scott -p tiger -verbose \ /weblogic/classes/weblogic/jms/ddl/jms_oracle.ddl With the Cloudscape database, no username or password are required. However, the Cloudscape JDBC driver uses the cloudscape.system.home system property to find the directory containing its database files. You supply the value for this property with the -D Java command option. Also, you must have the Cloudscape classes in your CLASSPATH. If you are using the evaluation version of Cloudscape, add weblogic/eval/cloudscape/lib/embeddedJBMS.zip to your CLASSPATH before you execute utils.Schema. Here is the utils.Schema command for Cloudscape: java -Dcloudscape.system. home=/weblogic/eval/cloudscape/data \ utils.Schema jdbc:cloudscape:demoPool;create=true \ COM.cloudscape.core.JDBCDriver -verbose \ /weblogic/classes/weblogic/jms/ddl/jms_cloudscape.ddl The Cloudscape JDBC URL specifies the demo database, which is included in the WebLogic distribution. The JMS tables have already been created in this database. Running the utils.Schema command will drop the tables and recreate them. If you are using JMS and EJB together in transactions, you should create the JMS tables in the same database you use for EJB persistence. You define a single JDBC connection pool and then assign both EJB and JMS to that connection pool, as described in the next section. Define a JMS connection poolDefine a JDBC pool in the weblogic.properties file to provide access to the database. If you do not use persistent messages with JMS, you do not need to set up a connection pool for JMS. If you have already set up a pool for EJB persistence, you do not need to add another, but you must set the weblogic.jms.connectionPool shown below to the name of your EJB connection pool. Here is an example JDBC connection pool definition using the Cloudscape JDBC driver: weblogic.jdbc.connectionPool.demoPool=\ url=jdbc:cloudscape:demo;create=true;autoCommit=false,\ driver=COM.cloudscape.core.JDBCDriver,\ initialCapacity=1,\ maxCapacity=5,\ capacityIncrement=2 weblogic.allow.reserve.weblogic.jdbc.connectionPool.demoPool=everyone weblogic.jms.connectionPool=demoPool The name of the connection pool is "demoPool." The url parameter gives the JDBC driver's connection URL. "demo" is the name of the Cloudscape database you created for JMS. The driver parameter specifies the JDBC driver class, which must be in the CLASSPATH of the WebLogic Server. This connection pool is created when the WebLogic Server starts, with one active database connection. As more connections are required, connections are added to the pool 2 at a time until the maximum of 5 connections is reached. The weblogic.allow property permits all users to get connections from the connection pool. You can restrict this access control list (ACL) if you choose. The WebLogic "system" user and any user who sends JMS messages must be included in the list. Define JMS ConnectionFactories, Queues, and TopicsConnectionFactories allow JMS clients to create JMS connections. They are configurable so that they create connections with predefined attributes. The JMS specification classifies ConnectionFactories, Queues, and Topics as "administered" objects. They are configured by the messaging system administrator and added to the JNDI namespace to allow access to JMS clients. To define a WebLogic JMS ConnectionFactory, add a weblogic.jms.connectionFactoryName property: weblogic.jms.connectionFactoryName.factoryName=jndiName The factoryName part of the property is a virtual name for this ConnectionFactory. The jndiName part is the string clients use to look up the ConnectionFactory in JNDI. WebLogic JMS provides two default factories, javax.jms.QueueConnectionFactory and javax.jms.TopicConnectionFactory. Since you can use the default connection factories, you usually do not have to configure connection factories. A ConnectionFactory can, however, be customized with three arguments: ClientID, DeliveryMode, and TransactionTimeout.
If you want to supply any of the ConnectionFactory arguments, add the following property: weblogic.jms.connectionFactoryArgs.factoryName=\ ClientID=clientID,\ DeliveryMode=mode,\ TransactionTimeout=seconds The factoryName has the same value as in the associated weblogic.jms.connectionFactoryName property. Define JMS Queues and TopicsThe JMS Queues and Topics that clients access may be defined in the weblogic.properties file with weblogic.jms.queue and weblogic.jms.topic properties. (You can also define them with JMS APIs or in the WebLogic Console.) Here is the syntax for these properties: weblogic.jms.queue.queueName=jndiName weblogic.jms.topic.topicName=jndiName The queueName or topicName part is the name of the Queue or Topic property. The jndiName is the string that clients use to look up the Queue or Topic in the JNDI namespace. The Queue and Topic used by several of the JMS examples are added to the JNDI namespace by default. The jndiName of the example Queue is javax.jms.exampleQueue. The jndiName of the example Topic is javax.jms.exampleTopic. Create database tables for transacted, durable subscribersThis configuration task is relevant, only if your system uses persistent message delivery and may contain multiple, active, transacted, durable subscribers. Internally, WebLogic JMS uses JMSMessageQueue tables to store the state of durable subscribers. By default, WebLogic JMS uses one table for all active durable subscribers. If the DBMS used as the backing store for JMS does not support row-level locking, this can lead to deadlocks in the system. MSSQL Server and Cloudscape do not support row-level locking. To avoid deadlocks, you can configure WebLogic JMS to use a separate JMSMessageQueue table for the transacted operations of each active durable subscriber by performing the following steps:
Create additional JMSMessageQueue tablesThe DDL files shipped in the weblogic/classes/jms/ddl directory can be modified to create additional JMSMessageQueue tables. Note that the number of tables created will serve as an upper limit to the number of active, transacted, durable subscribers allowed in your system. You should choose this number accordingly.
The following is the DDL syntax used to create the tables in a MSSQL
Server database. If you are using another database, refer to
the appropriate DDL file for the correct syntax.
For example, if you want to create three tables, you must add the following
lines to your DDL file:
Define the maximum number of active, transacted, durable subscribersWithin the weblogic.properties file, you must define the maximum number of active, transacted, durable subscribers with the weblogic.jms.maxTransactedDurableSubscribers property. This value should be equal to the number of JMSMessageQueue tables created. For example, if you have created three tables, the following line must be added to the weblogic.properties file:weblogic.jms.maxTransactedDurableSubscribers=3The default value for this property is zero, which indicates that all transactions will be done against a single JMSMessageQueue table. Again, this default behavior is fine for DBMSs that support row-level locking. WebLogic JMS implements the JavaSoft JMS 1.0.1 specification. The JMS API documentation is available on the JavaSoft website.
Import statementsWebLogic JMS uses the JavaSoft JMS API, javax.jms. You also need JNDI with JMS, and if you use transactions you need the JTS classes. Here are the basic imports for JMS applications: import java.util.*; import javax.naming.*; import javax.jms.*; import javax.jts.*; WebLogic JMS provides one public API for use with server session pools, an optional application server facility described in the JMS specification. If you implement a server session pool application, add this package to your import list: import weblogic.jms.ServerSessionPoolFactory.*
Concurrent use of JMS objectsJMS Connections, ConnectionFactories, Topics, and Queues support concurrent use. Other JMS objects -- including QueueSenders and QueueReceivers, TopicPublishers and TopicSubscribers, and Sessions -- can be accessed by only one thread at a time. Using transactions with JMSTo support transactions, JMS uses Java Transaction Service (JTS), which is implemented in the WebLogic Server. There are two ways to use transactions with JMS. If you are using only JMS in your transactions, you can create a transacted JMS session. If you are mixing other operations, such as EJB, with JMS operations, you should use a JTS UserTransaction in a non-transacted JMS session.
JMS clients create several objects to begin using WebLogic JMS. Here are the general steps for setting up a JMS client:
The init() method in the examples.jms.queue.QueueSend example shows how to set up a QueueSession for a JMS client. The init() method is reproduced here with added comments. public final static String JNDI_FACTORY= "weblogic.jndi.WLInitialContextFactory"; public final static String JMS_FACTORY= "javax.jms.QueueConnectionFactory"; public final static String QUEUE="javax.jms.exampleQueue"; private QueueConnectionFactory qconFactory; private QueueConnection qcon; private QueueSession qsession; private QueueSender qsender; private Queue queue; private TextMessage msg; /** * Create all the necessary objects for sending * messages to a JMS queue. */ public void init(Context ctx, String queueName) throws NamingException, JMSException { // The ctx object is a JNDI initial context passed // in by the main() method. // Look up the ConnectionFactory qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY); // Get a QueueConnection from the // QueueConnectionFactory qcon = qconFactory.createQueueConnection(); // Get a QueueSession that is not transacted // and acknowledges automatically qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); // Look up the Queue queue = (Queue) ctx.lookup(queueName); // Create a message producer (QueueSender) // for the Queue we looked up. qsender = qsession.createSender(queue); // Create a message object msg = qsession.createTextMessage(); // Start the connection qcon.start(); } You use the same process for setting up a Topic session, substituting the point-to-point object names with the publish/subscribe names: TopicConnectionFactory, TopicConnection, Topic, and TopicSession. To send a message, you first create the message, fill it in with the information you want to send, and then transmit it to its destination through the message producer. JMS provides six different message types, which are described in the section Message types earlier in this document. You create a message by calling a method on the Session object. Here is the code to create a TextMessage, set the text of the message, and send the message off to a Queue: msg = qsession.createTextMessage(); msg.setText("Welcome to WebLogic JMS"); qsender.send(msg); The body of a TextMessage holds a single String. The send() message in the example puts the String into the message and calls the QueueSender's send() method: /** * Send a message to a JMS queue. */ public void send(String message) throws JMSException { msg.setText(message); qsender.send(msg); } In the QueueSend example, messages originate from the client's QueueSender. The examples.jms.queue.QueueReceive example has a QueueReceiver object to receive the messages the QueueSend example produces. The code for setting up the receiver is very similar to QueueSend. If your application receives messages, you choose whether to receive them synchronously or asynchronously. The QueueReceive example receives messages asynchronously by implementing the javax.jms.MessageListener interface, which includes an onMessage() method. Here is the code from the init() method of the examples.jms.QueueReceive example that establishes the message listener: qreceiver = qsession.createReceiver(queue); qreceiver.setMessageListener(this); The first line creates the QueueReceiver object on the Queue. The second line sets the object that implements the MessageListener interface, in this case examples.jms.QueueReceive itself. When a message is delivered to the QueueSession, it is passed to the examples.jms.QueueReceive.onMessage() method. The onMessage() method processes messages received through the QueueReceiver. In the QueueReceive example, it checks that the message is a TextMessage and if so, prints the text of the message. If it receives a different message type, it uses the message's toString() method to display the message contents. In a message receiver, it is good practice to check that the the received message is of the type the message handler method expects. Here is the implementation of the onMethod() interface from the QueueReceive example: public void onMessage(Message msg) { try { String msgText; if (msg instanceof TextMessage) { msgText = ((TextMessage)msg).getText(); } else { // If it is not a TextMessage... msgText = msg.toString(); } System.out.println("Message Received: "+ msgText ); if (msgText.equalsIgnoreCase("quit")) { synchronized(this) { quit = true; this.notifyAll(); // Notify main thread to quit } } } catch (JMSException jmse) { jmse.printStackTrace(); } } To receive messages synchronously, the example would call qreceiver.receive() for each message instead of setting a listener with qreceiver.setMessageListener(). The receive() method blocks and waits for a message. You can set some standard Header fields before you send a message or on the send() method. When the send() method returns, JMS has set some other Header fields that you can inspect in the sending or receiving code. For example, the following code placed after the send() method displays the message ID WebLogic JMS assigned to the message: System.out.println("Sent message " + msg.getJMSMessageID() + " to " + msg.getJMSDestination()); Here are the Message class methods you use to set Header fields:
The delivery mode (DeliveryMode.PERSISTENT or DeliveryMode.NON_PERSISTENT), priority (0-9), and time to live (in milliseconds) can be set on the QueueSender or TopicPublisher send() method. For example, the following code sends a persistent message with a priority of 4 and a time to live of one hour: qsender.send(msg, DeliveryMode.PERSISTENT, 4, 3600000); The SenderServlet example shows how to set header fields in messages you send. The QueueBrowse example shows how to access header fields of received messages.
To set a property field, call the set method with the property name and value. Here is an example from the WebshareServlet example that sets two String properties and an int property: // Properties used for selectors msg.setStringProperty("User", user); msg.setStringProperty("Category", category); msg.setIntProperty("Rating", rating); The WebshareServlet example uses these properties in message selectors, which are described next. With selectors, WebLogic JMS can filter messages for a client. A message selector is a String with a syntax similar to the where clause of an SQL select statement. You specify a message selector with QueueSession.createReceiver() or TopicSession.createSubscriber(). Here are a few examples of selectors. See the javax.jms.Message javadoc or the JMS specification for full details of selector syntax. A selector is a Boolean expression. It can reference the property fields in a message, and the standard message header fields JMSDeliveryMode, JMSPriority, JMSMessageID, JMSTimestamp, JMSCorrelationID, and JMSType. Here are some examples of selector expressions: salary > 64000 and dept in ('eng','qa') (product like 'WebLogic%' or product like '%T3') and version > 3.0 hireyear between 1990 and 1992 or fireyear is not null fireyear - hireyear > 4 The following example shows how you would install a selector that filters out messages with priority less than 6: String selector = "JMSPriority >= 6"; qsession.createReceiver(queue, selector); To update a selector, you create a durable subscriber with the same client ID. The Webshare example allows clients to update the selector on their subscription. When a client loads the Servlet, they log in, entering an ID which becomes the client ID of their durable subscription. Initially, the selector for their subscription is TRUE -- all messages are delivered to their subscriber. The client can use a browser form to construct a new selector. WebshareServlet updates the durable subscriber by creating a new durable subscriber with the new selector. Here is the code that modifies the durable subscription: // Create a DurableSubscriber with the new selector tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY); topic = (Topic) ctx.lookup(TOPIC); connection = tconFactory.createTopicConnection(); // Override configured ClientID with the login ID connection.setClientID(userName); session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); // Create the subscription subscriber = session.createDurableSubscriber(topic, userName, selector, false); session.close(); connection.close(); To remove the selector from a durable subscription, just replace it with "TRUE" so that every message is passed through the filter.
WebLogic JMS implements an optional JMS facility for defining a server-managed pool of message consumers -- a ServerSessionPool. The ServerSessionPool receives messages from a Topic and passes them to a server-side MessageListener implementation that you provide to process the messages. Your class provides an onMessage() method that processes a message. The ServerSessionPool manages a pool of JMS Sessions, each executing your single-threaded onMessage() method, so that messages are processed in parallel. To create the ServerSessionPool, WebLogic provides a ServerSessionPoolFactory class. This factory, which is bound in the JNDI tree, creates a ServerSessionPool with your values for the following attributes:
When messages arrive on the Topic, the ServerSessionPool passes them to an instance of your MessageListener class. The sessionpool JMS example demonstrates how to set up a ServerSessionPool. The ListenerPoolSend class creates the ServerSessionPool, specifies the MsgListener class as the MessageListener implementation, and sends messages to the Topic. The MsgListener.onMessage() method simply prints the messages on the WebLogic Server output. The sessionpool example has two Java classes. The SessionPoolSend class sets up the ServerSessionPool and sends messages to it. The MsgListener class implements the onMessage() interface that prints the messages to the WebLogic Server's output. First, we look at the SessionPoolSend.java program. This class is designed to be executed from a separate JVM after the WebLogic Server is running. Its main() method gets a JNDI initial context, calls the init() method to create the ServerSessionPool, and then calls the readAndSend() method to send messages to the Topic: public static void main(String[] args) throws Exception { if (args.length != 1) { System.out.println( "Usage: java examples.jms.sessionpool.SessionPoolSend" + " WebLogicURL"); return; } // Get an initial JNDI context from the target server InitialContext ic = getInitialContext(args[0]); SessionPoolSend sps = new SessionPoolSend(); // Set up the ServerSessionPool sps.init(ic, TOPIC); System.out.println("JMS Session Pool Established"); readAndSend(sps); sps.close(); } The init() method does all the work of setting up the JMS environment. It actually does two jobs:
Here is the init() method: public void init(Context ctx, String topicName) throws NamingException, JMSException { // Set up the JMS objects readAndSend() needs tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY); tcon = tconFactory.createTopicConnection(); tsession = tcon.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); try { topic = (Topic) ctx.lookup(topicName); } catch (NamingException ne) { topic = tsession.createTopic(topicName); ctx.bind(topicName, topic); } // Create a publisher and message for readAndSend() tpublisher = tsession.createPublisher(topic); msg = tsession.createTextMessage(); // Start the (publisher) connection tcon.start(); // Create the ServerSessionPool. // First look up the SessionPoolFactory sessionPoolFactory = (ServerSessionPoolFactory) ctx.lookup(SESSION_POOL_FACTORY); // Create a ServerSessionPool sessionPool = sessionPoolFactory.getServerSessionPool( tcon, // Connection on the Topic 5, // Maximum of 5 sessions false, // Don't used transacted sessions Session.AUTO_ACKNOWLEDGE, // Auto-acknowledge // messages received // Name of the MessageListener to instantiate "examples.jms.sessionpool.MsgListener" ); // Create the ConnectionConsumer consumer = tcon.createConnectionConsumer(topic, "TRUE", sessionPool, 10); }
WebLogic controls access to internal resources like JMS through ACLs set up in the WebLogic Realm. Entries for ACLs in the WebLogic Realm are listed as properties in the weblogic.properties file. The access control list name for a queue is weblogic.jms.queue.queueName, where queueName is the name of a queue. The access control list name for a topic is weblogic.jms.topic.topicName, where topicName is the name of a topic. You can set the Permissions "receive" and "send" for a JMS queue or topic by entering a property in the properties file. If you do not set an ACL for a JMS queue or topic, all permissions for that queue or topic are by default granted to everyone. In the examples below, we illustrate how you can set ACLs for various JMS topics and queues. Peter, Brown, and Eric can receive messages from the "payroll" topic, but only Peter has permission to send messages to that topic. Bob has permission to send messages to the "reminder" queue. Since no ACL is set for the receive permission of the "reminder" queue, everyone can receive messages from that queue. Example: weblogic.allow.receive.weblogic.jms.topic.payroll=peter,brown,eric weblogic.allow.send.weblogic.jms.topic.payroll=peter weblogic.allow.send.weblogic.jms.queue.reminder=bob
In a cluster, all of the servers are running JMS independently. Conceptually, it is simpler for all clients to use the same instance of JMS on a particular member of the cluster. To accomplish this, it is necessary to have one of the servers in the cluster configured (via the per-server weblogic.properties file) to be the JMS provider. This means that the properties file should define the connection pool that JMS will use as well as the connection factory that all the clients will use to get to JMS. For example, the weblogic.properties file for one of the servers in the cluster may contain: weblogic.jdbc.connectionPool.csPool=\ url=jdbc:cloudscape:demo,\ driver=COM.cloudscape.core.JDBCDriver,\ initialCapacity=0,\ maxCapacity=5,\ capacityIncrement=1,\ weblogic.t3.waitSecondsForConnection=20,\ waitSecondsForConnection=20,\ props=user=none;password=none;server=none weblogic.allow.reserve.weblogic.jdbc.connectionPool.csPool=everyone java.system.property.cloudscape.system.home=C:/weblogic/eval/cloudscape/data weblogic.jms.connectionPool=csPool weblogic.jms.connectionFactoryName.trader=jms.connection.clusterFactory weblogic.jms.connectionFactoryArgs.trader=ClientID=traderReceive weblogic.jms.topic.exampleTopic=javax.jms.exampleTopic Clients that connect to the cluster and look up jms.connection.traderFactory in JNDI will be automatically routed to this server for their JMS connection.
|
|
Copyright © 2000 BEA Systems, Inc. All rights reserved.
|