JavaAxis2 Execution Framework

Axis2 Execution Framework

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Web services have become highly demanding and a large number of players have entered the Web service arena. Axis2 is the latest solution by Apache solutions to the Web service stack, which addresses some of the drawbacks of the Axis 1.x family and introduces some new concepts into the Web service stack. Axis2 is a highly flexible, easily configurable, highly reliable SOAP processing engine. One of the main advantages gained from Axis2 is the dynamic handler chain; although the notion of handler chain remains as in Axis 1.x, the underlying architecture is quite different.


Introduction


Axis2 is shaped by the experience from the Axis 1.x family and the advancements in the Web service stack during the last few years. Axis2 developers take conscious effort to make sure that Axis2 performs better in terms of speed and memory despite the fact that new features and functionalities are added. Among all those features and functionalities, the dynamic nature of the handler chain (Execution chain) is considerably important. The article published by Web service experts in Indiana University (Beytullah Yiliz, Shrideep Pallickara, and Geoffery Fox) on the topic of “Deployment Problems in Axis and Suggestions” has suggested that the requirement of dynamically configurable handler chain in Axis is as follows:


“In Axis, handlers are currently statically configured—the configuration being made when a service is being deployed. A handler cannot be added or removed from a service. Currently, Axis architecture allows cloning the handler chain. The cloned chain can replace a current one after required changes are applied. But this is not sufficient. Dynamic configuration of handler chains will be very useful. A deployment may have lots of handlers, but a user/handler should be able to select a group of handlers that a message would need to go through.”

In Axis2, the handler chain is easily configurable and has the ability of changing dynamically, the capability achieved through so-called phases, phase rules, and module engagement.


Handlers


If you have ever used any version of Axis, you should be familiar with the term “Handler,” the Apache terminology given for the “message interceptors” in any messaging system. Interceptor has its factual meaning in the context of messaging too, which intercepts the messaging flow and does whatever task it is assigned to do. In fact, an interceptor is the smallest execution unit in a messaging system so that, as the interceptor in Axis, handler does the same thing.


Handlers in Axis are stateless, meaning they keep their pass execution states in memory. A handler can be considered as a logic invoker with the input for the logic evaluation taken only from the MessageContext (MC). Handler has both read and writes access to MC.


Note: MessageContext can be seen as a property bag that keeps incoming or outgoing messages and other (maybe both) required parameters and properties to carry the message through the execution chain. On the other hand, via the MC one can access the whole system, such as global parameters, properties, and so forth.

Most of the time ( 99% of the time) handlers only touch the header block part of the SOAP message, which will either read a header (or headers), add a header(s) or remove a header(s). In the reading, if a header is targeted to a handler and if it cannot execute properly (message might be faulty) then it should throw an exception, and next chain driver (in Axis2 it is engine) would take necessary action depending on the flow, and phase.



Any handler in a chain has the capability to pause the message execution, meaning that the handler can stop the message flow if it cannot continue. Reliable messaging (RM) is a good example or the use case for that scenario that needs to pause the flow depending on some pre- and post conditions. In the case of RM, it works on the message sequence. If a service invocation consists of more than one message, and if the second one comes before the first, the RM handler will stop (rather pause) the execution of message invocation corresponding to the second message until it gets the first message. And, when it gets the first message, it will invoke that, and then, after, that will invoke the second message.


Writing a simple handler


Writing a handler in Axis is very simple. The only compulsory factor is that it has to extend from AbstractHandler. A simple handler is as follows:

public class SimpleHandler extends AbstractHandler {
   private String message;
   private QName name;
   public SimpleHandler() {
      this.message = "I am Simple Handler ";
   }
   public QName getName() {
      return name;
   }
   public void invoke(MessageContext msgContext) throws AxisFault {
      // write invocation logic here
}
   public void setName(QName name) {
      this.name = name;
   }
}

