There appears to be some inconsistency on how to use JMS resources, and setting up activationConfig
with proper @ActivationConfigProperty
on a @MessageDriven
annotation.
First, here is my resource config (glassfish-resources.xml, but translatable to other deployment descriptors). This is applied to Glassfish (asadmin add-resources glassfish-resources.xml
) along with the ActiveMQ Resource Adapter:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<resource-adapter-config name="activemq-rar"
thread-pool-ids="thread-pool-1"
resource-adapter-name="activemq-rar">
<property name="ServerUrl" value="tcp://localhost:61616"/>
<property name="UserName" value="admin"/>
<property name="Password" value="admin"/>
<property name="UseInboundSession" value="false"/>
</resource-adapter-config>
<admin-object-resource enabled="true"
jndi-name="jms/queue/myApp"
object-type="user"
res-adapter="activemq-rar"
res-type="javax.jms.Queue">
<description>MyApp JMS Queue</description>
<property name="Name" value="myAppAMQ"/>
<property name="PhysicalName" value="myAppAMQ"/>
</admin-object-resource>
<connector-resource enabled="true"
jndi-name="jms/factory/myApp"
object-type="user"
pool-name="jms/factoryPool/myApp">
<description>MyApp Connection Factory</description>
<property name="Name" value="myAppFactory"/>
</connector-resource>
<connector-connection-pool associate-with-thread="false"
connection-creation-retry-attempts="0"
connection-creation-retry-interval-in-seconds="10"
connection-definition-name="javax.jms.QueueConnectionFactory"
connection-leak-reclaim="false"
connection-leak-timeout-in-seconds="0"
fail-all-connections="false"
idle-timeout-in-seconds="300"
is-connection-validation-required="false"
lazy-connection-association="false"
lazy-connection-enlistment="false"
match-connections="true"
max-connection-usage-count="0"
max-pool-size="32"
max-wait-time-in-millis="60000"
name="jms/factoryPool/myApp"
ping="false"
pool-resize-quantity="2"
pooling="true"
resource-adapter-name="activemq-rar"
steady-pool-size="8"
validate-atmost-once-period-in-seconds="0"/>
</resources>
Here is my message provider bean. You'll notice that JNDI names are found and the ActiveMQ resources are used without error, the message sent to the proper queue:
@Stateless
@LocalBean
public class ServicesHandlerBean {
@Resource(mappedName = "jms/queue/myApp")
private Queue queue;
@Resource(mappedName = "jms/factory/myApp")
private ConnectionFactory factory;
public void sendJMSMessage(MessageConfig messageData) throws JMSException {
Connection connection = null;
Session session = null;
try {
connection = factory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(queue);
messageProducer.send(createJMSMessage(session, messageData));
} finally {
if (session != null) {
try {
session.close();
} catch (JMSException e) {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot close session", e);
}
}
if (connection != null) {
connection.close();
}
}
}
}
The confusion begins when defining a @MessageDriven bean. The following which uses mappedName throws an exception:
@MessageDriven(mappedName = "jms/queue/myApp")
public class MessageBean implements MessageListener
Warning: RAR8000 : The method setName is not present in the class :
org.apache.activemq.command.ActiveMQQueue Warning: RAR7097: No
setter method present for the property Name in the class
org.apache.activemq.command.ActiveMQQueue Info: visiting unvisited
references Info: visiting unvisited references Warning: RAR8501:
Exception during endpoint activation for ra [ activemq-rar ],
activationSpecClass [ org.apache.activemq.ra.ActiveMQActivationSpec ]
: javax.resource.ResourceException: Unknown destination type: null
Severe: MDB00017: [InvoiceProductionMessageBean]: Exception in
creating message-driven bean container: [java.lang.Exception] Severe:
java.lang.Exception
I'm forced to define my MDB as such:
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(propertyName = "connectionFactoryLookup", propertyValue = "jms/factory/myApp"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "myAppAMQ"),
@ActivationConfigProperty(propertyName = "messageSelector", propertyValue = " JMSType = 'TypeA' "),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
}
)
public class MessageBean implements MessageListener
AND I need to supply a glassfish-ejb-jar.xml telling the container to use the ActiveMQ resource, otherwise I get a java.lang.ClassCastException
:
Warning: RAR8501: Exception during endpoint activation for ra [
jmsra ], activationSpecClass [ com.sun.messaging.jms.ra.ActivationSpec
] : java.lang.ClassCastException:
org.apache.activemq.ra.ActiveMQConnectionFactory cannot be cast to
com.sun.messaging.jms.ra.DirectConnectionFactory Severe: MDB00017:
[MessageBean]: Exception in creating message-driven
bean container: [java.lang.Exception] Severe: java.lang.Exception
glassfish-ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-ejb-jar PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 EJB 3.1//EN" "http://glassfish.org/dtds/glassfish-ejb-jar_3_1-1.dtd">
<glassfish-ejb-jar>
<enterprise-beans>
<ejb>
<ejb-name>MessageBean</ejb-name>
<mdb-resource-adapter>
<resource-adapter-mid>activemq-rar</resource-adapter-mid>
</mdb-resource-adapter>
</ejb>
</enterprise-beans>
</glassfish-ejb-jar>
So, there seems to be some inconsistencies between how a producer can use a resource (JNDI), and how a consumer does (XML + @ActivationConfigProperty
). Also, the EE7 ActivationConfigProperty properties don't appear to work. For instance, using destinationLookup doesn't lookup the destination, and I'm forced to use ActiveMQ's destination
property.
ActiveMQ lists the following Activation Spec Properties:
acknowledgeMode (The JMS Acknowledgement mode to use. Valid values
are: Auto-acknowledge or Dups-ok-acknowledge)
clientId (The JMS Client ID to use (only really required for durable
topics))
destinationType (The type of destination; a queue or topic)
destination (The destination name (queue or topic name))
enableBatch (Used to enable transaction batching for increased
performance)
maxMessagesPerBatch (The number of messages per transaction batch)
maxMessagesPerSessions (This is actually the prefetch size for the
subscription. (Yes, badly named).)
maxSessions (The maximum number of concurrent sessions to use)
messageSelector (The JMS Message Selector to use on the subscription
to perform content based routing filtering the messages)
noLocal (Only required for topic subscriptions; indicates if locally
published messages should be included in the subscription or not)
password (The password for the JMS connection)
subscriptionDurability (Whether or not a durable (topic) subscription
is required. Valid values are: Durable or NonDurable)
subscriptionName (The name of the durable subscriber. Only used for
durable topics and combined with the clientID to uniquely identify the
durable topic subscription)
userName (The user for the JMS connection)
useRAManagedTransaction (Typically, a resource adapter delivers
messages to an endpoint which is managed by a container. Normally,
this container likes to be the one that wants to control the
transaction that the inbound message is being delivered on. But
sometimes, you want to deliver to a simpler container system that will
not be controlling the inbound transaction. In these cases, if you set
useRAManagedTransaction to true, the resource adapter will commit the
transaction if no exception was generated from the MessageListener and
rollback if an exception is thrown.)
initialRedeliveryDelay (The delay before redeliveries start. Also
configurable on the ResourceAdapter)
maximumRedeliveries (The maximum number of redeliveries or -1 for no
maximum. Also configurable on the ResourceAdapter)
redeliveryBackOffMultiplier (The multiplier to use if exponential back
off is enabled. Also configurable on the ResourceAdapter)
redeliveryUseExponentialBackOff (To enable exponential backoff. Also
configurable on the ResourceAdapter useJndi no false when true, use
destination as a jndi name)
Java EE7 spec lists the following Activation Spec Properties:
acknowledgeMode (This property is used to specify the JMS
acknowledgement mode for the message delivery when bean-managed
transaction demarcation is used. Its