Using a JMS Transport

Novell exteNd WSSDK is capable of exchanging SOAP messages using either an HTTP/HTTPS protocol or using a JMS protocol. This example illustrates how to develop a client and server using Novell exteNd WSSDK that exchange SOAP messages using JMS under the covers. The key feature is that the client is practically the same regardless of the tranport.

The key to configuring a JMS transport is the stub's binding, which must have a URL where the protocol is "jms". By default, the JMS transport will use a queue to exchange messages and the remainder of the URL is treated as the queue name, e.g. jms://myQueue.

If the location attribute in the soap:address element in the WSDL service's port binding is a URL with a jms protocol, the stub generated by rmi2soap will automatically be configured for the JMS transport. If the location is a URL with an http protocol, you must manually set a jms binding in the client:

   Binding jms = new Binding("soap", "jms://myQueue");
   stub.setCurrentBinding(jms);

1 Hello WSDL

This examples uses the familar hello world sample with a JMS transport. The WSDL document below has been modified slightly to introduce the concept of both a one-way and a two-way method:
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HelloService"
 targetNamespace="http://www.jms2"
 xmlns="http://schemas.xmlsoap.org/wsdl/"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:tns="http://www.jms2" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <types/>
 <message name="sayHelloRequest"/>
 <message name="sayHelloResponse">
  <part name="arg0" type="xsd:string"/>
 </message>
 <message name="notifyHelloRequest">
  <part name="arg0" type="xsd:string"/>
 </message>
 <message name="notifyHelloResponse"/>
 <portType name="Hello">
  <operation name="sayHello">
   <input message="tns:sayHelloRequest"/>
   <output message="tns:sayHelloResponse"/>
  </operation>
  <operation name="notifyHello">
   <input message="tns:notifyHelloRequest"/>
   <output message="tns:notifyHelloResponse"/>
  </operation>
 </portType>
 <binding name="HelloBinding" type="tns:Hello">
  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
  <operation name="sayHello">
   <soap:operation soapAction="http://www.jms2/sayHello"/>
   <input>
    <soap:body
     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
     namespace="http://www.jms2" use="encoded"/>
   </input>
   <output>
    <soap:body
     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
     namespace="http://www.jms2" use="encoded"/>
   </output>
  </operation>
  <operation name="notifyHello">
   <soap:operation soapAction="http://www.jms2/notifyHello"/>
   <input>
    <soap:body
     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
     namespace="http://www.jms2" use="encoded"/>
   </input>
   <output>
    <soap:body
     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
     namespace="http://www.jms2" use="encoded"/>
   </output>
  </operation>
 </binding>
 <service name="HelloService">
  <port binding="tns:HelloBinding" name="HelloPort">
   <soap:address location="jms://queue/queue0"/>
  </port>
 </service>
</definitions>

2 Hello Remote Interface

The generated RMI for the above WSDL is shown below:
// Generated by Novell exteNd Web Services SDK 5.0
// On Mon Dec 08 11:14:22 EST 2003
// From Hello.wsdl
                                                                           
package jms2;
                                                                           
public interface Hello
    extends java.rmi.Remote
{
    void notifyHello(java.lang.String arg0)
        throws java.rmi.RemoteException;
                                                                           
    java.lang.String sayHello()
        throws java.rmi.RemoteException;
}
The remote interface has the usual sayHello method, which is a two-way method returning a string. It also has a notifyHello method which is a one-way method that simply sends a message to a JMS destination.

3 The Client

The client application is very similar to the SOAP/HTTP client. We create the service and the stub in the usual fashion and invoke the one-way method. Please note that if your JMS provider requires any special configuration, you should use the configuration properties available in the stub base class. As an example, the JMS_QUEUE_REPLY_JNDI property must be set before invoking two-way methods.
package jms2;
                                                                           
import javax.naming.InitialContext;
                                                                           
import com.sssw.jbroker.web.portable.Stub;
                                                                           
public class Client
{
    public static void main(String[] args) throws Exception
    {
    |   // get the initial context
    |   InitialContext ctx = new InitialContext();
    |                                                                      
    |   // lookup the service for Hello
    |   HelloService svc = (HelloService)
    |       ctx.lookup("xmlrpc:soap:jms2.HelloService");
    |                                                                      
    |   // get the hello stub
    |   // this stub is already configured with a jms binding
    |   Hello hello = (Hello) svc.getHelloPort();
    |                                                                      
    |   // send a message oneway
    |   hello.notifyHello("Hello");
    |                                                                      
    |   // set the replyTo destination
    |   ((Stub)hello)._setProperty(Stub.JMS_QUEUE_REPLY_JNDI, "queue/queue1");
    |                                                                      
    |   // send a message and wait for a response
    |   System.out.println(hello.sayHello());
    }
}

4 Message Bean Implementation

The SOAP message sent out by the client using Novell exteNd WSSDK's JMS transport must be processed by a message listener, which is consuming message from the queue where the SOAP message was sent to, and which is possibly sending response messages on the replyTo queue. Below is a simply queue message listener, which looks for messages on "queue0" and responds to the reply queue if the replyTo header field is set:
package jms2;
                                                                           
import javax.jms.*;
import javax.naming.*;
                                                                           
public class MessageBean implements MessageListener, ExceptionListener
{
    public static void main(String[] args) throws Exception
    {
    |   // construct the message listener
    |   MessageBean bean = new MessageBean();
    |                                                                      
    |   // wait for messages
    |   System.out.print("waiting for messages ...\n");
    |   synchronized (bean) { bean.wait(); }
    |                                                                      
    |   // close the queue connection
    |   bean.close();
    }
                                                                           
    public MessageBean() throws Exception
    {
    |   // get the initial context
    |   InitialContext ctx = new InitialContext();
    |                                                                      
    |   // lookup the queue object
    |   Queue queue = (Queue) ctx.lookup("queue/queue0");
    |                                                                      
    |   // lookup the queue connection factory
    |   QueueConnectionFactory connFactory = (QueueConnectionFactory) ctx.
    |       lookup("queue/connectionFactory");
    |                                                                      
    |   // create a queue connection
    |   _queueConn = connFactory.createQueueConnection();
    |                                                                      
    |   // create a queue session
    |   _queueSession = _queueConn.createQueueSession(false,
    |       Session.AUTO_ACKNOWLEDGE);
    |                                                                      
    |   // create a queue receiver
    |   QueueReceiver queueReceiver = _queueSession.createReceiver(queue);
    |                                                                      
    |   // set an asynchronous message listener
    |   queueReceiver.setMessageListener(this);
    |                                                                      
    |   // set an asynchronous exception listener on the connection
    |   _queueConn.setExceptionListener(this);
    |                                                                      
    |   // start the connection
    |   _queueConn.start();
    }
                                                                           
    public void close() throws JMSException
    {
    |   _queueConn.close();
    }
                                                                           
    public void onMessage(Message message)
    {
    |   try {
    |   |   TextMessage tm = (TextMessage) message;
    |   |   System.out.println("\n" + tm.getText());
    |   |   Queue replyTo = (Queue) message.getJMSReplyTo();
    |   |   if (replyTo != null) {
    |   |   |   System.out.println("\nsending reply to " + replyTo);
    |   |   |   QueueSender sender = _queueSession.createSender(replyTo);
    |   |   |   TextMessage reply = _queueSession.createTextMessage(_response);
    |   |   |   sender.send(reply);
    |   |   |   sender.close();
    |   |   }
    |   } catch (JMSException jex) {
    |   |   System.err.println("failed to send: " + jex.getMessage());
    |   }
    |                                                                      
    }
                                                                           
    public void onException(JMSException exception)
    {
    |   System.err.println("an error occurred: " + exception);
    }
                                                                           
    private final QueueSession _queueSession;
    private final QueueConnection _queueConn;
                                                                           
    private final static String _response =
        "<Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'" +
        " xmlns='http://schemas.xmlsoap.org/soap/envelope/'" +
        " xmlns:xsd='http://www.w3.org/2001/XMLSchema'" +
        " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'" +
        " xmlns:SOAP-ENC='http://schemas.xmlsoap.org/soap/encoding/'>" +
        " <SOAP-ENV:Body>" +
        "  <ns1:sayHelloResponse" +
        "   SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'" +
        "   xmlns:ns1='http://www.jms2'>" +
        "   <result xsi:type='xsd:string'>Hello World!</result>" +
        "  </ns1:sayHelloResponse>" +
        " </SOAP-ENV:Body>" +
        "</Envelope>";
}
In order to build and run applications that use Novell exteNd WSSDK's JMS transport, a JMS provider must be available. You can for instance use jBroker MQ, which is part of the jBroker product family.
Copyright © 2000-2003, Novell, Inc. All rights reserved.