SwiftMQ 4.x/JBoss 3.0.3 IntraVM

Introduction

SwiftMQ 4.0.0 introduces a new intra-VM JMS client and includes an MBean in swiftmq.jar to start SwiftMQ as an intra-VM service in JBoss. This has been tested with SwiftMQ 4.0.0 and JBoss 3.0.3.

Note that you have to use the JMS XA/ASF Swiftlet!

Configuration

The following example assumes to use the JBoss default server, located under "<jboss-home>/server/default".

JBoss

SwiftMQ 4.x uses JMS 1.1 but JBoss 3.0.3 includes JMS 1.0.2 classes in "lib/jboss-j2ee.jar" so you have to delete all "javax/jms" classes out of this jar file. Then copy "jms.jar", "dom4j-full.jar" and "swiftmq.jar" from the router's "jars/" directory to JBoss' "lib/" directory.

Delete all "jbossmq-*.xml" files from "deploy/". The only remaining JMS related XML file should be "jms-service.xml".

Edit "deploy/jms-service.xml" and replace this part:

      <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
         name="jboss.mq:service=JMSProviderLoader,name=JBossMQProvider">
        <attribute name="ProviderName">DefaultJMSProvider</attribute>
        <attribute name="ProviderAdapterClass">
          org.jboss.jms.jndi.JBossMQProvider
        </attribute>
        <attribute name="QueueFactoryRef">java:/XAConnectionFactory</attribute>
        <attribute name="TopicFactoryRef">java:/XAConnectionFactory</attribute>
      </mbean>

with this:

      <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
               name="swiftmq:service=JMSProviderLoader,name=SwiftMQProvider">
        <attribute name="ProviderName">DefaultJMSProvider</attribute>
        <attribute name="ProviderUrl">smqp://intravm/timeout=10000</attribute>
        <attribute name="ProviderAdapterClass">com.swiftmq.appserver.jboss.SwiftMQAdapter</attribute>
        <attribute name="QueueFactoryRef">IVMQueueConnectionFactory</attribute>
        <attribute name="TopicFactoryRef">IVMTopicConnectionFactory</attribute>
        <depends>jboss:service=SwiftMQIntraVM</depends>
      </mbean>

Note that "smqp://intravm/timeout=10000" creates an intra-VM connection when using SwiftMQ's JNDI and both connection factory refs are intra-VM connection factories as well.

Next is to edit "conf/jboss-service.xml" to ensure SwiftMQ is started as an intra-VM service in JBoss. Add the MBean to start SwiftMQ right after the JNDI (Naming) MBean:

      <!-- ==================================================================== -->
      <!-- SwiftMQ Universal Router IntraVM                                               -->
      <!-- ==================================================================== -->
      <mbean code="com.swiftmq.appserver.jboss.SwiftMQIntraVMService"
        name="jboss:service=SwiftMQIntraVM">
        <attribute name="RouterWorkingDirectory">d:/swiftmq_4_0_0/scripts/win32</attribute>
        <attribute name="ConfigurationFilename">../../config/router1/routerconfig.xml</attribute>
        <depends>jboss:service=Naming</depends>
      </mbean>

The reason for the dependency from the Naming service is to ensure that it is up before SwiftMQ is started in case you like to use JNDI replication from SwiftMQ into JBoss' JNDI. The attribute "RouterWorkingDirectory" must point to the directory where the "smqr1" etc scripts are located, because any directory references in SwiftMQ's "routerconfig.xml" are relative to this directory. The attribute "ConfigurationFilename" contains the directory/name of the router's configuration file, relative to "RouterWorkingDirectory". Don't specify an absolute path here!

The last configuration step for JBoss is to change a dependency of the "EJBDeployer" service from JBossMQ to SwiftMQ.

Replace:

      <mbean code="org.jboss.ejb.EJBDeployer" name="jboss.ejb:service=EJBDeployer">
        <attribute name="VerifyDeployments">true</attribute>
        <attribute name="ValidateDTDs">false</attribute>
        <attribute name="MetricsEnabled">false</attribute>
        <attribute name="VerifierVerbose">true</attribute>
        <!-- Add a dependency on the JMS provider(jms-service.xml) for MDBs. If
          you are not using MDBs and JMS remove these.
        -->
        <depends>jboss.mq:service=JMSProviderLoader,name=JBossMQProvider</depends>
        <depends>jboss.mq:service=ServerSessionPoolMBean,name=StdJMSPool</depends>
      </mbean>

