http://www.developer.com/

Back to article

Avoiding Mistakes Made Using Axis2


March 3, 2006

There are a number of major areas where users can get into trouble when using Axis2. In this article, I provide possible solutions and suggestions to most of the problems you may face when you start to use Axis2. Even though this article is titled ‘10 Biggest Mistakes Developers make in Axis2’, rather than just citing problems and relevant solutions, I go one step ahead by explaining the major areas where you are most likely to get into trouble and by showing you how to overcome those situations.

1 — Trying To Do Advance Tasks Without Knowing Basics of Axis2

Axis2 is the next generation of web services stack, which is built on a new architecture. It was introduced in order to have a much more flexible, efficient and configurable Axis. Even though the architecture is new, some of the well-established concepts from Axis 1.x are preserved in Axis2.

Axis2 does, however, come with a lot of new features, enhancements and new industry specification implementations. Items such as AXIOM, Asynchronous Web service, MTOM, MEP support and archive-based deployment architecture are considerably esteemed among these new features and enhancements.

One of the main reasons of introducing Axis2 was to have proper XML processing model. Axis 1.x used DOM as its XML representation mechanism, but the draw back with DOM is the need to keep the complete objects hierarchy (corresponding to incoming message) in memory. For a message of small size this won’t be a problem, but when it comes to a large message this becomes an issue. It is to over come this problem Axis2 introduced a new XML representation for it base.

AXIOM (AXIs2 Object Model) is the base of Axis2, where any incoming SOAP message is represented as an object model called AXIOM inside Axis2. The advantage of AXIOM over other XML inforset representations is that it is based on PULL parser technique, while most others are based on PUSH parser technique. The main difference of PULL over PUSH is that in PULL technique invoker has the full control on the parser and can ask for the next event, where as in the case of PUSH, when the parser is asked to proceed it will fire the events until it reach the end of the document.

Since AXIOM is based on PULL parser technique it has so called ‘on-demand-building’ capability where object model will be built only if it is asked to do so, and, also if it is required one can directly access underline PULL parser from AXIOM and use that rather than building OM (Object Model).

If you don’t have a good understanding of AXIOM, then developing Web services with Axis2 is not an easy task. You will encounter different problems and you most likely won't use its optimization mechanisms. Of courses you can develop simple services without knowing anything about AXIOM, but if you are going to implement WS-spec or perform certain advance work with Axis2, it’s wiser to learn AXIOM first.

2 — Lack Of Knowledge On Axis2 Repository

In simple terms Axis2 is a SOAP processing engine with the main function of delivering incoming SOAP messages into the correct applications—and here every application is assumed to be a web service. In the mean while, just delivering an incoming message to an application is not enough. It is also required to have quality of services (QoS) like security and reliability.

To provide those QoS, or rather to extend Axis2 main functions, Axis2 has introduced the concept of extension modules. Axis2 repository keeps those two kinds of resources (web services and modules), in a simple term repository, a directory in the file system, which has some specific structure as shown in Figure 1.


Figure 1: Axis2 repository

As you can see there are three sub directories inside the repository and usage of them are as follows:

lib if both services and modules want to share some third party libraries then those should be placed in lib directory
modules all the extension modules, or rather, module archive files should be in the modules sub directory
services all the web services or rather service archive files should be there in the services sub directory.

The repository may contain Axis2 configuration file (axis2.xml) as well. When you start Axis2 for the very first time by giving repository location, if there is no axis2.xml found in the repository, it will copy the default axis2.xml file into repository and start the system using that axis2.xml. Thereafter a user can change that axis2.xml file if desired. Next time when the user starts Axis2, the system will be configured reflecting those changes as well.

Note: There is minor modification in the structure of the repository after Axis2 0.94 release. The axis2.xml file is located inside some other sub directory called conf inside the repository.

3 — Lack of Understanding regarding the Generation of WSDL

When working with WSDL files, it is possible to generate a service using WSDL that is given to you when you deploy the service. However, at run time you can end up receiving different WSDL when you ask for the specific service’s WSDL (?wsld).

In the Axis2 development process you should always think about the usability of product. Therefore a number of tools & IDE plug-ins have been developed to perform various tasks in Axis2. One such tool is WSDL2Code generation tool. As its name implies WSDL2Code generation tool generates source code for languages like Java and C++ using given WSDL. Note that only the WSDL2Java part has been completed and fully tested successfully.

