http://www.developer.com/

Back to article

Utilizing a Non-Java Web Service with Axis2


December 9, 2005

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.



Click here for a larger image.

Figure 1: Request processing model

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:

  1. Incoming URL: URL-based dispatching
  2. SOAP Action: SOAP action-based dispatching
  3. Addressing Headers: Addressing-based dispatching
  4. SOAP body first element: SOAP message-based dispatching

Note: In Axis2, there are two levels of dispatching;

  • Description dispatching (finding description)
    • Service dispatching (finding service)
    • Operation Dispatching (finding operation)
  • Context dispatching (finding corresponding contexts for the incoming message)
    • ServiceGroupContext dispatching
    • ServiceContext dispatching
    • OperationContext 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.



Click here for a larger image.

Figure 2: 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:

public class MyService {

    public void foo(OMElement inelement){
       // your code goes here
    }

    public OMElement echofoo(OMElement fooin){
       return fooin;
    }

}
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:

public interface MessageReceiver {
   public void receive(MessageContext messgeCtx) throws AxisFault;
}

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:

<service>
   //service level parameters and any other descriptions go here

   <operation name="foo" >
   <messageReceiver
      class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
   </operation>
   <operation name="baa" >
      <messageReceiver class="MyMessageReceiver"/>
   </operation>
</service>

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.

Writing a Non-Java Web Service

There are two new features in Axis2 that help write non-Java Web services with Axis2. They are as follows:

  1. Message receiver: Axis2 assumes the service end point as a message receiver (Axis2 does not have any business with the actual service implementation class), so it's up to the message receiver to talk to the service implementation class and get the response and send it to the request initiator, if any. Therefore, it is easy to write a MR that invokes a non-Java class to process a message.
  2. Service isolation: In Axis2, each service deployed in the system has its own class loaders. A class loader can be used to access all the resources corresponding to that particular service.

Note: The class loader for a given service can be obtained from its corresponding AxisService object (org.apache.axis2.description.AxisService). Say foo is an AxisService; a user can access his/her resources by using:

InputStream in =
   foo.getClassLoader().getResourceAsStream(ReourceName)

Writing a Sample Non-Java Web Service

Groovy (http://groovy.codehaus.org/) is a very advanced scripting language that can run on Java JVM, so this sample is based on writing a Web service using Groovy, deploying that in Axis2, and finally invoking using an Axis2 client (no need to be an Axis2 client). If you are not familiar with Groovy, don't worry. Try to get the concepts and apply them into some other languages that you are familiar with. The service class implemented using Groovy will look like Figure 4.

Figure 4: The Groovy service class

Writing a Message Receiver to Invoke the Service

The default message receivers mentioned above cannot handle this situation (the default message receivers are only for invoking Java services); therefore, to invoke this service there should be a custom message receiver. The message receiver's implementation logic is described below.

Step 1: Getting the service implementation class

The service implementation class is described in services.xml as a parameter. At deployment time, the service implementation class is neither loaded nor initialized, so at run time the service implementation class has to be loaded and initialized. The parameter that describes the service implementation class look like the following:

<parameter name="ServiceClass" locked="false">
   GroovyRcv.groovy
</parameter>

The message receiver implementation logic to get the service implementation class logic is as follows:

invokeBusinessLogic(MessageContext inMessage,
                    MessageContext outMessage) {
   try {
      inMessage.getServiceContext().getAxisService();
      Parameter implInfoParam = service.getParameter("ServiceClass");

Step 2: Creating a service object instance

First, take the input stream from the service class loader for the service implementation class. Then, create a service implementation class instance using that.

InputStream groovyFileStream = service.getClassLoader().
   getResourceAsStream(implInfoParam.getValue().toString());
GroovyClassLoader loader = new GroovyClassLoader();
Class groovyClass = loader.parseClass(groovyFileStream);
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();

Step 3

In Axis2, an incoming SOAP message is represented as an object model called AXIOM, but Groovy cannot work with AXIOM. It can handle Xpath and DOM-like XML inforset representations. Therefore, you cannot directly get an incoming SOAP message into a Groovy object. You first need to serialize that into the original SOAP message and get the input stream that corresponds to it.

OMElement firstChild =(OMElement)inMessage.getEnvelope().
   getBody().getFirstOMChild();
StringWriter writer = new StringWriter();
firstChild.serialize(new OMOutputImpl(XMLOutputFactory.newInstance().
   createXMLStreamWriter(writer)));
writer.flush();

String value = writer.toString();
InputStream in = new ByteArrayInputStream(value.getBytes());
Object[] arg = { in };

Step 4

Invoke the method using Java reflection. The return value of this invocation is a string, as shown in the Groovy service class above.

AxisOperation op = inMessage.getOperationContext().getAxisOperation();
String methodName = op.getName().getLocalPart();
Object obj = groovyObject.invokeMethod(methodName, arg);

Step 5

Create the response SOAP message by using the above return value and sending the response back to the client.

SOAPFactory fac = OMAbstractFactory.getSOAP11Factory();
SOAPEnvelope envelope = fac.getDefaultEnvelope();
OMNamespace ns = fac.createOMNamespace("http://soapenc/", "res");
OMElement responseElement = fac.createOMElement(methodName +
   "Response", ns);

String outMessageString = obj.toString();
responseElement.addChild(getpayLoad(outMessageString));

envelope.getBody().addChild(responseElement);
outMessage.setEnvelope(envelope);

Creating a Service Archive File

To deploy the service in Axis2, you must create a service archive file. For that, you need to do the following:

  • Compile the source code.
  • Write the service description file (services.xml).
  • Put "groovy-all-1.0-jsr-01.jar" in the class path (create a lib directory inside service archive and drop the above jar file into that).
  • Create a jar file out of all those resources and class files.

Note: To invoke this service, you do not need to have a specific client; you can use the normal Axis2 client (Call). Complete source code for the service and client are available for download from the Apache SVN repository.

Service code: http://svn.apache.org/repos/asf/webservices/axis2/trunk/java/modules/samples/src/sample/groovy

Client code: http://svn.apache.org/repos/asf/webservices/axis2/trunk/java/modules/integration/test/org/apache/axis2/groovy

Conclusion

Axis2 architecture is flexible and highly extensible; the ability to invoke a non-Java application using Axis2 shows its extensibility. The ability to write a custom message receives is not only useful to invoke a non-Java Web application, but also to build an application such as a work flow model on it (BPEL).

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date