With:

      <mbean code="org.jboss.ejb.EJBDeployer" name="jboss.ejb:service=EJBDeployer">
        <attribute name="VerifyDeployments">true</attribute>
        <attribute name="ValidateDTDs">false</attribute>
        <attribute name="MetricsEnabled">false</attribute>
        <attribute name="VerifierVerbose">true</attribute>
        <!-- Add a dependency on the JMS provider(jms-service.xml) for MDBs. If
          you are not using MDBs and JMS remove these.
        -->
        <depends>swiftmq:service=JMSProviderLoader,name=SwiftMQProvider</depends>
        <depends>jboss.mq:service=ServerSessionPoolMBean,name=StdJMSPool</depends>
      </mbean>

SwiftMQ

JMS Swiftlet

Create the two intra-VM connection factories "IVMQueueConnectionFactory" and "IVMTopicConnectionFactory":

      <swiftlet name="sys$jms">
        <intravm-connection-factories>
          <intravm-connection-factory name="IVMQueueConnectionFactory"/>
          <intravm-connection-factory name="IVMTopicConnectionFactory"/>
        </intravm-connection-factories>
        ...
      </swiftlet>

Queue Manager Swiftlet

JBoss uses a dead letter queue where it puts messages which have been redelivered too many times due to transaction rollbacks from MDBs. Create a queue you wish to use for this and create all other queues you need for your application. Ensure the flow control is disabled for the dead letter queue:

      <swiftlet name="sys$queuemanager">
        <queues>
          <queue name="jboss-deadletter" flowcontrol-start-queuesize="-1"/>
          <queue name="testqueue1"/>
          <queue name="testqueue2"/>
          <queue name="testqueue3"/>
          <queue name="testqueue4"/>
          <queue name="testqueue5"/>
        </queues>
      </swiftlet>

Topic Manager Swiftlet

Create all topics you need for your application:

      <swiftlet name="sys$topicmanager">
        <slow-subscriber-conditions/>
        <static-remote-router-subscriptions/>
        <topics>
          <topic name="testtopic1"/>
          <topic name="testtopic2"/>
          <topic name="testtopic3"/>
          <topic name="testtopic4"/>
          <topic name="testtopic5"/>
        </topics>
      </swiftlet>

JNDI Swiftlet

JBoss prefixes queues with "queue/" and topics with "topic/", therefore you must define a JNDI alias for each queue and topic you use. In case you like to send messages via SwiftMQ out of MDBs or EJBs, you must define a JNDI replication into JBoss' JNDI:

      <swiftlet name="sys$jndi">
        <aliases>
          <alias name="queue/DLQ" map-to="jboss-deadletter@router1"/>
          <alias name="queue/testqueue1" map-to="testqueue1@router1"/>
          <alias name="queue/testqueue2" map-to="testqueue2@router1"/>
          <alias name="queue/testqueue3" map-to="testqueue3@router1"/>
          <alias name="queue/testqueue4" map-to="testqueue4@router1"/>
          <alias name="queue/testqueue5" map-to="testqueue5@router1"/>
          <alias name="topic/testtopic1" map-to="testtopic1"/>
          <alias name="topic/testtopic2" map-to="testtopic2"/>
          <alias name="topic/testtopic3" map-to="testtopic3"/>
          <alias name="topic/testtopic4" map-to="testtopic4"/>
          <alias name="topic/testtopic5" map-to="testtopic5"/>
        </aliases>
        <jndi-replications>
          <jndi-replication name="jboss" destination-context="/swiftmq" enabled="true">
            <environment-properties>
              <environment-property name="java.naming.factory.initial"
                                    value="org.jnp.interfaces.NamingContextFactory"/>
            </environment-properties>
          </jndi-replication>
        </jndi-replications>
      </swiftlet>

Since SwiftMQ is used intra-VM, you don't need to specify a JNDI provider URL, otherwise it would be accessed via RMI.

Authentication Swiftlet

Dependent on your MDB configuration you might touch the default recource limits of SwiftMQ regarding the maximum sessions, producers, consumers per connection. You can define some higher values here:

      <swiftlet name="sys$authentication">
        ...
        <resource-limit-groups>
          <resource-limit-group name="public"
                                max-consumers="100"
                                max-producers="100"
                                max-sessions="100"
                                max-tempqueues="100"/>
        </resource-limit-groups>
        ...
      </swiftlet>

That's it! Start JBoss which starts SwiftMQ intra-VM, deploy your beans and enjoy!