Skip Headers
Oracle® Application Server Advanced Web Services Developer's Guide
10g Release 3 (10.1.3)
B25603-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

8 Using JMS as a Web Service Transport

This chapter describes how to employ JMS as an alternative transport mechanism for Web Services. It describes these major topics:

Understanding JMS as a Transport Mechanism

Building on top of JMS, Oracle Application Server Web Services support two messaging styles: one-way request messaging and two-way request and response messaging. One-way request messaging lets a Web service client unblock when the request message reaches a JMS queue. Two-way request and response messaging blocks a Web service client until the response message is received.

Using JMS as an Alternative to HTTP

Since SOAP is transport-independent and can be bound to any protocol, SOAP over JMS is an alternative messaging mechanism to the standard SOAP over HTTP messaging. Although both serve as a communication channel between a Web service provider and a Web service client, they are very different. When interoperability is the driving factor, use SOAP over HTTP because it is standardized by the Web Service Interoperability (WS-I) organization. When reliability, scalability, and asynchronous messaging are the key factors, consider SOAP over JMS.

JMS Supports Asynchronous and Reliable Messaging

SOAP over JMS ensures reliability because message delivery can be guaranteed. Messages sent by a Web service provider or client can be placed onto a queue and can be stored in persistent storage. In case of a communication failure, the failing message is retrieved from the persistent storage and re-sent until transmission is successful, which is extremely useful in transaction- and data-critical systems. Businesses that use Enterprise Application Integration (EAI) should find SOAP over JMS appealing because it boosts confidence when exchanging critical data between client and server.


Note:

Reliability can also be enabled for SOAP messaging over HTTP. For more information, see Chapter 5, "Ensuring Web Service Reliability".

Asynchronous messaging lets a client invoke a service without waiting for the response. Asynchronous invocation can be implemented by both synchronous and asynchronous transport. JMS as an asynchronous transport can provide a correlation mechanism for associating response messages with request messages. It also lets a client query the status of its requests, and retrieve the responses independently. These features, which HTTP lacks, make the implementation of asynchronous invocation easier for both service requestor and service provider.

JMS Permits Scalable Services

Scalability is another advantage with SOAP over JMS. Unlike HTTP, JMS can support high-volume connections, even for services that get tens of thousands of connections per second.

General Steps for Implementing JMS as a Transport Mechanism

Enabling JMS as a transport mechanism follows these general steps.

  1. Set up the queues that are to be used for sending and receiving SOAP messages. "Setting Up JMS Queues" provides more information on this step.

  2. Generate the Web service, specifying the JMS queue information for the SOAP transport.

  3. Generate the proxy (if necessary). When generating the proxy, you must identify the return queue. The return queue is the JMS queue on which you want to receive responses to Web service invocations. You can do this by declaring the return queue on the command line or in Ant tasks.

    "Assembling a Proxy that Uses JMS as a Transport" provides more information on this step.

Data Flow for JMS Transport

The following steps describe how data is passed between the Web service client and OracleAS Web Services when JMS is the transport mechanism. The WSDL elements and WebServicesAssembler arguments mentioned in the steps are described later in this chapter. Figure 8-1 illustrates the sequence of steps.

  1. In the Web service client, the message is sent as a request to a JMS queue in OC4J. The <jms:address> element in the WSDL provides the location of the target endpoint to which the message will be served from the JMS queue in OC4J.

  2. The client performs a JMS send operation to send the request to the sender queue in OC4J.

  3. The sender queue in OC4J accepts the request. If WebServicesAssembler was used to assemble the Web service, then the location of the sender queue is provided by the sendQueueLocation argument.

  4. The server runtime dequeues the request and serves it to the endpoint identified by the client's request.

  5. If the message has a reply (or response), the service puts the message on the reply-to queue. If WebServicesAssembler was used to assemble the Web service, then the location of the reply-to queue is provided by the replyToQueueLocation argument.

  6. The client blocks on waiting to receive a response on the reply-to queue (in case of a request-response operation), thus simulating a synchronous request-response. If the message exchange pattern was one way, the client does not wait for a response.

Figure 8-1 Data Flow for JMS Transport

Description of Figure 8-1 follows
Description of "Figure 8-1 Data Flow for JMS Transport"

Setting Up JMS Queues

Queues must be set up in the OracleAS Web Services container to identify the sender queue and the receiver queue. Each queue is identified by a <queue> element and a <queue-connection-factory> element.

The <queue> element contains a name and a location attribute. The name attribute specifies the queue's JNDI name. The location attribute specifies the queue's JNDI location. The queue element can also contain an optional description element to provide a text description of the queue.

The queue-connection-factory element also contains a name and a location attribute. The name attribute specifies the JNDI name of the JMS connection factory used to produce connections for the send or receive operation. The location specifies the factory's JNDI location.

If the queues are set up in the OC4J/JMS jms.xml configuration file, you can add two clauses to that file: one for the sender queue and one for the reply-to queue. For more information on JMS in the OC4J environment, see Oracle Containers for J2EE Services Guide.

Example 8-1 illustrates XML code that identifies the SOAP sender queue at the JNDI location jms/senderQueue. This queue uses jms/senderQueueConnectionFactory as the JMS connection factory to produce connections for the send operation. Similarly, the second clause identifies the SOAP receiver queue at the JNDI location jms/replyToQueue as the receiver queue. This queue uses jms/replyToQueueConnectionFactory as the JMS connection factory to produce connections for the response messages from the Web service endpoint.

Example 8-1 XML Code to Identify Sender Queue and Receiver Queue

...
<queue name="SOAP sender" location="jms/senderQueue">
    <description>A queue for SOAP messages</description>
</queue>
<queue-connection-factory
    name="jms/senderQueueConnectionFactory"
    location="jms/senderQueueConnectionFactory"/>
 
<queue name="SOAP receiver" location="jms/replyToQueue">
    <description>A queue for SOAP response messages</description>
</queue>
<queue-connection-factory
    name="jms/replyToQueueConnectionFactory"
    location="jms/replyToQueueConnectionFactory"/>
...

Assembling a Web Service Bottom Up that Uses JMS Transport

To configure JMS transport into a Web service that you are generating bottom up, extensions must be added to the WSDL that will identify a port that has JMS transport enabled. WebServicesAssembler provides two arguments that will add this information to the WSDL.

The following steps describe how to generate a Web service bottom up that uses JMS as its transport mechanism. The steps follow the standard procedure for assembling a Web service bottom up. For examples of bottom up Web service assembly, see "Assembling a Web Service with Java Classes" and "Assembling a Web Service with EJBs" in the Oracle Application Server Web Services Developer's Guide.

It is assumed that you have already configured the JMS queues for sending and receiving SOAP messages. "Setting Up JMS Queues" provides more information on queues.

  1. Generate the service artifacts by running the WebServicesAssembler with the assemble command. Specify the queue location and queue connection factory with sendQueueLocation and sendConnectionFactoryLocation. The WSDL generated by this Ant task is illustrated in Example 8-2.

    <oracle:assemble appName="echo"
            targetNamespace="http://www.oracle.com/echo"
            typeNamespace="http://www.oracle.com/echo"
            serviceName="EchoService"
            input="./build/classes/service"
            output="build"
            ear="build/echo.ear"
            style="rpc"
            use="encoded"
            createOneWayOperations="true"
            >
            <oracle:porttype 
                interfaceName="oracle.j2ee.ws.jmstransport.Echo"
                className="oracle.j2ee.ws.jmstransport.EchoImpl"
                 >
                 <oracle:port
                   uri="/echo"
                   sendQueueLocation="jms/senderQueue"
                   name="EchoPort"
                   sendConnectionFactoryLocation="jms/senderQueueConnectionFactory"
                </oracle:port> 
            </oracle:porttype>
     />
    
    
  2. Deploy the service.

    Deploy the EAR file in the standard manner into a running instance of OC4J. For more information on deploying EAR files, see the Oracle Containers for J2EE Deployment Guide.

  3. Generate the client code. This step is described in "Assembling a Proxy that Uses JMS as a Transport".

WSDL Extensions for JMS Transport

The following WSDL extensions define JMS transport for a Web service.

These are Oracle-proprietary WSDL extensions and may not be interoperable. If you are using JDeveloper or WebServicesAssembler to develop and deploy the endpoint bottom up, then these extensions are generated into the WSDL. Otherwise, if you are manually writing the WSDL or developing and deploying the Web service top down, then you should add these extensions.

The following URI is the namespace for the extensions described in this section.

xmlns:jms="http://www.oracle.com/technology/oracleas/wsdl/jms"

JMS Address Element

Only one <jms:address> element should be used in a port-component definition. This element should be used in place of a <soap:address> declaration.

<jms:address 
    jndiDestinationName="xxx"
    jndiConnectionFactoryName="xxx"/>

Table 8-1 describes the attributes of the <jms:address> element.

Table 8-1 Attributes of the <jms:address> Element

Attribute Name Description

jndiDestinationName

The JNDI name of the JMS queue that messages will be sent to. If you are generating the Web service bottom up, then this attribute will be set by the sendQueueLocation argument.

jndiConnectionFactoryName

The JNDI name of the connection factory that will be used. If you are generating the Web service bottom up, then this attribute is set by the sendConnectionFactoryLocation argument.


JMS Property Value Element

The <jms:propertyValue> element must be added to the <jms:address> section of the binding operation to identify the endpoint location. The general format is the following.

<jms:propertyValue
    name="string"
    type="type"
    value="string"/>

Table 8-2 describes the attributes of the <jms:propertyValue> element.

Table 8-2 Attributes of the <jms:propertyValue> Element

Attribute Name Description

name

The name of a property defined by JMS, by the JMS implementation, or by the user.

type

The datatype of the attribute.

value

A value that hard codes the value of this property in the WSDL.


The WebServicesAssembler uri argument can provide the value for the propertyValue element in the WSDL. When the uri argument is specified, the name attribute is set to endpoint-location, the type attribute is set to string and the value attribute is set to the value of the uri argument.

<jms:propertyValue name="endpoint-location" type="string" value="value of uri argument"/>

Example 8-2 illustrates the WSDL created by the Ant task in "Assembling a Web Service Bottom Up that Uses JMS Transport". The JMS transport configuration is highlighted in bold.

Example 8-2 WSDL with a JMS Transport Configuration

<?xml version = '1.0' encoding = 'UTF-8'?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
   xmlns:tns="http://www.oracle.com/echo"
   xmlns:jms="http://www.oracle.com/technology/oracleas/wsdl/jms"
name="Echo" targetNamespace="http://www.oracle.com/echo">
    <types>
        <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://www.oracle.com/echo"/>
    </types>
    <message name="Echo_echo">
        <part name="String_1" type="xsd:string"/>
    </message>
    <message name="Echo_echoInt">
        <part name="int_1" type="xsd:int"/>
    </message>
    <message name="Echo_echoIntResponse">
        <part name="result" type="xsd:int"/>
    </message>
    <message name="Echo_echoResponse">
        <part name="result" type="xsd:string"/>
    </message>
    <portType name="Echo">
        <operation name="echo" parameterOrder="String_1">
            <input message="tns:Echo_echo"/>
            <output message="tns:Echo_echoResponse"/>
        </operation>
        <operation name="echoInt" parameterOrder="int_1">
            <input message="tns:Echo_echoInt"/>
            <output message="tns:Echo_echoIntResponse"/>
        </operation>
    </portType>
    <binding name="EchoBinding" type="tns:Echo">
        <operation name="echo">
            <input>
                <soap:body use="encoded" namespace="http://www.oracle.com/echo" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" parts="String_1"/>
            </input>
            <output>
                <soap:body use="encoded" namespace="http://www.oracle.com/echo" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" parts="result"/>
            </output>
            <soap:operation soapAction=""/>
        </operation>
        <operation name="echoInt">
            <input>
                <soap:body use="encoded" namespace="http://www.oracle.com/echo"
 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" parts="int_1"/>
            </input>
            <output>
                <soap:body use="encoded" namespace="http://www.oracle.com/echo"
 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" parts="result"/>
            </output>
            <soap:operation soapAction=""/>
        </operation>
        <soap:binding style="rpc"
 transport="http://www.oracle.com/technology/oracleas/wsdl/jms"/>
    </binding>
    <service name="Echo">
        <port name="EchoPort" binding="tns:EchoBinding">
            <jms:address
             jndiConnectionFactoryName="jms/OracleSyndicateQueueConnectionFactory" 
    jndiDestinationName="jms/OracleSyndicateQueue" >
                <jms:propertyValue name="endpoint-location" type="string" 