Among all the methods in the above implementation, invoke(msgContext) is the most important to discuss. When a message is received to the Axis engine, it will call invoke methods of each handler by passing an argument as a corresponding message context, so that inside the invoke method all the processing logic should be implemented. Inside the invoke method handler, the author has full access to the SOAP message and all the required properties to process the message via the message context. In addition to that, if handler finds some pre-condition and is not satisfied with the invocation, the invocation can be paused as mentioned earlier. It should be noted that the Axis2 engine provides a facility to store and retrieve message context, so a handler can use those features to store and retrieve message context.

Phase


The concept of phase is completely new terminology to the Web service stack; it was introduced for targeting the dynamic ordering of handlers and to support phase rules. A phase can be defined in various ways:



  • It can be considered a logical collection of handlers.
  • It can be considered a specific time interval in the message execution.
  • It can be considered a bucket into which one can put his handler.

As described later, a flow can be considered as a collection of phases. Even though it has been mentioned earlier that the Axis engine will call the invoke method of a handler, it is not totally correct. In fact, the engine really calls the invoke method of each phase in a given flow; then, phase will sequentially invoke all the handlers in it. Although one can extend the AbstractHandler handler and create a new handler but phase, so the phase implementation logic cannot be changed. Therefore, each and every phase in Axis works in a simpler way and the difference among those is handlers in side phases.


A phase is designed to support phase rules. As described later, there are rules such as phaseFirst and phaseLast, so in a handler there are reserved slots to hold both phase first and phase last handlers. The rest of the handlers will be kept in a different list. A phase can, therefore, be graphically represented as follows:



Phase invocation mainly consist of three steps:



  1. If the phase first handler is not null, it will be invoked first.
  2. Then rest of the handlers (except phase last handler) will be invoked.
  3. Finally, if the phase last handler is not null, it will be invoked.

Note: Handlers inside a phase can be ordered by using phase rules.

Type of Phases


In Axis2 there are two levels of phases:



  • System pre-defined phase
  • User-defined phase

System pre-defined phase


System pre-defined phases are the phases that are invoked irrespective of the service, and no one can change the order of these phases although they are defined in the Axis configuration (called server.xml or client.xml). If someone changes the order of these phases, the deployment will not be allowed to start Axis. The whole purpose of defining them in a configuration file is to tell the service or module developer the capability of using them in their development. The phases in their order corresponding to inflow can be represented as follows:

All these phases have some semantic meaning as well. The TrasnportIn phase consists of a handler that performs depending on the type of transport. As the name implies, the PreDispatch phase is the phase that always invokes (its handlers) before the dispatch has taken place. Handlers like WS-addressing will always be in this phase. The Dispatch phase is the phase that does the dispatching, simply by finding the corresponding service and the operation for the incoming message. Therefore, the Dispatch phase consists of dispatching handlers. PostDispatch is the phase that is invoked after Dispatch is been invoked.


Note: In Axis2, there are mainly two dispatch handlers, called RequestURIBasedDispatcher and AddressingBasedDispatcher.

User-defined phase


There might be instances when service or module authors need to define a new phase; those phases are called user-defined phases. If someone wants to add a handler that should be invoked after the dispatching has taken place, in that case it is required to define a new phase. Another important thing is that phase rule has some limitations, as described later in the article. A combination of both phase rules and phase orders leads to build a more flexible and configurable handler chain.


Because there are four types of flows, for each flow phase orders are defined in the system configuration file; defining a new phase can be done by just adding a new phase element into the configuration file. Those phases can be referred by any handler. The default configuration file provided with Axis2 is as follows;

