Utilizing a Non-Java Web Service with Axis2

In simple terms, Axis2 is not just the next version of the Axis 1.x family; rather, it is a revolutionary version of Axis 1.x. Axis2 is no longer bound to request-response Web service invocation. As in the Axis 1.x family, there is no turning point like the "pivot point" in Axis2, and Axis2 is built totally on keeping asynchronous Web service invocation in mind. Axis2 acts as a pipe that carries the SOAP message from one end to other. The entry point to the pipe is a transport receiver, and the end point is a message receiver. After handing over the message to the message receiver, Axis2 does not care about the message. Therefore, it's up to the message receiver to invoke the service and send the response, if any, so service implementation class(es) need not always be a Java class; it can be something else as well.

How a Message Processes in Axis2

As mentioned above, Axis2 acts as a pipe that carries a SOAP message from the transport receiver to the message receiver. To make the invocation simple, the pipe is divided into four phases, as shown in Figure 1.

Note: In Axis2, those are the main phases in an execution chain (for an incoming message).

Pre-Dispatch

At this level or phase, all the processing required for dispatching to take place is carried out. As an example, message decryption can be considered one of the most commonly used processes in this phase.

Dispatching

The simple meaning of dispatching is finding the corresponding service endpoint for the incoming message. There are four types of dispatching criteria that Axis2 taken into account for dispatching:

Further exploration on dispatching goes beyond the scope this article.

Post-Dispatching

All the processing that is carried out after dispatching will happen in this stage. As an example, service level policy determination will take place in this phase.

Message Processing

All the above phases are executed irrespective of the service, but the message processing phase might vary from one service to another. As an example, there can be one service where RM (reliable messaging) has engaged to it and another not; then the execution will vary from one to another. The message processing phase always ends with a so-called message receiver; the Axis2 message receiver is somewhat similar to an Axis 1.x pivot point, but the similarity is not considerable.

What Message Receiver Is

The Axis2 execution chain is collection of phases; each phase is a logical group of handlers. The message receiver itself is a handler, but the only difference is that Axis2 treats that handler differently than others. If the message has gone through the execution chain without having any problems (no exceptions have occurred in the middle of the chain), the engine will hand over the message to the message receiver to do the business logic invocation. Figure 2 shows the location of the message receiver in the execution chain.

Note: The Axis2 architecture was built by keeping WSDL 2.0 in mind as well. Therefore, Axis2 supports almost all the MEPs defined in WSDL 2.0 (IN-OUT, IN-ONLY, and so forth), and the message receiver is the one that is responsible for handling MEPs.

On the other hand, the message receiver is the one that directly interacts with both the actual service implementation class and the Axis engine. (There can be an instance where no service implementation classes exist and all logic handles are the message receiver). Axis 1.x has the concept of "pivot point," where a request path and response path meet together, and where the actual service innovation takes place. You should notice that request-response behavior has not been burned into Axis2; simply, it is an asynchronous SOAP processing engine, but it can handle request-response tasks as well. As mentioned earlier, message receiver is the end of the inflow that interacts with service the impl class. Therefore, Axis2 does not care about the message after handing it over to the message receiver.

The Axis2 distribution consists of two message receivers (as listed below) to support two commonly used MEPs (In-Out and In only and their combinations):

RawXMLINOnlyMessageReceiver

RawXMLINOutMessageReceiver

Note: The above two message receivers are capable of handling an OM (AXIOM) in-OM-out scenario; you cannot have any data binding stuff with those message receivers. As an example, if your service implementation class is such that it takes OMElemenet as its method parameters and returns OMElemenent, the as result below shows:

Note: In Axis2, no RPC concepts are taken into the core part, but, to make the users happy, as an add-on feature RPC capability has been added by having a message receiver called RPCMessageReceiver. The RPCMessageReceiver is capable of handling all the simple types (String, int, char, byte, long, double, float, short, and boolean) and any kind of JavaBeans object types as well as SOAP multirefs.

Message receivers are just handlers; the only difference is that it has to extend from the MessageReciver interface and the interface so that it looks like the following:

Registering Message Receivers on a Per-Operation Basis

As mentioned earlier, a MR (Message Receiver) is MEP specific; its responsibility is to handle the MEP as defined. In Axis2, a Web service call is to access an operation or invoke a method in the service implementation class, and the description class that interacts with MEP is an AxisOperation class, so that the MR can be configured on a per-operation basis. This is a highly required feature in Web services. Say, for instance, there are two methods in a service class; one of them has a return type and other does not. It is so obvious it has to treat those two methods differently; that is why it is required to configure MR on a per-operation basis. The user can write his/her own MR and configure that as the MR for a given operation. The configuration is done by the service descriptor or services.xml, as shown below:

There are several ways to write a custom message receiver, and the way of extending an implementing those are shown in Figure3.

Figure 3: Message Receivers Hierarchy

Option 1: Implementing message receiver

Message receiver is the topmost interface and, as mentioned above, it has only one method called "receive()", so one can write a custom message receiver by implementing theMessageReceiver interface. It has full access to an incoming SOAP message and message context; this can be used for any MEP (both WSDL 2.0 and customer defined MEPs) implementation.

Option 2: Extending from AbstractMessageReceiver

The only difference with respect to the above scenario is that there are some addition methods that have been implemented, such as getting the service implementation class, creating its instance, and so forth. By extending AbstractMessageReceiver, one can use those methods directly and can create all the WSDL 2.0 MEPs and any new custom MEPs.

Option 3: Extending from AbstractInMessageReceiver

If you want to write a customer MR to handle in messages only, the best way is to extend from AbstractInMessageReceiver. In all the above two cases, the "receive()" method is to override, but here the "invokeBusinessLogic(MessageContext inMessage)" method has to be implemented.

Option 4: Extnding from AbstractInOutSyncMessageReceiver

The proper way to write a custom MR to handle in-out messages is to extend AbstractInOutSyncMessageReceiver, and as in Option 3, the "invokeBusinessLogic(MessageContext inMessage, MessageContext outMessage)" method has to be implemented. There is a big difference in this particular method with respect to Option 3. In Option 3, the method takes only one parameter and it is the incoming message context. This method takes two parameters; one is the incoming message context and other one is the outgoing message context.

Note: The outgoing message context is created by coping the required properties and descriptions from the incoming message context.