value="echo"/>
            </jms:address>
        </port>
    </service>
</definitions>

Adding JMS Transport Configuration with Deployment Descriptors

A JMS transport configuration can be passed to the Web service assembly by entering it into the oracle-webservices.xml deployment descriptor. This is an alternative to declaring the sendQueueLocation and sendConnectionFactoryLocation, arguments on the command line or Ant task.

When you enter the configuration into oracle-webservices.xml, use <jms-address> instead of <jms:address> and <jms-propertyValue> instead of <jms:propertyValue>. These elements should appear as subelements of the <port-component> element.

Example 8-3 illustrates an oracle-webservices.xml deployment descriptor that includes a JMS transport configuration. During assembly, a new WSDL will be created. The resulting WSDL will look like the one in Example 8-2. The JMS configuration is highlighted in bold. The jndiDestinationName and jndiConnectionFactoryName attributes are defined in "WSDL Extensions for JMS Transport".

Example 8-3 oracle-webservices.xml with JMS Transport Configuration

<oracle-webservices
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="oracle-webservices-server-10_0.xsd"
    schema-major-version="10" schema-minor-version="0">
    <webservice-description name="Echo">
        <port-component name="EchoPort">
            <runtime enabled="true">
                <jms-address jndiDestinationName="jms/senderQueue" 
jndiConnectionFactoryName="jms/senderQueueConnectionFactory" />
            </runtime>
        </port-component>
    </webservice-description>
</oracle-webservices>

Assembling a Web Service Top Down that Uses JMS Transport

For top down assembly, you must edit the WSDL to add the JMS address and property values for the endpoint.

The following steps describe how to generate a Web service that uses JMS as its transport mechanism. The steps follow the standard procedure for assembling a Web service described in "Generating the Web Service Top Down" in the Oracle Application Server Web Services Developer's Guide.

It is assumed that you have already configured the JMS queues for sending and receiving SOAP messages. "Setting Up JMS Queues" provides more information on queues.

  1. Provide a WSDL from which the Web service will be generated.

  2. Edit the WSDL to add the elements that define JMS transport. "WSDL Extensions for JMS Transport" describes the JMS transport elements.

  3. Use the WSDL as input to the WebServicesAssembler genInterface command.

  4. Compile the generated interface and type classes.

  5. Write the Java service endpoint interface for the Web service you want to provide.

  6. Compile the Java service endpoint interface.

  7. Generate the service by running the WebServicesAssembler tool with the topDownAssemble command.

    <oracle:topDownAssemble appName="bank"
                packageName="oracle.ws.server.bank"
                wsdl="./etc/Bank.wsdl"
                input="./build/classes/service}"
                output="build"
                ear="build/bank.ear"
                debug="true"
                fetchWsdlImports="true"
                >
                <oracle:classpath>
                    <oracle:pathelement path="${build.impl.dir}"/>
                    <oracle:pathelement location="${wsa.jar}"/>
                </oracle:classpath>
                <oracle:porttype
                  className="oracle.ws.server.bank.BankImpl"
                  classFileName="java/oracle/ws/server/bank/BankImpl.java"
                  >
                   <oracle:port name="BankPort" uri="bank2"/>
                   <oracle:port name="BankPortWithJMS" uri="/bank"/>
                   <oracle:port name="Soap12JmsEchoPort" uri="/soap12bank"/>
              </oracle:porttype>
            />
    
    
  8. Deploy the service.

    Deploy the EAR file in the standard manner into a running instance of OC4J. For more information on deploying EAR files, see the Oracle Containers for J2EE Deployment Guide.

  9. Generate the client code. This step is described in "Assembling a Proxy that Uses JMS as a Transport".

  10. Add the following client JAR files to the classpath. These client JAR files are required when the Web service client supports JMS as a transport mechanism. The J2EE_HOME environment variable in the paths represents the location where the Oracle Application Server or the standalone OC4J is installed.

    • J2EE_HOME/j2ee/home/lib/oc4j-unsupported-apis.jar

    • J2EE_HOME/j2ee/home/lib/oc4j-internal.jar

    "Web Service Client APIs and JARs" in the Oracle Application Server Web Services Developer's Guide, provides a description of all of the available OracleAS Web Services client JARs.

