How to “Axis” Web Services

From the Apache Axis web site

&#8220 Apache Axis is an implementation of the SOAP (“Simple Object Access Protocol”) submission to W3C.

From the draft W3C specification:

SOAP is a lightweight protocol for exchanging structured information in a decentralized, distributed environment. It is an XML based protocol that consists of three parts: an envelope that defines a framework for describing what is in a message and how to process it, a set of encoding rules for expressing instances of application-defined datatypes, and a convention for representing remote procedure calls and responses.

This project is a follow-on to the Apache SOAP project.

&#8221

We used Axis recently on a project where we needed to regularly poll a server to retrieve alerts and pre-generated reports. One of my pet peeves with SOAP is how complicated it is just to set up a simple web service. You wind up with these big and nasty XML request and response structures. XML is meant to be readable – some of the SOAP requests and responses I’ve seen are massive and it can be very difficult to find the actual meat of the messages when they’re buried inside the SOAP structures. Anyway, the good news is this:

Axis takes care of all of the SOAP communication.How does it do this you ask? Axis includes a pair of utilities: Java2WSDL and WSDL2Java that generate the WSDL file and Java classes needed effectively taking care of the details of the SOAP communication.

Here’s what is involved to set up a service as part of your web application.

  1. Download the axis jar and include it in your webapp’s WEB-INF/lib directory.
  2. Register the axis servlet in your web.xml file.
  3. Write the service – the business logic – and define a XML deployment descriptor so that axis knows about your service.
  4. Generate the WSDL file.
  5. Generate the java code needed for communicating with your service and use it in your client code.

A Step by step example: The PingService.

We created a ping service that would send back a response whenever it was called. We used it as a heartbeat monitor for our server.

Here’s the PingService code:

package ca.intelliware.webservice;

public class PingService {
  public String ping() {
    return "Hi There";
  }
}

The deployment descriptor for this service is shown below:

<deployment xmlns="http://xml.apache.org/axis/wsdd/"
  xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
...
<service name="PingService" provider="java:RPC">
  <parameter name="className" value="ca.intelliware.webservice.PingService"/>
  <parameter name="allowedMethods" value="*"/>
  <parameter name="scope" value="Session"/>
</service>
...
</deployment>

This snippet of XML is part of the server-config.wsdd file. This file gets deployed as part of the web app and resides in the WEB-INF directory.

The important parts of the web.xml are shown below:

...
<listener>
  <listener-class>org.apache.axis.transport.http.AxisHTTPSessionListener</listener-class>
</listener>
...
<servlet>
  <servlet-name>AxisServlet</servlet-name>
  <display-name>Apache-Axis Servlet</display-name>
  <servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
</servlet>

<servlet>
  <servlet-name>AdminServlet</servlet-name>
  <display-name>Axis Admin Servlet</display-name>
  <servlet-class>org.apache.axis.transport.http.AdminServlet</servlet-class>
  <load-on-startup>100</load-on-startup>
</servlet>

<servlet>
  <servlet-name>SOAPMonitorService</servlet-name>
  <display-name>SOAPMonitorService</display-name>
  <servlet-class>org.apache.axis.monitor.SOAPMonitorService</servlet-class>
  <init-param>
    <param-name>SOAPMonitorPort</param-name>
    <param-value>5001</param-value>
  </init-param>
  <load-on-startup>100</load-on-startup>
</servlet>
...
<servlet-mapping>
  <servlet-name>AxisServlet</servlet-name>
  <url-pattern>/servlet/AxisServlet</url-pattern>
</servlet-mapping>

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

<servlet-mapping>
  <servlet-name>AxisServlet</servlet-name>
  <url-pattern>/services/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>SOAPMonitorService</servlet-name>
  <url-pattern>/SOAPMonitor</url-pattern>
</servlet-mapping>

<!-- uncomment this if you want the admin servlet -->
<servlet-mapping>
  <servlet-name>AdminServlet</servlet-name>
  <url-pattern>/servlet/AdminServlet</url-pattern>
</servlet-mapping>
...
<!-- currently the W3C haven't settled on a media type for WSDL;
  http://www.w3.org/TR/2003/WD-wsdl12-20030303/#ietf-draft
  for now we go with the basic 'it's XML' response -->
<mime-mapping>
  <extension>wsdl</extension>
  <mime-type>text/xml</mime-type>
</mime-mapping>
...

Once deployed to the webserver you can get the WSDL file that describes how to use the service by hitting the following URL:

http://localhost:8080/myWebapp/services/PingService?wsdl

The returned WSDL file looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://localhost:8080/myWebapp/services/PingService"
  xmlns:apachesoap="http://xml.apache.org/xml-soap"
  xmlns:impl="http://localhost:8080/myWebapp/services/PingService"
  xmlns:intf="http://localhost:8080/myWebapp/services/PingService"
  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.4 Built on Apr 22, 2006 (06:55:48 PDT)-->

   <wsdl:message name="pingRequest">
   </wsdl:message>

   <wsdl:message name="pingResponse">
      <wsdl:part name="pingReturn" type="xsd:string"/>
   </wsdl:message>

   <wsdl:portType name="PingService">
      <wsdl:operation name="ping">
         <wsdl:input message="impl:pingRequest" name="pingRequest"/>
         <wsdl:output message="impl:pingResponse" name="pingResponse"/>
      </wsdl:operation>
   </wsdl:portType>

   <wsdl:binding name="PingServiceSoapBinding" type="impl:PingService">
      <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="ping">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="pingRequest">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
              namespace="http://webservice.intelliware.ca" use="encoded"/>
         </wsdl:input>
         <wsdl:output name="pingResponse">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
              namespace="http://localhost:8080/myWebapp/services/PingService" use="encoded"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>

   <wsdl:service name="PingServiceService">
      <wsdl:port binding="impl:PingServiceSoapBinding" name="PingService">
         <wsdlsoap:address location="http://localhost:8080/myWebapp/services/PingService"/>
      </wsdl:port>
   </wsdl:service>

</wsdl:definitions>

By using the above WSDL file and the WSDL2Java utility you can now generate java code for the client class to use to access the PingService. Here’s how to use the WSDL2Java utility:

java org.apache.axis.wsdl.WSDL2Java -o . -d Session -p ca.intelliware.webservice http://localhost:8080/myWebapp/services/PingService?wsdl

This will generate the following classes:

  1. PingService_PortType.java
  2. PingServiceService.java
  3. PingServiceServiceLocator.java
  4. PingServiceSoapBindingStub.java

Here’s the client code which shows how the generated classes are used:

package ca.intelliware.client;

import java.net.URL;
import org.apache.axis.client.Stub;
import org.apache.log4j.Logger;

public class Pinger {

  protected final String url;
  protected Logger logger = Logger.getLogger(getClass());

  public Pinger() {
    this.url = "http://localhost:8080/myWebapp/services/PingService";
  }

  public boolean ping() {
    try {
      logger.debug("pinging server at: " + url);

      PingServiceServiceLocator locator = new PingServiceServiceLocator();
      locator.setMaintainSession(true);
      PingService_PortType service = locator.getPingService(new URL(url));
      Stub stub = (Stub) service;
      stub.setMaintainSession(true);
      service.ping();

      return true;
    } catch (Exception e) {
      logger.error("Error:", e);
    }
    return false;
  }
}

This Pinger class is created in a separate thread and pings the server every few seconds to test the connection.

Obviously this is a very simple example. We created a number of other services that had more meat to them but this at least shows the steps involved in getting a service up and running. The best part is that you don’t have to touch the SOAP messages at all if you don’t want to.

P.

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply