Using the WebSphere MQ Transport for SOAP.

By Jesús Rodríguez.

 

Abstract:  The IBM WebSphere MQ Transport for SOAP (WMQS) is a new addition to the IBM MQSeries platform. WMQS allows both .NET and J2EE applications to invoke either .NET or J2EE Web Services via am MQSeries queue. This add-on is downloadable at no charge from IBM’s website at http://www-1.ibm.com/support/docview.wss?uid=pub1sc34665100 . This article describes the components and capabilities of WMQS as well as provides code samples to illustrate how to use WMQS in your applications. 

NOTE This article assumes that you are familiar with WebSphere MQ and .NET Web Services related technologies (ASMX).

Introduction

The time has come for Web Services to support a wider array of transports. Although technologies like WSE 2.0 and Indigo in the .NET environment and Systinet, WebLogic Server and Websphere Server in the J2EE environment provide support for just such multi-transport enabled Web Services, HTTP continues to be the nearly ubiquitous choice of transport for invoking Web Services. Among the alternative transports, Message Oriented Middleware (MOM) technologies like Websphere MQ, MSMQ or JMS, are of special significance because they implement the powerful, reliable capabilities of asynchronous invocation.

IBM recently introduced the IBM Websphere MQ Transport for SOAP (WMQS) which enables .NET and J2EE applications to take advantage of MOM technologies for invoking Web Services. Using WMQS, .NET or J2EE client applications can easily invoke either J2EE or .NET Web Services asynchronously by way of a WebSphere MQ queue.

WMQS Overview

WMQS provides an extra middleware layer over Websphere MQ that allows SOAP-formatted messages to be carried over an MQSeries Queue. These SOAP messages are used to invoke Web Services. WMQS relies on two components to accomplish this job, the WMQS Proxy Class(sender) and the WMQS Listener Application.

WMQS Proxy Class

The WMQS Proxy class (aka. the sender) is a development time component that exposes the Web Service’s methods as well as contains all of the information for accessing the Web Service’s queues during development time. This class can be generated as either a Java, C# or VB.NET class. You must reference this class from your .NET or J2EE client project.

WMQS Listener Application

The WMQS listener application is a runtime component which receives the SOAP message over an MQSeries queue and uses the SOAP data to invoke Web Service methods and accept a response. The file is an executable file which is generated using the deployWMQService utility that ships with WMQS.

The following figure provides an overview of the WMQS architecture

Figure 1: WebSphere MQ transport for SOAP.

This figure depicts the components involved when using WMQS to invoke Web Service methods.

The Invoking URI.

The information required to deliver SOAP messages to the target service is typically encapsulated in the URI. In the case of WMQS the URI must have a well-defined format that describes the following:

 

  • Queue Managers
  • The request queues
  • reply queues
  • Among other key aspects.

A typical URI used with WMQS may look like this:

.

wmq:SOAP.TestService@QM_laura?replyToQueue=ResponseQueue,connectQueueManager=QM_laura”

The following describes each of the components of the URI.

  • wmq:SOAP.TestService@QM_laura: Specifies that messages will be sent to the queue named SOAP.TestService. This is the request queue
  • replyToQueue=ResponseQueue: Specifies that responses will be delivered to the queue named ResponseQueue
  • connectQueueManager=QM_laura: Specifies the name of the target QueueManager as QM_laura.

Assuming that the required WMQS listener is active at runtime, when the URI is received the following actions will be performed by the WMQS Listener

 

  • Retrieves the message from the request queue
  • Invokes the Web Service method associated with the request queue
  • Puts the response message in the response queue.

 The following sections describe how to develop .NET client applications that can invoke both a .NET and J2EE Web service using WMQS and receive a response.

Invoke a J2EE Web Service from a .NET client application.

.NET Client à J2EE Web Service

WMQS provides a way for a .NET client to exchange request/responses messages with a J2EE Web Service over an MQSeries queue. The development steps required are as follows:

 

  1. Identify the J2EE Web Service to invoke
  2. Configure the Queues Managers and Queues
  3. Generate the WMQS Proxy Class and WMQS Listener for that Web Service
  4. Reference the WMQS Proxy Class in your .NET client application

Assuming that the Web Service is deployed and that the .NET Client application is started the only WMQS-specific function to perform at runtime is to activate the WMQS listener. The listener can be started by simply executing a .bat file generated in the deployment process.

1. Identify the J2EE Web Service

WMQS can be used to invoke any J2EE Web Service. You can select an existing web service or develop a very simple standard Web Service class such as the one illustared in Sample 2:

 

public class TestService

{

  public TestService() {

  }

 

  public String echostr(String msg)

  {

    return msg;

  }

}

 

2. Configure the Queue Managers and the Queues

 

Use the standard MQSeries tools to configure the necessary Queue Managers and queues.

3. Generate the WMQS Proxy Class and the WMQS Listener

 

The next step is to generate the WMQS Proxy Class (sender) and the WMQS Listener required to invoke the Web Service. The deployWMQService utility, shipped with WMPS, is used to generate the WMQS Proxy and the WMQS Listener. THe deployWMQService uility takes the following input parameters: 

 

  • The path containing the Java source files for the Web Service being invoked
  • The name of the QueueManager on which the service is to be hosted
  • The name of the request queue,
  • etc.

Below is a sample of the  C# proxy class generated by the deployWMQService. You use this class in your client .NET application in order to instantiate the Web Service methods and interact with the queues.

 

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Web.Services.WebServiceBindingAttribute(Name="TestServiceBindingSoap", Namespace="TestService_Wmq")]

public class TestServiceService : System.Web.Services.Protocols.SoapHttpClientProtocol {

   

    /// <remarks/>

    public TestServiceService() {

        this.Url = "wmq:SOAP.TestService@QM_laura?connectQueueManager=QM_laura";

    }

   

    /// <remarks/>

    [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="TestService_Wmq", ResponseNamespace="TestService_Wmq")]

    [return: System.Xml.Serialization.SoapElementAttribute("echostrReturn")]

    public string echostr(string in0) {

        object[] results = this.Invoke("echostr", new object[] {

                    in0});

        return ((string)(results[0]));

    }

   

    /// <remarks/>

    public System.IAsyncResult Beginechostr(string in0, System.AsyncCallback callback, object asyncState) {

        return this.BeginInvoke("echostr", new object[] {

                    in0}, callback, asyncState);

    }

   

    /// <remarks/>

    public string Endechostr(System.IAsyncResult asyncResult) {

        object[] results = this.EndInvoke(asyncResult);

        return ((string)(results[0]));

    }

}

 

4. Reference the WMQS Proxy Class in your .NET client application

Once you deploy the Web Service and start the listener all you need to do is develop a .NET client application that uses the generated C# process. The next code show a simple client that uses the proxy showed above.

public static void TestJavaServiceSync()

{

MQWebRequest.Register();

TestServiceService proxy= new TestServiceService();

string Result= proxy.echostr("Hello Java MQ Service");

Console.WriteLine(Result);

}

When invoking the TestJavaServiceSync the following SOAP message is produced and delivered to the request queue.

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="TestService_Wmq" xmlns:types="TestService_Wmq/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><tns:echostr><in0 xsi:type="xsd:string">Hello Java MQ Service</in0></tns:echostr></soap:Body></soap:Envelope>

 Note: In is interesting to note that despite of the asynchronous nature of all the queue-based technologies the WMQS listener actually invokes the Web Service in a synchronous way. That is, when we invoke a Web Service method through the WMQS Listener, the operation does not return until the response message has been received. So even though the process is composed of various asynchronous stages, it is still synchronous in nature.

 

NOTE  The current version of WMQS requires that J2EE Web Services be implemented through Apache Axis Framework. This feature excludes the use of JWS files.

Invoke a .NET Web Service from a .NET client application

.NET Client à .NET Web Service 

The steps for configuring access to a .NET Web Service are the same as those required for invoking a J2EE Web Service. However, the listener generated is slightly different than the equivalent listener generated for the J2EE Web Services. The .NET listener does not currently handle pure JMS messages that include an MQRFH2 header. This is primarily because the C# classes for WebSphere MQ do not currently support JMS style messages. Client applications to Microsoft .NET services must therefore use native WebSphere MQ rather than pure JMS. This difference is not relevant if you use the MQ native infrastructure to deliver the messages.

The development process for a .Net client application is also mostly the same when invoking a .NET Web Service or a J2EE Web Services. However when invoking a .NET Web Service the real interoperability occurs one-level below the client-service model. That is, the real interoperability relies in the transport layer and its communication with the superior layer. Developers can take advantage of this feature to develop .NET-.NET Web Services applications that use WebSphere MQ as transport.

 

Advanced WMQS

 

The following sections explore some of the more interesting scenarios for using WMQS:

  • Customizing the Default WMQS Proxy Class for Request-Response
  • Implementing a Truly Asynchronous .NET client

Customizing the Default WMQS Proxy Class for Request-Response

Although the Proxy class generated that is generated by the utility provides just about everything you need at initial generation, there are a couple of tweaks that are required in order to get you ready to go. First, in order to invoke request-response operations you must modify the URI to include the ResponseQueue. In our example the complete URI looks like the following:

wmq:SOAP.TestService@QM_laura?replyToQueue=ResponseQueue,connectQueueManager=QM_laura”  

In this case the ResponseQueue is the queue intended to receive the response messages. The WMQS Listener generated as part of the deployment process is intended to monitor the request queue for incoming messages. The listener is derived from the Java class javax.jms.MessageListener. During proxy generation the method onMessage() from this base class is overridden. At application runtime, this method is automatically called by the base class when a message arrives. This method picks up the incoming JMS message, extracts the text of the message and then feeds it to the Axis engine for processing. Both the SOAP processing and the actual invocation of the service itself are performed within the listener thread. The SOAP response message from Axis is then returned to the client via the WebSphere MQ response queue. The JMSListener can accept messages in either TextMessages or BytesMessages format and return the responses in the same format.  

The correlation between request-response messages pairs is done using an id. The JMS listener uses the getJMSDestination() method to determine whether

the request message was sent via JMS or raw MQ. This is so that it can process

both messages from the Java JMS sender WMQSender and from the Microsoft

.NET MQWebRequest sender. The response message is then set to use the

same form. The two forms are very similar however messages returned over JMS include an RFH2 header, while the native form does not.  

Then the JMSListener pickup the message and uses the Axis framework to invoke the required method. Later takes the response and again uses the Axis framework to codify the response into a SOAP messages and send it to the response queue.

As we can see the process is completely transparent to the developer and all the logic relies over the Listener. Very similar is the process to interact with a .NET Web Service using WebSphere MQ.  

Implementing a Truly Asynchronous .NET client

To this point we have focused on describing how.NET clients can invoke Web Services using a “synchronous” message pattern.

WebSphere MQ transport for SOAP allows developing asynchronous Web Service clients. Asynchronous communication is a fantastic feature of Web Services – based applications. When we use WebSphere MQ as transport your application has at least one layer of asynchrony. However as we have seen in the above sections the client applications invoke Web Service operations in a synchronous way. Another option is to take advantage of WMQS to invoke Web Services operations in an asynchronous way. This is a very useful feature for some scenarios in which the target operations take some time.

In order to be able to apply the this long term “asynchrony facility” to the client-service interaction, the client architecture becomes somewhat more

complicated. The client must first register its intent to invoke services asynchronously by calling, in the case of invoking .Net Web Services, the method MQSOAP.Async.Request().It is necessary to pass to this method a reference to an object that has been derived from the class MQSOAP.Async.CallBack and which overrides the function CallBackFunction(). The following code shows a simple asynchronous client for our Web Service.

[Serializable]

class TestStateClass : MQSOAP.Async.CallBack

  {

    public override void CallBackFunction()

          {

            TestService proxy= new TestService();

          MQSOAP.Async.Response(this);

            string res = proxy.EchoStr("Hello Java MQ Service");

            Console.WriteLine("ASYNC RPC reply is: " + res);

          MQSOAP.MQResponseListener.stopListener();

          }

  }

 

public static void TestJavaServiceAsync()

  {

    MQSOAP.MQWebRequest.Register();

    // Create a context object

    TestStateClass requestContext = new TestStateClass();

    MQSOAP.Async.Request(requestContext);

    TestService proxy= new TestService();

    try

    {                                

          proxy.EchoStr("Hello Java MQ Service");

          MQSOAP.MQStartResponseListener sl = new MQSOAP.MQStartResponseListener(proxy.Url);

    }

    catch (Exception e)

    {

          if (0 >= e.ToString().IndexOf("No Response Expected")) throw(e);

    }

  }

 The CallBackFunction is invoked when a reply is received from the Web Service. The class that implements the CallBackFunction must be serialized to a queue named MQSOAP.SIDE.QUEUE. This queue is created when the setupmq script is executed. The listener started monitors the response queue, when a message is received it reconstructs the callback object and invokes the CallBackFunction method.

This is all that you need to do to invoke Web Services in an asynchronous way. The process is amazingly simple and can be very useful in some scenarios.  

Using WebSphere MQ classes for .NET (Low level messaging)

As explained in the above sections, the necessary logic to pickup and process the request-responses SOAP messages resides in the WMQS listeners. So that all we need to do to invoke a Web Service is to send a SOAP message to a well-defines queue that is associated with a WMQS Listener. It is also possible to invoke Web Service operations using WebSphere MQ .NET classes instead of generated proxies. In this case the developer retains control over the SOAP messages produced. Although an in-depth description of the WebSphere MQ classes for .NET lies outside the scope of this article. The following example shows a generic code used to send a SOAP message to a well-defined queue.

MQQueueManager mananger= new MQQueueManager(QueueManagerName...);

MQQueue soapqueue = mananger.AccessQueue(QueueName..., 0x10, QueueManagerName..., null, null);

MQMessage soapmessage = new MQMessage();

soapmessage.ReplyToQueueName = ResponseQueueName...;

soapmessage.Persistence = 1;

soapmessage.Priority = 0;

soapmessage.CharacterSet= 1208;

soapmessage.Encoding= 546;

byte[] serialisedContext= Encoding.UTF8.GetBytes(SoapMessage...);

soapmessage.Write(serialisedContext, 0, serialisedContext.GetLength(0));

soapqueue.Put(soapmessage, new MQPutMessageOptions());

soapqueue.Close();

The code to receive the response message can also be developed using the same classes. Low-level messaging is an additional option to consider in scenarios when you need more control over the SOAP messages or when you don’t have access to the required high-level proxies.  

Summary

This article described the capabilities of the IBM WebSphere MQ transport for SOAP and how it can be used to allow .NET clients to invoke either .NET or J2EE Web Services over an WebSphere MQ queue using SOAP. Using WebSphere MQ as the transport allows the developers to take advantage of the classic MOM benefits like reliability and enhanced performance that is typically associated with asynchronous messaging. The IBM WebSphere MQ transport for SOAP bridges the gap between J2EE and .NET as well as between Web Services and MOM technologies.

 

No Comments