Assembling a Proxy that Uses JMS as a Transport

When working with JMS as a transport mechanism you must ensure that the client code provides the JNDI names of the JMS queue and the connection factory for the reply-to queue which will be used for send operation JMS messages. The WebServicesAssembler arguments replyToQueueLocation and replyToConnectionFactoryLocation can provide these values. Used with the genProxy command, these arguments generate a proxy stub that can be used with JMS transport. The arguments will generate a stub configured with values for a queue that will receive response messages.

If you do not use the replyTo* arguments to generate a proxy stub, and the endpoint contains request/response operations, then you must set the replyTo* arguments programmatically so that response messages can be received. "Setting the Send Queue Location and Connection Factory Programmatically" describes how to provide this information directly in your code.

The following steps describe how to generate a proxy stub that uses JMS as its transport mechanism. The steps follow the standard procedure for assembling a proxy stub that are described in How to Assemble a J2SE Web Service Client with a Static Stub in the Oracle Application Server Web Services Developer's Guide,.

It is assumed that you have already configured the JMS queues for sending and receiving SOAP messages. "Setting Up JMS Queues" provides more information on queues.

  1. Provide the URI to the WSDL, the name of the output directory, the package name, and the locations of the JMS queue and connection factory as input to the WebServicesAssembler genProxy command.

    <oracle:genProxy
           wsdl="http://localhost:8888/bank/bank?WSDL"
           output="build/src/proxy"
           packageName="oracle.ws.client.bank"
           >
           <oracle:port 
             replyToConnectionFactoryLocation="jms/receiverQueueConnectionFactory"
             replyToQueueLocation="jms/receiverQueue"
           </oracle:port>
       />
    
    

    This command generates the client proxy and stores it in the build/src/proxy directory. The client application uses the stub to invoke operations on a remote service.

  2. Use the client utility class file created by genProxy as your application client, or use it as a template to write your own client code. The client utility class file is one of a number of files created by genProxy.

  3. Compile the client files and put them in the classpath.

    List the appropriate JARs on the classpath before compiling the client. "Classpath Components for Clients Using a Client Side Proxy" in the Oracle Application Server Web Services Developer's Guide lists all of the JAR files that can possibly be used on the client classpath. As an alternative to listing individual JARs, you can include the client-side JAR, wsclient_extended.jar on the client classpath. This JAR file contains all the classes necessary to compile and run a Web service client. The classes are from the individual JAR files listed in "Setting the Web Service Proxy Client Classpath" in the Oracle Application Server Web Services Developer's Guide. This appendix provides information on wsclient_extended.jar and the client classpath.

    For JMS clients, you must also include the oc4j-internal.jar and oc4j-unsupported-apis.jar files on the classpath. "JMS Transport-Related Client JAR File" in the Oracle Application Server Web Services Developer's Guide. provides more information on the oc4j-internal.jar and oc4j-unsupported-apis.jar files.

    To provide a JNDI configuration for the client, add the jndi.properties file to the client classpath.

  4. Run the J2SE JMS client from the command line.

Writing Client Code to Support JMS Transport

The following sections describe how to write Web service clients that use JMS transport.

Writing Client Stub Code for JMS Transport

Stub code for a client that uses JMS transport is very similar to code for clients that use HTTP transport. The difference is that the endpoint address must be set to the unique URI that identifies the JMS endpoint. "Writing Web Service Client Applications" in the Oracle Application Server Web Services Developer's Guide provides more information on writing client code for J2SE client applications.

Example 8-4 illustrates client stub code that uses JMS transport to send messages. The code that sets the endpoint address to the unique URI that identifies the JMS endpoint is highlighted in bold.

Example 8-4 Client Stub Code to Send Messages with JMS Transport

...
ServiceFactory serviceFactory = ServiceFactory.newInstance();
        Echo_Service echoService = (Echo_Service) serviceFactory.loadService(Echo_Service.class);
        Echo_PortType echoPort = echoService.getEchoPort();
        ((Stub)echoPort)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, "/echo/echo");  
         String echo = echoPort.echo("Test echo");
...

Setting the Send Queue Location and Connection Factory Programmatically

When you are working with JMS as a transport, client stub code requires to you to identify the JNDI names of the JMS queue and the connection factory for the reply-to queue for send operation JMS messages. If you do not provide these values when you generate the proxy stub code, you can add them programmatically. OracleAS Web Services provides two properties in the oracle.webservices.transport.OracleStub class that allow you to do this.

  • JMS_TRANSPORT_REPLY_TO_FACTORY_NAME—specifies the JNDI name of the JMS connection factory to be used as the default reply-to of all send operation JMS messages. This property is comparable to the replyToConnectionFactoryLocation WebServicesAssembler argument.

  • JMS_TRANSPORT_REPLY_TO_QUEUE_NAME—specifies the JNDI name of the JMS queue to be used as the default reply-to of all send operation JMS messages. This property is comparable to the replyToQueueLocation WebServicesAssembler argument.

Example 8-5 illustrates client stub code that uses these properties to set the JNDI name of the JMS queue and the connection factory for the reply-to queue for send operations. The code that sets the properties is highlighted in bold.

Example 8-5 Setting replyTo* Parameters Programmatically

ServiceFactory serviceFactory = ServiceFactory.newInstance();
   Echo_Service echoService = (Echo_service)serviceFactory.loadService(Echo_Service.class;
   Echo_PortType echoPort = echoService.getEchoPort();
      ((Stub)echoPort)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, "/echo/echo");
      ((Stub)echoPort)._setProperty(OracleStub.JMS_TRANSPORT_REPLY_TO_FACTORY_NAME, "jms/receiverQueueConnectionFactory");
      ((Stub)echoPort)._setProperty(OracleStub.JMS.TRANSPORT_REPLY_TO_QUEUE_NAME, "jms/receiverQueue");
   String echo = echoPort.echo("Test echo");

Writing DII Code for JMS Transport

If you are writing code for a Dynamic Invocation Interface (DII) client, you must create JmsAddress objects for the sender queue and the receiver queue. These objects are then used to declare an JmsClientTransportFactory object programmatically. This will allow the client to get response messages from a Web service invocation.

The JmsAddress and JmsClientTransportFactory classes belong to the oracle.webservices.transport package.

Example 8-6 illustrates DII client code for sending messages through JMS transport. The code which illustrates how JmsClientTransportFactory is created, set up, and used is highlighted in bold.

Example 8-6 DII Client Code to Send Messages Through JMS Transport

...
QName operation = new QName("http://www.oracle.com/echo", "echo");
            Call call = getCall(operation, SOAPVersion.SOAP_1_1);
            call.setTargetEndpointAddress("/echo/echo");
            JmsAddress jmsAddress = new JmsAddress("jms/senderQueue", "jms/senderQueueConnectionFactory");
            JmsAddress replyToAddress = new JmsAddress("jms/receiverQueue", "jms/receiverQueueConnectionFactory");
            JmsClientTransportFactory transportFactory = new JmsClientTransportFactory(jmsAddress, replyToAddress);
            ((OracleCall) call).setClientTransportFactory(transportFactory);
...

Limitations

See "Using JMS as a Web Service Transport".

Additional Information

For more information on: