Apache Sandesha2 User's Guide

This document introduces you to Apache Sandesha2. This will first take you through a step by step process of developing a sample application using Sandesha2. In the latter sections you will be introduced to some advance features making you more familiar with the application.

Contents

Introduction

Sandesha2 is a Web Service-ReliableMessaging (WS-RM) implementation for Apache Axis2. With Sandesha2 you can make your Web services reliable, or you can invoke already hosted reliable Web services.

If you want to learn more about Apache Axis2, refer to Apache Axis2 User Guide and Apache Axis2 Architecture Guide.

If you want to know about the design of Sandesha2 refer to Sandesha2 Architecture Guide.

Sandesha2 supports the WS-ReliableMessaging specification. It fully supports the WS-ReliableMessaging 1.0 specification (February 2005) ( http://specs.xmlsoap.org/ws/2005/02/rm/ws-reliablemessaging.pdf ).

This specification has been submitted to OASIS and currently being standardized under the OASIS WS-RX Technical Committee as WSRM 1.1 (see http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=ws-rx ). Sandesha2 currently supports Committee Draft 3 of the specification being developed under this technical committee ( http://docs.oasis-open.org/ws-rx/wsrm/200602/wsrm-1.1-spec-cd-03.pdf ).

Your First Service with Sandesha2

This section will give you step by step guidelines on creating a Web service with reliability and making it available within your Axis2 server. This simple service will have a single one-way operation (ping) and a request-response operation (echoString).

The steps are as follows:"

1. Download the Axis2 Webapp distribution (Axis2.war file) and deploy it within Tomcat. Extract the webapp so that you can edit the files of the webapp. (this will also be done if you run tomcat with the axis2.war file within the webapps folder).

2. Add a user phase named RMPhase to the inFlow, outFlow of inFaultFlow of the axis2.xml file which is situated under the webapps/axis2/WEB-INF/conf directory. The 'Phases' part of a axis2.xml file with RMPhase is given below.

<axisconfig name="AxisJava2.0">
    <!-- OTHER PARTS OF THE CONFIGURATOIN-->
    <phaseOrder type="inflow">
         <phase name="Transport">
            <!-- TRANSPORT PHASE HANDLERS-->
        </phase>
        <phase name="Security"/>
        <phase name="PreDispatch"/>
        <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
            <!-- DISPATCH PHASE HANDLERS-->
        </phase>
        <phase name="OperationInPhase"/>
        <phase name="RMPhase"/>
    </phaseOrder>
    <phaseOrder type="outflow">
        <phase name="RMPhase"/>
        <phase name="OperationOutPhase"/>
        <phase name="PolicyDetermination"/>
        <phase name="MessageOut"/>
    </phaseOrder>
    <phaseOrder type="INfaultflow">
        <phase name="PreDispatch"/>
        <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
            <!-- DISPATCH PHASE HANDLERS-->
        </phase>
        <phase name="OperationInFaultPhase"/>
        <phase name="RMPhase"/>
    </phaseOrder>
    <phaseOrder type="Outfaultflow">
        <!--      user can add his own phases to this area  -->
        <phase name="RMPhase"/>
        <phase name="OperationOutFaultPhase"/>
        <phase name="PolicyDetermination"/>
        <phase name="MessageOut"/>
    </phaseOrder>
</axisconfig>

2 Get a Sandesha2 binary distribution. Extract this to obtain the sandesha module file (which has the format sandesha2-<VERSION>.mar). Put this to the webapps/axis2/WEB-INF/modules directory.

3. Create the service implementation java file as given below. Compile this after adding all the libraries within the webapps/axis2/WEB-INF/lib directory to your classpath.

RMSampleService.java

package sandesha2.samples.userguide;

import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;

public class RMSampleService {

    private static Map sequenceStrings = new HashMap();  //TODO make this non static
    private final String applicationNamespaceName = "http://tempuri.org/"; 
    private final String Text = "Text";
    private final String Sequence = "Sequence";
    private final String echoStringResponse = "echoStringResponse";
    private final String EchoStringReturn = "EchoStringReturn";
  
    public OMElement echoString(OMElement in) throws Exception {

        OMElement textElem = in.getFirstChildWithName(new QName (applicationNamespaceName,Text));
        OMElement sequenceElem = in.getFirstChildWithName(new QName (applicationNamespaceName,Sequence));

        if (textElem==null)
            throw new Exception ("'Text' element is not present as a child of the 'echoString' element");
        if (sequenceElem==null)
            throw new Exception ("'Sequence' element is not present as a child of the 'echoString' element");

        String textStr = textElem.getText();
        String sequenceStr = sequenceElem.getText();

        System.out.println("'EchoString' service got text '" + textStr + "' for the sequence '" + sequenceStr + "'");

        String previousText = (String) sequenceStrings.get(sequenceStr);
        String resultText = (previousText==null)?textStr:previousText+textStr;
        sequenceStrings.put(sequenceStr,resultText);

        OMFactory fac = OMAbstractFactory.getOMFactory();
        OMNamespace applicationNamespace = fac.createOMNamespace(applicationNamespaceName,"ns1");
        OMElement echoStringResponseElem = fac.createOMElement(echoStringResponse, applicationNamespace);
        OMElement echoStringReturnElem = fac.createOMElement(EchoStringReturn, applicationNamespace);

        echoStringReturnElem.setText(resultText);
        echoStringResponseElem.addChild(echoStringReturnElem);

        return echoStringResponseElem;
    }
  
    public void ping(OMElement in) throws Exception  {
        OMElement textElem = in.getFirstChildWithName(new QName (applicationNamespaceName,Text));
        if (textElem==null)
            throw new Exception ("'Text' element is not present as a child of the 'Ping' element");

        String textValue = textElem.getText();

        System.out.println("ping service got text:" + textValue);
    }
}

4. Create the services.xml service configiration file as given below. Note that this has engaged the sandesha2 module for this service.

services.xml

<service name="RMSampleService">
   <parameter name="ServiceClass" locked="xsd:false">sandesha2.samples.userguide.RMSampleService</parameter>

   <module ref="sandesha2" />

   <description>
        The userguide Sample service.
   </description>

   <operation name="ping" mep="http://www.w3.org/2004/08/wsdl/in-only"> 
       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver" />
   </operation>  
   <operation name="echoString">
       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
   </operation>
</service>

5. Set RMSampleService.class and the services.xml files obtained from the previous steps in the folder structure below. Create a RMInteropService.aar file by compressing it using the jar tool.

----META-INF
--------services.xml
----sandesha2
-------samples
-----------userguide
---------------RMSampleService.class

6. Deploy the service by dropping it to the webapp/axis2/WEB-INF/services directory.

Now your service is deployed with reliable messaging capability!

Writing Clients for Reliable Services

1. Create a repository folder in your file system (let's call it Client_Repo).

2.Put the client_axis2.xml file that comes with the Sandesha2 distributions to the Client_Repo.

3. Create a sub folder named 'modules' in the Client Repo and add the sandesha and addressing module files to that. Your folder structure should look like following now.

-- Client_Repo  
------ client_axis2.xml
-------modules
-------------sandesha2.mar
-------------addressing.mar

4. Write your client code as given in the following example scenarios. In these scenarios the variable CLIENT_REPO_PATH should be given the full path to the Client Repo folder in a java compatible manner. To compile these you will have to add all the library files that come with the Axis2 distribution and the sandesha2-client-<VERSION>.jar file to your classpath.

For e.g.:

CLIENT_REPO_PATH = c:\\sandesha2\\repository

Client Code for a One-Way RM Service Call

UserguidePingClient.java

package sandesha2.samples.userguide;

import java.io.File;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.sandesha2.client.SandeshaClientConstants;


public class UserguidePingClient {

    private static final String applicationNamespaceName = "http://tempuri.org/"; 
    private static final String ping = "ping";
    private static final String Text = "Text";
    private static String toEPR = "http://127.0.0.1:8080/axis2/services/RMSampleService";
    private static String CLIENT_REPO_PATH = "Full path to the Client Repo folder";

    public static void main(String[] args) throws AxisFault {

        String axis2_xml = CLIENT_REPO_PATH + File.separator + "client_axis2.xml";
        ConfigurationContext configContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem(CLIENT_REPO_PATH,axis2_xml);

        Options clientOptions = new Options ();
        clientOptions.setTo(new EndpointReference (toEPR));

        ServiceClient serviceClient = new ServiceClient (configContext,null);
        clientOptions.setAction("urn:wsrm:Ping");
        serviceClient.setOptions(clientOptions);

//      serviceClient.engageModule(new QName ("sandesha2"));
//      serviceClient.engageModule(new QName ("addressing"));

        serviceClient.fireAndForget(getPingOMBlock("ping1"));
        serviceClient.fireAndForget(getPingOMBlock("ping2"));

        clientOptions.setProperty(SandeshaClientConstants.LAST_MESSAGE, "true");
        serviceClient.fireAndForget(getPingOMBlock("ping3"));

        serviceClient.finalizeInvoke();
    }

    private static OMElement getPingOMBlock(String text) {
        OMFactory fac = OMAbstractFactory.getOMFactory();
        OMNamespace namespace = fac.createOMNamespace(applicationNamespaceName,"ns1");
        OMElement pingElem = fac.createOMElement(ping, namespace);
        OMElement textElem = fac.createOMElement(Text, namespace);

        textElem.setText(text);
        pingElem.addChild(textElem);

        return pingElem;
    }
}

Let's find out the differences between this code and a client code without RM:

You have to engage the sandesha and addressing modules. This has to be done only if your axis2.xml file does not globally add these. For example, if you are using the axis2_client.xml as in the previous file that comes with the Sandesha2 distribution, these two lines have to be omitted (as done in the previous code example). Otherwise Axis2 will throw the exception "org.apache.axis2.AxisFault: Trying to engage a module which is already engaged".

Before the last invocation you have to set the LAST_MESSAGE property. Otherwise the sequence will not terminate properly.

Client Code for a Request-Reply RM Service Call

UserguideEchoClient.java

package sandesha2.samples.userguide;

import java.io.File;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.soap.SOAPBody;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.client.async.AsyncResult;
import org.apache.axis2.client.async.Callback;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.sandesha2.client.SandeshaClientConstants;

public class UserguideEchoClient {

    private final static String applicationNamespaceName = "http://tempuri.org/"; 
    private final static String echoString = "echoString";
    private final static String Text = "Text";
    private final static String Sequence = "Sequence";
    private final static String echoStringResponse = "echoStringResponse";
    private final static String EchoStringReturn = "EchoStringReturn";
    private static String toEPR = "http://127.0.0.1:8080/axis2/services/RMSampleService";

    private static String CLIENT_REPO_PATH = "Full path to the Client Repo folder";

    public static void main(String[] args) throws Exception {

        String axis2_xml = CLIENT_REPO_PATH + File.separator +"client_axis2.xml";
        ConfigurationContext configContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem(CLIENT_REPO_PATH,axis2_xml);
        ServiceClient serviceClient = new ServiceClient (configContext,null);

        Options clientOptions = new Options ();
        clientOptions.setTo(new EndpointReference (toEPR));
        clientOptions.setTransportInProtocol(Constants.TRANSPORT_HTTP);
        clientOptions.setUseSeparateListener(true);
        serviceClient.setOptions(clientOptions);

//      serviceClient.engageModule(new QName ("sandesha2"));
//      serviceClient.engageModule(new QName ("addressing"));

        Callback callback1 = new TestCallback ("Callback 1");
        serviceClient.sendReceiveNonBlocking (getEchoOMBlock("echo1","sequence1"),callback1);
        Callback callback2 = new TestCallback ("Callback 2");
        serviceClient.sendReceiveNonBlocking(getEchoOMBlock("echo2","sequence1"),callback2);

        clientOptions.setProperty(SandeshaClientConstants.LAST_MESSAGE, "true");
        Callback callback3 = new TestCallback ("Callback 3");
        serviceClient.sendReceiveNonBlocking(getEchoOMBlock("echo3","sequence1"),callback3);

        while (!callback3.isComplete()) {
            Thread.sleep(1000);
        }
        
        Thread.sleep(4000); 
    }

    private static OMElement getEchoOMBlock(String text, String sequenceKey) {
        OMFactory fac = OMAbstractFactory.getOMFactory();
        OMNamespace applicationNamespace = fac.createOMNamespace(applicationNamespaceName,"ns1");
        OMElement echoStringElement = fac.createOMElement(echoString, applicationNamespace);
        OMElement textElem = fac.createOMElement(Text,applicationNamespace);
        OMElement sequenceElem = fac.createOMElement(Sequence,applicationNamespace);

        textElem.setText(text);
        sequenceElem.setText(sequenceKey);
        echoStringElement.addChild(textElem);
        echoStringElement.addChild(sequenceElem);

        return echoStringElement;
    }

    static class TestCallback extends Callback {

        String name = null;
        public TestCallback (String name) {
            this.name = name;
        }

        public void onComplete(AsyncResult result) {
            SOAPBody body = result.getResponseEnvelope().getBody();

            OMElement echoStringResponseElem = body.getFirstChildWithName(new QName (applicationNamespaceName,echoStringResponse));
            OMElement echoStringReturnElem = echoStringResponseElem.getFirstChildWithName(new QName (applicationNamespaceName,EchoStringReturn));

            String resultStr = echoStringReturnElem.getText();
            System.out.println("Callback '" + name +  "' got result:" + resultStr);
        }

        public void onError (Exception e) {
            System.out.println("Error reported for test call back");
            e.printStackTrace();
        }
    }
}

Here the differences from a normal request-reply client code is as follows:

Follow the instructions in the previous scenario to do the module engagement correctly.

You have to tell Axis2 to use a separate channel for the responses by using 'useSeperateListner' method of the options object. Also make sure that you set the incoming transport protocol using the 'setTransportInProtocol' method.

Also you have to set the LAST_MESSAGE property as explained in the previous scenario.

In the current implementation you are not able to get single channel responses with Sandesha2. Because of this if you expect a response message, you must have a return endpoint accessible from the server side. But making two channel blocking invocations is perfectly valid. But make sure that you have set a suitable timeout interval in your options object.

Advance Client Scenarios

This section will introduce you to some Client API features which you may not use for general cases. These features will be useful if you have some knowledge in WSRM (Web service Reliable Messaging) and if you want to customize the default behavior of Sandesha2 to make it work according to your requirements. Some of these have to be done by simply setting a property in the 'Options' object which you set to your ServiceClient. For these you have to add the sandesha2-client-<VERSION>.jar to your classpath. For others, you have to use a special class called SandeshaClient, which is available in the Sandesha-<VERSION>.jar file. Both these comes with Sandesha2 distributions.

Getting Acknowledgements and Faults to a Given Endpoint

In the default configuration, response path for acknowledgements and faults related to a sequence is the anonymous endpoint. For example, HTTP transport will send acknowledgements and faults in the HTTP response of request messages. If you want to avoid this and if you want to get acknowledgements and faults to a different endpoint, add following part to the client code before doing any invocation. Note that this does not effect the path of your application level faults. Only RM faults which occur within the Sandesha2 will be sent to this endpoint.

clientOptions.setProperty(SandeshaClientConstants.AcksTo,<endpoint>); //example endpoint - http://tempuri.org/acks.

Managing Sequences

In the default behaviour Sandesha2 assumes that messages going to the same endpoint should go in the same RM sequence. Messages will be sent in different RM sequences only if their WS-Addressing To address is different. But if required you can instruct Sandesha2 to even send messages that have the same WS-Addressing To address in two or more sequences. To do this you have to set a property called Sequence Key.

clientOptions.setProperty(SandeshaClientConstants.SEQUENCE_KEY,<a string to identify the sequence>);

If the sequence key is different, Sandesha2 will send messages in two sequences even if they are sent to the same endpoint.

Offering a Sequence ID for the Response Sequence

This is a concept of reliable messaging which may not be very useful to you as a end user. Here what you do is offering a sequence ID for the sequence to be created in the response side within the Create Sequence Request message of the request path. If you provide this and if the Sandesha2 server accepts the offered sequence ID it can refrain from doing the Create Sequence message exchange in the response path. To do this, add the following to the client code.

clientOptions.setProperty(SandeshaClientConstants.OFFERED_SEQUENCE_ID,<new uuid>);

Creating a Sequence Without Sending any Messages

Sometimes you may need Sandesha2 client to start a sequence with a server without sending any real application messages. When you ask for this, Sandesha2 will do a Create Sequence message exchange and obtain a new sequence ID from the server. Later you can send application messages with this newly created sequence. A boolean parameter in this can also be used to tell whether to send an offer (Read the previous part on offering sequence IDs to learn more about this) . The line you have to add to your client code for doing these is as follows.

SandeshaClient.createSequence (ServiceClient serviceClient, booleanoffer);

There is another method which takes a third parameter, which is the Sequence Key (Read the previous part on Sequence Keys to learn more about this). So with this you can create two or more sequences which can be identified from different Sequence Keys.

SandeshaClient.createSequnce (ServiceClient serviceClient, boolean offer,
String sequenceKey);

Sending Acknowledgement Requests from the Client Code

You can ask the Sandesha2 to get an acknowledgement from a server with which it is maintaining a sequence. This may be useful in a case where your SequenceReports indicate that some of the messages you sent have not been acknowledged and when you want to verify that. You can do this by adding following line to the client code.

SandeshaClient.sendAckRequest (ServiceClient serviceClient);

You can use following method to send an acknowledgement request to a specific sequence identified by the Sequence Key.

SandeshaClient.sendAckRequest (ServiceClient serviceClient, String sequenceKey);

Selecting the Specification Version Which you Want to Work in

As it was explained earlier Sandesha2 supports two WSRM specifications. The default is the submitted WSRM specification. But if you want to change this and work in the new OASIS WSRM specification, set the following property in the Options object.

clientOptions.setProperty(SandeshaClient.RM_SPEC_VERSION,Sandesha2Constants.SPEC_VERSIONS.v1_1);

To go back to the WSRM submitted specification set the property as follows.

clientOptions.setProperty(SandeshaClient.RM_SPEC_VERSION,Sandesha2Constants.SPEC_VERSIONS.v1_0);

Terminating a Sequence from the Client Code

You can terminate an on going sequence at any time by adding the line given in this section to your client code. Remember that if you terminate a sequence some of your messages may not get delivered to the service. This is the recommended way for old WSRM submitted specification (the default). See the section 'Sequence Management of Sandesha2' for more details.

SandeshaClient.terminateSequence (ServiceClient serviceClient);

To terminate a specific sequence use following.

SandeshaClient.terminateSequence (ServiceClient serviceClient, String sequenceKey);

Closing a Sequence from the Client Code

You can close an ongoing sequence at any time by adding the line given in this section to your client code. Sequence close feature is only available for new WSRM specification being developed under OASIS. Remember that if you do not close elegantly, some of your messages may not get delivered to the service. Again, see the section on Sequence Management of Sandesha2 for more details. You can issue following command from your client code to close a sequence.

SandeshaClient.closeSequence (ServiceClient serviceClient);

To close a specific sequence use following.

SandeshaClient.closeSequence (ServiceClient serviceClient, String sequenceKey);

Blocking the Client Code until a Sequence is Complete

After your client code delivered some messages to the RM layer, you may have to wait for some time until the RM layer does its work. The time you have to block depends on your system performance and network latencies. It may be easier to ask the RM layer to block until its work is done by issuing one of the following commands in your client code.

SandeshaClient.waitUntilSequenceCompleted (ServiceClient serviceClient);

SandeshaClient.waitUntilSequenceCompleted (ServiceClient serviceClient, String sequenceKey);

You can also give the maximum number of seconds the RM Layer should block. The blocking will stop at the end of this maximum time even if the sequence is not terminated or not timed out. But note that internally RM is still working. So even though the blocking stops, RM layer will continue its work until you exit the program.

SandeshaClient.waitUntilSequenceCompleted (ServiceClient serviceClient, long maxWaitingTime);

SandeshaClient.waitUntilSequenceCompleted (ServiceClient serviceClient, long maxWaitingTime, String sequenceKey);

Sequence Management of Sandesha2

This section will explain you about the sequence managing method of Sandesha2. This is basically about four things, each explained in following sub topics.

Starting a New Sequence

Sandesha client gets two properties given by the client to decide the sequence in which it should send a particular application message. First one is the address of the WS-Addressing To endpoint reference. The second is a special constant given by the client called Sequence Key which is set as a property in the Options object as I explained before. Sandesha2 client generates a value called Internal Sequence ID by combining these two values. All messages having the same Internal Sequence ID will be sent in a single sequence, until that particular sequence is terminated.

Sequences that carry messages from the client to a server are called request sequences and ones that carry messages from the server to the client are called response sequences. Sandesha2 always keep a single response sequence corresponding to a particular request sequence.

Terminating a Sequence

There are currently two methods to terminate a particular sequence from the Client API. The first method is to set the Last Message property as it was explained earlier. After all the messages up to the last message get delivered reliably Sandesha2 will terminate that sequence. Remember that if you are working on the Submitted WSRM specification (the default), this is the only method you can use.

If you are working on the new WSRM specification (see previous section on Selecting the Specification Version if you want to know how to set this), these is an alternate method you can use to terminate a sequence. You can keep invoking the ServiceClient to send messages, without setting a Last Message property. After you finish your work call following function to terminate the sequence.

SandeshaClient.terminateSequence (ServiceClient);

You can use the function below to terminate a sequence identified by a particular Sequence Key.

SandeshaClient.terminateSequence (ServiceClient, SequenceKey);

When a request sequence is terminated, Sandesha2 will wait till all the response messages are reliably delivered to the client and after which will terminate the response sequence as well.

Closing a Sequence

New WSRM specification being developed under OASIS introduces a new feature called closing a sequence. When a sequence is closed the server will not except new application messages, but will accept RM control messages like acknowledgement requests. If you are writing your code for this specification you can use following functions to close the current sequence.

SandeshaClient.closeSequence (ServiceClient);

You can use the function below to close a sequence identified by a particular Sequence Key.

SandeshaClient.terminateSequence (ServiceClient,, SequenceKey);

Timing Out a Sequence

Depending on its policy configurations Sandesha2 may time out certain sequences. When a sequence is timed out, it is considered finalized and cannot be used any more. There are basically two ways a sequence can time out, and both can be configured using policies. See 'InactivityTimeout' and 'MaximumRetransmissionCount' parts of the 'Configuring Sandesha2' sub topic for more details.

Working with Sandesha Reports

Sandesha introduces a feature called Sandesha Reports with which you can get status information about the sequences managed by Sandesha2. There are basically two kinds of reports, each explained in following subtopics.

SandeshaReport

This gives information on all the incoming and outgoing sequences Sandesha2 system is managing. When we consider a particular endpoint, an incoming sequence is a sequence to which that endpoint is working as a RM-Destination (RMD). An outgoing sequence is a sequence to which this endpoint works as a RM-Source (RMS).

A SandeshaReport include following information:

To get a SandeshaReport at any time, invoke following method from your client code.

SandeshaClient.getSandeshaReport (ConfigurationContext c);

SequenceReport

A SequenceReport gives information on a specific sequences that a Sandesha system is working on. This can be an incoming sequence or an outgoing sequence.

A SequenceReport will give following information:

  1. Status of the sequence which can be one of the following.
  2. Sequence Direction
  3. Sequence ID of the sequence
  4. Internal sequence ID of the sequence.
  5. Number of completed messages of the sequence.

A messages is considered as completed when a RMS has successfully sent the message to the RMD and received an acknowledgement.

To get an incoming sequence report, you have to issue following command from your client code.

SandeshaClient.getIncomingSequenceReports (ConfigurationContext configCtx);

To get an outgoing Sequence Report you can invoke any of the following functions.

SandeshaClient.getOutgoingSequenceReport (ServiceClient serviceClient);
SandeshaClient.getOutgoingSequenceReport (String to,String sequenceKey,ConfigurationContext configurationContext);
SandeshaClient.getOutgoingSequenceReport (String internalSequenceID,ConfigurationContext configurationContext);

Sandesha Listener Feature

You can use this new feature to register a listener class in Sandesha2 and get notified when specific event happens in the system. The basic interface is given below.

public interface SandeshaListener {
    public void onError(AxisFault fault);
    public void onTimeOut(SequenceReport report);
}

You can implement this class and set an object of that type as a property in the Options object in your client code. An example is given below.

options.setProperty (SandeshaClientConstants.SANDESHA_LISTENER, new SandeshaListnerImpl ());

Currently SandeshaListener defines the following two methods- onError & onTimedOut.

onError

This will be invoked if Sandesha2 receives a fault SOAP message for one of the protocol messages it sent. The parameter will be an AxisFault representing that fault message. Remember that this will not be invoked for faults that occur due to application messages or any other messages that do not get originated from Sandesha2. They will not be considered by the Sandesha2 system as valid application messages.

onTimeOut

As mentioned in the earlier section Sequence Management of Sanesha2, there is a possibility of an inactive sequence timing out. When a specific sequence times out, this method of the SandeshaListener will be invoked giving a report of that sequence as a parameter.

Delivery Assurances of Sandesha2

As it was mentioned in the Architecture Guide, Sandesha2 provide an in-order exactly-once delivery assurance. In-order means that Sandesha2 will guarantee delivering of the messages to the Web service in the order of their message numbers. If you use a Sandesha2 client this will be the order you called the invocation methods of your service client. Exactly-once delivery assurance means that Sandesha2 will make sure that the service will be invoked only once for each message. As it was mentioned earlier Sandesha2 retransmits messages to obtain reliability. Due to the exactly-once delivery assurance you can be sure that your service gets invoked only once.

If you require the performance to be maximized and if you do not want ordering, you can configure Sandesha2 to invoke messages in the order they arrive. Read 'Configuring Sandesha2' section below to learn how to do this.

Configuring Sandesha2

Sandesha2 provides a set of configurations which you can use to customize its execution behavior. All these configurations are available in a WS-Policy format. These policies can be in the module.xml file of the Sandesha module or in the services.xml file of a service on which Sandesha2 module has been engaged. Most of the policies in the module.xml can be overridden by setting different values in a services.xml. But some policies cannot be overridden and must be set correctly in the module.xml file.

You will find each Sandesha2 policy and the way an alteration of it can effect Sandesha2. Make sure that you set these values carefully. Setting incompatible types or values may cause Sandesha system to malfunction. Normally if Sandesha2 can detect that the value you have set is incompatible, it will set a default value which is mentioned in the SandeshaConstants class.

AcknowledgementInterval

When a RMD receives an application message and when it has to send acknowledgements to an endpoint (other than the anonymous URL), it will not send this message immediately but will wait for some time to see whether there are any other messages (for example application response messages) going towards the destination of the acknowledgement message. If it finds any, the acknowledgement message is piggybacked in this second message and both are sent together. If the RMD does not find any messages that go towards the destination of the acknowledgement within a specific time interval, the acknowledgement is sent as a stand alone message. This time interval is called the acknowledgement interval and can be configured in Sandesha2 policies. The measurement unit is in milliseconds.

RetransmissionInterval

As it was mentioned earlier some messages in RM should be retransmitted until a proper response or acknowledgement is returned. After sending a message once, the RMS will wait for some time before sending it for the second time. This waiting time between the first and second retransmission attempts is given by this policy. If the policy given later called the ExponentialBackoff is set to false the time gap between all the retransmissions attempts will have the same value, which is the RetransmissionInterval. Measurement unit is in milliseconds.

ExponentialBackoff

Value of this can either be 'true' or 'false'. This measure is used to adjust the retransmission attempts so that an RMD does not get flooded with a large number of retransmitted messages. If this is 'true', a time gap between two retransmissions will be twice as the time gap between previous two retransmissions. For example, if the time gap between the fourth and fifth retransmission attempts is twenty seconds the time gap between the fifth and sixth attempts will be forty seconds. If this property is set to 'false', all retransmissions will have the same value, which is given by the 'RetransmissionInterval' property.

MaximumRetransmissionCount

This gives the maximum number of times a message has to be retransmitted. When a specific message gets retransmitted a maximum number of times, and is still not sent correctly to the RMD, it will not be sent again and the request will be marked as Timed Out. When a sequence is timed out, it cannot be used any more. If the value of this property is '-1' there is no limit in the number of retransmission attempts.

InactivityTimeout

A Sandesha2 RMS always keeps track of the last time a particular RMD responded to a request by it. If the RMD does not response within the time limit given by the time interval given by this measure, the RMS will give up attempting and will mark the sequence as Timed Out. After timing out the particular sequence, it cannot be used any more. If the value of this is -1, there is not inactivity timeout limit The measure of this is given by the property 'InactivityTimeoutMeasure'.

InactivityTimeoutMeasure

This gives the measure of the property 'InactivityTimeout'. The value of this can be seconds, minutes, hours or days. If you give a value that cannot be interpreted the default will be used.

InvokeInOrder

As it was mentioned earlier, Sandesha2 implement the in-order invoking delivery assurance. This property can be used to turn this on or off. The value of this has to be 'true' if in-order invoking has to be enabled. It has to be false if in-order invoking has to be disabled. Please remember that this is a non-overridable property. I.e. value you set in the module.xml is the one that is used for all the services and will not be overridden for a particular service by setting a different value there.

StorageManager

This gives the storage manager implementation class used by Sandesha2. You have to mention the full qualified class name here. Please read the Sandesha2 Architecture Guide for more details on creating your own storage manager. This is also a property that cannot be overridden, i.e., value you set in the module.xml is the one that is used for all the services and will not be overridden for a particular service by setting a different value there.

MessageTypesToDrop

This is a property that may not be very useful to an end user, but may be useful for some debug purposes. As it was mentioned earlier Sandesha2 gives a Message Type to each message it sends. For example, Create Sequence messages will have the type 1 and Acknowledgement messages will have the type 4. You can add a comma separated list of integers in the property telling Sandesha2 not to send messages of those types.