Axismora Architecture Guide

Contents

Introduction
Architecture Overview
Handlers
SOAP Deserializer
SOAP Serializer
Wrapper
Provider
Deployed Service Information Manager
Logger
Dynamic Class Loader
Exception


Introduction

This documentation explains the design of axis-Mora.



Architecture Overview

The basic axis architecture of Handler model has not changed in Axis-Mora.There is a request flow and a response flow and each of them has their own handlers.

1) The processing of the SOAP request can be described as follows. On the first call, the Axis engine is initialized. It reads the WSDD file, creates deployment object and initializes the HandlerPool. (The DOM is used to parsing at this level).
2) TransportListener listens the HTTP request and passes the service name using SOAP action. It also passes input stream and output stream to the Axis engine.
3) Axis engine creates MessageContext object (Which acts as a mediator that takes care of the interaction between the components). MessageContext parses the Envelope and Headers using DeserializationContext and stores it in itself (i.e. MessageContext). The body is parsed to the Wrapper. (The data is parsed only when they are needed. For this parsing we use XMLPullParser).
4) Request Handlers process the MessageContext . Handlers are supposed to deal with the Headers only. If they are using the body (e.g.:-encryption) they should write it back to the stream.
5) Then the provider (This is actually a minimal one, most of logic passed to the Wrapper) locates the wrapper and invokes the service. The result is set to the MessageContext as a result object.
6) Response Handlers process the MessageContext.
7) When the MessageContext comes back to the AxisEngine, engine calls the serialize() method to write the response back.


Axis Engine

There is one axis engine in the system. It has WSDDDeployment and HandlerPool objects. As all the requests are served as a call on the engine. The concurrency has been taken care of. Axis engine will call the handlers in the right order. In case of error SOAPFault is set and the Handlers invoked so far driven back on onFault().



Handlers

The Handler API functionally equivalent to the Axis1.1 Handler API. There are certain deviations due the architecture considerations. For more information please refer to Handler API document.



SOAP Deserializer

We are using the XMLPullParser for the deserialization.

Reasons for using XMLPUll

  1. With XMLPullParser, one can parse the data only when it is needed. Everything need not be kept in memory. (Low memory requirements).
  2. Parsing can be done even when the whole SOAP message is not yet available.
  3. XMLPull ideally supports our design. It allows the Wrapper (without storing all the SAXevents) to ask for what does it need. The main advantage is here. Wrapper of a web service knows what to expect next (i.e. whether to expect an int , String and etc … ). So it would be faster if we give the responsibility to the wrapper to deserialize the SOAP message rather than pre-deserializtion and storing it. This design decision is expected to increase performance speed and decrease memory requirements.
Since there are fundamental differences in deserialization we could not reuse the DeserializationContext. Therefore we wrote our own DeserializationContext.

How Does DeserializationContext work?

  1. The parser parses the Envelope and validate it. Then it creates a new org.apache.axis.message.SOAPEnvelope. (validating codes borrowed by existing architecture mostly.)
  2. It parses headers create the SOAPHeaderElement. The complex XML structures available in the SOAPHeader is stored in class called SOAPHeaderElementContent as a vector of org.w3c.Elelements. This is done based on a state diagram model.
  3. Then the body start tag is validated and (read the method if RPC) control is given to the Wrapper.
  4. Deserialization of the SOAP body is done upon the request by the wrapper.


SOAP Serializer

Serialization subsystem of axis has not been changed. Serialization of axis has been completely reused in axis-Mora. The serialization is done by the means of calling the output(SerializationContext) method of the SOAPEnvelope of axis. Serializing process can be briefly explained as below.

  1. Headers and Body are kept separately in MeassageContext.
  2. After processing is done AxisEngine calls the serialize() method in the MeassageContext.
  3. At this point (i.e. within the serialize() method ) SOAPHeaders and the SOAPBody are added to the envelope. Then the method output(SerializationContext)of SOAPEnvelope is called. This would cause the SOAPMessage to be written to the outputstream. We are simply reusing the axis serializationContext.

Note:- But you have to make sure the object value of the SOAPHeaderElement and SOAPBodyElement should be such that the SerializationContext can find serializers for the values at the type mapping.


In order to make the above method to work the following had to be taken care of.

Registering the Serializers can be done by adding the Seralizers which can serialize a instance of Result, and HeaderElementContent. The serializer is added to the default type mapping. Used value is enabled by adding to default type mapping and edit the DefaultTypeMappingImpl **this is used in the implementation **

Add the Serializer as a default type mapping

    TypeMappingRegistry reg = new TypeMappingRegistryImpl();
    javax.xml.rpc.encoding.TypeMapping t = 
	reg.getOrMakeTypeMapping("www.opensurce.lk/axismora/encoding"); 
    sc.getTypeMapping().register(Result.class,Constants.SOAP_RESULT,
	new ResultSerializerFactory(),null); 
    t.register(Parameter.class,Constants.SOAP_RESULT,new resultSerializerFactory(),null);



Wrapper

Before going on to the wrapper part let’s see what is the state of the request now. The request SOAP message is accessed up to the body level. The rest i.e. SOAP body will be accessed by the wrapper. The SOAP body is parsed into the wrapper class. Here wrapper deserializes the body, gets the parameters and calls the web service. When the web service returns the result, the wrapper sets it into the message data.

Wrapper Architecture

Consider a web service named Ws with a method name foo which returns a complex type X and accepts a complex type Y as an argument. Then there will be a wrapper class for the web service Ws named as WsService(For every service’s wrapper’s name will be the service name with the appended name “Service”).

Web service Wrapper

For the service named Ws the wrapper will be named WsService. This class extends the BasicHandler which have the method invoke( MessageContext msgcontext) . In fact BasicHandler implements the Handler API, which has one method - invoke(MessageContext msgcontext).


The methods in the wrapper ::

For each method in the web service wrapper contains a private method. This private method has the same method-name as the corresponding method of the webservice.

e.g.: In this case the private method wiil be "private foo(msgcontext)". This method will get the parameters for the actual method by deserializing the body and call the actual method with giving these parameters.

invoke(MessageContext msg)- This will be called by the AxisEngine, just like any other handler. Code inside the invoke method looks up the method name and it calls the private method that with the name ( refer the above diagram).

After calling the method, the returned result is set it in to the MessageContext.

Serializing and Deserializing the objects

Deserialization of the SOAPBody is done at the wrapper. Wrapper is written with the complete awareness of the web service. Hence after finding out the method name the wrapper knows what is there in the SOAPBody. For example in the above example when the wrapper finds out the method name is “foo” it knows that the SOAPBody contains the object of the complex type – X. Therefore the deserialize methods are called at the private method corresponding to the web service.Deserialization of simple types are in-built. For complex types the wrapper calls the method - deserialize(MessageContext msgData) of the complex type, i.e. each complex type object must have a method called deserialize(MessageContext msgData) where the deserialization occurs. After the deserialize(MessageContext msgData) method of the complex object is called values will be set to the complex type object.

Wrapper class then will call the actual web service method with parsing the expected parameters. Then the result will be set it to the MessageContext.


For example the private method in the wrapper corresponding to webservice ::


private foo(MessageContext msg){ 
    X . deserialize(msgdata) 
    Result r = ws.foo(x); 
    msgdata.setResult(r); 
} 

The serialization part of the result will be done by calling the serialize method of the particular complex type object. This calling is done by the AxisEngine , when it wants to serialize the particular result in the response soap body.

How to deserialize the body?

We have discussed so far that the wrapper and type objects are responsible for deserializing the body part of the SOAP Request. For doing it, MessageContext interface provides the following methods.


What happens when Error occurs?

If the error occurs at the wrapper level then the SOAPFault is set in to the MessageContext and wrapper discard the accessing.

Built-in Classes

Here we have built in type classes for eight simple types and String classes.

Wrapper Generator tool

We provide a wrapper generator tool for creating the wrapper classes, type classes and web services. This is done by reading the wsdl file. So the burden of the deserialization and serialization is taken care of generator.

Advantages and the Features of the wrapper concept.

Major advantage of the wrapper is, we throw away the reflexion part of the axis and instead of it we uses the wrapper concept. So it gives up the runtime mapping ,the performance is remarkable compare to the axis.



Provider

All the types’ providers are treats equally by the architecture. The wrapper will take care of actual behavior. E.g. to have EJB deployed it should we wrapped by the Wrapper in suitable scope.

Deployed Service Information Manager

This is the logically the same as in the existing architecture. The WSDDDeployment class is rewritten using the logics of the existing WSDDDeployment as to match with the expected interfaces.

Logger

The logger form apache commons-logging.jar is being used.

Dynamic Class Loader

Class.forname() we are there. Loading the classes are done by the Handler Pool not in the org.apache.axis.deployement.wsdd.

Exception

Use the AxisFault for wrap the exception.