bea.com | products | dev2dev | support | askBEA
 Download Docs   Site Map   Glossary 
Search

WebLogic Server Frequently Asked Questions

 Previous Next Contents View as PDF  

FAQs: JMS

The WebLogic JMS Product

Configuration

Persistent Stores

Administration

Transaction Support

JMS Programming Practices

Message-Driven Beans

Q. What makes WebLogic JMS unique?

A. The following features make WebLogic JMS unique:

Q. Where can I learn more about WebLogic JMS?

The following links provide more information about WebLogic JMS:

Q. Are there C/C++ interfaces to WebLogic JMS?

A. No, this is not supported.

Q. Is there a smaller version of the weblogic.jar file for supporting clients?

Yes. Prior to version 8.1 Beta, client applications that incorporated WebLogic Server functionality required the entire WebLogic Server distribution (weblogic.jar and weblogicaux.jar) on the client machine. WebLogic Server now provides two new client .jar files that include only the functionality needed for small-footprint J2EE client functionality. The new files are:

The new client .jar files are located in the /server/lib subdirectory of the WebLogic Server installation directory (for example, c:\bea\weblogic81b\server\lib). The new client .jar files are not supported with JDK 1.3.x or earlier.

Q. How do I start WebLogic Server and configure JMS?

A. Refer to "Managing JMS" in Programming WebLogic JMS for detailed instructions on starting WebLogic Server, accessing the Administration Console, and configuring Weblogic JMS.

Q. How do I configure WebLogic JMS security?

A. Previous to WebLogic Server 7.0, ACLs were used to protect WebLogic resources. In WebLogic Server version 7.0 and later, security policies answer the question "who has access" to a WebLogic resource. A security policy is created when you define an association between a WebLogic resource and a user, group, or role. A WebLogic resource has no protection until you assign it a security policy.

For instructions on how to set up security for all WebLogic Server resources, see "Setting Protections for WebLogic Resources" in the Administration Console Online Help.

Q. Can I still use the default connection factories supported in WebLogic JMS 5.1?

A. Yes. For detailed information about using 5.1 connection factories in later versions of WebLogic JMS, see "Porting WebLogic JMS Applications" in Programming WebLogic JMS.

Q. Why does JMSSession.createTopic or JMSSession.createQueue fail to create a destination in WebLogic JMS 8.1? (It worked in version 5.1?)

A. For a detailed explanation of this issue, refer to the "JMS FAQ" in the version 6.1 Frequently Asked Questions.

Q. How do I programmatically get a list of Queues or Topics?

A. The following program uses MBeans:

import weblogic.management.*;
import weblogic.management.configuration.*;

InitialContext ic = new InitialContext();
MBeanHome home = (MBeanHome)ic.lookup(MBeanHome.ADMIN_JNDI_NAME);

for(Iterator i = o.getMBeansByType("JMSTopic").iterator();
i.hasNext(); ){
WebLogicMBean wmb = (WebLogicMBean)i.next();
System.out.println("topic name found: " + wmb.getName());
}
for(Iterator i = o.getMBeansByType("JMSQueue").iterator(); i.hasNext(); ){
WebLogicMBean wmb = (WebLogicMBean)i.next();
System.out.println("queue name found: " + wmb.getName());
}

Q. How do I use a temporary destination?

A. You must create a template on every JMSServer where you want to be able to create temporary destinations. You can specify multiple JMSServer entries to support Temporary Template and the system will load balance among those JMSServers to setup the temporary destination. See How do I start WLS and configure JMS? for a description about how to configure JMS. The resulting template definition looks something like the following:

<JMSTemplate  Name="MyTemplate"/>

The JMSServer is defined something like:

<JMSServer Name="MyJMSServer" TemporaryTemplate="MyTemplate" Targets="MyServer" >

After the template name, you can set any queue/topic attribute you want in the template (not including a JNDI name or topic multicast settings). The template is at the outer most level; that is, it should not be nested in your <JMSServer>.

Temporary destinations can only be consumed by the creating connection. Using topics, you create your temporary topic and subscribe to that temporary topic. If you want someone to publish to that temporary topic, you need to tell that someone what your topic is. You can send them a message and include your temporary topic in the JMSReplyTo field. The creator of the TemporaryTopic and the subscriber must be one in the same.

import javax.jms.TopicSession;
TemporaryTopic myTopic = mySession.createTemporaryTopic();
TopicSubscriber = mySession.createSubscriber(myTopic);

Temporary topics do not get names and cannot be subscribed to by other connections. When you create a temporary topic, the JMS provider returns a javax.jms.Topic. You then need to advertise that topic to other parties (those who want to publish to the topic), putting it in your JMSReplyTo field so that they can respond. In general, no one else can subscribe to the topic. You advertise the topic any way you want. Topics are Serializable (or, in our case, Externalizable), which allows you to pass them around in RMI calls, through a file, binding it to a name in JNDI, etc. In short, create the topic at the subscriber side and advertise so that others can publish. You can get multiple subscribers on the same connection and get concurrent processing using multiple sessions.

Q. How do I use MBeans to print runtime statistics?

A. Newsgroup article news://newsgroups.bea.com/3B3B77A9.CDCE3954@not.my.address.com contains a program to print JMS statistics based on runtime MBeans.

Q. Can two JMS servers share the same persistent store?

A. No. Each JMS server must have its own unique persistent store. Two file-based JMS persistent stores may share the same directory, but their messages will be stored in different files. In this case, the filenames will contain different prefixes.

Two JDBC-based JMS persistent stores may share the same database, but they must be configured to use a different Prefix Name which will be prepended to the database tables. For more information on configuring the JDBC Prefix Name, see "JMS JDBC Stores" in the Administration Console Online Help. If they are configured with the same Prefix Name, persistent messages will be corrupted and/or lost.

Q. Which types of JDBC databases does WebLogic JMS support?

A. The JMS database can be any database that is accessible through a JDBC driver. WebLogic JMS detects some drivers for the following databases:

The weblogic/jms/ddl directory within the weblogic.jar file contains JMS DDL files for these databases, which are actually text files containing the SQL commands that create the JMS database tables.

Q. How do I use a third-party JDBC driver with WebLogic JMS?

If your JDBC driver is not included in the list of drivers in the question about JDBC databases supported by WebLogic JMS, then the tables required by JMS must be created manually.

Note: WebLogic Server only guarantees support for the JDBC drivers included in the previous list. Support for any other JDBC driver is not guaranteed.

The .ddl files located in the weblogic/jms/ddl directory of the weblogic.jar file may be used as templates. Use the jar utility supplied with the JDK to extract them to the weblogic/jms/ddl directory using the following command:

jar xf weblogic.jar weblogic/jms/ddl

Note: If you omit the second parameter (weblogic/jms/ddl), the entire jar file is extracted.

Follow the procedures in JDBC Database Utility in Programming WebLogic JMS to manually create the database tables for the JDBC store.

Another option is to consider using a file store instead of a JDBC store. File stores are easier to configure and may provide significantly better performance.

Q. What if my JDBC database becomes corrupt?

The procedures for removing and regenerating the JDBC store tables or creating the database tables manually are described in detail in JDBC Database Utility in Programming WebLogic JMS.

Q. How do I use persistence?

