JBossEAP5IntegrationwithTibcoEMS

Version 20

    This article highlights some of the basic steps required to integrate JBoss EAP 5 with TibcoEMS. This article should also work with JBoss EAP 4.x, however, I have not tested tested this at this time.

     

    Introduction

    This article differs from:

    [IntegrationWithTibcoEMS|http://community.jboss.org/wiki/IntegrationWithTibcoEMS]

    and the TibcoEMS administration documents in the following:

     

    • Does not replace and remove JBoss messaging from the JBoss Installation (JBoss messaging can still be removed, but this is optional since the DefaultJMSProvider has not been replaced)
    • Defines a TIBCOJMSProvider
    • Provides a DLQ configuration without changing standardjboss.xml and replacing the DefaultJMSProvider with TIBCOJMSProvider
    • Has been tested on JBoss EAP 5
    • Uses authentication with Tibco EMS

     

    Credits

    The content in this page is based on TibcoEMS documentation for JBoss4.x. Some of the content has also been borrowed from the article:

    [IntegrationWithTibcoEMS|http://community.jboss.org/wiki/IntegrationWithTibcoEMS]

    including the sample mdb code for testing.

     

    A special thanks to Marjono Reksopuro, Susanta Mondal and Michael McKernan for their help with Tibco Administration, integration and testing for this configuration.

    TibcoEMS Configuration

    The steps in this section outline the steps required to create a test queue on TibcoEMS as well as the DLQ.

     

    * Please note this EMS configuration assumes the following:

    - Authorization enabled
    - Username/Password are set to: admin/admin 
    - A single instance running locally:   localhost with port of 7222.
    - If you need to have FT Pairs for failover, the url should be changed from   tcp://localhost:7222, tcp://localhost:7222  to  tcp://firstmachine:firstport,tcp://secondmachine:secondport

    Step1

    Start the tibemsd server and the tibemsadmin console.

    Queues and Connection Factories

     

    Step2

    Create two queues (queue/myTestQueue and queue/DLQ) and two XA connection factories (TIBXAQueueConnectionFactory and TIBXATopicConnectionFactory), by entering the following commands in tibemsadmin:      
        > connect

     

        > create queue queue/myTestQueue

     

        > create queue queue/DLQ

     

        > create factory TIBXAQueueConnectionFactory xaqueue url=tcp://localhost:7222

     

        > create factory TIBXATopicConnectionFactory xatopic url= tcp://localhost:7222

     

    Tibco pairs for Failover:

     

        > create factory TIBXAQueueConnectionFactory xaqueue url=tcp://localhost:7222, tcp://localhost:7222

     

        > create factory TIBXATopicConnectionFactory xatopic url= tcp://localhost:7222, tcp://localhost:7222

     

    JBoss Configuration

    The steps in this section outline the steps required to configure JBoss to connect withTibcoEMS.

    Step1

    Add TIBCO EMS and the TIBCO EMS adapter class for JBoss to the CLASSPATH of the JBoss server. There are two options to accomplish this:

     

    Option1

    Add the following lines under the <server> element in the file $JBOSS_HOME/jboss-as/server/myinstance/conf/jboss-service.xml:


    <!-- TIBCO Enterprise Message Service classpath -->

    <classpath codebase="file:/C:\tibco\ems\5.1\lib" archives="tibjms.jar" ></classpath>

     

    Option2

    Copy tibjms.jar file to:

    $JBOSS_HOME/jboss-as/server/myinstance/lib

     

    Step2

    Create a new datasource file called tibco-jms-ds.xml or whatever name you prefer, and place it in:

    $JBOSS_HOME/jboss-as/server/myinstance/deploy

     

    And add the following contents to the file mentioned above:

    {noformat}
    
    <?xml version="1.0" encoding="UTF-8"?>
    <connection-factories>
    
    <!-- The Tibco 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">TIBXAQueueConnectionFactory</attribute>
          <attribute name="TopicFactoryRef">TIBXATopicConnectionFactory</attribute>
          <attribute name="Properties">
                    java.naming.security.principal=admin
                    java.naming.security.credentials=admin
                    java.naming.factory.initial=com.tibco.tibjms.naming.TibjmsInitialContextFactory
                    java.naming.factory.url.pkgs=com.tibco.tibjms.naming
                    java.naming.provider.url=tcp://localhost:7222
    
          </attribute>
    </mbean>
    
    
    <!-- JMS XA Resource adapter, use this to get transacted JMS in beans -->
    <tx-connection-factory>
         <jndi-name>TibcoXA</jndi-name>
         <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>TibcoXARealm</security-domain-and-application>
    </tx-connection-factory>
    </connection-factories>
    {noformat}
    
    
    

    Step3

    Notice that a security domain reference is present in the tibco-jms-ds.xml file. Therefore, modify the file $JBOSS_HOME/jboss-as/server/myinstance/conf/login-config.xml file as follows and add the TibcoXARealm within the <properties> element:

     

    <application-policy name="TibcoXARealm">
      <authentication>
          <login-module code="org.jboss.resource.security.ConfiguredIdentityLoginModule" flag="required">
            <module-option name="principal">admin</module-option>
            <module-option name="userName">admin</module-option>
            <module-option name="password">admin</module-option>
            <module-option name="managedConnectionFactoryName">jboss.jca:service=TxCM,name=TibcoXA</module-option>
          </login-module>
        </authentication>
    </application-policy>
    

    Step4

    When the JBoss server invokes JNDI and encounters the tibjmsnaming scheme, the server must be able to find the TIBCO Enterprise Message Service URLConnectionFactory. Therefore, modify the file $JBOSS_HOME/jboss-as/server/myinstance/conf/jndi.properties as follows:

     

    Change:

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

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

     

     

    When Using a Client

    Step1

    When the client program invokes JNDI, it should use the TIBCO Enterprise Message Service JNDI server. Modify %JBOSS_CLIENT%\jndi.properties to use TIBCO Enterprise Message Service JNDI by setting the following property:   
    java.naming.factory.initial=com.tibco.tibjms.naming.TibjmsInitialContextFactory

     

    Step2

    Add EMS_HOME\lib\tibjms.jar to the CLASSPATH of the client program.

     

    MDB configuration

    The sample mdb code from can be used:

    [IntegrationWithTibcoEMS|http://community.jboss.org/wiki/IntegrationWithTibcoEMS]

     

    Update your jboss.xml file to look as follows:

     

    <?xml version="1.0"?>
    <jboss>
       <resource-managers>
         <resource-manager>        
    
           <res-name>queuefactoryref</res-name>
           <res-jndi-name>java:/TibcoXA</res-jndi-name>
         </resource-manager>
       </resource-managers>
       <enterprise-beans>
         <message-driven>
           <ejb-name>SampleMDB</ejb-name>
           <configuration-name>Tibco Message Driven Bean</configuration-name>
           <destination-jndi-name>queue/myTestQueue</destination-jndi-name>
           <mdb-user>admin</mdb-user>
           <mdb-passwd>admin</mdb-passwd>
           <resource-ref>
             <res-ref-name>jms/QCF</res-ref-name>
             <resource-name>queuefactoryref</resource-name>
           </resource-ref>
         </message-driven>
       </enterprise-beans>
    
     
       <!-- container configuration for Tibco EMS -->
       <container-configurations>
         <container-configuration extends="Standard Message Driven Bean">
           <container-name>Tibco Message Driven Bean</container-name>
           <invoker-proxy-binding-name>tibco-message-driven-bean</invoker-proxy-binding-name>
         </container-configuration>
       </container-configurations>
     
       <!-- The JmsProviderAdapterJNDI must match the ProviderName in SERVER_HOME/deploy/tibco-jms-ds.xml file. -->    
    
       <invoker-proxy-bindings>
         <invoker-proxy-binding>
           <name>tibco-message-driven-bean</name>
           <invoker-mbean>default</invoker-mbean>
           <proxy-factory>org.jboss.ejb.plugins.jms.JMSContainerInvoker</proxy-factory>
             <proxy-factory-config>
               <JMSProviderAdapterJNDI>TIBCOJMSProvider</JMSProviderAdapterJNDI>
               <ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>
               <MinimumSize>1</MinimumSize>
               <MaximumSize>15</MaximumSize>
               <KeepAliveMillis>30000</KeepAliveMillis>
               <MaxMessages>1</MaxMessages>
               <MDBConfig>
                 <ReconnectIntervalSec>10</ReconnectIntervalSec>
                 <DLQConfig>
                   <DestinationQueue>queue/DLQ</DestinationQueue>
                   <MaxTimesRedelivered>10</MaxTimesRedelivered>
                   <TimeToLive>0</TimeToLive>
                   <DLQUser>admin</DLQUser>
                   <DLQPassword>admin</DLQPassword>
                 </DLQConfig>
               </MDBConfig>
             </proxy-factory-config></proxy-factory>
           </invoker-proxy-binding>
         </invoker-proxy-bindings>
    </jboss>
    

     

    *Note: The above configuration uses an EJB2 configuration, for EJB3 the following annotations can be used:

    @ActivationConfigProperty(propertyName="providerAdapterJNDI", propertyValue="java:/TIBCOJMSProvider"),
    @ActivationConfigProperty(propertyName="DLQJNDIName", propertyValue="queue/DLQ"),
    @ActivationConfigProperty(propertyName="DLQUser", propertyValue="admin"),
    @ActivationConfigProperty(propertyName="DLQPassword",propertyValue="admin")

     

    Upon a restart of the JBoss instance, you shold have a working configuration.

     

    ----------------------- Below this line added by matti.kaikkonen@teliasonera.com Sept 13, 2012 --------------------------------

     

    MDB Configuration with Automatic Reconnection

     

    If you have had a problem with your JMS clients not reconnecting after bouncing EMS or losing network connection then you want to look into this option. The problem here is that the number of times to attempt to reconnect to the JMS provider needs a new property "reconnectAttempts" and by default it is 5.  This property is available from JBoss Application 5 GA.  Prior to this version, reconnection attempts were infinite by default. In the above format it is not possible to define the reconnectAttempts. I have tested this with JBoss 5.1.0GA.

     

    Update your jboss.xml file to look as follows - replace the invoker-proxy-binding block with following. Look here for documentation.

     

    <invoker-proxy-binding>
        <name>tibco-message-driven-bean</name>
        <invoker-mbean>default</invoker-mbean>
        <proxy-factory>org.jboss.ejb.plugins.inflow.JBossJMSMessageEndpointFactory</proxy-factory>
        <proxy-factory-config>
            <activation-config>
                <activation-config-property>
                    <activation-config-property-name>providerAdapterJNDI</activation-config-property-name>
                    <activation-config-property-value>TIBCOJMSProvider</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>minSession</activation-config-property-name>
                    <activation-config-property-value>1</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>maxSession</activation-config-property-name>
                    <activation-config-property-value>15</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>keepAlive</activation-config-property-name>
                    <activation-config-property-value>30000</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>maxMessages</activation-config-property-name>
                    <activation-config-property-value>1</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>reconnectInterval</activation-config-property-name>
                    <activation-config-property-value>10</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>reconnectAttempts</activation-config-property-name>
                    <activation-config-property-value>1000000</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>useDLQ</activation-config-property-name>
                    <activation-config-property-value>true</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>DLQHandler</activation-config-property-name>
                    <activation-config-property-value>org.jboss.resource.adapter.jms.inflow.dlq.GenericDLQHandler</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>DLQJNDIName</activation-config-property-name>
                    <activation-config-property-value>queue/DLQ</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>DLQUser</activation-config-property-name>
                    <activation-config-property-value>admin</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>DLQPassword</activation-config-property-name>
                    <activation-config-property-value>admin</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>DLQMaxResent</activation-config-property-name>
                    <activation-config-property-value>10</activation-config-property-value>
                </activation-config-property>
            </activation-config>
            <endpoint-interceptors>
                <interceptor>org.jboss.proxy.ClientMethodInterceptor</interceptor>
                <interceptor>org.jboss.ejb.plugins.inflow.MessageEndpointInterceptor</interceptor>
                <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
                <interceptor>org.jboss.invocation.InvokerInterceptor</interceptor>
            </endpoint-interceptors>
        </proxy-factory-config>
    </invoker-proxy-binding>
    

     

    How to make the sample mdb code fully recover from JMS connection issues?


    With the above change we have taken care of the message listener part so that the onMessage works after a disconnect. But the sendReply doesn't recover without some extra code. You need to catch the JMSException when sending the reply, and first close the session and connection (look at the ejbRemove), and then reconnect again (look at setup) before retrying to send the reply message.

     

    You can get some ideas from this POJO MDB example here.

     

    Attached is a modified TIBCO tibjmsMsgAsyncConsumer example that demonstrates use of automatic reconnection with plain Java. It is a simple request-reply server. The tibjmsMsgProducer demonstrates a simple request-reply client with automatic reconnection.

     

    If you need access to multithreaded TIBCO examples they can be found in the EMS samples directory (any EMS installation). Or here. TIBCO EMS documentation is available at docs.tibco.com. And you can download an evaluation version of EMS here.

     

    I experimented also with the TibjmsConnectionFactory.setReconnAttemptCount/Delay/Timeout settings. Changing those defaults helps only to reconnect during a fairly short period depending on other settings like client to server heartbeat parameters and/or your TCP settings in your operating system. It seems that if EMS has "purged the client connection" due to a network issue ( about 15 mins for my EMS/Linux server when client heartbeat is not activated, less with heartbeat on ), setting the ReconnAttemptCount to a big number does not help any more, and EMS logs repeatedly that reconnect failed.

     

    So my advice is to register an exception listener and loop until a new connection is created. Perhaps delays between connect attempts need to be carefully considered not to create too big log files during connection issues.

     

    After all this trial and error I honestly think that it's perhaps easier to not to use EJB/MDB at all but to use plain Java for TIBCO JMS (or any JMS provider). Or use TIBCO Businessworks for your JMS projects, because it makes life easy .

     

    How to test your implementation for automatic reconnection/recovery from JMS connection issues?

    Option1

    If you don't have access to a TIBCO EMS server that you can bounce or kill anytime then here is one possible way to test it. The idea is to manipulate the routing table of the linux or windows workstation where you run your JBoss and in that way simulate a loss of connectivity. Here are examples that I have used.

     

    Linux: if the ip address of the TIBCO EMS server is 192.168.1.38 then

    Simulate network issue

    route add -net 192.168.1.38 netmask 255.255.255.255 reject

    Recover connectivity

    route del -net 192.168.1.38 netmask 255.255.255.255 reject

    This works also - in my case eth0 device is connected and eth1 is WLAN that is disconnected
    route add -net 192.168.1.38 netmask 255.255.255.0 dev eth1

     

    Windows7: if the ip address of the TIBCO EMS server is 192.168.1.38 then

    Simulate network issue

    route ADD 192.168.1.38 MASK 255.255.255.255 169.254.138.21                # where 169.254.138.21 is my VMware Network Adapter Autoconfiguration address

    Recover connectivity

    route DELETE 192.168.1.38

     

    Option2

    If you can bounce or kill TIBCO EMS then either do a clean shutdown (CTRL-C in the EMS console does that) or use kill -9 / Task Manager>End Process to simulate a crash.

     

    The method in Option 1 works also from the EMS server workstation. You can keep EMS running and block the network between the EMS server and client. And see what happens on the server side, and when does EMS decide to purge the connection etc.

    EMS Server settings

    Adding these rows to end of your tibemsd.conf will help you with testing. This enables EMS and the EMS client to detect network connection failures much faster.

     

    client_heartbeat_server = 3
    server_timeout_client_connection = 10
    server_heartbeat_server = 3
    server_timeout_server_connection = 10
    server_heartbeat_client = 3
    client_timeout_server_connection = 10
    

    Other tools

    Using wireshark gives you an idea what is happening on the wire. And if you have an EMS installation then you should use GEMS.

    How to use a durable topic subscriber instead for the mdb?

     

    To use the sample mdb code (change also reply to destination from queue to topic) you just need to change all references to queues to topics. That's not a problem. The configuration of jboss.xml and ejb-jar.xml is the trickier part. In the jboss.xml replace <resource-managers> and <enterprise-beans> blocks with following. This is tested with JBoss 5.1.0GA.

     

     

    <resource-managers>
            <resource-manager>        
                <res-name>topicfactoryref</res-name>
                <res-jndi-name>java:/TibcoXA</res-jndi-name>
            </resource-manager>
    </resource-managers>
    <enterprise-beans>
            <message-driven>
                <ejb-name>SampleMDB</ejb-name>
                <configuration-name>Tibco Message Driven Bean</configuration-name>
                <destination-jndi-name>topic/B</destination-jndi-name>
                <mdb-user>admin</mdb-user>
                <mdb-passwd>admin</mdb-passwd>
                <mdb-subscription-id>SampleMDB</mdb-subscription-id>
                <mdb-client-id>123</mdb-client-id>
                <resource-ref>
                    <res-ref-name>jms/TCF</res-ref-name>
                    <resource-name>topicfactoryref</resource-name>
                </resource-ref>
            </message-driven>
    </enterprise-beans>
    

     

     

    And the following replaces the original ejb-jar.xml.

     

     

    <?xml version="1.0"?>
    <!DOCTYPE ejb-jar
       PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
       "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
    
    <ejb-jar>
        <enterprise-beans>
            <message-driven>
                <ejb-name>SampleMDB</ejb-name>
                <ejb-class>com.unisys.tibcojboss.mdb.SampleMDB</ejb-class>
                <transaction-type>Container</transaction-type>
                <acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>
                <message-driven-destination>
                    <destination-type>javax.jms.Topic</destination-type>
                    <subscription-durability>Durable</subscription-durability>
                </message-driven-destination>
                <resource-ref>
                    <res-ref-name>jms/TCF</res-ref-name>
                    <res-type>javax.jms.TopicConnectionFactory</res-type>
                    <res-auth>Container</res-auth>
                </resource-ref>
            </message-driven>
        </enterprise-beans>
    </ejb-jar>
    

     

    TIBCO EMS specific settings

    Dead Letter Queue

    When using TIBCO EMS you don't need to use the DEAD LETTER QUEUE functionality. You can disable it by setting useDLQ to false and removing other DLQ related entries. This is the most usual use case for messaging.

     

    TIBCO EMS supports another type of functionality via Undelivered Message Queue and maxRedelivery property. Refer to TIBCO EMS docs.

     

                <activation-config-property>
                    <activation-config-property-name>useDLQ</activation-config-property-name>
                    <activation-config-property-value>false</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
    

     

    MaxSession

    For most use cases a "singleton-message-driven-bean" or single threaded operational mode is enough. In the above example maxSession=15 and it seems to create 15 JMS connections / sessions and 15 beans. Set maxSession=1 to work in single threaded mode - this creates one JMS Connection / Session. TIBCO EMS throughput with one session is easily hundreds of messages per second. (Naturally it depends on many factors - test your installation with code snippets in the samples/java folder like tibjmsMsgProducerPerf and tibjmsMsgConsumerPerf.) So, it's not due to one session performance that you would want to have parallel processing.

     

    If your application works in single threaded mode, you get as a byproduct preserved order of messages that is actually in many cases the requirement.

     

                <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-property>