Thursday, March 31, 2011

Communicating with WSO2 App Server via JMS-using JMS transport

 Introduction
Messaging is a live wire of the modern enterprises. In Enterprise messaging, a messaging client shoule be facilitated with both sending messages to and receiving messages from any other messaging client or a messaging broker. In an era where businesses take place in various platforms, platform interoperability is a key factor in heterogeneous working environment. Various services may use various communication protocols such as TCP, CORBA, RMI etc. JMS is one such communication protocol that a general SOA business possess.
JMS is a standard protocol for reliable enterprise messaging and is enriched with
    * asynchronous messaging - A JMS broker can deliver messages to a client as the messages arrive, without any special request made by the client in order to receive them
    * reliable messaging - JMS messaging ensures that a message is delivered only once with respect to one request.
In a communication channel, the distinct endpoints may be working in different protocols. The challenge of transforming the message protocols is taken up by message brokers. Therefore the sender or the receiver are free from the hassle of knowing each other end point's communication medium.
WSO2 Carbon Framework supports establishing such JMS connections with brokers such as Apache ActiveMQ. This capability is available in every WSO2 product, but with slightly different configurations. Except that, following a similar procedure, one can easily set up a JMS client communicating with an HTTP server or vice versa.
In this article, we will look at a use case where a JMS client communicate with an HTTP enabled server. There the client will first talk to JMS Queue on ActiveMQ. From there, the message will be directed to the server's respective service.
In here, we will select WSO2 Application Server as our deploying environment as an example.

JMS Configuration for AS

    Step 1
Download the latest version of AS from here . Extract the downloaded binary distribution to a preffered location of your file system. We will refer this as AS_HOME.
    Step 2
Download Apache ActiveMQ 5.2.0 from here. Extract the downloaded distribution to a location in your file system. We will call this ACTIVEMQ_HOME.
    Step 3
First it is required to start the ActiveMQ broker. Navigate to ACTIVEMQ_HOME/bin directory in a terminal. Execute the script named 'activemq'. In Linux, you have to give the command 'sh activemq'. More information on starting ActiveMQ in various platforms can be found here. This will activate the JMS broker with the following status message log.
    INFO TransportServerThreadSupport - Listening for connections at: tcp://localhost:61616
    INFO TransportConnector - Connector openwire Started
    INFO TransportServerThreadSupport - Listening for connections at: ssl://localhost:61617
    INFO TransportConnector - Connector ssl Started
    INFO TransportServerThreadSupport - Listening for connections at: stomp://localhost:61613
    INFO TransportConnector - Connector stomp Started
    .......................................
    .......................................
    INFO TransportConnector - Connector vm://localhost Started
   
    Step 4
Now the Carbon server also should be enabled with JMS. To achieve that, copy the following jars which resides in ACTIVEMQ_HOME/lib to the AS_HOME/lib/core/WEB-INF/lib directory.
    1. activemq-core-5.2.0.jar
    2. geronimo-jms_1.1_spec-1.1.1.jar
    3. geronimo-j2ee-management_1.0_spec-1.0.jar
        
    This action should follow with modifying the axis2.xml of Application Server (AS_HOME/repository/conf/axis2.xml) in such a way that the server is configured to JMS transport.
    The JMS listener or the JMS transport Receiver configuration should be as follows
   
    <transportReceiver name="jms" class="org.apache.axis2.transport.jms.JMSListener">
<parameter name="myTopicConnectionFactory">
    <parameter name="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>
    <parameter name="java.naming.provider.url">tcp://localhost:61616</parameter>
    <parameter name="transport.jms.ConnectionFactoryJNDIName">TopicConnectionFactory</parameter>
</parameter>
<parameter name="myQueueConnectionFactory">
    <parameter name="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>
    <parameter name="java.naming.provider.url">tcp://localhost:61616</parameter>
    <parameter name="transport.jms.ConnectionFactoryJNDIName">QueueConnectionFactory</parameter>
</parameter>
<parameter name="default">
    <parameter name="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>
    <parameter name="java.naming.provider.url">tcp://localhost:61616</parameter>
    <parameter name="transport.jms.ConnectionFactoryJNDIName">QueueConnectionFactory</parameter>
