10 Annotations you can use on your MDBs

This article covers the annotations you can apply on Message Driven Beans to configure specific aspects of the subscription.

You can configure Message Driven Beans through a wide list of Properties. Most of them are activation configuration properties (e.g.  name-value pairs that are passed to the MDB container at deployment time). You can declare these properties either with the ejb-jar.xml deployment descriptor and with the @ActivationConfigProperty annotation on the MDB bean class. Let’s see in detail all the possible annotations you can apply.

subscriptionDurability

By default, messages published to a topic are delivered only to subscribers which are active. Durable Subscriptions make it possible for a subscriber to receive JMS messages which are published while the subscriber application was away. This implies another subtle difference with Non Durable subscriptions: a Durable subscription can recover a server stop/crash provided that its messages are configured to be Persistent. On the other hand, Non durable subscriptions never recover from a server crash:

+----------------------------+        +-----------------------------+
|                            |        |                             |
|    Durable Subscriptions   |        |  Non Durable Subscription   |
+----------------------------+        +-----------------------------+
|                            |        |                             |
| Receives messages also     |        | Receives messages when the  |
| when the subscriber is     |        | subscriber is active        |
| not active                 |        |                             |
|                            |        | Never survive server restart|
| Can survive server restart |        |                             |
|                            |        |                             |
+----------------------------+        +-----------------------------+

Here are the key annotations of it:

@ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
@ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "NonDurable")

destinationType

This property can let you discriminate if you are consuming messages from a Queue or Topic. No further explanation needed.

@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic")
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")

connectionFactoryLookup

This property is essential if you want to use a non default Connection factory such as a Remotely defined Factory:

@ActivationConfigProperty(propertyName = "connectionFactoryLookup", propertyValue = "RemoteConnectionFactory")

shareSubscriptions

Since JMS 2.0 it is possible to use Shared Subscription, which means that messages from a Topic can be shared by multiple consumers. This can improve the scalability of your JMS system. If you are using MDBs as consumers, the effect is that the message will be delivered to only one of the shared consumers:

@ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "mytopic"),
@ActivationConfigProperty(propertyName = "shareSubscriptions", propertyValue="true"),

destinationLookup

This is the JNDI name of the queue/topic that the MDB subscribes to. The Queue/Topic needs obviously to be available in your server configuration.

@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "topic/ExampleTopic"),

messageSelector

A message selector allows a JMS consumer filter messages that it receives from a particular topic or queue. A message selector uses message properties and headers as criteria in conditional expressions. These expressions use Boolean logic to declare which messages should be delivered to a client.

For example, if you want to get only those messages whit order id > 100:

@ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "orderid > 100")

Sender example:

Message message = session.createMessage();
message.setObjectProperty("orderid", "15");
producer.send(message);

maxSession

This property determines the maximum number of JMS sessions that the JCA Resource Adapter can concurrently deliver messages to the MDB Pool. (See next to learn more about the MDB Pool). For example:

+----------------------------------------------------+
|                                                    |
| +--------------+                                   |
| |              |                                   |
| |    JCA       |            +------------------+   |
| |              |            |                  |   |
| |    JMS       |            |                  |   |
| |  Sessions    +--------------->  MDB Pool     |   |
| |              |            |                  |   |
| |  maxSession  |            |                  |   |
| |              |            |                  |   |
| |              |            |                  |   |
| |              |            +------------------+   |
| |              |                                   |
| |              |                                   |
| +--------------+                                   |
|                                                    |
+----------------------------------------------------+
@ActivationConfigProperty( propertyName = "maxSession", propertyValue = "someNumber")

How do I ensure that messages are consumed in the same order as they are produced ?

Contrary to what the name queue suggests, messages don’t have to be delivered in the order sent. If the message driven bean pool contains more than one instance then messages can be processed concurrently. Therefore, there is no guarantee about message ordering.

However, you can set the maxSession attribute to 1, so that only one JMS Session will run at the same time. Example for MDB Consumer:

<message-driven>
            <ejb-name>MyMDB</ejb-name>
            <ejb-class>com.demo.ProcessorMDB</ejb-class>
            <activation-config>
               <activation-config-property>
                  <activation-config-property-name>maxSession</activation-config-property-name>
                  <activation-config-property-value>1</activation-config-property-value>
               </activation-config-property>
            </activation-config>
</message-driven>

Keep in mind that maintaining message ordering has obvious performance implications.

Pool size

The MDB pool size governs the amount of MDB instances that are available for processing the inflow Session. The org.jboss.ejb3.annotation.Pool lets you reference your pool configuration. For example:

@org.jboss.ejb3.annotation.Pool(value="mdb-strict-max-pool") 

Please note that the mdb-strict-max-pool is applied to each deployed EJB instance. Take this into account if you are deploying multiple MDB classes.

acknowledgeMode

The acknowledgment protocol allows the JMS provider to monitor the progress of a message so that it knows whether the message was successfully produced and consumed. With AUTO_ACKNOWLEDGE mode the acknowledgment happens implicitly after the onMessage() handler returns. The use of CLIENT_ACKNOWLEDGE allows the application to control when the acknowledgment is sent.

@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")

Mind it: If you’re configured to use PERSISTENT messages, any exceptions in onMessage() will persist the message for re-delivery based on broker and destination settings. If you’re using NON_PERSISTENT messages, any exception in onMessage() typically discards the message.

Resource Adapter

This annotation can let you use a Resource Adapter to connect to a non-default JMS Broker:

@ResourceAdapter("activemq-ra.rar")  

How to build applications with JBoss annotations

Please notice that the above annotation requires a JBoss specific dependency. You need to add the following dependency to your Maven project:

<dependency>
         <groupId>org.jboss.ejb3</groupId>
         <artifactId>jboss-ejb3-ext-api</artifactId>
         <scope>provided</scope>
</dependency>

See the following tutorial for a complete example of it: Integrate ActiveMQ with WildFly