Axis: The next generation of Apache SOAP

Apache takes its SOAP implementation to new heights

Over the past couple of years, the Simple Object Access Protocol (SOAP) has taken off at rocket speed. A solid understanding of SOAP concepts has become essential for any strong software professional, especially software architects. The reason is quite simple. SOAP provides the foundation for one of the most exciting developments in the software industry today: Web services. Web services are exciting because they take application integration and interoperability to a new level never possible before, even with Java and J2EE (Java 2 Platform, Enterprise Edition).

To summarize, SOAP offers the following:

  1. An XML-based wire protocol, which is thus Web/firewall friendly
  2. A universally accepted W3C (World Wide Web Consortium) standard backed by all major and minor market players, including Microsoft, Sun Microsystems, IBM, and HP

Before diving into this article, you might want to review my previous JavaWorld series, "Clean Up Your Wire Protocol with SOAP," where I explain the basics of SOAP and why it proves so critical to the future of distributed computing:

In those articles, I focused on how developers could use Apache SOAP to build SOAP-based projects. Since then, Apache has completely rebuilt its SOAP implementation, creating a new project called Axis. In this article, I provide a high-level overview of the improvements Axis targets. I also show how to create and deploy a simple Web service with Axis.

What is Axis?

All software developers understand the importance of software toolkits; they prove essential to ensuring high developer productivity in this era of rapid application development. Coding with SOAP is no different. Although you could handcraft all your XML-based SOAP messages, you would probably want to use a SOAP toolkit to speed your development. After all, you don't handcode all your RPC (remote procedure call) messages in bits and bytes; why should SOAP messages be any different?

One such toolkit is available for SOAP. Apache SOAP's first generation was based on SOAP4J, IBM's donated codebase. I covered this excellent implementation in Parts 2 through 4 of my earlier series. As good as it was, Apache SOAP is now better. Axis is not just a rewrite of Apache SOAP, but a complete re-architecture. For Axis, Apache plans two alpha releases with partial functionality, a beta release with complete functionality, and a final release, Axis 3.0, which will supersede Apache SOAP 2.2. Alpha 1 was released in August 2001 and alpha 2 was released in September 2001. Though alpha 3 was issued in December 2001, this article focuses on the alpha 2 release (which features the same functionality as alpha 3).

When complete, Axis will:

  1. Support SOAP 1.1, just as Apache SOAP 2.2 does. For example, Axis will completely support the SOAP concept of mustUnderstand headers. Axis's final release will have a few SOAP 1.2 features as well as partial support for pluggable XML protocols.
  2. Likely prove much faster and more resource efficient than Apache SOAP, since it uses SAX (Simple API for XML) instead of DOM (Document Object Model). SAX allows lazy parsing of XML documents, which in many cases is more efficient -- especially when the entire XML document does not need to be parsed or kept in memory for long time periods.
  3. Have a clean and simple abstraction for designing transports -- i.e., senders and listeners for SOAP over various protocols such as SMTP (Simple Mail Transfer Protocol), FTP, message-oriented middleware, and so on. Also, the engine's core will be completely transport independent.
  4. Automatically generate WSDL (Web Services Description Language) from deployed services. The Axis alpha 2 version also comes with the wsdl2java tool for building Java proxies and skeletons from WSDL documents. Thus, you not only get the WSDL for an Axis-deployed service, but you can also build stubs and skeletons from the WSDL for extremely easy client code development. Note that the WSDL that feeds into the wsdl2java tool can originate from any source as long as it adheres to the WSDL specification. I'll show you an example of using this feature later.
  5. Support EJB (Enterprise JavaBeans) deployment as services. This resembles a feature provided by some application servers, such as BEA WebLogic Server.
  6. Feature improved deployment support and the ability to drop Java files into a deployment directory and expose the classes as services. I'll show you an example of this later.
  7. Better interoperate with Microsoft's SOAP implementation and .Net services. Over the past year, Apache and Microsoft have undergone several iterations of their SOAP implementations; with each iteration, they become more interoperable with each other. For details, see the summary of the last Apache/Microsoft interoperability meeting.

Although I use the future tense in the bullet points above, the alpha 2 release already includes many of these features.

Now, let's install Axis and create a simple service with it.

Install Axis

Although the Axis installation guide is fairly straightforward, these instructions will further ease the process:

First, ensure you have a Web server installed. I use Tomcat. If you have another Web server, you can still download Tomcat's latest version (version 4.0.1, at the time of this publication) from http://jakarta.apache.org/tomcat/index.html. Unzip the downloaded zip file into your C drive, or your preferred drive. (Note that I refer to the C drive in all my instructions.) You should see Tomcat installed in the directory C:\jakarta-tomcat-4.0.1 (if you have a different version, substitute your version number in place of 4.0.1). I will refer to this directory as TOMCAT_HOME.