<phaseOrder type="inflow">
      <!--  System pre defined phases       -->
      <phase name="TransportIn"/>
      <phase name="PreDispatch"/>
      <phase name="Dispatch"/>
      <phase name="PostDispatch"/>
      <!--  System pre defined phases       -->
      <!--   After Postdispatch phase module author or service
             author can add any phase he wants      -->
      <phase name="userphase1"/>
   </phaseOrder>
   <phaseOrder type="outflow">
      <!--      user can add his own phases to this area  -->
      <phase name="userphase1"/>
   </phaseOrder>
   <phaseOrder type="INfaultflow">
      <!--      user can add his own phases to this area  -->
      <phase name="userphase1"/>
   </phaseOrder>
   <phaseOrder type="Outfaultflow">
      <!--      user can add his own phases to this area  -->
      <phase name="userphase1"/>
   </phaseOrder>

Note: Adding a new phase cannot be done at the run time. If you add a new phase element to the system configuration file, those changes won’t be applied to the running system. For those changes to take place, it is necessary to restart the system.

Phase rule


The main idea of phase rules is to correctly locate a handler relatively to one another inside a phase. In addition to that, direct or indirect phase rules help to implement pre conditions and post conditions of a handler. Say, for instance, you do not have phase rules; in that case, to create a handler chain at deployment time, you have to have some way of specifying them. It might be a configuration file, but with that you cannot provide a dynamic nature into a handler chain. In another case, service authors might not be aware of WS-module and their handlers, so there should be a proper way of adding module related handlers into the chain as well. Therefore, the idea of phase and phase rules has been introduced to sustain the dynamic nature of a handler or an execution chain.


Characterizing a phase rule can be based on one more of the following properties that will be discussed below:



  • Phase name: Name of the phase that the handler must place
  • Phase first (phaseFirst): The first handler of the phase
  • Phase Last (phaseLast): The last handler of the phase
  • Before (before): Should be positioned before a given handler
  • After (after): Should be positioned after a given handler
  • Before and after: Should placed between given two handlers

Phase name

“phase” is a compulsory attribute for any phase rule; it tells the phase in which the handler must fit in. The rule to be a valid phase name is that it should to known to the system that must be either a system pre-defined phase or a user-defined phase.


phaseFirst


As the name implies, if someone wants a handler to be invoked as the first handler in a given phase irrespective of other handler in the phase, he has to set phaseFirst attribute to “true.” A phase rule only with phaseFirst and phase will be as follows:

<handler name="simple_Handler "
         class="org.apache.axis.handlers.SimpleHandler ">
   <order phase="userphase1" phaseFirst="true"/>
</handler>

phaseLast


As in phaseFirst, if someone wants his handler to be run last in a given phase irrespective of other handlers, he has to set phaseLast to “true.”


before


There may be situations when a handler should always run before some other handler no matter what the exact location is. Real-time use case can be that a security handler wants to run before the RM handler. The logic has to be written as below and the value of before attribute is the referred handler name:

<handler name="simple_Handler2 "
         class="org.apache.axis.handlers.SimpleHandler2 ">
   <order phase="userphase1" befoer=" simple_Handler "/>
</handler>

Note: Axis2 phase rule processing logic has to be implemented in such a way that if the handler referred by before the attribute is not available in the phase at the time rule is been processed, then it just ignores the rule and will place the handler immediately after phsaeFirts handler (if it is available, or else will be placed in the first location).


after


As before, if a handler always runs after some other handler, the phase rule can be written by using the after attribute. It should look like the example given below, and the value of after attribute is the referred handler name:

<handler name="simple_Handler3 "
         class="org.apache.axis.handlers.SimpleHandler3 ">
   <order phase="userphase1" after=" simple_Handler2"/>
</handler>

after and before


If a handler needs to be run between two different handlers, the phase rule can be written by using the before and after attribute. The values of both before and after attributes are the names of referred handlers. The correct way of writing a phase rule will be as follows:

<handler name="simple_Handler4"
         class="org.apache.axis.handlers.SimpleHandler4">
   <order phase="userphase1"
          after=" simple_Handler1"
          before=" simple_Handler2"/>
</handler>

Note: If there is a phase rule with both phaseFirst and phaseLast set to true, that phase cannot have any more handlers. The phase has only one handler.

Invalid phase rules


Validity of a phase rule is an important factor in Axis2. There can be many ways to get the same handler order by using different kinds of phase rules. But, when writing a phase rule, it is required to check to see whether the rule is a valid rule. There may be many ways in which a phase rule becomes an invalid rule. Some of them are:



  • If there is a phase rule of a handler with either phaseFirst or phaseLast attribute set to true, it cannot have before or after appearing in the phase rule. If they do, then the rule is invalid.
  • If there is a phase rule of a handler with both phaseFirst and phaseLast set to true, that particular phase cannot have more than one handler. If someone tries to write a phase rule that inserts a handler into the same phase, the second phase rule is invalid.
  • There cannot be two handlers in one phase with their phaseFirst attribute set to true.
  • There cannot be two handlers in one phase with their phaseLast attribute set to true.
  • If the rule is such that before attribute is referred to phaseFirst handler, the rule is invalid.
  • If the rule is such that after attribute is referred to phaseLast handler, the rule is invalid.

<handler name="simple_HandlerError "
         class="org.apache.axis.handlers.SimpleHandlerError ">
   <order phase="userphase1"
             before=" simple_Handler" phaseFirst="true"/>
</handler>

Note: Phase rules are defined per handler basic, and any handler in the system must fit in to a phase in the system.


Flow


Flow is simply a collection of phases, and the order of phases inside a flow is defined in server.xml. Because phase is a logical collection and which is in fact a virtual concept, a flow can be assumed as a handler chain (collection of handlers). There are four types of flows in Axis2:



  • InFlow
  • OutFlow
  • InFaultFlow
  • OutFaultFlow

InFlow: When a message comes in (request message), the message has to go via the InFlow. All the handlers in the InFlow will be invoked. In*Flows are somewhat different from Out*Flows. The flow consist of two parts. The first part is from the beginning to Dispatcher (up to and including postdispatch phase). The second part will be there only if a corresponding service is found at the end of dispatch phase. Therefore, the second part of the flow is InFlow of the corresponding operation for the incoming message. So, the InFlow consists of global part and operation part.


InFaultFlow: This flow will be invoked if any fault occurs while processing the incoming request. If a fault occurs before dispatching takes place, the global part of the flow will be executed, or else complete flow (including operation fault flow) will be executed.


OutFlow: When a message is going out from the server (say response) the OutFlow will be invoked, as a result of response or the out going message is always bound to an operation, and there is nothing similar to dispatching in the out path. Therefore, unlike InFlow, OutFlow does not consist of two parts. Therefore, there is no concept of global phases in the out flow.


OutFaultFlow: If something goes wrong in the out path, the out fault flow will be invoked.



Note: There can be many services deployed in the system. Each service can have more than one operation.

Dynamic handler chain through module engagement


In Axis2, a module can be considered as a collection of handlers, so by engaging a module either globally to a service or to an operation, module handlers will be placed in the corresponding phases. If a module is engaged globally, that will affect all the services in the system, and there is a probability of changing both global and operations flows (each operation in all the services). If a module is engaged to a service, flows belonging to all the operations in that particular service will be changed. If a module is engaged to an operation, each flow in that operation may be changed.


The only way of changing a flow is adding a handler(s) to a phase in the flow. Therefore, module engagement will cause the handler chain dynamically. A module can be engaged dynamically or statically. If someone wants to engaged a module statically he/she has to specify them in description files (if it is to a service or to an operation then in service.xml, if it is to be globally, then server.xml).


Note: The real-time scenario of runtime module engagement is by WS-Policy, where WS-Policy handlers can engage a module at the runtime by considering message headers.

Conclusion


Axis2 is fair enough to provide Web service interaction with dynamic and flexible execution framework. Flexibility is achieved using the concept of phases and phase rules, and the dynamic nature of the execution chain has been achieved by runtime module engagement.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories