http://www.developer.com/

Back to article

Developing Java Web Services with AXIS


December 6, 2004

Apache Axis has made developing Java Web services a breeze. In this article, I will discuss some guidelines that prove to be very helpful when developing Java Web services using Axis. This article discusses the customization of Axis and the deployment of Web services; it does not discuss the theory of Web services, XML, Java, and so forth.

What Is Apache Axis?

The definition from Axis' Web site http://ws.apache.org/axis/: "Apache Axis is an implementation of the SOAP ("Simple Object Access Protocol") submission to W3C."

For me, the more suitable definition is: "Axis turns Java code into Web services."

Downloading Axis (Java)

Download the latest version of Axis (Java) from their Web site, http://ws.apache.org/axis. At the time of this writing, 1.1 is the stable release and 1.2 is in the alpha release. These guidelines are based in Axis 1.1. I will refer to this download as the Axis archive from this point onwards.

Customizing Axis

The following steps discuss how to customize Axis for your Web applications.

Step 1: Customizing web application

You can start with a new or existing standard Java-based Web application, also known as Web Application Archive or WAR. I assume that you know how to build a WAR file and what its contents are.

To enable a Web application to expose Web services, you need to customize the Web application so that it can use Axis engine. You need to perform three steps:

  1. Customize WEB-INF/web.xml.
  2. Add the Axis libraries into the WEB-INF/lib folder.
  3. Create a server-config.wsdd file.

If you are developing a new Web application, the quickest way to customize is to copy the axis folder from the Axis archive's webapps folder and rename it to your own Web application. You can safely delete the samples folder inside the classes folder of your new Web application. You may rename the index.html to your liking, say testaxis.html. It can help you later on to test the axis engine.

If you already have a Web application, you need to copy all the servlet mappings from the axis/WEB-INF/web.xml of the Axis archive into your Web application's web.xml file. You also need to copy all jar files from the axis/WEB-INF/lib folder to your Web application's lib folder. If you want to test your Web application later on, at least copy index.html and happyaxis.jsp from the axis folder to the root of your Web application. You can rename index.html to your liking, say testaxis.html.

Now that you have completed Steps 1 and 2 of customization, the third important step is to create the WEB-INF/server-config.wsdd file. The wsdd stands for Web service description file. It is an XML file used by the Axis engine. It contains definitions of the Web services that Axis deploys from your Web application.

The minimal contents of server-config.wsdd file are as follows:

<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 <globalConfiguration>
  <parameter name="adminPassword" value="admin"/>
  <parameter name="attachments.Directory" value="./attachments"/>
  <parameter name="attachments.implementation"
             value="org.apache.axis.attachments.AttachmentsImpl"/>
  <parameter name="sendXsiTypes" value="true"/>
  <parameter name="sendMultiRefs" value="true"/>
  <parameter name="sendXMLDeclaration" value="true"/>
  <parameter name="axis.sendMinimizedElements" value="true"/>
  <requestFlow>
   <handler type="java:org.apache.axis.handlers.JWSHandler">
    <parameter name="scope" value="session"/>
   </handler>
   <handler type="java:org.apache.axis.handlers.JWSHandler">
    <parameter name="scope" value="request"/>
    <parameter name="extension" value=".jwr"/>
   </handler>
  </requestFlow>
 </globalConfiguration>
 <handler name="LocalResponder"
          type="java:org.apache.axis.transport.local.LocalResponder"/>
 <handler name="URLMapper"
          type="java:org.apache.axis.handlers.http.URLMapper"/>
 <handler name="Authenticate"
          type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
 <service name="AdminService" provider="java:MSG">
  <parameter name="allowedMethods" value="AdminService"/>
  <parameter name="enableRemoteAdmin" value="false"/>
  <parameter name="className" value="org.apache.axis.utils.Admin"/>
  <namespace>http://xml.apache.org/axis/wsdd/</namespace>
 </service>
 <service name="Version" provider="java:RPC">
  <parameter name="allowedMethods" value="getVersion"/>
  <parameter name="className" value="org.apache.axis.Version"/>
 </service>
<transport name="http">
  <requestFlow>
   <handler type="URLMapper"/>
   <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
  </requestFlow>
 </transport>
 <transport name="local">
  <responseFlow>
   <handler type="LocalResponder"/>
  </responseFlow>
 </transport>
</deployment>

Step 2: Test the Axis engine

If you have copied the index.html and happyaxis.jsp files and axis folder to your Web application, you can use index.html (or whatever you have renamed it) to test the Axis engine. Deploy your Web application in your favorite application server and access the above-mentioned test file. Click Validate to validate the Axis and View to view the deployed Web services. Everything should go fine by now!

Publishing Web Services Using Axis

Now that you have customized your Web application to use Axis as a SOAP engine, it's time to publish the Web services. Axis provides two ways to deploy the Web services. Both of these methods are also covered in detail in the Axis User's guide. The discussion on the first technique is similar to the one discussed in the official documentation. The discussion of the second technique, however, differs primarily in the usage of the wsdd file. I prefer to use the server-config.wsdd file to make the suggested advanced changes.

Instant Deployment: Renaming .java to .jws

The simplest and most straightforward way to deploy Web services is to rename the .java file to .jws and place it in the root of your Web application. JWS stands for Java Web Service. Say you have a .java file named Calculator.java; you then can rename it to Calculator.jws, place it in the root of your Web application, deploy your Web application, and finally you can access the WSDL contents of the Web service as http://yourhost:yourport/yourwebapp/Calculator.jws?wsdl.

It's simple indeed, yes, but only for the simplest application. One of the major caveats of using this technique is that you are forced to use mainly primitive data types and some very common Java classes such as java.util.Date (an exact mapping list is available on the Axis Web site) as method arguments and method return types. In other words, you cannot use your custom made classes (also sometimes referred to as Value Objects or VOs) as method parameters or return types.

Advanced Deployment: Configuring the server-config.wsdd File

The advanced deployment allows us to use our own classes as parameter values and return type of methods. Value Objects or VOs are typically used to represent the collection of data that needs to be passed on via methods.

Here's an example to explain the advanced deployment. Create a class, say as EmployeeManager.java. It contains two methods: getAllEmployees that returns array of Employee class and setEmployee that has Employee class array as an input parameter. The Employee class is a typical Java bean containing, for instance, getters/setters for name (String), salary (double), and designation (String).

The EmployeeManager class will act as a Web service that exposes two Web methods. Here are the sample definitions of the above two classes:

package mypackage;
/**
 * Web service front end for employees. Provides web methods.
 * 
 * @author saleemu
 */
public class EmployeeManager {
    /**
     * Get all employees
     * @return array of Employee array
     */
    public Employee[] getAllEmployees() {
        Employee[] employees = null;
        //load Employee array from some DAO
        return employees;
    }
    
    /**
     * Save employees
     * @param employees array of Employee objects
     */
    public void setEmployee(Employee[] employees) {
        //call some DAO to save employee array
    }
    
}

---
package mypackage;
/**
 * Employee Value Object
 * @author saleemu
 */
public class Employee {
    private String name;
    private double salary;
    private String designation;
    
    

    /**
     * @return Returns the name.
     */
    public String getName() {
        return name;
    }
    /**
     * @param name The name to set.
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * @return Returns the salary.
     */
    public double getSalary() {
        return salary;
    }
    /**
     * @param salary The salary to set.
     */
    public void setSalary(double salary) {
        this.salary = salary;
    }
    /**
     * @return Returns the designation.
     */
    public String getDesignation() {
        return designation;
    }
    /**
     * @param designation The designation to set.
     */
    public void setDesignation(String designation) {
        this.designation = designation;
    }
}

Once you have your Web services front end class, required beans, and so on, compile them and either place the generated .class file in the WEB-INF/classes folder of your Web application or archive them to jar and place them in the WEB-INF/lib folder of your Web application.

Now, it's time to modify the server-config.wsdd file and add a service element that will define your Web service. Here is the typical definition of a service element for the above mentioned class; I have bolded the important information that will differ from one Web service to another:

<service name="EmployeeWebService" provider="java:RPC">
  <parameter name="allowedMethods" value="*"/>
  <parameter name="className" value="mypackage.EmployeeManager"/>

  <beanMapping languageSpecificType="java:mypackage.Employee"
               qname="ns1:Employee" xmlns:ns1="urn:mypackage"/>

</service>

The sub-element parameter defines the class that will act as a Web service and how many methods are allowed to act as Web methods.

The beanMapping sub-element points to your custom bean. This element allows Axis to handle (most appropriately serialize and de-serialize) the Java classes that are not handled by default by Axis (mostly primitive) and they follow the Java bean style setter and getter methods. You have to define as many bean mappings as the beans used by the Web method and the beans used within those beans.

What about the classes that do not follow Java bean style specifications and you want to use them with Axis? Axis allows you to write custom a Serializer and Deserializer to handle such classes. How to write a custom Serializer/Deserializer is a complete topic in itself. The Axis official documentation does not provide much detail on how to write them and there is very little help available on the Internet. I had to dive into the Axis source code to come up with my own custom Serializer and Deserializer for java.sql.Blob. Maybe I'll write another article completely on that topic.

Now that you have customized the server-config.wsdd file, you can access your new Web service's WSDL by using URL, for example, as http://yourhost:yourport/yourwebapp/services/EmployeeWebService?wsdl.

Accessing Your Web Services

Learning exactly how to access a Web service from a Java client or .NET client is beyond the scope of this article; it deserves an article of its own. Nevertheless, WSDL2Java is the excellent tool to generate proxy classes to access any Web service, similarly by the way that adding a Web reference in a Visual Studio.NET project generates all necessary classes to access any Web service.

Conclusion

Axis has simplified the development of Java Web services. Its customization allows you to make your Web applications expose Web services and Web methods without much of the hassle.

Happy Java Web service programming.

Sitemap | Contact Us

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