Monday, October 27, 2008

SAVAN: Behind the scene

It's highly recommended that you read my previous post before going any further with this one.

Let me summarize a bit, what we did there.

We deployed a sample application with Axis2/Savan to demonstrate WS-Eventing.

The sample application had three components.

1. Event source[axis2-savan-event-source] - a stock quote service publishes stock prices iteratively

2. Event sink[axis2-savan-event-sink] - a stock quote consumer subscribes to the stock quote service to receive events

3. [axis2-savan-client] - initiates subscription for the stock quote consumer

Let's get started.

If you go through the services.xml of StockQuoteService, you'll find that we expose no operations there.
<!-- src/META-INF/services.xml -->
<service name="StockQuoteService" scope="application">

<module ref="savan" />
<module ref="addressing" />

<parameter name="ServiceClass" locked="false">
org.apache.ws.axis2.StockQuoteService
</parameter>

</service>
See whether following surprises you. Hit http://localhost:8080/axis2/services/ on your browser and observe the operations available under StockQuoteService.

If it's not the services.xml which added those operations, who else could it be?

It's basically the 'Savan' module does that [Remember!!! services.xml engages savan module to the StockQuoteService].

In otherwords engaging savan module will seemlessly add three more operations to your service.

Let's get into more deeper.

Extract the savan-SNAPSHOT.mar file inside [AXIS2_HOME]\repository\modules [Remember!!! you were asked to read my previous post :).]

You'll find module.xml inside META-INF directory. Lets dig into the module.xml.
<module name="savan" class="org.apache.savan.module.SavanModule">

<operation name="SavanInOutOperation" mep="http://www.w3.org/2004/08/wsdl/in-out">
<messageReceiver class="org.apache.savan.messagereceiver.SavanInOutMessageReceiver"/>
<actionMapping>http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe</actionMapping>
<actionMapping>http://schemas.xmlsoap.org/ws/2004/08/eventing/Renew</actionMapping>
<actionMapping>http://schemas.xmlsoap.org/ws/2004/08/eventing/GetStatus</actionMapping>
<actionMapping>http://schemas.xmlsoap.org/ws/2004/08/eventing/Unsubscribe</actionMapping>
</operation>

<operation name="atom" mep="http://www.w3.org/2004/08/wsdl/in-out">
<messageReceiver class="org.apache.savan.atom.AtomMessageReceiver"/>
</operation>

<operation name="publish" mep="http://www.w3.org/2004/08/wsdl/in-out">
<messageReceiver class="org.apache.savan.messagereceiver.PublishingMessageReceiver"/>
<actionMapping>http://ws.apache.org/ws/2007/05/eventing-extended/Publish</actionMapping>
</operation>

</module>
Hold on a second. Lets cover bit of ground on Axis2.

One of the fundamental goals of SOAP processing frameworks is to deliver an incoming message to the targeted application.

The process of finding correct target application is known as 'dispatching'.

Let's have a look at the following section extracted from [AXIS2_HOME]\conf\axis2.xml.
<phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
<handler name="RequestURIBasedDispatcher"
class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
<handler name="SOAPActionBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
<handler name="RequestURIOperationDispatcher"
class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
<handler name="SOAPMessageBodyBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
<handler name="HTTPLocationBasedDispatcher"
class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
<handler name="GenericProviderDispatcher"
class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
<handler name="MustUnderstandValidationDispatcher"
class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
</phase>
You can see a set of handlers being configured to execute under the 'Dispatch' phase.

All the dispatchers first try to find the service with the information it has. They do this if the dispatchers invoked before it had not found a service.

If the service is already found, the findService method of the dispatcher will just pass through. Then it tries to find an operation within the service, if a service is found by then.

Again, the dispatcher will do this only if other dispatchers invoked prior to it had not found an operation. Likewise, all the dispatchers put a collaborative effort in doing this. This will enable one dispatcher to find a service and another dipatcher to later find the operation.

If you'd like to read more on how Axis2 finds the service with the corresponding operation, read this.

Lets configure the TCP monitor to track subscription message. This explains how you can configure TCP monitor.

Once configured and run the Client, you'll see the following SOAP request, for the subscription.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>http://localhost:8080/axis2/services/StockQuoteService</wsa:To>
<wsa:MessageID>urn:uuid:F873BC9C2A4F33B6961225131910519</wsa:MessageID>
<wsa:Action>http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe</wsa:Action>
</soapenv:Header>
<soapenv:Body>
<wse:Subscribe xmlns:wse="http://schemas.xmlsoap.org/ws/2004/08/eventing">
<wse:Delivery>
<wse:NotifyTo>
<wsa:Address xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
http://localhost:8080/axis2/services/StockQuoteConsumer
</wsa:Address>
</wse:NotifyTo>
</wse:Delivery>
</wse:Subscribe>
</soapenv:Body>
</soapenv:Envelope>
Once you look at the SOAP message and the extract from the axis2.xml which displays the set of available handlers for dispatching, you will not find a matching handler.

In this case, dispatching has to happen through WS-Addressing information.

So, once we engaged the 'addressing' module to the service, AddressingBasedDispatcher will be available for it during the "Addressing" phase.

With this, Axis2 will get to know, the message is destined to http://localhost:8080/axis2/services/StockQuoteService.

As I mentioned previously in this post, engaging savan module it self with the StockQuoteService has added three more operations to the service. Those three operations are defined in the savan module.xml - shown above.

You'll see that http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe is mapped to the operation "SavanInOutOperation" [in module.xml] - in that case org.apache.savan.messagereceiver.SavanInOutMessageReceiver will be invoked.

By going through the above, you will figure out that all Subscribe/Renew/GetStatus and Unsubscribe operations are handled by the org.apache.savan.messagereceiver.SavanInOutMessageReceiver. In other words, that is exactly what savan module does.

Once a request to Subscribe being received at the 'savan' module, it will create a SubscriberStore for the 'publishing' [event source] service and will add the required information regarding the 'receving'[event sink] service to it.

If you look at the following code from [axis2-savan-event-source]\org.apache.ws.axis2\StockQuoteService, you will notice that Line:1 will get the SubcriberStore for the corresponding service, in this case, for the StockQuoteService, and if it's not null, then will publish events.
store = CommonUtil.getSubscriberStore(serviceContext.getAxisService());

if (store != null)  {
data = getNextPublicationData();
publicationClient = new PublicationClient(serviceContext.getConfigurationContext());
publicationClient.sendPublication(data, serviceContext.getAxisService(),null);
}

1 comments:

Anonymous said...

Thanks very much for this review of how
Savan adds operations to an existing
service. It was both concise and informative.

On our project we are attempting to employ
both Savan, for its WS-Eventing capabilities,
and Rampart, for security.

I don't understand how I can effectively
advertise (in the service WSDL) and
enforce security policy for operations
that are not directly defined by the service,
for example "subscribe".
If I attach ws-policy at the level of a service,
it will cover the subscribe operation.
In our environment, though, I'd like to apply
more stringent security requirements on
subscribe than other operations.
Is there a way to do this?

Even more troublesome is the publiscation
operation. For this operation, then the
StockQuoteService acts as a client to each
of the subscribers, invoking the Publish
operation for each subscriber. How do I ensucre
that these invocations satisfy the ws-policy
associated with the Publish operation?
Each subscriber could have a different
ws-policy associated with this operation.
Since publication is handled for my service
indirectly by Savan (and does not itself
address these security issues),
I don't know what to do.

Any suggestions and/or references to other
information on how to integrate Savan and
Rampart would be greatly appreciated.