Version 26

    WARNING: This is not official JBoss documentation

    This information is provided by people from the community on how they configured Tibco EMS.

    You should validate for yourself that this configuration is correct for you using the

    Tibco documentation.

     

    The following are the steps you must complete in order to configure Tibco EMS as a JMS provider in JBoss.  This  configuration was tested on JBoss EAP 4.x.

     

     

    1. Configure Tibco JMS Provider

    In order to achieve that you have to reconfigure JMSProviderLoader MBean to load Tibco EMS. You can modify jms-ds.xml file or create a new file (something like tibco-jms-ds.xml).

    **

    <mbean code="org.jboss.jms.jndi.JMSProviderLoader" 
                name=":service=JMSProviderLoader,name=TibjmsProvider">
        <attribute name="ProviderName">TIBCOJMSProvider</attribute>
        <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
        <attribute name="QueueFactoryRef">XAQueueConnectionFactory</attribute>
        <attribute name="TopicFactoryRef">XATopicConnectionFactory</attribute>
        <attribute name="FactoryRef">XAConnectionFactory</attribute>
        <attribute name="Properties">     
           java.naming.factory.initial=com.tibco.tibjms.naming.TibjmsInitialContextFactory
           java.naming.provider.url=tcp://localhost:7222
        </attribute>
      </mbean>

    Note: I'm using the XA versions because of the HA/Clustered environment required for this configuration.

     

    First, when the application has to send a message it has to look up a Connection Factory (e.g., to get Connection from which to get Session from which to get Sender etc.). It is doing so by looking up java:comp/env/jms/QCF in JBoss JNDI registry. However in the case of integrating Tibco EMS, the QueueConnectionFactory(QCF) object we want in return should be Tibco EMS implementation of QCF. In other words we want to be able to forward JNDI request from JBoss to Tibco. We can do this by defining a NamingAlias MBean in the above mentioned configuration files.

       <mbean code="org.jboss.naming.NamingAlias"
                name="DefaultDomain:service=NamingAlias,fromName=QueueConnectionFactory">
        <attribute name="ToName">tibjmsnaming://localhost/XAQueueConnectionFactory</attribute>
        <attribute name="FromName">QueueConnectionFactory</attribute>
       </mbean>
    

    So, when the client does a lookup for a resource with the name jms/QCF as such: iniCtx.lookup("java:comp/env/jms/QCF");, application server links it to JNDI name associated with this resource via jboss.xml or jboss-web.xml etc.

       <resource-ref>
        <res-ref-name>jms/QCF</res-ref-name>
        <jndi-name>QueueConnectionFactory</jndi-name>
       </resource-ref>
    

    In this case it is QueueConnectionFactory. When JBoss sees a request for QueueConnectionFactory it does its own look up in Tibco JNDI on the name configured in NaminAlias MBean, which is tibjmsnaming://localhost/XAQueueConnectionFactory and returns implementation of QCF provided by the Tibco EMS. So the whole flow of JNDI lookup looks somewhat like this:

    Jms/QCF >> QueueConnectionFactory >> tibjmsnaming://localhost/XAQueueConnectionFactory 
    

    And you can configure as many namong aliases as the connection factories you have.

     

    Also replace (for JBoss EAP 4.3) tx-connection-factory section to be able to send messages using annotations from ejb-3 (can be session beans or same MDB):

      <tx-connection-factory>
        <jndi-name>JmsXA</jndi-name>
        <xa-transaction></xa-transaction>
        <rar-name>jms-ra.rar</rar-name>
        <connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>
        <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Queue</config-property>
        <config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/TIBCOJMSProvider</config-property>
        <max-pool-size>20</max-pool-size>
        <security-domain-and-application>JmsXARealm</security-domain-and-application>
      </tx-connection-factory>
    

     

     

    Here is the complete fragment of tibco-jms-ds.xml that has two aliased connection factory

    <!-- =================== TIBCO EMS JMS provider loader ================== -->
      
      <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
                name=":service=JMSProviderLoader,name=TibjmsProvider">
        <attribute name="ProviderName">TIBCOJMSProvider</attribute>
        <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
        <attribute name="QueueFactoryRef">XAQueueConnectionFactory</attribute>
        <attribute name="TopicFactoryRef">XATopicConnectionFactory</attribute>
        <attribute name="Properties">     
           java.naming.factory.initial=com.tibco.tibjms.naming.TibjmsInitialContextFactory
           java.naming.provider.url=tcp://localhost:7222
        </attribute>
      </mbean>
      
      
      <!-- Redirect QueueConnectionFactory to TIBCO Enterprise Message Service -->
      
      <mbean code="org.jboss.naming.NamingAlias"
                name="DefaultDomain:service=NamingAlias,fromName=QueueConnectionFactory">
        <attribute name="ToName">tibjmsnaming://localhost/XAQueueConnectionFactory</attribute>
        <attribute name="FromName">QueueConnectionFactory</attribute>
      </mbean>
      
      
      <mbean code="org.jboss.naming.NamingAlias"
                name="DefaultDomain:service=NamingAlias,fromName=ConnectionFactory">
        <attribute name="ToName">tibjmsnaming://localhost/QueueConnectionFactory
        </attribute>
        <attribute name="FromName">ConnectionFactory</attribute>
      </mbean>
    
      <tx-connection-factory>
        <jndi-name>JmsXA</jndi-name>
        <xa-transaction></xa-transaction>
        <rar-name>jms-ra.rar</rar-name>
        <connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>
        <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Queue</config-property>
        <config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/TIBCOJMSProvider</config-property>
        <max-pool-size>20</max-pool-size>
        <security-domain-and-application>JmsXARealm</security-domain-and-application>
    <!--
            <config-property name="UserName" type="java.lang.String">user</config-property>
            <config-property name="Password" type="java.lang.String">password</config-property>
    -->
      </tx-connection-factory>
      
     <!-- ==================================================================== --> 
    

     

    2. JNDI Propertries

    Now, when JBoss encounters the tibjmsnaming url scheme, it has to know how to connect, which means it has to have UrlConnectionFactory provided by Tibco. For that we would have to make a change in jndi.properties to the following property: java.naming.factory.url.pkgs.

    java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces:com.tibco.tibjms.naming
    

     

    3. Provider Adapters

    This one is simple. Since we are using Tibco EMS as our provider, we will need to use their adapter, that we've configured in step 1. To do this you would make a change to standardjboss.xml file, to point JMSProviderAdapterJNDI element from DefaultJMSProvider to TIBCOJMSProvider. Here is a complete segment:

     <!-- =================== TIBCO EMS TIBCOJMSProvider ========================== -->
            
      <JMSProviderAdapterJNDI>TIBCOJMSProvider</JMSProviderAdapterJNDI>
            
     <!-- ========================================================================= -->
    

     

    4. Dead Letter Queue (DLQ)

    In order to use Tibco EMS Dead Letter Queue, you must point DestinationQueue element of the same file standardjboss.xml to JNDI name of DLQ provided by Tibco EMS.

    In the same file standardjboss.xml, you would make a change to point to a

     <!-- =================== TIBCO EMS DLQ ========================== -->
    
      <DestinationQueue>tibjmsnaming://localhost/queue/DLQ</DestinationQueue>
                     
     <!-- ========================================================================= -->
    

     

    5. Remove JBossMQ Service

    You don't need to deploy JBossMQ if running Tibco EMS, so simply remove the following files from deploy directory:

    jms/jbossmq-service.xml
    jms/jbossmq-destinations-service.xml
    

     

    Note: For JBoss EAP 4.3 I had to remove everything from jms directory except our -ds.xml file and jms-ra.rar (otherwise you will be getting error messages about not deployed components).

     

    6. Server/Client class path

    To satisfy class path dependencies on both the client and the server side, include tibjms.jar file in the class path of client and server. This file comes with distribution of Tibco EMS. On the server it could be done by either copying file into the lib directory of your server configuration (e.g., server/default/lib) or by including the following XML fragment eight after the server tag in jboss-service.xml.

     <!-- =================== TIBCO EMS Service classpath ========================== -->
    
      <classpath codebase="file:/C:\TIBCO\EMS\clients\java" archives="tibjms.jar" ></classpath>
    
     <!-- ========================================================================== --> 
    

    Make sure to include the correct codebase path.

     

    At this point you are done. Make sure Tibco is running and you have the right URLs in your config files and start the server.

     

    7. Sample code

    Attached you'll see TibcoJBoss.zip file. It contains an Eclipse configured project. To run it follow the following steps:

    1. Import project to Eclipse

    2. Run packaging-build.xml (ANT file). It will create tibcoejb.jar, which will contain SampleMDB.

    3. Drop it into the deploy directory of JBoss configuration you set up for Tibco EMS.

    4. Run the SampleClient

    You should see these log mesages:

    00:06:03,859 INFO  [STDOUT] SampleMDB constructor
    00:06:03,859 INFO  [STDOUT] SampleMDB setMessageDrivenContext() org.jboss.ejb.MessageDrivenEnterpriseContext$MessageDrivenContextImpl@49f9fa
    00:06:03,859 INFO  [STDOUT] SampleMDB ejbCreate() 
    00:06:03,879 INFO  [STDOUT] SampleMDB Message type: null
    00:06:03,879 INFO  [STDOUT] SampleMDB Message text: Hello Tibco
    00:06:03,879 INFO  [STDOUT] SampleMDB Message ID: ID:EMS-SERVER.1C44419DE1F1E3:4
    00:06:03,879 INFO  [STDOUT] SampleMDB sending reply to dest: Queue[queue/A]
    

     

    That's pretty much it!!!

     

    8. Sample code for sending and receiving messages from EJB or MDB using annotations

     

    To receive messages you need to configure your EJB-3 MDB to receive messages from TIBCO:

     

    @MessageDriven(name = "MyMDB", activationConfig = {
              @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
              @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/A"),
              @ActivationConfigProperty(
                        propertyName="providerAdapterJNDI",
                        propertyValue="java:/TIBCOJMSProvider")
    

     

    Then you'll need a connection factory (taken as a workaround from JBAS-4805). This will inject the connectionfactory for you:

     

         @Resource(mappedName="java:/JmsXA", type=javax.jms.ConnectionFactory.class)
         private QueueConnectionFactory queueConnectionFactory;
    
    

     

    A sample code for a bean that send and receives messages from the same queue with Tibco isn't that complex.

     

    Note 1 : if you want to distribute your architecture : machine 1 hosting Jboss and machine 2 hosting EMS, the only parameters that you have to change on machine 1 config files are the ones with tcp://localhost. Replace localhost with the IP or hostname of your EMS server.

     

    Note 2 : if you enabled authorization on the EMS server, you have to add the credentials in the property list when declaring the TibjmsProvider MBean.

     

    Note 3 : as a consequence to removing

    jms/jbossmq-service.xml
    jms/jbossmq-destinations-service.xml
    

    you now have to create the queues and the factories (XAQueueConnectionFactory and XATopicConnectionFactory) in EMS from the Administration Console. Refer to the documentation provided by TIBCO to review the EMS setup.

    If you want to send messages from a bean using annotations you also have to create a generic factory reference XAConnectionFactory (FactoryRef). Some details about here: ConfigJMSProvider.

    Do not forget to create a dead letter queue for tibco.

     

    Note 4: If your Tibco EMS imports data from Rendevouz it can't modify JMS headers which means you wont get JMSMessageID in the message which breaks the Dead Letter Queue. If this is the case then you would need to implement your own error-handling or you can in case of error just resend the message to the same queue (yes gives you overhead) and let EMS actually assign the message id automatically.

     

    Note 5 : If Tibco EMS is in a cluster you cant directly reference the queue urls. For example lets say there is a global queue "myglobalqueue" and two EMS instances tibjmsnaming://firstnode:7222 and tibjmsnaming://secondnode:7222 .. Performing a lookup on cxt.lookup("tibjmsnaming://firstnode:7222/myglobalqueue,tibjmsnaming://secondnode:7222/myglobalqueue) will break. In fact tibco's docs say that for failover lookups you can only define the node list in the PROVIDER_URL when creating your jndi context.

     

    One solution is to define an external context

     

    <mbean code="org.jboss.naming.ExternalContext" 
           name="jboss.jndi:service=ExternalContext,jndiName=tibco">
            <use-java-context>false</use-java-context>
        <attribute name="JndiName">tibco</attribute>
        <attribute name="Properties">
            java.naming.factory.initial=com.tibco.tibjms.naming.TibjmsInitialContextFactory
            java.naming.provider.url=tibjmsnaming://firstnode:7222,tibjmsnaming://secondnode:7222
            java.naming.factory.url.pkgs=com.tibco.tibjms.naming
        </attribute>
        <attribute name="RemoteAccess">true</attribute>
        <attribute name="InitialContext">javax.naming.InitialContext</attribute>
    
    </mbean>
    
      <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
          name=":service=JMSProviderLoader,name=JMSProvider">
        <attribute name="ProviderName">DefaultJMSProvider</attribute>
        <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
        <attribute name="FactoryRef">tibco/ConnectionFactory</attribute>
        <attribute name="QueueFactoryRef">tibco/QueueConnectionFactory</attribute>
        <attribute name="TopicFactoryRef">tibco/TopicConnectionFactory</attribute>
    
      </mbean>
    
       <mbean code="org.jboss.naming.NamingAlias"
                name=":service=NamingAlias,fromName=jms/myQueue">
        <attribute name="ToName">tibco/myglobalqueue</attribute>
        <attribute name="FromName">jms/myQueue</attribute>
       </mbean>
    

     

    Now to reference tibco's resources you can use tibco/resourcename and jboss will delegate to the external context.

     

    Note 6: There's a very nasty bug with JBoss with the DLQ handling. Tibco like other providers uses the JMSXDeliveryCount property to keep track of delivery attempts, The GenericDQLHandler is broken.  The only solution I found is to roll your own implementation, and then use the DLQHandler activation config property in the MDB, Jboss seems to ignore anything you stick in standardjboss.xml even if you put the invoker config gumph in the jboss.xml.. Any exceptions during an onmessage causes an infinite loop.