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:
<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 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();
}
Page Numbers :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18