In simple terms code generation is the creation of source code in some programming language for a given WSDL, so that users need not to worry about the WSDL or generating correct SOAP messages. All of this is handled by the code generated by the WSDL2Code generation tool.

The most common problem users face is that they generate server side code or rather service skeleton for a given WSDL and then they filled the skeleton the way they want (it is the nature in contract first approach). Then they create a service archive file for that service and deploy it in Axi2.

When Axis2 finds a service what it does is first it check whether there are any WSDL files in META-INF directory. If there is give the priority to the WSDL files and using those Axis2 web service will be created. If no WSDL files are found then it goes through services.xml file to find the service implementation class. Using that class, it generates a WSDL file using a process called Java2WSDL. This will only taken place if the service class was implemented using Java. Bottom line, when some one ask for ?wsdl for that particular service it will show the generated WSDL.

In the case of automatic WSDL generation, it first investigates the service implementation class using both Java reflection and JAM (annogen) and then generate XML schema for the given class and then generate the rest of the WSDL document. Most of the time (99% of the time) the generated WSDL file will differ from the original WSDL file that was used to generate service skeleton.

Note: I you generate client side code or stub using both of the above WSDL files you will get completely different set of classes, but that won’t affect to the request SOAP message.

4 — Writing Correct services.xml For Service Group And Single Service

A service archive file can contain one or more services, but one service archive file can only have one services.xml file or rather one services configuration file. The simplest scenario is having one service inside an archive file. In that case services.xml can be written as one of the following format;

Option 1:

<service> 
    <parameter name="serviceClass">
        org.apache.axis2.MyService
    <parameter>
    …………
    ………… 
<service>

I should note here that in the above, the case name of the service will always be the name of the archive file.

Option 2:

<serviceGroup>
    <service name="MyService"> 
         <parameter name="serviceClass">
             org.apache.axis2.MyService
         <parameter>
         …………
         ………… 
      <service>
<serviceGroup>

In option 2 the name attribute of the service element is a mandatory attribute, and value of the name attribute become the name of the service and name of the service group will be the name of the archive file.

In the case of multiple services in one service archive (service group) case, the services.xml file should look like option 2 and should contain <service name=""> </service> for each of the services in the archive file. Each of the services will be named using the value of the name attribute corresponding to its service element. As an example, if the service archive file contains two services then services.xml should look like below:

<serviceGroup>
    <service name="ABC"> 
         <parameter name="serviceClass">
             org.apache.axis2.ABCService
         <parameter>
      <service>
    <service name="XYZ"> 
         <parameter name="serviceClass">
             org.apache.axis2.XYZService
         <parameter>
      <service>
<serviceGroup>

5 — Relating wslds And Services in a Service Archive File

As discussed in the previous section the problem of getting a completely different wsdl files at the runtime can be solved by putting the original wsdl file in to an archive file. So if you are interested in seeing the same wsdl at the run time, then you have to put the wsdl file into META-INF directory in the service archive file in which case, you can name the wsdl file the way you want. There are, however, some rules that need to be followed if you try to put the original wsdl into a service archive.

Rule 1: In the case of single service archive case (service archive contain only one service), then as discussed above name of the service always be the name of the archive file. Then name of the service archive file should be the name of the service element in the wsdl (local name), as an example if the wsdl look like follows,

<wsdl:definitions xmlns:wsdl=http://schemas.xmlsoap.org/wsdl/ …..>
<wsdl:types>
<xs:schema targetNamespace="http://org.apache.axis2/xsd" … >
</xs:schema>
</wsdl:types>
<wsdl:portType name="MyPort">
</wsdl:portType>
<wsdl:binding name="MyBiding" type="tns: MyPort">
</wsdl:binding>

<wsdl:service name="MyService">
     <wsdl:port name=" MyPort " binding="tns: MyBiding ">
        <soap:address location="http://127.0.0.1:3502/axis2/services/MyService " /> 
    </wsdl:port>
</wsdl:service>
 

In this case the name of the service archive should be MyService.aar , then only the correct mapping will taken place and user can get the same wsdl that he used to generate the service.

Rule 2: In the case of a service group, you can put more than one (depending on the requirement) wsdl file and you can relate them using the same logic discussed in Rule 1. As an example if you have two wsdl files, and its service elements are named “foo" and “bar" respectively then the services.xml file should look like as follows

<serviceGroup>
     <service name="foo">
             ……………………
             …………………….
      </service>
      <service name="bar">
             ……………………
             …………………….
       </service>
</ serviceGroup>

6 — Parameters and Properties

Axis2 has two hierarchies called description hierarchy (static data) and context hierarchy (dynamic data). Static data are the data that are coming from different descriptors like axis2.xml, services.xml and module.xml, while dynamic data are populated and used at the run time. Parameters are designed to be used as static data, and they can be defined in anywhere in the above description files. Most of the time parameters are to configure the system. You can use parameters at the run time as well. For example if a service wants to write data to a file, then the name of the file can be taken from parameters, and some other use case can be database parameters for a module like WS-transaction. The way of defining a parameter in any of the descriptors is as follows:

 <parameter name="myPara" locked="flase">Any XML junk, String, int , etc</parameter>
 

You should note that parameters are designed to store primitive data types such as String or int double and OM elements, NOT any type of objects. However, it is not invalid to store any types of object inside a parameter but that is not the right way to follow.

Properties are designed to share data across run time environment, and value of the property can be any type. So main difference between parameters and properties is, parameters are stayed in description hierarchy and properties are stayed in context hierarchy. The simplest usage of a property could be to share data between two handlers in the execution chain, one handler can set some property in the message context and some other handler can perform some validation depending on that property.

Most of the time users are trying to misuse properties and parameters, and they trying to access them in the wrong way. For example, they define parameters in a description file and trying to access them as properties at runtime. In this case, they won't get the required result. Rather, most of the time a null point exception results. At runtime what you have is message context, so message context has to access them separately.

Object obj = msgCtx.getProperty(String key);
Parameter parameter = msgCtx.getParameter(String key);

7 — Service and Module Isolation

In Axis2 both the services and modules are said to be isolated, meaning each of them has their own classloaders. Service isolation (module isolation as well) is a very important feature in real time environment where if two different services want to use two different version of some third party library. How can they achieve their goals unless they have separate class loading mechanisms? What happens if the two versions are put into the same location? Since the full qualified name (including package name) of the two classes are the same in the both the versions, which will be picked by the Thread Context Class Loader (TCCL)?

You can't initialize two versions of the same class in one JVM, therefore Axis2 introduced service isolation to tackle this problem. If you want to use two versions of the same third party library then put them into service archive file so that the two services will be able to load without having any problems.

It should not that if you put some resources in a side service archive file (say foo), then you cannot directly access those resources from some other location. You have get foo’s classloader and the load the resources using that.

There are a few ways to access resources in a service archive:

Option 1: If you are trying to access the resources outside of the service implementation class (for example, if you trying to initialize a service implementation class at the message receiver level) then the correct way follows:

First get the corresponding AxisService , since class loader reference is there in the AxisService.

   AxisService service = msgCtx.getAxisService();

Next get its class loader,

ClassLoader loader = service.getClassLoader ();

If you want to load or initialize some class in the archive file

Class servicClass =Class.forName(“MyServiceClass" , loader,true);

If you want to read a resource file in it, then

InputSream in=loader.getResourceAsStream(“MyResources");

Option 2: Inside service implementation class or any classes loaded by the service class loader, then the correct way of accessing the class loader is:

ClassLoader loader = getClass().getClassLoader();

Using this loader you can load resources, load classes, and more.

You should note that when a service deploys in the system and when it get initialize in axis2, all the classes in the archive file are loaded using the class loader created for that particular service, and it parent class loader may either be TCCL or a system class loader (Class loader common to both services and modules) in addition to that class loading taken place in child first technique.

It should be noted that any classes or resources in either module or service cannot be access using TCCL, since service resources are not visible through TCCL.

8 — Getting Access to MessageContext From Service Classes

In Axis2 the last handler of the incoming execution chain is the message receiver. One of the main jobs of Axis2 is to deliver message to MessageReceiver. It is then its up to the MessageReceiver to hand the message to the application or do the processing by itself. Axis2 come with set of default MessageReceivers so that if you want, you can use them for your services. In the mean time you can write your own message receivers for your service and use them for their services.

If you, as the service author, are trying to write a MessageReceiver for a service then you can write it the way you want. The advantage in this case is that you should know about the service implementation class and thus you can program a message receiver so that it can pump message context into the service implementation class.

Most of the time service authors are not going to write their own MessageReceiver (it is not require to do so in all the cases) and they try to use default message receivers (depending on his requirement). In that case a service author does not have any control on the message receivers, and it will be getting either OMElement or Java object(s). But there can be many instances where a service author is required to access a Message Context inside the service implementation class (say for an instance to access HTTP headers needed to get the message context). To solve this problem, Axis2 has given an indirect path that is not incorrect. If you want to access incoming message context inside your service implementation class add the following method to service implementation class;

public void init(MessageContext msgctx){
  // store the message context 
}

And if you want to access both incoming and outgoing message contexts then add the following method to service implementation class.

public void init(MessageContext inMessge, MessageContext outMessage) {
 // store the message contexts 
}

9 — Trying to invoke two channel invocations without engaging Addressing

One of the key features in Axis2 is its asynchronous invocation capability. There are two level of asynchronous that Axis2 support:

  1. Asynchronous behavior in client programming model
    A client program does hang, but there is blocking in the transport senders (transport blocking).
  2. Actual transport asynchronous behavior
    Two transports are used for incoming and outgoing (transport non-blocking).

In the first case there is no real asynchronous invocation as far as transport is concerned, where the transport sender sends the request and then listens to the input stream to get the response. When it gets the response, the client program will be notify (client has to give callback object , so that it will be called whenever transport gets the response ).

In the second case one there are two transports for both sending and receiving, so transport sender sends the request and finishes its work. There has to be another transport listener to get the response. The most important thing in this case is that outgoing message has to have wsa:ReplyTo header; otherwise, the server does not way to send the response. In the incoming message server will send the response to wsa:ReaplyTo (which is the address of the initiator) addressing and it will send wsa:relatesTo and the other addressing headers as well. This implies that the addressing module should be available in the system to process the request. Therefore Axis2 has constraint saying that no one can invoke any service using two channels unless he has engaged addressing.

10 — Session Management and Service Scope Problem

Axis2 session management was introduced very recently, and it supports four levels of service scope or the session scopes:

  1. Application scope
  2. SOAP session scope
  3. Transport session scope
  4. Request scope

The basic rule is if you deploy some service in one of the above scope then you will be able to get session corresponding to that scope. For example if a service author deploys his service in application scope, then that service gets application session.

A service author can specify the service scope in the optional services.xml file. If the service author does not specify scope, then the default scope would be Request scope. The right way of specifying the scope is as follows:

<service name="MyService" scope="application"> 
</service>

Then the deployment person can deploy the service in the right scope. Note that one service cannot be deployed with two scopes.

Application session takes the longest lifetime and is equivalent to the lifetime of the system. If a service is deployed in application scope, then to manage session client need not to do any thing (no need to send any session data). The most important thing with application scope is that there will be only one instance of the service implementation class throughout the lifetime of the server instance.

In the case of SOAP session, it has a shorter lifetime than application session. In Axis2 the definition of SOAP session is to access set of service in a service group or to manage session across all the services belong to service group. To get into correct SOAP session user has to send a specific SOAP header called service group id. SOAP session corresponding to some service invocation will be removed from the system if that does not get touch for period of 30s. It should be note that if service is deployed in SOAP session scope, then each session will have its own service class instances that implies that if some service is deployed in SOAP session scope there can be multiple instance of the service implementation class.

In the case of Transport session, session management or finding the correct session object is achieved using some transport specific data such as in the case of HTTP it is HTTP cookies. If a service is deployed in transport session, then there will be services instance for each transport sessions. The interesting thing with this approach is that a user can have multiple SOAP sessions in one transport session. To get into the correct SOAP session (which is stored in Transport session), you have to send the service group id SOAP header in addition to cookies.

There is no any session management for request session scope, that’s only for one request so no need to have any session around it.

In Conclusion

As you can see, there are a number of major areas where users can get into trouble when using Axis2. Hopefully you have gain some insights into how to avoiding such mistakes as you work with Axis2.

# # #

Sitemap | Contact Us

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