| <?xml version="1.0" encoding="iso-8859-1"?> |
| <!-- |
| 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. |
| --> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
| "http://www.w3.org/TR/html4/loose.dtd">
|
| <html>
|
| <head>
|
| <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/>
|
| <title>Sandesha2 Architecture guide</title>
|
| <meta name="generator" content="amaya 9.2.1, see http://www.w3.org/Amaya/"/>
|
| </head>
|
|
|
| <body lang="en">
|
| <h1>Apache Sandesha2 Architecture Guide</h1>
|
|
|
| <h2>Content</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>
|
|
|
| <h2>Introduction</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 <em>long</em>
|
| 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><strong>Following diagram explains operation of the RMS
|
| and the RMD</strong>.</p>
|
|
|
| <p><img alt="WS-RM Model" src="images/RMModel.jpg"/>
|
| <a>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. </a></p>
|
| <a name="architecture"></a>
|
|
|
| <h2>Architecture</h2>
|
|
|
| <img alt="Architecture" src="images/architecture.jpg"/>
|
|
|
| <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>
|
|
|
| <h3>Handlers</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 alt="Storage" src="images/handlers.jpg"/>
|
|
|
| <a name="globalin"></a>
|
|
|
| <h4>SandeshaGlobalInHandler</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><strong>Some of these functions are given below:</strong></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>
|
|
|
| <h4>SandeshaInHandler</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>
|
|
|
| <h4>SandeshaOutHandler</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>
|
|
|
| <h4>RMMessageReceiver</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>
|
|
|
| <h3>Sender</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>
|
|
|
| <h3>In Order Invoker</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>
|
|
|
| <h3>Storage Framework</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><strong>Following diagram gives a brief view of the
|
| Sandesha2 storage framework.</strong></p>
|
|
|
| <img alt="Storage" src="images/storage.jpg"/>
|
| <a name="RMbeans"></a>
|
|
|
| <p>Storage framework defines several beans that extend the
|
| RMBean abstract class. They are given below:</p>
|
| <ol>
|
| <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>
|
| <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>
|
| <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/><strong><font size="4">InMemory
|
| Implementation<br/></font></strong><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>
|
|
|
| <h2>Delivery Assurances</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><strong>If ordering (in-order) is enabled</strong>, 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><strong>If in-order invocation is not enabled</strong> 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"><strong>Configuring
|
| Sandesha</strong></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: <strong>AcknowledgementInterval:</strong> time between
|
| sending acknowledgements<br/><strong>RetransmissionInterval:</strong> time
|
| between retransmitting messages<br/><strong>MaximumRetransmissionCount:</strong>
|
| max count to retry sending unacknowledged
|
| messages<br/><strong>ExponentialBackoff:</strong> if true the time between
|
| message retransmission attempts will grow
|
| exponentially.<br/><strong>InactivityTimeout:</strong> time that the sequence is
|
| allowed to remain inactive before it is cleaned
|
| up.<br/><strong>SequenceRemovalTimeout:</strong> time to wait after a sequence is
|
| terminated before removing the sequence state from the
|
| store.<br/><strong>InvokeInOrder:</strong> if true messages will only be
|
| delivered to the webservice endpoint in the exact order they were sent by the
|
| RMS.<br/><strong>MessageTypesToDrop:</strong> the set of message types (stored by
|
| number, see Sandesha2Constants.MessageTypes) that are elligible to drop by the
|
| RMS.<br/><strong>StorageManager:InMemoryStorageManager:</strong> the classname to
|
| use for the volatile
|
| storagemanager<br/><strong>StorageManager:PermanentStorageManager:</strong> the
|
| classname to use for the non-volatile
|
| storagemanager<br/><strong>SecurityManager:</strong> 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/><strong>ContextManager:</strong> the
|
| class to use to ensure the inOrderInvoker thread uses a specific context. A
|
| NO-OP implementation is shipped with Sandesha.<br/><strong>EPRDecorator:</strong>
|
| 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/><strong>MakeConnection:Enabled:</strong> if true, makeConnection
|
| messages will be used when sandesha is performing synchronous
|
| messaging.<br/><strong>MakeConnection:UseRMAnonURI:</strong> if true,
|
| makeConnection messages used for synchronous messaging will use the RM anonymous
|
| URI.<br/><strong>MakeConnection:UseMessageSerialization:</strong> if true
|
| messages are serialized into binary when sbeing stored in the
|
| storageManager.<br/><strong>EnforceRM:</strong> if true any non-RM messages
|
| recieved by the RMD will cause an exception to be shown.<br/></p>
|
| <a name="es"></a>
|
| <h2>Example Scenario</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>
|
|
|
| <h3>Client Side</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 "reference message", 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>
|
|
|
| <h3>Server Side</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
|
| "worker" 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><em>Lets assume that the message number of this message is
|
| 2.</em></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>
|
| </body>
|
| </html>
|