A. Use the following guidelines:

  1. Make sure the JMSServer you are using has a store configured. The JMSServer configuration entry in the config.xml file should contain a line of the form
    Store="<YOUR-STORE-NAME>" 

    Note that if JMS boots without a store configured, it is assumed the customer did not want one, and persistent messages are silently downgraded to non-persistent (as specified for JMS 1.0.2b).

  2. Make sure you are not using "Message.setJMSDeliveryMode". This is overwritten, as it is a vendor-only method.
  3. Make sure you are calling either:
    QueueSender.send(msg, deliveryMode, ...)

    -- or --

    QueueSender.setDeliveryMode(deliveryMode)

    -- or --

    set DefaultDeliveryMode mode on connection factory in the config.xml file to persistent (the QueueSender.setDeliver/send overrides this value). Similarly, for topics, you would set this via the TopicPublisher.

  4. Make sure you don't have "DeliveryModeOverride" set to Non-Persistent on the Destination in the config.xml file.
  5. If you are using pub/sub, only durable subscriptions persist messages. Non-durable subscriptions have no need to persist messages, as by definition they only exist for the life of the server.
  6. If you are using JDBC, the JDBC tables, JMSSTATE and JMSSTORE, are created automatically when the JMS server boots. The DDL files used to create the tables are stored in weblogic.jar in weblogic/jms/ddl. The example configuration below shows a JDBC store for Oracle (refer to the Certifications page for the latest Oracle certification information). To manually create the tables (also deleting any existing tables), run java utils.Schema as described in the previous question.

See the question, "How do I start WLS and configure JMS?" for a description of how to configure JMS.

Here is a sample config.xml file resulting from configuring JMS. It should look similar to yours. If you want JMS to use a file store instead of a database, just change JDBCStore to FileStore in the JMSServer section.

<Server Name="myserver"
ListenPort="7001" DefaultProtocol="t3"
ThreadPoolSize="8" >
</Server>
<Security Realm="defaultRealm"
GuestDisabled="false" />
<Realm Name="defaultRealm"
FileRealm="defaultFileRealm" />
<FileRealm Name="defaultFileRealm"
/>
<JMSServer Name="TestJMSServer"
TemporaryTemplate="TestTemplate1"
Targets="myserver" Store="JDBCStore">
<JMSQueue Name="TestQueue1"
JNDIName="jms.queue.TestQueue1"
Template="TestTemplate1"
/>
</JMSServer>
<JMSTemplate Name="TestTemplate1"
/>
<JMSFileStore Name="FileStore"
Directory="myfilestore"
JMSServer="TestJMSServer"
/>
<JMSJDBCStore Name="JDBCStore"
ConnectionPool="testpool2"
JMSServer="TestJMSServer"
/>
<JDBCConnectionPool Name="testpool2"
Targets="myserver"
URL="jdbc:weblogic:oracle"
DriverName="weblogic.jdbc.oci.Driver"
InitialCapacity="0"
MaxCapacity="1"
CapacityIncrement="1"
Properties="user=SCOTT;password=tiger;server=bay816"
/>
</Domain>

The following is a sample class that sends a Topic message on construction:

import javax.naming.*;
import javax.jms.*;
import java.util.Hashtable;
public class t
{
public final static String DESTINATION="jms.topic.TestTopic1";
private TopicConnectionFactory connectionFactory;
private TopicConnection connection;
private TopicSession session;
private TopicPublisher producer;
private TextMessage message;
private Topic destination;
public t()
{
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
env.put(Context.PROVIDER_URL, "t3://localhost:7001");
InitialContext ctx = new InitialContext(env);
destination = (Topic) ctx.lookup(DESTINATION);
connectionFactory = (TopicConnectionFactory)
ctx.lookup("javax.jms.TopicConnectionFactory");

connection = (TopicConnection)
connectionFactory.createTopicConnection();
session = (TopicSession) connection.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);

producer = (TopicPublisher) session.createPublisher(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
message = (TextMessage) session.createTextMessage();
message.setText("hello world");
producer.publish(message);
} catch (Exception e) {
}
}
}

Q. How does a file store compare with a JDBC store?

A. The following are some similarities and differences between file stores and JDBC stores:

Q. How do the JMS server/destination message maximum and threshold values work?

A. The byte and message maximum values are quotas - not flow control. Message quotas prevent a WebLogic JMS server from filling up with messages and possibly running out of memory, causing unexpected results. When you reach your quota, JMS prevents further sends with a ResourceAllocationException (rather than blocking). You can set quotas on individual destinations or on a server as a whole.

The thresholds are also not flow control - though they would be better suited to that application than the quotas. The thresholds are simply settings that when exceeded cause a message to be logged to the console to let you know that you are falling behind.

Note: WebLogic JMS 7.0 and later has a flow control feature that enables a JMS server or destination to slow down message producers when it is becoming overloaded. Specifically, when a JMS server/destination exceeds its specified bytes or messages thresholds, it instructs producers to limit their message flow. For more information, see "Tuning JMS" in the Administration Console Online Help.

Note that the messages maximum setting on a connection factory is not a quota. This specifies the maximum numbers of outstanding messages that can exist after they have been pushed from the server but before an asynchronous consumer has seen them; it defaults to a value of 10.

Q. How do I configure JDBC so that the JMS JDBC Store recovers automatically?

A. If you are using a JDBC store when the DBMS goes down and then comes back online, JMS cannot access the store until WebLogic Server is shut down and restarted. To work around this problem, configure the following attributes on the JDBC connection pool associated with the JMSJDBCStore:

TestConnectionsOnReserve="true"\
TestTableName="[[[catalog.]schema.]prefix]JMSState"

Q. What is the value of WebLogic JMS clustering in version 8.1?

A. In version 6.x, you could establish cluster-wide, transparent access to destinations from any server in the cluster by configuring multiple connection factories and using targets to assign them to WebLogic Servers, as described in "Managing JMS" in the Programming WebLogic JMS. Each connection factory can be deployed on multiple WebLogic Servers. The administrator could configure multiple JMS servers on the various nodes in the cluster—as long as the servers are uniquely named—and can then assign destinations to the various JMS servers.

For WebLogic JMS 7.0 and later, the administrator can also configure multiple destinations as part of a single distributed destination set within a cluster. Producers and consumers are able to send and receive to the distributed destination. In the event of a single server failure within the cluster, WebLogic JMS then distributes the load across all available physical destinations within the distributed destination. For more information, see "Distributed Destination Tasks" in the Administration Console Online Help.

WebLogic JMS 7.0 and later also takes advantage of the migration framework implemented in the WebLogic Server core for clustered environments. This allows WebLogic JMS to properly respond to migration requests and bring a JMS server online and offline in an orderly fashion. This includes both scheduled migrations as well as migrations in response to a WebLogic Server failure. For more information, see "Managing JMS" in the Programming WebLogic JMS.

Q. How can I control on which WebLogic Server(s) my application will run?

A. A system administrator can specify on which WebLogic Server(s) applications will run by specifying targets when configuring connection factories. Each connection factory can be deployed on multiple WebLogic servers.

Note: If you use the default connection factory, you have no control over the WebLogic Server on which the connection factory may be deployed. If you would like to target a particular WebLogic Server, create a new connection factory and specify the appropriate JMS server target(s).

Q. How do I perform a manual fail-over?

A. The procedures for recovering from a WebLogic Server failure, and performing a manual failover, including programming considerations, are described in detail in "Managing JMS" in the Programming WebLogic JMS.

Q. Does the WebLogic JMS server find out about closed or lost connections, crashes, and other problems and does it recover from them?

A. Yes, provided the client closes its resources, the network connection fails, or the JVM it's in exits, even for multicast pub/sub. It detects losses of "peers" and recovers.

Q. Do I need to use the WLS T3 protocol?

A. J2EE is all about making the interfaces standard. WebLogic's implementation of the RMI specification uses a proprietary wire-protocol known as T3. Sun's reference implementation of RMI uses a proprietary protocol called JRMP. The fact is that WebLogic developed T3 because they needed a scalable, efficient protocol for building enterprise-class distributed object systems with Java.

While T3 is specific to WebLogic, your application code does not need to know anything about T3 so you should not worry about this. Externalize the "WebLogic-specific strings" (PROVIDER_URL, INITIAL_CONTEXT_FACTORY, etc.) to a properties file (or somewhere) and you can make your code completely portable to where you only need change these in the properties file to get your code to run on another J2EE application server.

Q. How do I do HTTP tunneling?

A. If you want to use HTTP tunneling (wrap every message in HTTP to get through a firewall), you need to add TunnelingEnabled="true" into your <Server> definition in the config.xml file or check the appropriate box on the console. Then use a URL like http://localhost:7001 instead of t3://localhost:7001 for Context.PROVIDER_URL when getting your InitialContext. If you want HTTP tunneling with SSL, use https://localhost:7002 (where https uses HTTP tunneling with SSL and 7002 is the secure port that you configured). You will pay a performance penalty for doing this, so only use tunneling it if you really need to (i.e., need to go through a firewall).

Q. Does WebLogic JMS support SSL?

A. Yes, SSL is supported in the WebLogic JMS implementation. It is automatically used based on using a URL starting with "t3s:" instead of "t3:" when looking up the initial JNDI context.

Q. How do I integrate non-WebLogic JMS providers with WLS?

A. Refer to the white paper, "Using Foreign JMS Providers with WebLogic Server" (jmsproviders.pdf) on http://dev2dev.bea.com/resourcelibrary/whitepapers.jsp?highlight=whitepapers for a discussion on integrating MQ Series, IBus MessageServer, Fiorano, and SonicMQ.

Q. How do two-phase or global transactions relate to WebLogic JMS?

A. A two-phase or global transaction allows multiple resource managers (including EJBs, databases, and JMS servers) to participate in a single transaction.

For example, a client can use a two-phase transaction to send a message from a queue on one JMS server (server A) to a queue on another JMS server (server B). Each server has a unique persistent store. When the transaction is committed, the message is made visible on server B. If the transaction rolls back, the message is put back on the queue on server A.

Note: If both queues happen to be on the same JMS server, then a one-phase transaction is used.

Q. Why is my WebLogic JMS work not part of a user transaction (i.e., called within a transaction but not rolled back appropriately)? How do I track down transaction problems?

A. Usually this problem is caused by explicitly using a transacted session which ignores the external, global transaction by design (a JMS specification requirement). A transacted JMS session always has its own inner transaction. It is not affected by any transaction context that the caller may have.

It may also be caused by using a connection factory that is configured with "UserTransactionsEnabled" set to false.

  1. You can check if the current thread is in a transaction by adding these two import lines:
    import javax.transaction.*
    import weblogic.transaction.*;

    and adding the following lines (i.e., just after the begin and just before every operation).

    Transaction tran = TxHelper.getTransaction();
    System.out.println(tran);
    System.out.println(TxHelper.status2String(tran.getStatus()));

    This should give a clear idea of when new transactions are starting and when infection is occurring.

  2. Ensure that the thread sending the JMS message is infected with a transaction. Check that the code is not using a transacted session by setting the first parameter of createQueueSession or createTopicSession to false. Note that creating the connection and/or session is orthogonal to the transaction. You can begin your transaction before or after. You need only start the transaction before you send or receive messages.
  3. Check that the UserTransactionsEnabled flag is explicitly set to true for the connection factory in the config.xml file since the default for user-configured connection factories for this value is false. If you are using one of the pre-configured connection factories they are set as follows:
    weblogic.jms.ConnectionFactory disables user transactions so don't use this one for the case where user transactions are desired;

    javax.jms.QueueConnectionFactory and javax.jms.TopicConnectionFactory enable user transactions.
  4. You can trace JTA operations by starting the server with this additional property:
    -Dweblogic.Debug.DebugJMSXA=true

    You should see trace statements like these in the log:

    XA ! XA(3163720,487900) <RM-isTransactional() ret=true>

    This can be used to ensure that JMS is infected with the transaction.

Q. How can an application do a JMS operation and have it succeed, independent of the result of the transaction?

A. Basically, the JMS operation must be done using a transacted session or the transaction must be suspended/disabled as follows (pick one or more of the following).

  1. Suspend the current transaction prior to making the JMS call and resume it after completing it. The code looks something like this:
    import javax.transaction.Transaction;
    import javax.transaction.TransactionManager;
    TransactionManager tranManager= TxHelper.getTransactionManager();
    Transaction saveTx = null;
    try {
    saveTx = tranManager.suspend();
    ... do JMS work, it will not participate in transaction
    } finally {
    // must always resume suspended transactions!
    if (saveTx != null) tranManager.resume(saveTx);
    }
  2. Use a transacted session by specifying true for the first parameter to createQueueSession or createTopicSession.
  3. Use a connection factory with user transactions disabled. That is, check that the UserTransactionsEnabled flag is explicitly set to false for the connection factory in the config.xml file or use the default for a user-configured connection factory for this value which is false. The pre-configured connection factory weblogic.jms.ConnectionFactory disables user transactions.

A transacted JMS session always has its own inner transaction. It is not affected by any transaction context that the caller may have. A non-transacted JMS session is more complicated. If you use the WLS 6.x or later default factory weblogic.jms.ConnectionFactory, the session does not participate in a user transaction because the UserTransactionsEnabled flag is set to "False". However, if you use the deprecated WebLogic 5.1 default javax.jms.QueueConnectionFactory or javax.jms.TopicConnectionFactory factories, or you define your own factory and set the UserTransactionsEnabled flag to "True", the JMS session participates in the outer transaction, if one exists and the JMS session is not transacted.

Q. What happens if acknowledge() is called within a transaction?

A. As per Sun Microsystems' JMS specification, when you are in a transaction, the acknowledgeMode is ignored. If acknowledge() is called within a transaction, it is ignored.

Q. Why do I get an error when using a non-transacted TopicSession from a transaction-required EJB?

A. Whenever two resources (such as JMS and a database) participate in a transaction, the transaction becomes two-phase. The database driver you are using is not XA compatible and can't normally participate in a two-phase transaction. The solution is to either use an XA compatible driver, or to configure the JDBCTxDataSource value to set enableTwoPhaseCommit to true. The caveat for the latter is that this can lead to heuristic errors. If you don't want JMS to participate in the current transaction, see the question "How can an application do a JMS operation and have it succeed, independent of the result of the transaction?".

Q. Can I use a one-phase commit if my WebLogic JMS JDBC store is on the same database for which I am doing other database work?

A. No. WebLogic JMS is its own resource manager. That is JMS itself implements XAResource and handles the transactions without depending on the database (even when the messages are stored in the database). That means whenever you are using JMS and a database (even if it is the same database as the JMS messages are stored) then it is 2PC.

You may find it will aid performance if you ensure the connection pool used for the database work exists on the same server as the JMS queue—the transaction will still be two-phase, but it will be handled with less network overhead. Another performance boost might be achieved by using JMS file stores rather than JMS JDBC stores.

Q. How do I integrate an XAResource with WLS to get JTA transactions with another resource manager?

A. See the white paper, "Using JTA Transactions to Envelope WLS JMS and IBM MQSeries" (jmsjta.doc) on http://dev2dev.bea.com/resourcelibrary/whitepapers.jsp?highlight=whitepapers for a discussion on integrating MQ Series.

Q. Why do I get an exception when I start up WebLogic JMS using an XA driver or with a TX data source?

A. You cannot use a TX data source with JMS. JMS must use a JDBC connection pool that uses a non-XAresource driver (you can't use an XA driver or a JTS driver). Do not set the enableTwoPhaseCommit option. JMS does the XA support above the JDBC driver.

Q. Is WL JMS XAResource compliant?

A. Yes. WebLogic JMS 8.1 fully implements the XAResource interface, as defined in the JTA specification. Version 8.1 also supports the XAConnection, XAConnectionFactory, XAQueueConnection, XAQueueConnectionFactory, XAQueueSession, XASession, XATopicConnection, XATopicConnectionFactory, and XATopicSession methods. These methods are defined as optional in Sun Microsystems' JMS specification and are not part of the XAResource interface.

The XAResource interface has methods like start, prepare, and commit that the transaction manager needs to manage a JTA transaction, and these are provided by WebLogic JMS. When you wrap a JMS send or receive with a JTA transaction (begin/commit), the JMS work is part of that transaction (unless you are using a transacted session).

It does mean that you can't use an XAQueueConnectionFactory to get an XAQueueConnection to get an XAQueueSession to call getXAResource(). However, WebLogic JMS is automatically registered by WebLogic JTA so you don't need to worry about that. It also means that you can't use WebLogic JMS with another transaction manager driving the transaction (at least, not with any documented interfaces).

Q. Why can't I receive a message that I send within a container-managed transaction?

A. If you are using container-managed transactions, the original message sent from the EJB will never be sent. Here is what is happening.

  1. Container starts transaction.
  2. Start method.
  3. Generate new message.
  4. Send message (message isn't sent - it's buffered until transaction commit).
  5. Do a blocking receive on a queue.
  6. End method.
  7. Transaction Commit never Reached because original message was never sent because you can't get past blocking receive.

The solution is to either use bean-managed transactions, or to break the send and receive into two separate methods.

Q. What happens to a message that is rolled back or recovered?

A. When a message is rolled back or recovered, it is requeued. Where it goes in the queue is a function of the message relative to the sort order for the queue and the other messages in the queue.

In an unordered queue (most typical), the message would typically go at the head of the queue (since the queue is still sorted by arrival time - FIFO) unless some other message is being recovered at that same time, but still the sort order resolves any conflicts. The message is redelivered to the first available consumer as soon as possible. If there are no consumers when it is requeued, then it would just sit there until there is one.

You can configure the maximum number of times that a message may be requeued. You can also specify a delay time before which the message will not be available after being requeued. If a message reaches its maximum requeue limit, it is put on an error destination if one is configured or silently dropped.

Q. Is it possible to set aside a message and acknowledge it later?

A. There are no special primitives for doing this. Here are two possible solutions.

One approach is to use multiple sessions as in the following:

while (true) {
Create a session, subscribe to one message on durable subscription
Close session
Save session reference in memory
To acknowledge the message, find the session reference and call
acknowledge() on it.
}

Another solution is to use transactions and suspend the work as follows:

start transaction
while(true) {
message = receive();
if (message is one that I can handle)
process the message
commit
} else {
suspend transaction
put transaction aside with message
start transaction
}
}

To "acknowledge" the message:

resume user transaction
commit

To "recover" the message:

resume user transaction
rollback

Each time you suspend, you need to push the transaction onto a stack or list possibly with the message so you can process it or roll it back later. This solution is high overhead in that there can be a large build up of outstanding transactions. Note that transactions have timeouts and it may rollback on its own, which means you can get the message again (in a different transaction). Note also that there are some practical limits on the number of transactions you should leave outstanding. The default limit is something like 10000. Eventually you want to go back to your stack/list and commit/rollback the transactions. Note that transaction references (javax.transaction.Transaction) are not Serializable.

Q. How should I use sorted queues?

A. Destination keys are used to define the sort order for a specific destination. Destination keys can be message header or property fields. For a list of valid message header and property fields, refer to the Programming WebLogic JMS.

Queues can be sorted in ascending or descending order based on the destination key. A destination is considered to be first-in-first-out if a destination key is defined as ascending for the JMSMessageID message header field, and last-in-first-out if defined as descending. The key defined for the JMSMessageID header field, if specified, must be the last key defined in the list of keys.

You can define multiple destination keys to sort a destination.

To create a destination key, use the Destination Keys node in the Administration Console. For more information, refer "Destination Key Tasks" in the Administration Console Online Help.

Q. How does sorting on message priority work?

A. First, you need to add a key to the destination (by default, they are not sorted), choosing JMSPriority as the key. If you want 0 to be your highest priority, make the key ascending. If you want 9 to be the highest priority, make the key descending.

Second, the priority must be set using either the producer or on the send, not the message.

Third, the priority sorting only comes into play if there are multiple messages waiting on the queue. If the receiver is always caught up with the sender, then the messages will be processed in the order in which they come in.

Q. How do I deal with a listener that doesn't keep up with messages being sent?

A. Here are a few guidelines:

Q. How do I get a thread dump to help track down a problem?

A. Ways to get a thread dump:

Q. Do client identifiers need to be unique?

A. Using durable subscribers, if subscribing from two different clients and using the same connection factory and the connection factory has a configured clientID, distinct clientID's must be set for each after the TopicConnection has been created. Each connection needs a unique clientID. If you configure a connection factory with a clientID, you can only create one TopicConnection with that factory until that one connection is closed.

Q. Are messages passed by copy/value or reference?

A. Messages, from an application point of view, are passed by value (a copy is made). Internally, every effort is made to optimize message passing.

When the producer is on the same JVM as the JMS server, a copy is made of the message before it is actually placed in the destination. If a consumer is on the same JVM as the JMS server, a copy is made before it is given to the consumer. This preserves the message that is actually in the destination. Passing by reference is a violation of Sun Microsystems' JMS specification. Specifically, if one person produces a message and then modifies the message in their space it should not affect the message that was already sent. As such, the message sent must be a copy. The same is true on the receive side. If someone consumes the message and then does something like a clear properties, sets a header field or makes any modification of any kind, that change cannot affect the messages received by other consumers. So, the messages given to receivers on the same JVM are also copies (one for each receiver). Also, if you pass a reference to a receiver and the receiver modifies the message and then does a rollback or a recover, the message in the destination would be modified for the person who eventually does receive it. Then it appears that the message sent is not the message received. It has been modified by someone who received it but then put it back.

Q. How do I manage a queue to view and delete specific messages?

A. Write a program that uses a QueueBrowser. Then delete specific messages by using a selector with the message identifier as in the following example:

String selector = "JMSMessageID = '" + message.getMessageID() + "'";

Keep in mind that the queue browser is a not a "live" view of the queue. It is a snap-shot.

Q. How do I close a queue so that the messages will not be reloaded at the next server startup?

A. JMS does not define the deletion of queues. Using WebLogic JMS, you can administratively create and delete queues. There is no way to dynamically delete queues at run-time.

You can acknowledge the messages or not use persistence. Further, you can use temporary queues. They exist only for the life of the connection. You can also use durable subscriptions. A durable subscriber's message gets deleted if that durable subscriber unsubscribes, but the topic continues to exist.

Q. Why does an Object Message print as null after it is received?

A. The object isn't deserialized until ObjectMessage.getObject() is called. The toString() will continue to print null until this occurs. WebLogic JMS 6.x or later automatically deserializes the message if the application has not called setObject().

Q. In what order are messages delivered to a consumer?

A. Order is maintained between any producer and consumer for like delivery mode, sort order, and selector in the absence of a rollback or recover. There are no guarantees of order when multiple producers send to a single consumer or multiple consumers receive from multiple producers.

Order is generally maintained between a producer and a consumer. However, non-persistent messages can get ahead of persistent messages of a higher sort order (i.e., higher priority), can move ahead of each other and a recover or rollback puts messages that were already received back into the queue/topic, which affects order.

Most messaging systems (including WebLogic JMS) maintain order between a producer and a destination and then order between the destination and the consumer. So, once things arrive at the destination, the order does not change.

Finally, the asynchronous pipeline that is supported in WebLogic JMS affects the ordering. By default there can be as many as ten outstanding messages pushed out from the server to an asynchronous client that have not been seen by the client yet. If the asynchronous consumer is "caught" up, these messages will not be sorted. Destination sorting does not occur in the pipeline. If a destination is sorted by priority, and a new message comes in of higher priority than those messages already in the pipeline, it will not leap ahead in the pipeline, it will become first in the destination. The size of the pipeline is configurable; see the MessagesMaximum setting on the connection factory used. If you want real priority sorting, change the maximum number of messages on the factory to one.

Q. Why do I get an exception when trying to find a connection factory?

A. The exception is usually something like java.io.InvalidClassException or java.lang.NoClassDefFoundError.

Make sure weblogic.jar is in the CLASSPATH of the client. Also make sure you have the correct Java run-time jar files included (i.e., you might need rt.jar).

Q. Why should I avoid using message selectors?

A. We recommend avoiding an architecture that requires heavy use of selectors. If you need to use selectors, try to use topic selectors. They only incur a charge once per message per subscriber. If the message doesn't match a subscriber's selection criteria, it is simply ignored and not placed in that subscriber's "subscription".

For Queues, selectors can be much more heavy-weight. Each receive request can incur a scan of the entire queue in a search for a message that matches the receiver's selection criteria. This can get really bad if the selection criteria are restrictive and the queue depth is large.

The topic generally performs better. However, it depends on the message mix and queue depth. When using queues, if there are a lot of messages that don't match what you are looking for, you are going to compare your selector against those messages over and over again each time you go back to look for one of yours. When using a topic, each message is compared against all consumers exactly once. There is never any duplicate work.

Also, if you are using synchronous queuing (posting a receive call), each time you go you have to look for a message. That is, you wait during the time the server is comparing. When you use topics, the message has been compared up front and essentially put in your own private queue. You don't have to look at that point. It is FIFO from your own private queue. The server can do the comparisons while you are processing orders as opposed to your application blocking while the server finds you a message.

Q. Is it possible to have multiple queue receivers listening on the same queue, using message selectors (typically filtering on a correlation ID) to determine which listener actually receives the message?

A. Sun Microsystems' JMS specification does not define the behavior. WebLogic JMS 6.x or later supports this. Whenever a message lands on the queue, JMS will look at all of the consumers for the queue in the order in which they did their receives; whoever is the first to match the message receives the message. For asynchronous queue consumers, you must set your listener first, and then you will be first in the consumer list. However, each time an asynchronous queue consumer receives a message, the consumer goes to the end of the list. Note that unlike topics, if a message does not match a selector, it is left in the queue until someone has no selector, or a selector that does match.

Q. Is there a way to make a queue such that if one application has one object as listener on that queue, no other application can listen to the messages on that queue?

A. No. An alternative is to create a topic with a single durable subscription because a durable subscription may only have one consumer associated with it. The only drawback is that selectors would no longer work the same as they do with queues. Changing the selector on a durable subscription "resets" the subscription as per Sun Microsystems' JMS specification, causing all messages currently in the subscription to be deleted.

Q. Why doesn't setting values work using javax.jms.Message.setJMSPriority, DeliveryMode, Destination, TimeStamp or Expiration?

A. These methods are for vendor use only. The message values are overwritten on each send/publish. You should use the equivalent methods on the MessageProducer, QueueSender, or TopicPublisher to set these values (i.e., setJMSPriority, setDeliveryMode, setTimeToLive). Check to see that these values are not being overridden by the optional template configuration override values.

Q. What care must be taken when multi-threading WebLogic JMS clients?

A. The rules for multi-threading are described in section 2.8 of the JMS specification, with additional language in sections 4.4.6 on session usage, 4.4.9 on using multiple sessions, and 4.4.17 on concurrent message delivery. In a nutshell, it states that JMS sessions are single-threaded. Consequently, if multiple threads simultaneously access a session or one of its consumers or producers the resulting behavior is undefined. In addition, if multiple asynchronous consumers exist on a session, messages will be delivered to them in series and not in parallel.

To take advantage of multiple threads with JMS, use multiple sessions. For example, to allow parallel synchronous receive requests, design the application so that only one consumer may be active per session and use multiple sessions.

Q. How should an application be set up to subscribe to multiple topics?

A. If you want to listen to N topics, using N subscribers and N sessions gives you concurrency up to N simultaneous threads of execution provided you have that many threads to work with. N subscribers and 1 session serializes all subscribers through that one session. If the load is heavy they may not be able to keep up without the extra threads. Also, if you are using CLIENT_ACKNOWLEDGE, N sessions gives you N separate message streams that can be individually recovered. Having 1 session crosses the streams giving you less control.

As of version 6.x or later, WebLogic JMS on the server side efficiently uses a small, fixed number of threads independent of how many client sessions there are.

Q. How should I use blocking and asynchronous receive() calls?

A. The synchronous receive() method blocks until a message is produced, the timeout value, if specified, elapses or the application is closed. We strongly recommend that you avoid using blocking receive() calls on the server side because a synchronous receive() call consumes resources for the entire duration that the call is blocked.

Server deadlock might also result if receiving messages use client servlets, as described in the section "Receiving Messages with Client Servlets" in Programming WebLogic JMS.

When methods are received asynchronously, the application is notified using a message listener only when a message has been produced, so no resources are consumed waiting for a message.

Q. What precautions should I take when I use blocking receive() calls?

A. If your application design requires messages to be received synchronously, we recommend using one of the following methods listed in order of preference:

Note: Use of this option should be minimized, as it may deadlock a busy server.

Q. What is the NO_ACKNOWLEDGE acknowledge mode used for?

A. The NO_ACKNOWLEDGE acknowledge mode indicates that received messages do not need to be specifically acknowledged which improves performance, but risks that messages are lost. This mode is supported for applications that do not require the quality of service provided by session acknowledge and that do not want to incur the associated overhead.

Messages sent to a NO_ACKNOWLEDGE session are immediately deleted from the server. Messages received in this mode are not recovered and, as a result, messages may be lost and/or duplicate message may be delivered if an initial attempt to deliver a message fails.

Note: You should avoid using this mode if your application cannot handle lost or duplicate messages. Duplicate messages may be sent if an initial attempt to deliver a message fails.

In addition, we do not recommend that this acknowledge mode be used with persistent messaging, as it implies a quality of service that may be too low for persistent messaging to be useful.

Q. When should I use multicast subscribers?

A. Multicasting enables the delivery of messages to a select group of hosts that subsequently forwards the messages to multicast subscribers. The benefits of multicasting include:

Note: Multicasting is only supported for the Pub/sub messaging model.

For an example of when multicasting might be useful, consider a stock ticker. When accessing stock quotes, timely delivery is more important than reliability. When accessing the stock information in real-time, if all, or a portion, of the contents is not delivered, the client can simply request the information be resent. Clients would not want to have the information recovered in this case because by the time it is redelivered it would be out-of-date.

Multicast messages are not guaranteed to be delivered to all members of the host group. For messages requiring reliable delivery and recovery, you should not use multicasting.

Q. When should I use server session pools and connection consumers?

A. WebLogic JMS implements an optional JMS facility for defining a server-managed pool of server sessions. This facility enables an application to process messages concurrently. A ConnectionConsumer object uses a server session to process received messages. If message traffic is heavy, the connection consumer can load each server session with multiple messages to minimize thread context switching. Multiple connection consumers can share server sessions in a server session pool.

To learn how to use the connection consumers within an application, see the section Processing Messages Concurrently in Programming WebLogic JMS, or the javax.jms.ConnectionConsumer javadoc.

Note: Server session pools can also be implemented using Message Driven Beans. Using MDBs is preferable to using server session pools; this issue is addressed in, "How do server session pools and message driven beans compare?" For information on using message driven beans to implement server session pools, see Programming WebLogic Enterprise JavaBeans.

Q. How do I issue the close() method within an onMessage() method call and what are the semantics of the close() method?

A. If you wish to issue the close() method within an onMessage() method call, the system administrator must select the Allow Close In OnMessage check box when configuring the connection factory. For more information, see JMS Connection Factories in the Administration Console Online Help guide. If this check box is not selected and you issue the close() method within an onMessage() method call, the call will hang.

The close() method performs the following steps to execute an orderly shutdown:

When you close a connection, all associated objects are also closed. You can continue to use the message objects created or received via the connection, except the received message's acknowledge() method. Closing a closed connection has no effect.

Note: Attempting to acknowledge a received message from a closed connection's session throws an IllegalStateException.

When you close a session, all associated producers and consumers are also closed.

For more information about the impact of the close() method for each object, see the appropriate javax.jms javadoc.

Q. How do I publish an XML message?

A. Follow these steps:

  1. Generate XML from the DOM document tree.
  2. Serialize the generated DOM document to a StringWriter.
  3. Call toString on the StringWriter and pass it into message.setText.
  4. Publish the message.

Q. How do I use WebLogic JMS in an applet?

A. This topic is covered in news://newsgroups.bea.com/3ad321d5@newsgroups.bea.com.

Q. How do I use a startup class to initialize and later reference WebLogic JMS objects?

A. This topic is covered in news://newsgroups.bea.com/3ad0d7f3@newsgroups.bea.com. The sample code does not cleanup properly at shutdown. You can use a shutdown class that does something like the following:

JMSobject WLSobject = null;
try {
WLSobject = JMSStartUp.getJMSobject();
WLSobject.JMSCleanup();
} catch(Exception e) {}

Servlets can provide a nice solution to provide both initialization and cleanup. See the question in this section "What is the standard way for creating threads, doing initialization, etc. within the application server?".

Q. Is it possible to send or receive a message from within a message listener?

A. Yes. You can send to or receive from any queue or topic from within in a message listener.

If it's not an MDB, you can use the same Connection or Session that the onMessage() is part of to do this. When you create your message listener, you pass in a session in your constructor. Then you have access to the session in your onMessage method and you would be able to make synchronous, not asynchronous, calls from within the onMessage method. Do not use another Session that is servicing another onMessage() because that would multi-thread that Session and Sessions don't support multi-threading.

When things are done non-transactionally, there can be duplicates or lost messages (assuming your onMessage() code is attempting to forward messages):

  1. If you call acknowledge after the publish() and the acknowledge fails for whatever reason (network/server failure), then you will see the message again and will end up publishing twice (possible duplicate semantics). You can try to keep track of sequence numbers to detect duplicates but this is not easy.
  2. If you call acknowledge before the publish(), you get at-most-once semantics. If the publish() fails, you don't know if the failure occurred before or after the message reached the server.

If you want exactly once, transactional semantics using onMessage, you must use transactional MDBs. The onMessage() for a transactional MDB starts the transaction, includes the WebLogic Server JMS message received within that transaction and the publish() would also be in the same transaction. The following code sends a response to each message that it receives. It creates the connection, etc. in the ejbCreate method so that it doesn't need to create it every time onMessage is called. The QueueSender is anonymous (null Queue) since we don't know to whom we will have to reply. The ejbRemove method cleans up by closing the connection. This same approach can be used to create a receiver, subscriber or publisher.

import javax.ejb.CreateException;
import javax.ejb.EJBContext;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Hashtable;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.jms.*;
public class MDB
implements MessageDrivenBean, MessageListener {
public static final String WLSqcf =
"javax.jms.QueueConnectionFactory";
public static final String WLSqname =
"jms.queue.TestQueue1";
public static final String WLSurl =
"t3://localhost:7001";
public static final String WLSJNDIfactory =
"weblogic.jndi.WLInitialContextFactory";
private MessageDrivenContext context;
private QueueSession session;
private QueueConnection connection = null;
private QueueConnectionFactory factory;
private InitialContext ctx;
private QueueSender QueueSender;
// Required - public constructor with no argument
public MDB() {}
// Required - ejbActivate
public void ejbActivate() {}
// Required - ejbRemove
public void ejbRemove() {
context = null;
if (connection != null) {
try {
connection.close();
} catch(Exception e) {}
connection = null;
}
}
// Required - ejbPassivate
public void ejbPassivate() {}
public void setMessageDrivenContext(
MessageDrivenContext mycontext) {
context = mycontext;
}
// Required - ejbCreate() with no arguments
public void ejbCreate () throws CreateException {
try {
// Get the initial context
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, WLSJNDIfactory);
env.put(Context.PROVIDER_URL, WLSurl);
env.put(Context.REFERRAL, "throw");
ctx = new InitialContext(env);
    factory = (QueueConnectionFactory)ctx.lookup(WLSqcf);
  // Create a QueueConnection, QueueSession, QueueSender
connection = factory.createQueueConnection();
session = connection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
queueSender = session.createSender(null);
connection.start();
} catch (Exception e) {
throw(new CreateException(e.toString()));
}
}
// Implementation of MessageListener
// Throws no exceptions
public void onMessage(Message msg) {
try {
System.out.println("MDB: " +
((TextMessage)msg).getText());
msg.clearBody();
((TextMessage)msg).setText("reply message");
queueSender.send((Queue)msg.getJMSReplyTo(), msg);
}
catch(Exception e) { // Catch any exception
e.printStackTrace();
}
}
}

This approach creates a connection per EJB/MDB instance, so you might want to create a producer pool that is shared by the EJB instances. This is done by writing a class that populates a static pool with producers (see the next question for a sample producer pool). The onMessage call grabs a producer when needed. Since Sessions must be single threaded, make sure there is only one producer per session within the producer pool.

Q. How do I create a producer pool?

A. The following is some pseudo-code for a producer class.

class ProducerPool {
static Hashmap pSets = new Hashtable();
static Hashmap inUse = new Hashtable();
QueueSender get(String contextURL,
String connectionFactoryName,
String destinationName) {
String lookup = contextURL+";"+connectionFactName+";"+destName;
synchronized(pSets) {
producer set = pSets.get(lookup);
if (set != null && set not empty)
qs = set.removeFirst();
}
if (producer == null) {
create ctx
get connect factory
create connection
create session
look up destination
qs = create queue sender
}
synchronized(inUse) {
inUse.put(qs, lookup);
}
return qs;
}
void put(QueueSender qs) {
String lookup;
synchronized(inUse) {
lookup = inUse.remove(p);
}
synchronzied(pSets) {
producer set = pSets.get(lookup);
if (set == null) {
producer set = new producer set
pSets.put(lookup, producer set);
}
producer set.add(qs);
}
}
}

Note: Static classes may be garbage collected if there are no references to them, so make sure the application server has a permanent pointer to them in some manner. One way is to reference it permanently from within a servlet or EJB when they are initialized at startup.

Here is an example of using the producer pool within the onMessage method.

onMessage() {
QueueSender qs = ProducerPool.get(...);
qs.send(...);
ProducerPool.put(qs);
}

You can pre-populate this pool by calling it from a startup class or a load-on-start servlet class.

Q. What are pending messages in the console?

A. Pending means the message could have been:

A rolled back message remains pending until the transaction actually rolls back. Rolling it back multiple times does not cause double counting, nor does an exception that set a transaction as rollbackOnly followed by an actual rollback.

Current implies messages that are not pending.

Total implies total since server last started. The byte counts only consider the payload of messages which includes the properties and the body but not the header.

Q. How do I use a less than or greater than on a message selector in ejb-jar.xml?

A. Enclose the selector in a CDATA section. That will prevent the XML parser from thinking that less than or greater than is a tag.

<jms-message-selector>
<![CDATA[ JMSXAppID <> 'user' ]]>
</jms-message-selector>

Q. Is it better to have more or fewer sessions for a given number of subscribers?

A. Using N sessions for N subscribers gives you concurrency up to N simultaneous threads of execution provided you have as many threads to work with. Each Session gets its own thread as long as there are enough threads available. Otherwise, the sessions serially reuse the available threads.

One session for N subscribers serializes all subscribers through that one session. If the load is heavy they may not be able to keep up without the extra threads.

If you are using CLIENT_ACKNOWLEDGE, N sessions gives you N separate message streams that can be individually recovered. Having one session crosses the streams giving you less control.

Q. Are foreign destinations handled within foreign JMS messages?

A. WebLogic Server JMS does not know what to do with foreign destinations that it runs into. This issue has been discussed with Sun and the specification does not clearly define destinations well enough for vendors to interoperate at that level. They agree that it is sufficient not to handle foreign destinations preferably in such a way that sending/receiving still work. For WebLogic JMS, if you do a setJMSdestination (you should not because it is only for the provider to set it) with a foreign destination, it gets ignored (set to null). Similarly, if you do a setJMSReplyTo for a foreign destination, WebLogic JMS will ignore it (set it to null).

Q. What is the standard way to create threads, do initialization, etc. within the application server?

A. Threads should generally not be created by the user directly is because things may not work correctly. User-created threads do not have some of the thread-local variables pre-set by WebLogic when it creates it's own execute threads, the associated transaction context, or the environment such as the proper class loader. The WebLogic-specific way of doing this is with a startup class or using the WebLogic Time Services. The portable way to do this is to define a load-on-startup servlet, doing the initialization in the init() method and the cleanup in the destroy() method. The servlet itself does nothing. This approach also allows for undeploy/redeploy of the application without restarting the server, including proper cleanup/initialization each time. It also providers more dynamic management of the dependent classes without restarting the server.

Q. Why do I get a JNDI problem when I name a Topic A.B and a second Topic A.B.C?

A. This is a JNDI implementation issue. JNDI uses the dots to build a directory-like structure. A given element cannot be both a node and a leaf in the tree. In this example, B is used as a leaf off of A, but then is used as a node off of which C is a leaf.

Q. How many messages are sent across the network for processing topic messages?

A. If there are three subscribers for a message, for example, one of which with a selector that does not match, how many messages are sent?

In WebLogic JMS 6.x or later, when all three consumers are in the same session, we send one copy of the message across the network for all subscribers that are not flow-controlled. Once a consumer is flow-controlled for not acknowledging enough messages, no messages are sent until flow control is eased. So, the answer is usually one, but may be two. The selection is done on the server side so a subscriber that doesn't match doesn't have to discard anything.

Q. What should an XPATH selector look like?

A. The following is an example of an XPATH selector. Pay careful attention to the use of double and single quotes.

String selector = 
"JMS_BEA_SELECT('xpath', '/recipient/transport/text()') = 'email'";
tsubscriber = tsession.createSubscriber(topic, selector, false);

JMS_BEA_SELECT is a built-in function in WebLogic JMS SQL syntax. You put it in your selector string when you create a consumer. Note the use of single quotes around xpath, the XML tab, and the string value.

Q. How do I handle request/response using WebLogic JMS?

A. There are several approaches to handling request/response processing with JMS.

Q. How do I put a message back on the queue for processing?

A. The following are several approaches:

Q. Is it okay to add new sessions and subscribers to a Queue or Topic Connection once it has been started?

A. Yes, with one caveat. You may not add new subscribers/consumers to a session if it already has active async consumers. Sessions must only be accessed single-threaded as per Sun Microsystems' JMS specification spec. If you feel you need to do this, create a new Session and add it to that one instead.

You can add receivers to a started connection. A receiver in itself is not asynchronous. You need a listener to make it asynchronous. The first creation of a receiver is always safe. If you then add a listener for that first receiver, you have to worry for any future receivers in that same session. You can create new sessions and the first receiver for that session with no worries.

Once you want to create a second receiver in a session, if the first receiver has a MessageListener, you have to take care to make sure there are no other threads of execution in that session. You can do this by stopping the connection or actually creating your receiver from the onMessage routine of the first receiver.

Q. What can I do when I get java.lang.OutOfMemoryError because producers are faster than consumers?

A. Quotas can be used to help this situation. Your sender will then receive ResourceAllocationExceptions and the server will stay up.

As of WLS 6.1 SP02 or later, you can use the Message Paging feature, which can free up valuable virtual memory during peak message load periods by swapping out messages from virtual memory to persistent storage when message loads reach a specified threshold. For more information, see "Tuning JMS" in the Administration Console Online Help.

Q. Why have different connection factories?

A. To get multiple different sets of connection attributes. Clients that need different behaviors should use different factories. If all of your clients need the same behavior, then one factory is sufficient.

Q. How should connections and sessions be allocated?

A. Think of a connection as a single physical connection (a TCP/IP link). A session is a means for producing and consuming an ordered set of messages. Creating a connection is generally expensive. Creating a session is less expensive. Generally people use one connection and share across all the threads with each thread having its own session. If you have thread groups and need to start/stop/close the resources for a given group, one connection per group is good. A group can have exactly one thread.

Q. How does an application know if an application server goes down?

A. There are two exception listeners that you can register. Sun Microsystems' JMS specification defines Connection.setExceptionListener that tells you if there is a problem with the connection. That means that all consumers under that connection are also in trouble. The reason you will get the connection exception is because the WebLogic server you connect to on the other side is dead or not responding or someone killed your connection via the Mbean interface.

However, for WebLogic Server JMS, you may have multiple sessions in a connection, with the sessions going to multiple backend servers. WebLogic Server has an extension for this called WLSession.setExceptionListener that tells you if there is a problem with a session. For more information see http://e-doc.bea.com/wls/docs70/javadocs/weblogic/jms/extensions/WLSession.html.

Q. Is there a way to dynamically change an existing selector for a TopicConsumer using setMessageSelect(String s)?

A. No. Once you instantiate the consumer the selector is fixed at the time that the consumer is created. Changing the selector is like removing the current consumer, removing all associated messages and then creating a new one.

Q. How can I avoid asynchronous message deadlocks?

A. Due to a limitation in Sun Microsystems' JMS specification, asynchronous messages can become deadlocked if the close() method of a session is inside a user-synchronized block. To resolve this, you must move the close() method outside the user-synchronized block. For example:

public class CloseTest() {
private void xxx() {
synchronized (this) {
create connection/session/consumer
initialize and set a listener for this consumer;
wait();
connection.close();
}
}
 private void onMessage(Message message) {
synchronized (this) {
notify();
}
}
}

Before the connection.close() method is closed, another message can be delivered to the onMessage routine by the JMSProvider. The main() method thread owns the monitor lock for the CloseTest method. Before the onMessage() method of the CloseTest class fires, JMS sets INLISTENER as the state for the session in JMSSession (the JMS specification says that the close() method must wait for the onMessage routine), so that the main() method thread can wait for the onMessage routine to complete.

Now when the onMessage routine tries to acquire the monitor lock, it blocks waiting for the main() method thread to give up, and the main() method thread is waiting for the onMessage to be completed.

JMS also blocks when the close() method of a consumer is done from an onMessage routine and the allowCloseInOnMessage attribute is set to false in the config.xml file.

Q. What are the advantages of message-driven beans?

A. The message-driven bean is a stateless component that is invoked by the EJB container as a result of receiving messages from a JMS queue or topic. It then performs business logic based on the message contents, effectually freeing you from any JMS configuration and reconnection chores.

The message-driven bean model allows EJB developers to work with a familiar framework and set of tools, and also provides access to the additional support provided by the container. The goal of the message-driven bean model is to assure that developing an EJB that is asynchronously invoked to handle the processing of incoming JMS messages is as easy as developing the same functionality in any other JMS MessageListener.

One of the main advantages of using message-driven beans in place of the standard JMS MessageListener is that a JTA transaction can be started for you automatically and the received message will be part of that transaction. In this case, other operations can be infected with the same JTA transaction such as database operations. This is the only way to infect a message from an asynchronous consumer and another JTA operation with the same transaction.

For more information on message-driven beans, see Designing Message-Driven Beans in Programming WebLogic Enterprise JavaBeans.

Q. How does concurrency work for message-driven beans?

A. The way concurrency is achieved for Queues is by spawning one JMSSession per MDB instance in the pool. Since JMSSessions are processed in parallel by JMS, concurrency is obtained naturally this way and JMS takes care of delivering the message to, at most, one listener. If an MDB is deployed to multiple servers in a cluster, JMSSessions are created for each MDB instance on each server and load balancing will be done across them.

Within a single server, one topic consumer is used to pass out messages to multiple threads to get the concurrency while producing only a single copy of each message. You can configure multiple MDBs to listen on the same topic and each MDB will receive a copy of every message. When using multiple servers, each server gets its own consumer and therefore its own copy of each message. It is not currently possible to share a consumer across multiple servers. If you want a message to be processed by exactly one MDB, use a queue.

One customer had an example where topic MDBs are needed in which there will be multiple implementations of the MDBs listening on the same topic. In other words, more than one MDB with a different implementation may be subscribing to the same topic. The client has no advanced way of knowing how many different kinds of MDBs may be listening on the same topic, but it is possible for there to be more than one listener, therefore topics, not queues. For each kind of MDB listening on the topic, the message is delivered exactly once (i.e., the message will be delivered exactly once to an instance in each named MDB pool listening on the topic).

Q. Can an MDB be a message producer or both a producer and consumer?

A. Yes. You have no JMS context inside the MDB so you will need to establish a connection, session and producer yourself. One option is to do this every time you come into the onMessage routine for the MDB. This is sufficient if the message rate is relatively low. The second option is to establish the necessary objects in ejbActivate(). Note that the objects are not serializable so they can't be passivated for a stateful session bean or an entity bean. When the EJB deactivates, you need to close the associated objects. The third option is that you could build up a JMS connection/sender session pool within a startup class complete with your own synchronization and blocking to get a connection. There is an example in the answer to the question in this section, "Is it possible to send or receive a message from within a message listener?".

Q. If an MDB uses a durable subscription, will messages be accumulated if the MDB is not deployed?

A. Not at this time. Before the MDB is deployed the first time, no messages are accumulated for when it is deployed. This is different from passivated. Just because the MDB is not currently active doesn't mean it isn't deployed. The container still maintains the subscription and gives out messages to the MDBs.

Q. How do I use non-WebLogic JMS provider destinations to drive MDBs?

A. See the "Using Foreign JMS Providers with WebLogic Server" white paper (jmsproviders.pdf) on http://dev2dev.bea.com/resourcelibrary/whitepapers.jsp?highlight=whitepapers for a discussion on this topic.

Q. Can you use a foreign JMS provider to drive an MDB transactionally?

A. Yes. In WebLogic Server 7.0 and later, you can deploy an MDB that supports container-managed transactions against a foreign JMS provider. If the MDB is configured with a "transaction-type" attribute of "Container" and a "trans-attribute" of "Required", then WLS will use XA to automatically enlist the foreign JMS provider in a transaction. (See the next question for an example of an MDB that uses container-managed transactions.)

If the foreign JMS provider does not support XA, then you cannot deploy an MDB that supports container-managed transactions with that provider. Furthermore, if the JMS provider does support XA, you must ensure that the JMS connection factory that you specify in the weblogic-ejb-jar.xml file supports XA—each JMS provider has a different way to specify this.

See the white paper, "Using Foreign JMS Providers with WebLogic Server" (jmsproviders.pdf.doc) on http://dev2dev.bea.com/resourcelibrary/whitepapers.jsp?highlight=whitepapers for an example of how to configure an MDB to use a foreign provider.

Q. How do I use JTA transactions within an MDB?

A. In the ejb-jar.xml file, define the transaction type as Container and the trans-attribute as Required, as in the following example:

<ejb-jar>
<enterprise-beans>
<message-driven>
<ejb-name>MDB</ejb-name>
<ejb-class>MDB</ejb-class>
<transaction-type>Container</transaction-type>
<message-driven-destination>
<destination-type>javax.jms.Queue</destination-type>
</message-driven-destination>
</message-driven>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>MDB</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>
Required
</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

To roll back a transaction, you can either use the Weblogic extension TXHelper or you can use the MDB context as in the following code examples:

UserTransaction ut =
weblogic.transaction.TXHelper.getUserTransaction();
ut.setRollbackOnly();

or

private MessageDrivenContext context;
public void setMessageDrivenContext(
MessageDrivenContext mycontext) {
context = mycontext;
}
public void onMessage(Message msg) {
try { // some logic
}
catch(Exception e) {
System.out.println("MDB doing rollback");
context.setRollbackOnly();
}

Q. How do server session pools and message driven beans compare?

A. MDBs listen on exactly one destination. Consumers listen on exactly one destination. ConnectionConsumers listen on exactly one destination.

A ServerSessionPool can have multiple ConnectionConsumers, which allows you to have a single MessageListener being fed by multiple consumers.

ServerSessionPools do not infect the MessageListener with a transaction, so the receipt of the message that initiated the listener is not part of the transaction. For an MDB, you can specify transaction as being REQUIRED and the driving message is part of the transaction.

ServerSessionPools have the limitation that the destination on which its connection consumers are listening must be hosted by the same JVM. That is, you cannot have a server session pool listening on a remote queue or topic and foreign (non-WebLogic Server JMS) destinations are not supported. MDBs can be distributed and can have foreign destinations.

MDBs currently receive one message per deployment (in Service Pack 1). If you have an MDB with multiple instances on a single server listening on a topic, it will receive only one copy of the a published messages regardless of the number of instances. If you have an MDB deployed across multiple machines listening on a topic, each deployment will receive a copy of any published message on that topic. You will get multiple copies of the message distributed evenly across all of your MDB deployments.

 

Back to Top Previous Next