</parameter>
</transportReceiver>
This only will not fulfill the requirement of JMS configuration for the server. Since the server needs to do the responding as well via JMS transport , it should have the following line too uncommented in the axis2.xml file.
<transportSender name="jms" class="org.apache.axis2.transport.jms.JMSSender"/>
These configurations allow the user to use the JMS Transport of the WSO2 AS with Apache ActiveMQ JMS broker.
    Step 5
    Start the WSO2 AS. This can be done by running the sh wso2server.sh within the AS_HOME/bin directory in a terminal. If you have successfully configured the WSO2 AS, you should see the following lines being printed on your console as the log.
    [2011-03-13 12:26:37,931] INFO {org.apache.axis2.transport.jms.JMSSender} - JMS Sender started
    [2011-03-13 12:26:37,932] INFO {org.apache.axis2.transport.jms.JMSSender} - JMS Transport Sender initialized...
    ...
    [2011-03-13 12:26:40,406] INFO {org.apache.axis2.transport.jms.JMSConnectionFactory} - JMS ConnectionFactory : myTopicConnectionFactory initialized
    [2011-03-13 12:26:40,407] INFO {org.apache.axis2.transport.jms.JMSConnectionFactory} - JMS ConnectionFactory : myQueueConnectionFactory initialized
    [2011-03-13 12:26:40,408] INFO {org.apache.axis2.transport.jms.JMSConnectionFactory} - JMS ConnectionFactory : default initialized
    [2011-03-13 12:26:40,408] INFO {org.apache.axis2.transport.jms.JMSListener} - JMS Transport Receiver/Listener initialized...
    ...
   
   
    This ensures that the JMS transport has successfully started by connecting to the ActiveMQ broker. When the AS has fully started up, it will print an info log as shown below.
    [2011-03-13 12:26:56,216] INFO {org.wso2.carbon.core.internal.StartupFinalizerServiceComponent} - WSO2 Carbon started in 37 sec
   
    Login to AS and navigate to Manage menu. Under Services, you will see List menu. Go to List, then a list of deployed services will be displayed. There you will see a various services. Click on any service and you will be directed to particular service's dashboard.
    Let's take the version service. Under Endpoints, you will see the following endpoint.
    jms:/version?transport.jms.DestinationType=queue&transport.jms.ContentTypeProperty=Content-Type&java.naming.provider.url=tcp://localhost:61616&java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory&transport.jms.ConnectionFactoryJNDIName=QueueConnectionFactory
This confirms that Version service is now exposed over JMS transport as well after the above configurations.
    Now you should be able to communicate via JMS to the WSO2 Application Server.
   

Real World Scenarios

    You can try by your own how this JMS broker works with Application Server. What you need to do is create a message client that communicates with the JMS broker and do the above configurations. This will facilitate a remote client that uses JMS to talk to a Carbon server which the service was only exposed through http/https earlier and now exposed in JMS. For this we will consider WSO2 AS 4.0.0
    As shown in the image below, the JMS transport will be taken care by the JMS broker. (Also, if the service is not exposed in JMS, the client can do a general http/s GET request from the service deployed in the AS. )
First you need to do the above actions and configurations stated in Step 1-4. Now it is required to create a client that will talk to the AS. To generate the client, go to AS_HOME/bin from a console. From there type the following command to generate a client stub. We will do this for the version service available in AS. In a console, give the following command.
    sh wsdl2java.sh -uri http://localhost:9763/services/version?wsdl out -uw
This will generate the client stub in the directory AS_HOME/bin/out.
Or else you can go to the version service, from the service listing of AS and click on 'Generate Client' option there. Tick only on the unwrapping(uw) command. This too will generate a client stub for you in your preffered directory.
    Now you can import these generated stub classes to any IDE that you prefer. You can create a project in Eclipse using the generated Build.xml or import to IntelliJIDEA  using the built  pom.xml
Now, write a client in the project that you created importing the stub classes. A sample client will be as below.
    package org.apache.ws.axis2;
    import org.apache.axis2.AxisFault;
    import org.apache.axis2.context.ConfigurationContext;
    import org.apache.axis2.context.ConfigurationContextFactory;
    import java.rmi.RemoteException;
    public class JMSClient {
     public static void main(String[] args) throws AxisFault {
        ConfigurationContext cc = ConfigurationContextFactory.createConfigurationContextFromFileSystem(null,
         "/home/manisha/program_Files/wso2appserver-4.0.0/bin/client/repo/axis2.xml");
        String url = "jms:/version?transport.jms.DestinationType=queue&transport.jms." +
         "ContentTypeProperty=Content-Type&java.naming.provider.url=tcp://manisha:61616&java.naming.factory." +
         "initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory&transport.jms." +
         "ConnectionFactoryJNDIName=QueueConnectionFactory";
        VersionStub stub = new VersionStub(cc, url);
        try {
         System.out.println("====Connected to App Server====");
         System.out.println("\t"+stub.getVersion());
         System.out.println("===============================");
        } catch (RemoteException e) {
         e.printStackTrace();
        }
     }
    }
We need to enable JMS in client side too. Therefore, create a client repository (Just create a directory as AS_HOME/bin/client/repo/ and copy the axis2.xml in there). Make sure to enable JMS transportReceiver and TransportSender in client's axis2.xml.
Run the created client. You will get the response back with axis2 version as follows.
   
        ====Connected to App Server====
        WSO2 AppServer-4.0.0
    ===============================
   
    Similarly you can try out with any service that can be deployed in AS and access them with a JMS client via a JMS broker.
In most of the real world scenarios, the above communication takes place through a firewall proxy. The following two images depicts different instances that JMS communication occurs via a proxy.
This is an example of a user that uses JMS and requests for an http service deployed in an AS. There the proxy service should be exposed via JMS and a transformation occurs within the ESB where JMS is transformed into an http request and sent to the AS. When the proxy hits with the AS's response in http, it translates to JMS and sent back to the client.
Here the ESB's axis2.xml needs to be configured to send and receive JMS requests and responses.
The above image displays how a client that uses http requests to access a service that is exposed in JMS via a proxy. Here also the transformations of http to JMS and vice versa takes place inside ESB proxy. This is an instance where AS should be configured to send and receive JMS request and responses.
Likewise you can simply achieve any complex communication network with heterogeneous transport protocols via this simple configuration.

No comments:

Post a Comment