JBossWS - WS Reliable Messaging

Version 1

    Requirements

     

     

    Use Cases Requirements

    The following use cases must be supported

    Reliable Messaging Scenarios

    • One-Way anonymous client (see RMAnonymousOneWayTestCase)
    • One-Way addressable client (see RMAddressableOneWayTestCase)
    • Request-Reply anonymous client (see RMAnonymousReqResTestCase)
    • Request-Reply addressable client (see RMAddressableReqResTestCase)

    Secure Reliable Messaging Scenarios

    • Secured One-Way anonymous client (see RMSecuredAnonymousOneWayTestCase)
    • Secured One-Way addressable client (see RMSecuredAddressableOneWayTestCase)
    • Secured Request-Reply anonymous client (see RMSecuredAnonymousReqResTestCase)
    • Secured Request-Reply addressable client (see RMSecuredAddressableReqResTestCase)

     

     

    A Reliable One-Way Anonymous Test

    This test is located in trunk/src/test/java/org/jboss/test/ws/jaxws/wsrm/oneway directory. This type of test is described in "Scenario #1.1. One-Way Anonymous Client" WCF (Indigo) Introperability Lab: Reliable Messaging. This is a typical  enterprise use case where a client sends data to a service for processing  but does not wait for a response -- that's why it's called "One-Way". However, the client wants assurances that the messages are received by the service.

    The message flow in this test is as follows:

    Reliable Messaging Operation

    +-------------+      +--------+                                +------+   +-------------+
    |   Client    |      |   RM   |                                |  RM  |   |   Service   |
    | Application |      | Source |                                | Dest |   | Application |
    +-------------+      +--------+                                +------+   +-------------+
           |                  |                                        |             |
           | create           |        CreateSequence                  |             |
           +----------------->|--------------------------------------->|             |
           |                  |             SeqId                      |             |
           |                  |<---------------------------------------|             |
           |                  |                                        |             |
           |                  |                                        |             |
           | Client Data      | Client data + SeqId + MsgId            | Client data |
           +----------------->|--------------------------------------->|------------>|
           |                  |     Srv data + SeqAck                  |   Srv data  |
           |                  |<---------------------------------------|<------------|
           |                  |                                        |             |
           |                  |                                        |             |
           | Client Data      | Client data + SeqId + MsgId            | Client data |
           +----------------->|--------------------------------------->|------------>|
           |                  |     Srv data + SeqAck                  |   Srv data  |
           |                  |<---------------------------------------|<------------|
           |                  |                                        |             |
           |                  |                                        |             |
           | Client Data      | Client data + SeqId + MsgId            | Client data |
           +----------------->|--------------------------------------->|------------>|
           |                  |     Srv data + SeqAck                  |   Srv data  |
           |                  |<---------------------------------------|<------------|
           |                  |                                        |             |
           |                  |                                        |             |
           | terminate        | TerminateSequence + SeqId + LastMsgId  |             |
           +----------------->|--------------------------------------->|             |
           |                  | TerminateSequenceResponse              |             |
           |                  |<---------------------------------------|             |
    • The client initiates the establishment of a reliable communication channel by sending a CreateSequence protocol message.
    • The service creates a sequence identifier to uniquely identify the reliable channel. The service returns this identifier in a CreateSequenceResponse protocol message.
    • The client sends three application messages. Each of these messages is accompanied with header information containing the sequence identifier for the channel and a message number identifying the message.
    • For each application message received, the service responds with a SequenceAcknowledgement identifying what messages have been received. The service does this without having to wait for the business logic to complete processing.
    • If the client sees that some of the messages it sent have not been received, it retransmits those messages. (This situation is not tested in this test.)
    • The client closes the channel when the channel is no longer needed. Again, if the client sees that some of the messages it sent have not been received, it resends those messages. (That is not exercised in this test.)
    • The client sends a TerminateSequence protocol message.
    • The service responds with TerminateSequenceResponse indicating that the request has been accepted for processing.

     

     

    JBossWS Based WS-RM Client

       public void testWSRMClient() throws Exception
       {
          // get service proxy first
          QName serviceName = new QName(targetNS, "OneWayService");
          URL wsdlURL = new URL(serviceURL + "?wsdl");
          Service service = Service.create(wsdlURL, serviceName);
          OneWayServiceIface proxy = (OneWayServiceIface)service.getPort(OneWayServiceIface.class);
    
          // set addressing properties
          BindingProvider bp = (BindingProvider)proxy;
          AddressingProperties props = AddressingClientUtil.createAnonymousProps(wsaAction, serviceURL);
          bp.getRequestContext().put(JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES_OUTBOUND, props);
    
          // call one way method three times
          for (int i = 0; i < 3; i++)
             proxy.echo("Hello World: " + i);
    
          // close WS-RM sequence
          ((RMProvider)proxy).closeSequence(); // this is optional operation
       }
    

    Using a reliable messaging (RM)-based web service is no different than using  any SOAP-based web service. First you create a proxy to the service  Then you obtain a port defined in that service, in this case, OneWayServiceIface. Then you can send application messages to that service by calling the echo method on the port proxy. In this test, three messages are sent.

    The last optional step is calling closeSequence() on the RMProvider. This signals JBossWS to close and terminate the RM sequence.

    You can see the exchanged messages in test.log after test execution.

     

    WSDL

    The port that this test uses is named OneWayPort. It references the following policy binding:

    <wsp:Policy 
    wsu:Id="exactly_one_in_order_rm_delivery"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <wsp:All>
      <wsrmp:DeliveryAssurance xmlns:wsrmp="http://docs.oasis-open.org/ws-rx/wsrmp/200702">
       <wsp:Policy>
        <wsp:ExactlyOne>
         <wsp:All>
          <wsrmp:ExactlyOnce/>
          <wsrmp:InOrder/>
         </wsp:All>
        </wsp:ExactlyOne>
       </wsp:Policy>
      </wsrmp:DeliveryAssurance>
    </wsp:All>
    </wsp:Policy>

    The RMASssertion in the policy binding specifies an RM policy assertion for the service.  This WS-RM policy attachment defines that all messages will be delivered exactly once and in order to the target endpoint. You can find out more about RM policy  assertions in the WS-ReliableMessaging Policy specification. The main point here  is that including the RMAssertion in the WSDL, then referencing it in the  OneWayPort wsdl definition plus using RMProvider.createSequence() causes operations on that port to use reliable messaging.

     

    Client Side

    Activating WS-RM on Client Side

    There are just two steps necessary to achieve that:

    • use client configuration that contains both WS-Addressing and WS-RM handler in the handlers chain
    • client configuration must contain message-retransmission element and can contain backports-server. Both elements are part of client-config/reliable-messaging configuration element.

    Here is the sample client configuration:

      <client-config>
        <config-name>Secured WSRM Client</config-name>
        <reliable-messaging>
          <backports-server port="7777"/><!-- when this element is present WS-RM client is addressable -->
          <message-retransmission attempts="50" interval="10" timeout="3"/>
        </reliable-messaging>     
        <post-handler-chains>
          <javaee:handler-chain>
            <javaee:protocol-bindings>##SOAP11_HTTP</javaee:protocol-bindings>
            <javaee:handler>
              <javaee:handler-name>WSAddressing Handler</javaee:handler-name>
              <javaee:handler-class>org.jboss.ws.extensions.addressing.jaxws.WSAddressingClientHandler</javaee:handler-class>
            </javaee:handler>
            <javaee:handler>
              <javaee:handler-name>WSRM Handler</javaee:handler-name>
              <javaee:handler-class>org.jboss.ws.extensions.wsrm.jaxws.RMClientHandler</javaee:handler-class>
            </javaee:handler>
            <javaee:handler>
              <javaee:handler-name>WSSecurity Handler</javaee:handler-name>
              <javaee:handler-class>org.jboss.ws.extensions.security.jaxws.WSSecurityHandlerClient</javaee:handler-class>
            </javaee:handler>
          </javaee:handler-chain>
        </post-handler-chains>
      </client-config>

    Client Side Architecture

    Current WS-RM client side prototype fits very well into existing JAX-WS architecture. That means the implementation is transparent with already provided features such as WS-Security and WS-Addressing.

    Before we will dive into architecture details lets define some basic terms:

    • RM Provider - is the interface that can be used by clients to create and close RM sequences
    • Endpoint Proxy - is any endpoint proxy created using Service.getPort(..., SEI.class) methods
    • RM Client Handler - is the client side in/outbound JAX-WS handler
    • JBossWS Messaging Layer - is the underlying SOAP based messaging framework

    The following image illustrates how client side WS-RM support fits into the existing architecture:

    Client-architecture.png

    The RM Provider (represented by interface org.jboss.ws.extensions.wsrm.api.RMProvider) is the only entry point that can be used on client side to create and close WS-RM sequences. The RM Provider define methods createSequence() and closeSequence(). The createSequence() method creates either addressable or anonymous WS-RM client. The only difference between addressable and anonymous is that addressable version of RM client starts its own http server on client side to receive callbacks from endpoint while anonymous version doesn't.

    Once user will create the sequence he can send as many messages (doesn't matter whether they follow one way or request response messaging pattern) using endpoint proxy to the server side. When user is finished he can to call closeSequence() method on RM Provider to terminate the existing sequence. But this is optional.

     

    RM Channel

    All magic related to addressable vs. anonymous client is implemented in RM Channel. RM Channel is the transport wrapper that is responsible for reliable message delivery. The following two images demonstrate the difference between anonymous vs. addressable client:

    The following image illustrates how reliable messaging channel works for anonymous clients:

    Client-side-anonymous-architecture.png

     

    The following image illustrates how reliable messaging channel works for addressable clients:

    Client-side-addressable-architecture.png

     

    Lets talk about the objects you can see on the pictures.

    • RM Message Assembler - translates JBossWS messages to RM sources and vice-versa.
    • RM Sender - the heart of the RM Channel ensures the reliable message delivery to the server side. It resends the messages if response didn't arrive in specified time or server/service is not available at the moment. The resending interval, timeout settings and count of attempts to deliver the message is specified in JAX-WS configuration file. Here's the config file example:
    <jaxws-config
      xmlns="urn:jboss:jaxws-config:2.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:javaee="http://java.sun.com/xml/ns/javaee"
      xsi:schemaLocation="urn:jboss:jaxws-config:2.0 jaxws-config_2_0.xsd">
      <client-config>
        <config-name>Standard WSRM Client</config-name>
        <reliable-messaging>
          <backports-server port="7777"/>
          <message-retransmission attempts="50" interval="10" timeout="3"/>
        </reliable-messaging>     
        <post-handler-chains>
          <javaee:handler-chain>
            <javaee:protocol-bindings>##SOAP11_HTTP</javaee:protocol-bindings>
            <javaee:handler>
              <javaee:handler-name>WSAddressing Handler</javaee:handler-name>
           <javaee:handler-class>org.jboss.ws.extensions.addressing.jaxws.WSAddressingClientHandler</javaee:handler-class>
            </javaee:handler>
            <javaee:handler>
              <javaee:handler-name>WSRM Handler</javaee:handler-name>
              <javaee:handler-class>org.jboss.ws.extensions.wsrm.RMClientHandler</javaee:handler-class>
            </javaee:handler>
          </javaee:handler-chain>
        </post-handler-chains>
      </client-config>
    </jaxws-config>
    
    • RM Tasks Queue - the job queue used by RM Sender. It holds RM tasks to be executed. Each RM Task tries to send the message to the server side.
    • RM Thread Pool - keeps worker threads (daemons). Each worker thread waits for job to execute.
    • Remoting Output/Input Streams - the remoting transport.
    • RM Backports Server - HTTP server used by addressable WS-RM clients.

     

     

    Server Side

    Activating WS-RM on Server Side

    There are just two steps necessary to achieve that:

    • associate WS-RM Policy 1.1 with the target endpoint
    • use endpoint configuration that contains both WS-Addressing and WS-RM handler in the handlers chain

    How to Associate WS-RM Policy With the Endpoint

    It is really simple. You can do that e.g. using PolicyAttachment annotation. Here is simple example how to achieve that:

    @PolicyAttachment
    (
       @Policy
       (
          policyFileLocation = "WEB-INF/wsrm-exactly-once-in-order-policy.xml",
          scope = PolicyScopeLevel.WSDL_BINDING
       )
    )
    ...
    public class SEIImpl implements SEIIface
    {
       ...
    }
    

    where wsrm-exactly-once-in-order-policy.xml file (packaged to endpoint archive) has the following content:

    <?xml version="1.0" encoding="UTF-8"?>
    <wsp:Policy
       wsu:Id="exactly_one_in_order_rm_delivery"
       xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
       xmlns:wsrmp="http://docs.oasis-open.org/ws-rx/wsrmp/200702"
       xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
       <wsrmp:DeliveryAssurance>
          <wsp:Policy>
             <wsrmp:ExactlyOnce/>
             <wsrmp:InOrder/>
          </wsp:Policy>
       </wsrmp:DeliveryAssurance>
    </wsp:Policy>
    

    See WS-RM Policy 1.1 specification to see other possible combinations that can be created using this specification.

     

    Server Side Architecture

    Current WS-RM server side prototype fits very well into existing JAX-WS architecture. That means again that implementation is transparent with already provided features such as WS-Security and WS-Addressing.

    The following image illustrates how server side WS-RM support fits into existing architecture:

    Server-architecture.png

    The most important object on this picture is RM Invocation Handler that does all the WS-RM magic. This invocation handler is associated with the target endpoint in deployment time. There is RM Deployment Aspect registered in the Microcontainer that checks whether endpoint has WS-RM Policy associated or not. If this special policy is detected RM Invocation Handler is associated with the target endpoint during endpoint deployment process.

     

    WS-RM and WS-Security

    There is nothing special about WS-RM and WS-Security integration. It simply works. The only thing user needs to do is to setup WS-Security on both client and server sides correctly. The only important thing about WS-RM plus WS-Security integration is that WS-Security Handler must always be the last one in the handlers chain.