Second, download Axis's latest release from http://xml.apache.org/axis/index.html. Unzip this zip file into your C drive as well. Axis should now be installed in the directory C:\axis-1_0 (for version 1.0, alpha 2). I will refer to this directory as AXIS_HOME.

Third, copy the Axis folder from AXIS_HOME\webapps into TOMCAT_HOME\webapps.

Now copy xerces.jar from your Xerces installation into the TOMCAT_HOME\webapps\axis\WEB-INF\lib directory. If you don't have Xerces, you can download it for free from http://xml.apache.org/xerces2-j/index.html. All you have to do is download the zip file and unzip it into your C drive. xerces.jar will be in the root of your Xerces installation -- for example, C:\xerces-1_4_4.

Finally, set up a context in the server.xml file in the directory TOMCAT_HOME\conf by adding this line:

<Context path="/axis" docBase="axis" debug="0" reloadable="true"/>

That's it. Axis is now installed and ready to use.

Create the Web service

Like the service in "Clean Up Your Wire Protocol with SOAP, Part 2," the Web service that we will create here is the "Hello World" of Web services. As you can see below, it is a class that has one method, sayHelloTo(), which takes a name as its only parameter and returns a customized hello message. Note that the class is not littered with any Axis-specific code:

public class HelloServer 
{
    public String sayHelloTo(String name)
    {
      System.out.println("sayHelloTo(String name)");
      return "Hello " + name + ", How are you doing?";       
    }
}

Deploy the Web service the easy way

To deploy this Hello World Web service, just copy and paste the HelloServer.java file into the TOMCAT_HOME\webapps\ directory and change its extension from .java to .jws. That's all there is to it; the Web service is deployed and ready for use. And you didn't even have to compile the Java file! This is Axis feature number 6 (described above) in action.

When a client invokes a service deployed in this manner, Axis will automatically locate the file, compile the class, and convert SOAP calls correctly into your service class's Java invocations. As you will see in the next section, the service name corresponds to the name of the .jws file. The magic that allows the Web server to invoke the Axis engine (i.e., servlet) when a .jws file is requested is located in the TOMCAT_HOME\webapps\axis\WEB-INF directory. This file's appropriate section is shown below:

<servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>*.jws</url-pattern>
 </servlet-mapping>

Based on the above configuration information, whenever Tomcat -- or any J2EE-compliant Web server -- encounters a .jws file in the Axis context (set up above during installation), it will invoke the AxisServlet. The AxisServlet then performs its magic as described above.

Create the client

Now let's create a simple client that we'll use to test the service. The code to do that is shown here:

package javaworld.axis;
import org.apache.axis.client.ServiceClient;
public class Client1
{
      public static void main(String[] args) throws Exception 
      {      
                String endpoint = "http://localhost:8080/axis/HelloServer.jws";
        
            ServiceClient client = new ServiceClient(endpoint);
            String ret = (String)client.invoke("","sayHelloTo",new Object [] {args[0]});
            System.out.println(ret);
      }   
}

As with Apache SOAP, the client code is a bit more involved than the server code. But it is much simpler than the equivalent Apache SOAP client code, which is also shown below for reference. To understand the code below, please refer to "Clean Up Your Wire Protocol with SOAP, Part 2."

package javaworld.axis
import java.net.URL;
import java.util.Vector;            
import org.apache.soap.SOAPException;
import org.apache.soap.Constants;
import org.apache.soap.Fault;
import org.apache.soap.rpc.Call;
import org.apache.soap.rpc.Parameter;
import org.apache.soap.rpc.Response;
                             
public class Client
{
   public static void main(String[] args) throws Exception 
   {      
         URL url = new URL("http://localhost:8080/apache-soap/servlet/rpcrouter");         
         String name = args[0];
         
         // Build the call.
         Call call = new Call();
         call.setTargetObjectURI("urn:Hello");
         call.setMethodName("sayHelloTo");
         call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);         
         Vector params = new Vector();         
         params.addElement(new Parameter("name", String.class, name, null));
         call.setParams(params);
         // Invoke the call.
         Response resp = null;         
         try
         {
            resp = call.invoke(url, "");
         }
         catch( SOAPException e )
         {
            System.err.println("Caught SOAPException (" + e.getFaultCode() + "): " + e.getMessage());
            System.exit(-1);
         }
   
         // Check the response.
         if( !resp.generatedFault() )
         {
            Parameter ret = resp.getReturnValue();
            Object value = ret.getValue();            
            System.out.println(value);
         }
         else
         {
            Fault fault = resp.getFault();            
            System.err.println("Generated fault: ");
            System.out.println ("  Fault Code   = " + fault.getFaultCode());  
            System.out.println ("  Fault String = " + fault.getFaultString());
         }
      }
      catch(Exception e)
      {
         e.printStackTrace();
      }
   }   
}

It should be obvious that Axis does a much better job shielding the client developer from the details. In the simplest case (as the one in this article), you need to create only an instance of the class org.apache.axis.client.ServiceClient, which requires the service endpoint as its constructor parameter. The endpoint here is http://localhost:8080/axis/HelloServer.jws, since (1) the Web server is on the same machine as the client; (2) Tomcat by default listens for HTTP requests on port 8080; and (3) the service is deployed as HelloServer.jws. Finally, you invoke any method on the service by simply calling the invoke() method on the ServiceClient instance. At the very least, invoke() requires both the method's name on the service to invoke, and an Object array of parameters.

Test the service

To test the service, begin by compiling the client using the following command sequence. Note that axis.jar must be included in the CLASSPATH to successfully compile the client application:

set CLASSPATH=AXIS_HOME\lib\axis.jar
javac Client1.java

Start Tomcat if it's not already started. To start Tomcat, run the startup.bat batch file located in TOMCAT_HOME\bin\. Next, run the client application:

set CLASSPATH=C:\dev\;AXIS_HOME\lib\axis.jar;AXIS_HOME\lib\log4j-core.jar
java javaworld.axis.Client1 John

This time, in addition to axis.jar, you must also include log4j-core.jar, which is the jar file that contains classes used by axis.jar's classes for logging. Also, C:\dev is the directory containing the javaworld package, so you must include it in the CLASSPATH too.

Deploy the Web service the flexible way

Deploying the Web service as a .jws file works for simple services such as the one in this article. However, this approach fails to meet most commercial Web services' flexibility requirements, such as the ability to specify custom type mappings or create handler chains. Instead, most deployments will probably use deployment files such as the one shown below for our Web service:

<m:deploy xmlns:m="AdminService">
 <service name="HelloServer" pivot="RPCDispatcher">
  <option name="className" value="javaworld.axis.HelloServer"/>
  <option name="methodName" value="sayHelloTo"/> 
 </service>
</m:deploy>

The deployment XML shown above is fairly simple and does not use or demonstrate any of the advanced features allowed in such deployment files. However, let's say that I wanted to define a logging mechanism in the form of an Axis handler -- handlers follow the Chain of Responsibility design pattern (see Resources). I could do this by simply adding the following section to the deployment file:

<!-- define a logging handler configuration -->
 <handler name="logger" class="loggers.LogHandler">
  <option name="filename" value="HelloServer.log"/>
 </handler>

As I mentioned earlier, Axis offers a much more flexible and capable deployment process. In the previous section, I illustrated how simple deploying Web services in Axis can be. In this section, I give you a peek into Axis's more flexible and capable aspects.

The configuration above is self-explanatory. I have basically created a new service that uses the class javaworld.axis.HelloServer and exposes the sayHelloTo() method. If I want to expose more methods, I would replace the single sayHelloTo() method name with a space-delimited list of method names. However, don't get too attached to this XML descriptor format: in Axis's final release, this XML will change to the Axis Web Service Deployment Descriptor (WSDD) format. The same configuration in WSDD format is shown below for reference:

<deployment xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 <service name="HelloServer" provider="java:RPC">
  <parameter name="className" value="javaworld.axis.HelloServer"/>
  <parameter name="methodName" value="sayHelloTo"/>
 </service>
</deployment>

Note: As of alpha 2, when deploying Web services as a .jws file, you should leave the service class in the default package, i.e., with no package declaration. On the other hand, when deploying services with a configuration file, as we did above, you should declare an explicit package -- for example, I've added a package javaworld.axis declaration in HelloServer.java. Following these guidelines will save you many headaches.

To deploy the service with a configuration file, follow these steps:

  1. Make sure that Tomcat is started.
  2. Create a javaworld\axis directory in the TOMCAT_HOME\webapps\axis\WEB-INF\classes\ directory.
  3. Compile HelloServer.java and copy the resulting HelloServer.class into the Axis directory created in Step 2. You don't need to set a CLASSPATH to compile HelloServer.java.
  4. Now execute the following commands:

    set CLASSPATH=C:\axis-1_0\lib\axis.jar;C:\axis-1_0\lib\log4j-core.jar;C:\xerces-1_4_4\xerces.jar
    java org.apache.axis.client.AdminClient deploy.xml
    

    Here, deploy.xml is a file that contains the configuration XML shown above, not the WSDD form. If you want to test the newly deployed Web service, just change the following line in the client:

    String endpoint = "http://localhost:8080/axis/HelloServer.jws";
    

    to:

    String endpoint = "http://localhost:8080/axis/servlet/AxisServlet";
    

    Also replace this line:

    String ret = (String)client.invoke("","sayHelloTo",new Object [] {args[0]});
    

    with:

    String ret = (String)client.invoke("HelloServer","sayHelloTo",new Object[]{args[0]});
    

    This time, instead of the endpoint being a .jws file, it is the AxisServlet. The servlet locates and instantiates an instance of the class corresponding to the service name HelloServer and converts the SOAP messages into Java calls. The servlet then invokes the Java calls on the instantiated service class.

Abstract SOAP altogether

Most toolkits used for client-side Web services development are criticized because they require the client to have protocol-specific (e.g., SOAP-specific) knowledge. Overcoming this shortcoming has garnered much interest since Web services are protocol independent. IBM has been working on a toolkit called the Web Services Invocation Framework (WSIF), which abstracts all SOAP knowledge and instead works directly off the WSDL service description.

Similarly, in "Clean Up Your Wire Protocol with SOAP, Part 4," I created a class based on Java dynamic proxies that would abstract all SOAP details and make using SOAP-based services as intuitive as using any other Java class. Axis does that as well, but in a different way. Axis takes Apache SOAP one step further; it understands WSDL. WSDL is an XML-based language for describing Web services. You can use Axis to create a proxy (or stub) for your clients to abstract away SOAP and thus ease client-side development; it's simple. Just run the wsdl2java tool using the following commands from the directory that contains the javaworld.axis package:

set CLASSPATH=C:\axis-1_0\lib\axis.jar;
   C:\axis-1_0\lib\log4j-core.jar;C:\xerces-1_4_4\xerces.jar;
   C:\axis-1_0\lib\wsdl4j.jar;C:\axis-1_0\lib\clutil.jar
java org.apache.axis.wsdl.Wsdl2java -p javaworld.axis.proxy http://localhost:8080/axis/HelloServer.jws?wsdl

wsdl2java creates Java classes from a Web service's WSDL description. Axis automatically generates WSDL for any deployed service when you append ?wsdl to the end of the service endpoint URL.

Now change the client as shown below:

package javaworld.axis;
public class Client2 
{
  public static void main(String[] args) throws Exception
  {
    
    javaworld.axis.proxy.HelloServer server = new javaworld.axis.proxy.HelloServer();
    javaworld.axis.proxy.HelloServerPortType port = server.getHelloServerPort();
 
    // make the call   
    String ret = port.sayHelloTo(args[0]);
    System.out.println(ret);
  }
}

Wow, that's neat! The client now interacts with the Web service in WSDL terms instead of SOAP terms. SOAP is completely abstracted away, and the client is now protocol neutral. You can try it by compiling the client as follows:

set CLASSPATH=C:\dev\;C:\axis-1_0\lib\axis.jar;C:\axis-1_0\lib\log4j-core.jar;
  C:\xerces-1_4_4\xerces.jar;C:\axis-1_0\lib\wsdl4j.jar;C:\axis-1_0\lib\clutil.jar
javac Client2.java

Then, run the client as shown here:

set CLASSPATH=C:\dev\;C:\axis-1_0\lib\axis.jar;C:\axis-1_0\lib\log4j-core.jar;
   C:\xerces-1_4_4\xerces.jar;C:\axis-1_0\lib\wsdl4j.jar;C:\axis-   1_0\lib\clutil.jar
java javaworld.axis.Client2 John

Axis turns around Apache SOAP

In this article, I have only scratched the surface of Axis's new features. Remember, Axis is not just a rewrite of Apache SOAP; it is a complete re-architecture. It provides a SOAP toolkit that offers more than a library to abstract SOAP messages. Axis also has built-in support for WSDL and lets you create client-side proxies (or stubs) using Web services' WSDL definitions. With all its new features, Axis has truly taken Apache SOAP to the next level.

Tarak Modi, a senior specialist at North Highland, has been architecting scalable, high-performance, distributed applications for more than seven years. His professional experience includes hardcore C++ and Java programming; working with Microsoft technologies such as COM, MTS, and COM+; Java-based technologies including J2EE; and CORBA. He has a bachelor's degree in electrical engineering, a master's degree in computer engineering, and an MBA concentrating in information systems. Tarak is coauthor of the upcoming book, Professional Java Web Services, from Wrox. To learn more about Tarak, please visit his Website at http://tmodi.home.att.net/.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more