blob: 4add9dc542be31b549d79dcb086e8b27df2a869e [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- Generated by Apache Maven Doxia Site Renderer 1.3 at May 4, 2013 -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Sandesha2 -
Sandesha2 Architecture guide</title>
<style type="text/css" media="all">
@import url("./css/maven-base.css");
@import url("./css/maven-theme.css");
@import url("./css/site.css");
</style>
<link rel="stylesheet" href="./css/print.css" type="text/css" media="print" />
<meta name="Date-Revision-yyyymmdd" content="20130504" />
<meta http-equiv="Content-Language" content="en" />
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /><meta name="generator" content="amaya 9.2.1, see http://www.w3.org/Amaya/" />
</head>
<body class="composite">
<div id="banner">
<a href="http://www.apache.org/" id="bannerLeft">
<img src="http://www.apache.org/images/asf-logo.gif" alt="Apache Software Foundation" />
</a>
<a href="index.html" id="bannerRight">
<img src="images/Sandesha.jpg" alt="Sandesha" />
</a>
<div class="clear">
<hr/>
</div>
</div>
<div id="breadcrumbs">
<div class="xleft">
<span id="publishDate">Last Published: 2013-05-04</span>
&nbsp;| <span id="projectVersion">Version: 1.6.3-SNAPSHOT</span>
</div>
<div class="xright"> <a href="../core/" title="Axis2">Axis2</a>
|
<a href="http://www.apache.org" class="externalLink" title="Apache">Apache</a>
</div>
<div class="clear">
<hr/>
</div>
</div>
<div id="leftColumn">
<div id="navcolumn">
<h5>Apache Sandesha2</h5>
<ul>
<li class="none">
<a href="index.html" title="Home">Home</a>
</li>
<li class="expanded">
<a href="javascript:void(0)" title="Downloads">Downloads</a>
<ul>
<li class="none">
<a href="download.cgi" title="Releases">Releases</a>
</li>
<li class="none">
<a href="http://svn.apache.org/repos/asf/axis/axis2/java/sandesha/trunk" class="externalLink" title="Source Code">Source Code</a>
</li>
</ul>
</li>
<li class="expanded">
<a href="javascript:void(0)" title="Documentation">Documentation</a>
<ul>
<li class="none">
<a href="userGuide.html" title="User Guide">User Guide</a>
</li>
<li class="none">
<strong>Architecture Guide</strong>
</li>
<li class="none">
<a href="apidocs/index.html" title="Java Docs">Java Docs</a>
</li>
</ul>
</li>
<li class="expanded">
<a href="javascript:void(0)" title="Project Information">Project Information</a>
<ul>
<li class="none">
<a href="mail-lists.html" title="Mailing Lists">Mailing Lists</a>
</li>
<li class="none">
<a href="team-list.html" title="Project Team">Project Team</a>
</li>
<li class="none">
<a href="issue-tracking.html" title="Issue Tracking">Issue Tracking</a>
</li>
<li class="none">
<a href="source-repository.html" title="Source Repository">Source Repository</a>
</li>
</ul>
</li>
<li class="none">
<a href="http://www.apache.org/licenses/" class="externalLink" title="License">License</a>
</li>
<li class="none">
<a href="http://www.apache.org/foundation/sponsorship.html" class="externalLink" title="Sponsorship">Sponsorship</a>
</li>
<li class="none">
<a href="http://www.apache.org/foundation/thanks.html" class="externalLink" title="Thanks">Thanks</a>
</li>
<li class="none">
<a href="http://www.apache.org/security/" class="externalLink" title="Security">Security</a>
</li>
</ul>
<a href="http://maven.apache.org/" title="Built by Maven" class="poweredBy">
<img class="poweredBy" alt="Built by Maven" src="./images/logos/maven-feather.png" />
</a>
</div>
</div>
<div id="bodyColumn">
<div id="contentBox">
<!-- Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License. --><html>
<h1>Apache Sandesha2 Architecture Guide</h1>
<div class="section"><h2>Content<a name="Content"></a></h2>
<ul>
<li><a href="#intro">Introduction</a></li>
<li><a href="#architecture">Architecture</a>
<ul>
<li><a href="#hnd">Handlers</a>
<ul>
<li><a href="#globalin">SandeshaGlobalInHandler</a></li>
<li><a href="#in">SandeshaInHandler</a></li>
<li><a href="#out">SandeshaOutHandler</a></li>
</ul></li>
<li><a href="#rmm">RMMessageReceiver</a></li>
<li><a href="#sender">Sender</a></li>
<li><a href="#ioi">Inorder Invoker</a></li>
<li>Polling Manager</li>
<li><a href="#sf">Storage Framework</a></li>
</ul></li>
<li><a href="#da">Delivery Assurances</a></li>
<li><a href="#config">Configuring Sandesha</a></li>
<li><a href="#es">Example Scenarios</a>
<ul>
<li><a href="#cs">Client Side</a></li>
<li><a href="#ss">Server Side</a></li>
</ul>
</li>
</ul>
<a name="intro"></a>
<div class="section"><h2>Introduction<a name="Introduction"></a></h2>
<p>Sandesha2 gives reliable messaging capabilities to
Axis2. From the point of view of the Axis2 engine, Sandesha2 is a module. When
this module is engaged to a service, clients have the option of invoking it in a
reliable manner. In the client side Sandesha2 module can be used to interact
with existing reliable Web services.</p>
<p>According to the Web service-ReliableMessaging (WS-RM)
specification which is implemented by Sandesha2, reliable communication happens
between two endpoints. These endpoints are called the RM Source (RMS) and the RM
Destination (RMD). Before communication, RMS and RMD perform a message exchange
to create a relationship called a Sequence between them. A Sequence is always
identified by a unique Sequence Identifier.</p>
<p>Each message of a sequence is numbered, starting from one. In
Sandesha2 the maximum number of messages a sequence can support is 2 <sup>64</sup>
(size of <i>long</i>
data type). Of course practically this may be limited by the memory available
for your system . The message number is used by the destination to support
additional delivery assurances. This will be explained later in this tutorial.</p>
<p>The reliability is obtained basically using
acknowledgements. RMS is required to send each message one or more times to the
RMD. RMD sends back acknowledgements to notify the successful reception of
messages. After receiving an acknowledgement for a certain message RMS can stop
the retransmission of that message.</p>
<p>When all messages of a certain sequence have been
successfully transmitted to RMD, RMS sends a TerminateSequence message. If RMD
receives this message it can free any resources allocated for this sequence.
Otherwise resource de-allocation will happen based on a timeout.</p>
<p><b>Following diagram explains operation of the RMS
and the RMD</b>.</p>
<p><img src="images/RMModel.jpg" alt="WS-RM Model" />
Sandesha2 supports two reliable messaging specifications. It
fully supports the WS-ReliableMessaging February 2005 specification and
February 2007 specification which was created by collaborative efforts
of several companies. </p>
<a name="architecture"></a>
<div class="section"><h2>Architecture<a name="Architecture"></a></h2>
<img src="images/architecture.jpg" alt="Architecture" />
<p>Sandesha2 components are used in a completely symmetric
manner, in the server side and client as shown in the diagram above. Lets just
consider a single side for this discussion.
<a name="hnd"></a></p>
<div class="section"><h3>Handlers<a name="Handlers"></a></h3>
<p>Sandesha2 adds three handlers to the execution chain of
Axis2. Two of these handlers are added to a special user phase called 'RMPhase'
of in and out flows. The other handler is added to the predispatch phase of the
inFlow. These handlers and their functions are given below.</p>
<img src="images/handlers.jpg" alt="Storage" />
<a name="globalin"></a>
<div class="section"><h4>SandeshaGlobalInHandler<a name="SandeshaGlobalInHandler"></a></h4>
<p>This handler is added to the predispatch phase of the
inFlow. Since this is a global phase, this handler will be called for each and
every message that comes to the Axis2 system. To maximize performance, the very
first function of this handler is to identify whether the current message can be
processed by it. It checks whether the message is intended for a RM enabled
service, and if so, check the message type to further verify whether it should
be processed globally. This handler was placed to perform functions that should
be done before the instance dispatching level of Axis2.</p>
<p><b>Some of these functions are given below:</b></p>
<ul>
<li>Detecting duplicate messages.</li>
<li>Detecting faults that occur due to RM control messages and
reporting them.</li>
</ul>
<a name="in"></a>
</div><div class="section"><h4>SandeshaInHandler<a name="SandeshaInHandler"></a></h4>
<p>This is added to the RMPhase of the inFlow. Since
RMPhase is a user phase, this handler will only be invoked for messages that are
aimed at RM enabled service. This handler processes the SOAP header of the
message. Acknowledgement headers, Acknowledgement requests and sequence
processing headers are processed by this handler. Sandesha2 has a special set of
classes called message processors which are capable of processing each type of
message. Depending on the type, the message is send through the
'processInMessage' method of the message processor which will do the further
processing of it.</p>
<a name="out"></a>
</div><div class="section"><h4>SandeshaOutHandler<a name="SandeshaOutHandler"></a></h4>
<p>This handler is responsible for doing the basic outFlow
processing. This will first generate an ID called the Internal Sequence ID which
is used to identify the sequence this message should belongs to. All the
messages having the same Internal Sequence ID will be sent within a single
sequence. An Internal Sequence ID will have a corresponding Sequence ID which
would be obtained after the Create Sequence message exchange. In the client side
the Internal Sequence ID is the combination of the wsa:To address and a special
value given by the client called Sequence Key. In the server side the Internal
Sequence ID is a derivation of the Sequence ID value of the messages of the
incoming sequence.</p>
<p>Before sending the message through other handlers the
SandeshaOutHandler will send it through the 'processOutMessage' method of the
respective message processor.</p>
<a name="rmm"></a>
</div><div class="section"><h4>RMMessageReceiver<a name="RMMessageReceiver"></a></h4>
<p>All the Reliable messaging operations
(CreateSequence/CloseSequence etc) have the RMMessageReceiver as the ultimate
receiver for the message. The RMMessageReceiver will identify the type of RM
control message. Sandesha2 has a special set of classes called message
processors which are capable of processing each type of message. Depending on
the type, the message is send through the 'processInMessage' method of the
message processor which will do the further processing of it.</p>
<a name="sender"></a>
</div></div><div class="section"><h3>Sender<a name="Sender"></a></h3>
<p>Sender is responsible for transmission and retransmission of
messages. The Sender is a separate thread that keeps running all the
time. At each iteration Sender checks whether there is any messages to
be sent. If there is any, it is sent to the destination. Sender also
identifies messages that has to be retransmitted and keep re-sending
them until a maximum limit decided by <a href="userGuide.html#cs" target="_blank">Sandesha2 policies</a> is exceeded.</p>
<a name="ioi"></a>
</div><div class="section"><h3>In Order Invoker<a name="In_Order_Invoker"></a></h3>
<p>InOrderInvoker is another separate thread that is
started by the Sandesha2 system. This is started only if Sadesha2 has been
configured to support in-order delivery assurance. InOrderInvoker makes sure
that it invokes messages of a sequence only in the order of message numbers.
<a name="sf"></a></p>
</div><div class="section"><h3>Storage Framework<a name="Storage_Framework"></a></h3>
<p>Sandesha2 storage framework is one of the most important
parts of the Sandesha2 system. This was designed to support the RM message
exchange while being independent of the storage implementation used. The storage
framework defines a set of interfaces and abstract classes that can be
implemented by a particular storage implementation. Sandesha2 system comes with
an in-memory storage implementation. There can be other implementations based on
different databases and persistence mechanisms.</p>
<p><b>Following diagram gives a brief view of the
Sandesha2 storage framework.</b></p>
<img src="images/storage.jpg" alt="Storage" />
<a name="RMbeans"></a>
<p>Storage framework defines several beans that extend the
RMBean abstract class. They are given below:</p>
<ol style="list-style-type: decimal">
<li>RMSBean (fields - internalSequenceID, createSeqMsgID,
sequenceID, createSequenceMsgStoreKey, referenceMessageStoreKey,
securityTokenData, clientCompletedMessages, toEPR, soapVersion, replyToEPR,
rMVersion, acksToEPR, terminated, serviceName, pollingMode)</li>
<li>SenderBean (fields - messageContextRefKey,
internalSequenceID, messageNumber, messageID, messageType, send, resend,
sentCount,timeToSend)</li>
<li>RMDBean (fields - sequenceID, nextMsgToProcess,
pollingMode, referenceMessageKey, toEPR, replyToEPR, rMVersion, acksToEPR,
terminated, serviceName, pollingMode)</li>
<li>InvokerBean (fields - invoked,messageContextRefKey,
sequenceID, msgNo)</li>
</ol>
<p>There are four bean manager interfaces corresponding to
each of above beans.They are as follows:</p>
<ol style="list-style-type: decimal">
<li>RMSBeanMgr</li>
<li>InvokerBeanMgr</li>
<li>RMDBeanMgr</li>
<li>SenderBeanMgr</li>
</ol>
<p>Sandesha2 also defines a StorageManager interface that
defines methods to create each of these bean managers and to create a
Transaction object which should implement the Transaction interface. Transaction
interface defines commit and rollback methods. The StorageManager interface is
also responsible for storing, updating, retrieving and deleting of
MessageContext instances for a sequence.</p>
<p>Collectively each Sandesha2 storage implementation
should have following classes:</p>
<ol style="list-style-type: decimal">
<li>An implementation of the StorageManager interface.</li>
<li>Implementations of the four Bean Manager interfaces.</li>
<li>An implementation of the Transaction interface.</li>
</ol>
<p>These classes can be packed as a jar archive and added
to the classpath. The name of the StorageManager implementation class must be
mentioned in Sandesha2 policy configurations. This will be picked up after a
restart of the the Axis2 engine.<br /><br /><b><font size="4">InMemory
Implementation<br /></font></b><br />As discussed, Sandesha ships with an
InMemory implementation of the storage manager. Perhaps the most significant
point of interest in this implementation is the transaction model. Transactions
are scoped by thread: a transaction can only be associated with one thread ever
and a thread can only have one transaction active at any single point in time.
Any storage manager beans touched by the transaction will be enlisted into the
transaction in such a way that any other transactions that attempt to touch the
beans will block until the enlisting transaction completes (either commits or
rollsback).</p>
<a name="da"></a>
</div><div class="section"><h2>Delivery Assurances<a name="Delivery_Assurances"></a></h2>
<p>Sandesha2 can provide an in-order exactly-once delivery
assurance. The ordering (in-order) is optional. You can disable it using
Sandesha2 policy configurations. The ordering is done using the <a href="#ioi">InOrderInvoker thread</a> that was
introduced earlier.</p>
<p><b>If ordering (in-order) is enabled</b>, SandeshaInHandler pauses the execution of an incoming
application message. As a result of this, the message will not go through rest
of the handler chain in the first invocation. Note that it also starts the
InOrderInvoker thread if it is stopped. This thread goes through the paused
messages and resume each of them in the order of message numbers.</p>
<p><b>If in-order invocation is not enabled</b> the SandeshaInHandler will not pause the messages and they
will go in their full execution path in one go.</p>
<p>The delivery assurance to be used depends on your
requirements. If you want the invocation to be as fast as possible, and you do
not care about ordering, disable in order invocation. But if you want message to
be invoked in the order they were sent by the client, you have to enable it.
There could be a considerable performance improvements if this feature is
disabled. Specially if majority of the messages come out of order. In the
current implementation, each message (identified by sequenceID and message
number) will be invoked only once. So exactly once delivery assurance is
guaranteed. You cannot ask Sandesha2 to invoke the same message more than
once.<br /><br /><font size="5"><b>Configuring
Sandesha</b></font><br /><br /><a name="config"></a>Sandesha is configured using various means, and
this configuration is made accesible in the SandeshaPolicyBean object, which is
stored in the AxisDescription as a property at module init time. The
configuration data can be loaded by examing the policies in the sandesha
module.xml, from default values (if there is nothing in the module.xml) or from
property files if explicitly driven by client code.<br />Some of the possible
options to configure are: <b>AcknowledgementInterval:</b> time between
sending acknowledgements<br /><b>RetransmissionInterval:</b> time
between retransmitting messages<br /><b>MaximumRetransmissionCount:</b>
max count to retry sending unacknowledged
messages<br /><b>ExponentialBackoff:</b> if true the time between
message retransmission attempts will grow
exponentially.<br /><b>InactivityTimeout:</b> time that the sequence is
allowed to remain inactive before it is cleaned
up.<br /><b>SequenceRemovalTimeout:</b> time to wait after a sequence is
terminated before removing the sequence state from the
store.<br /><b>InvokeInOrder:</b> if true messages will only be
delivered to the webservice endpoint in the exact order they were sent by the
RMS.<br /><b>MessageTypesToDrop:</b> the set of message types (stored by
number, see Sandesha2Constants.MessageTypes) that are elligible to drop by the
RMS.<br /><b>StorageManager:InMemoryStorageManager:</b> the classname to
use for the volatile
storagemanager<br /><b>StorageManager:PermanentStorageManager:</b> the
classname to use for the non-volatile
storagemanager<br /><b>SecurityManager:</b> the class to use in order to
process any WS-Security tokens associated with a sequence. A NO-OP
implementation is shipped with Sandesha.<br /><b>ContextManager:</b> the
class to use to ensure the inOrderInvoker thread uses a specific context. A
NO-OP implementation is shipped with Sandesha.<br /><b>EPRDecorator:</b>
the class to use in order to augment any endpoint references with any extra
information required. A NO-OP implementation is shipped with
Sandesha.<br /><b>MakeConnection:Enabled:</b> if true, makeConnection
messages will be used when sandesha is performing synchronous
messaging.<br /><b>MakeConnection:UseRMAnonURI:</b> if true,
makeConnection messages used for synchronous messaging will use the RM anonymous
URI.<br /><b>MakeConnection:UseMessageSerialization:</b> if true
messages are serialized into binary when sbeing stored in the
storageManager.<br /><b>EnforceRM:</b> if true any non-RM messages
recieved by the RMD will cause an exception to be shown.<br /></p>
<a name="es"></a>
<div class="section"><h2>Example Scenario<a name="Example_Scenario"></a></h2>
<p>This part explains how Sandesha2 framework works internally for
the most common RM scenario, which is the sending of a couple of Ping
messages from a client to the server. We will mainly look at how
Sandesha2 uses its storage to do the RM message exchange correctly.
While going through the following, keep the <a href="#RMbeans">RM
Beans and their fields</a> which were mentioned
earlier, in mind.</p>
<a name="cs"></a>
<div class="section"><h3>Client Side<a name="Client_Side"></a></h3>
<ul>
<li>Client does the first fireAndForget method invocation
of a serviceClient after setting necessary properties.</li>
<li>Message reaches the SandeshaOutHandler which detects
it as an application message. The processing is delegated to the
processOutMessage method of the Application Message Processor.</li>
<li>Application Message Processor generates the Internal
Sequence ID as explained earlier. It understands that this is a new sequence
and generates a Create Sequence Message for it. The Application Message gets
paused.</li>
<li>Application Message Processor adds an entry to the
RMS bean manager representing the newly created Create Sequence message. This
entry has three properties. The sequenceID property is initially null. The
createSeqMsgID is the message ID of the created CreateSequence message. The
internalSequenceID property gets the generated Internal Sequence ID value.</li>
<li>Application Message Processor adds two entries to the
SenderBeanManager. One which has the send property to 'false' represents the
application message, other which has the send property to 'true' represents
the CreateSequence message. The Sender thread sends (and retransmits) only the
CreateSequence message.</li>
<li>Application Message Processor stores three
MessageContext instances inside the StoreManager. The first is the
CreateSequence message, the second a &quot;reference message&quot;, which is a copy of
the CreateSequence message. The third is the application message.</li>
<li>After some time the client side would receive a
Create Sequence Response message from the server. The SandeshaInHandler
delegates the processing to the CreateSequenceResponse message processor. It
finds the correct CreateSequence manager entry using the
createSequenceMessageID property (which is in the relatesTo entry of the
response message).</li>
<li>Client updates the sequenceID property of the RMS
bean manager entry. Also the send value of the application message entries are
set to 'true'. The sender starts transmitting and retransmitting application
messages.</li>
<li>When the client receives acknowledgements for the
messages it send, they are delivered to the Acknowledgement Processor which
removes the corresponding application message entries from the Sender bean
manager.</li>
<li>If an acknowledgement says that all the sent messages (up to
last message) was successfully received, the Acknowledgement Processor
creates a Terminate Sequence message and adds a corresponding entry to
the Sender bean manager.</li>
</ul>
<a name="ss"></a>
</div><div class="section"><h3>Server Side<a name="Server_Side"></a></h3>
<ul>
<li>Server receives a CreateSequence message. It
generates a new sequence ID and creates a new Create Sequence Response message
containing this ID.</li>
<li>CreateSequence message processor processInMessage
creates an RMD bean representing the server side of the sequence. The sequence
identifier for this sequence is stored in the RMD bean and the bean is added
to the RMD bean manager. The initial value for nextMsgNoToProcess property is
1.</li>
<li>The CreateSequence message processor starts the
&quot;worker&quot; threads for the sequence. This includes the Sender thread for
response messages and the Invoker thread if the StorageManager returns one.</li>
<li>The CreateSequenceResponse message is created and
sent immediately by the CreateSequence message processor.</li>
<li>After some time the server receives an application
message. The SandeshaGlobalInHandler retrieves the RMD bean which matches the
inbound sequence. A check is made to ensure this is not a duplicate message
before processing is allowed to continue.</li>
<li>The server side SandeshaInHandler delegates this to the
RMMessageReceiver which creates an acknowledgement message and sends
it. If in-order invocation is enabled, an entry is added to the
InvokerBeanManager representing this new application message.
<p><i>Lets assume that the message number of this message is
2.</i></p></li>
<li>The InOrderInvoker which keeps looking at the
InvokerBeanManager entries sees that there are entries to be invoked.</li>
<li>The InOrderInvoker checks the entry of the RMDBean
manager of the relevant sequence and sees that it is 1. But since only message
number 2 is present in the invokerBeanManager entries, the invocation is not
done.</li>
<li>After some time, application message 1 also comes.
Now the Invoker sees this entry and invokes the message. It also updates the
nextMsgNoToProcess property of RMD Bean to 2. The Invoker again checks whether
the new entry for the nextMsgNoToProcess (2) is present in the
InvokerBeanManager entries. Since this is present it is also invoked. The
value is again updated (to 3) but no invocation is done since an entry is not
found.</li>
<li>Some time later the server may receive a TerminateSequence
message. It can partly remove the resources allocated for the sequence.
The other part of resources (which is required by the InOrderInvoker)
is removed after the invocation of the last message.</li>
</ul>
</div>
</html>
</div>
</div>
<div class="clear">
<hr/>
</div>
<div id="footer">
<div class="xright">
Copyright &#169; 2005-2013
<a href="http://www.apache.org/">The Apache Software Foundation</a>.
All Rights Reserved.
</div>
<div class="clear">
<hr/>
</div>
</div>
</body>
</html>