How does concurrency work for message-driven beans?
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.
For Topics in WebLogic JMS 6.1, there is one JMSSession per bean instance in the pool. Because of the way Topics work, the session, and thus every bean instance, receives a copy of each message published on that Topic. (There was also a problem that caused parallel processing not to work correctly. This has been fixed for WLS 6.0 Service Pack 1.) 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).
Which of the following are valid relationships between JMS objects in the WebLogic Server?
a. A single JMS store can support multiple JMS servers.
b. Multiple consumers may consume from the same queue, but multiple producers may not send to the same queue.
c. Multiple JMS Servers may exist on one WebLogic 6.0 server.
d. A JMS Server can be deployed on only one server.
Choices C and D correct. JMS is an enterprise messaging system, which enables applications to communicate with one another through the exchange of messages. WebLogic JMS provides a full implementation of the JMS API.JMS objects are the objects necessary to connect to the JMS, and send and receive messages.
The major components of the WebLogic JMS Server architecture include WebLogic JMS servers implementing the messaging facility, Client applications, JNDI and Backing stores (file or database) for storing persistent data. Two or more JMS servers cannot share the same persistent store. 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. Multiple consumers may consume from the same queue and multiple producers may send messaged to the same queue. Multiple JMS servers may exist on the same WebLogic server, but a JMS server can be deployed only on server at a time.
Can an MDB be a message producer or both a producer and consumer?
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 "Is it possible to send or receive a message from within a message listener?"
Can you use a foreign JMS provider to drive an MDB transactionally?
No. The message is asynchronously received outside a transaction and there is no J2EE API to then associate the message with a transaction.
The only reason this works for WebLogic Server JMS is that we have defined a WebLogic Server extension interface that has a method to associate a message with a transaction. This interface, MDBTransaction, is defined in news://newsgroups.bea.com/3b3a009b$1@newsgroups.bea.com. It has one method, associateTransaction(), that takes a javax.jms.Message parameter. This message must be associated with the transaction. We are hoping that other JMS vendors interested in integrating with WebLogic Server will implement this interface.
Another approach called source managed transactions, would be for there to be an API to tell the JMS provider to start a transaction on your behalf before delivering the message to an asynchronous consumer. This API doesn't exist in J2EE either. Even if there were such a provision, few non-WLS JMS providers can begin and drive such a transaction by themselves.
The current solution is to move all messages from the foreign destination to a WebLogic Server JMS destination (within a transaction if the foreign JMS provider supports it) and have that WebLogic Server JMS destination drive the MDB transactionally (using the WLS JMS special interface). Currently, the messages can be moved between providers using code similar to that described in the "Using Foreign JMS Providers With WebLogic Server" white paper. This code could be contained in a startup class that starts a thread and does the following:
while (true) {
start a transaction
receive a message synchronously with timeout
if timed_out { rollback and continue }
do the work
commit the transaction }
Doing a synchronous receive will have a problem in that the transaction may time out before the message is received. You can do the receive with a specified timeout, allowing enough time left in the transaction to complete the work. If the receive fails, roll back the transaction and try again. It is also not as efficient as MDBs since it does a synchronous instead of asynchronous receive (it ties up threads). Also, if you get a lot of timeouts, you will be burning more CPU.
Eventually, WLS JMS will provide a bridge to handle this message passing out-of-the box.
With any of these approaches, the XAResource must be registered with the Transaction Manager (this is done automatically for WebLogic Server JMS).
How do I use JTA transactions within an MDB?
In the ejb-jar.xml file, define the transaction type as Container and the trans-attribute as Required, as in the following example:
Required
To rollback 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();
}
No comments:
Post a Comment