JBoss AS 7 – Remote JMS queue


Today I’d like to post a quick, laconic, and hopefully 100% correct sample of remote JMS queue utilization in JBoss 7 AS. Diagram posted below shows the target environment where one application server instance hosts JMS queue, and the other one acts as message producer and consumer.

Remote JMS Environment

JBoss2 (queue owner) configuration:

<hornetq-server>
   <security-domain>hornetq-security-domain</security-domain>
   ...
   <jms-destinations>
      <jms-queue name="RemoteQueue1">
         <entry name="queue/RemoteQueue1"/>
         <entry name="java:jboss/exported/jms/queue/RemoteQueue1"/>
      </jms-queue>
   </jms-destinations>
</hornetq-server>
...
<security-domains>
   ...
   <security-domain name="hornetq-security-domain" cache-type="default">
      <authentication>
         <login-module code="UsersRoles" flag="required">
            <module-option name="usersProperties" value="/opt/jboss3/standalone/configuration/jms-users.properties"/>
            <module-option name="rolesProperties" value="/opt/jboss3/standalone/configuration/jms-roles.properties"/>
         </login-module>
       </authentication>
   </security-domain>
</security-domains>
[jboss@jmsenv Desktop]$ cat /opt/jboss3/standalone/configuration/jms-users.properties
jmsuser=jmspassword
[jboss@jmsenv Desktop]$ cat /opt/jboss3/standalone/configuration/jms-roles.properties
jmsuser=guest

The security related entries are not required if you decide to assign unauthorized users to “guest” group (which is by default allowed to send and receive messages). This can be achieved by adding <module-option name="unauthenticatedIdentity" value="guest"/> to login module configuration.

JBoss1 (queue user) configuration:

<hornetq-server>
   ...
   <connectors>
      <connector name="remote-jms-nonmgmt">
         <factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class>
         <param key="host" value="192.168.117.159"/>
         <param key="port" value="5445"/>
      </connector>
      <netty-connector name="remote-jms-mgmt" socket-binding="remote-jms-binding"/>
   </connectors>
   <jms-connection-factories>
      ...
      <connection-factory name="ConnectionFactory1NonMgmt">
         <connectors>
            <connector-ref connector-name="remote-jms-nonmgmt"/>
         </connectors>
         <entries>
            <entry name="java:/ConnectionFactory1NonMgmt"/>
         </entries>
      </connection-factory>
      <pooled-connection-factory name="ConnectionFactory1Mgmt">
         <user>jmsuser</user>
         <password>jmspassword</password>
         <connectors>
            <connector-ref connector-name="remote-jms-mgmt"/>
         </connectors>
         <entries>
            <entry name="java:/ConnectionFactory1Mgmt"/>
         </entries>
      </pooled-connection-factory>
   </jms-connection-factories>
</hornetq-server>
...
<socket-binding-group name="full-ha-sockets" default-interface="public">
   ...
   <outbound-socket-binding name="remote-jms-binding">
      <remote-destination host="192.168.117.159" port="5445"/>
   </outbound-socket-binding>
</socket-binding-group>

Producer code:

@Resource(mappedName = "java:/ConnectionFactory1Mgmt")
private ConnectionFactory connectionFactory;

public void sendMessage(String text) {
   Connection connection = connectionFactory.createConnection();
   Session session = connection.createSession( false, Session.AUTO_ACKNOWLEDGE );
   Queue queue = session.createQueue( "RemoteQueue1" );
   MessageProducer producer = session.createProducer( queue );
   connection.start();
   TextMessage message = session.createTextMessage();
   message.setText( text );
   producer.send( message );
   session.close();
   connection.close();
}

Message-Driven Bean consumer code:

import org.jboss.ejb3.annotation.ResourceAdapter;

@ResourceAdapter("ConnectionFactory1Mgmt")
@MessageDriven(
   name="ConsumerMdb",
   activationConfig = {
      @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
      @ActivationConfigProperty(propertyName="destination", propertyValue="queue/RemoteQueue1")
})
public class ConsumerMdb implements MessageListener {
   ...
}

Here you might need to import org.jboss.ejb3:jboss-ejb3-ext-api:2.0.0 library into you project, but don’t forget to mark it as provided by the runtime environment.

Manually consuming messages from EJB (inside container):

InitialContext context = new InitialContext();
ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup( "ConnectionFactory1NonMgmt" );
Connection connection = connectionFactory.createConnection( "jmsuser", "jmspassword" );
Session session = connection.createSession( false, Session.AUTO_ACKNOWLEDGE );
Queue queue = session.createQueue( "RemoteQueue1" );
MessageConsumer consumer = session.createConsumer( queue );
connection.start();
Message message = consumer.receive();

General notes:

  1. Use <pooled-connection-factory> for MDBs and message producers deployed inside container.
  2. Use <connection-factory> for non-managed producers and consumers (including the remote once).

Reading:

  1. JBoss forum thread: https://community.jboss.org/message/722711.
  2. Justin Bertram explaining my doubts (thanks!): https://community.jboss.org/message/780778.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: