I used Apache Axis for three separate variations of the test application. The first is a doc/lit version that's pretty much equivalent to the JAX-RPC RI one. The second is using Castor data binding for converting payloads to and from XML, as has been recommended by several articles and discussions on the Axis lists. The third is an rpc/enc version, added to the tests only for comparison purposes (since rpc/enc is a legacy approach that should no longer be used).

The distribution zip for each Axis version includes its own build.xml Ant build file in the root directory of the unpacked zip. Before running Ant you'll need to modify the build.properties file in the root directory to define the path for the Axis distribution on your system. The default Ant target in each case builds the client and server code for the test application, respectively to the /build/client/classes and /build/server/classes directories. For details on deploying and running the generated code, see the "Deploying and running" section at the bottom of this page.

The customized code for each version of the application is in the /src directory tree of the distribution. This includes a copy of the earthquake data for the server, along with versions of the server QuakeBase class and the test client modified to work with the generated data classes. On the server side, it also includes one class that is initially generated by Axis but then modified to actually call the service implementation. In the case of the rpc/enc version, this customized code tree also contains the template class definitions used only for generating the original WSDL.

Axis conventions and build practices seem to change without much notice, so you may encounter problems with building these versions of the test application using different Axis distributions. The Axis 1.2 Beta distribution, for instance, does not include the Castor serializer and deserializer code, so you'll need to rebuild this yourself (or build those classes and add them in directly) if you want to test with that distribution. The Axis 1.2 Beta also used a slightly different convention for names generated by the WSDL2Java tool, so you'll also need to correct compile errors in some of the prebuild code.

Axis doc/lit

Support for doc/lit in Axis has historically been very spotty. I was unable to build the test application as a doc/lit service using Axis 1.1, for instance. This support is greatly improved in the 1.2 series, though, and I had no problems with the basic implementation using recent builds.

The doc/lit support still has some limitations, though, as compared with the JAX-RPC RI (which includes Sun's extensions to the JAX-RPC standard). These mainly involved the types used in the schema description of the XML data. My original schema included one use of an xs:token type, as well as xs:ID and xs:IDREF types as links between XML component strutures. Axis used its own specialized classes for all of these, which I found unhelpful (especially because the classes used for the xs:ID and xs:IDREF were basically just String wrappers, with no way of treating these as linkages between objects). I finally just converted all of these to xs:string and handled the links between objects via my own string-to-object maps.

Once I'd simplified the schema to avoid these problem types I was able to run code generation from WSDL using the supplied WSDL2Java tool and modify the classes as necessary to hook into my actual service implementation. The Ant build.xml for this example handles the details of running the WSDL2Java tool to generate code in the /build/generate directory tree, then copies the appropriate generated classes to the /build/client and /build/server directory trees and merges in prebuilt code from the /src/client and /src/server directory trees. The prebuilt server code includes the com.sosnoski.seismic.axislit.SeismicBindingImpl class that actually implements the service, which replaces the null server implementation generated each time by WSDL2Java.

Axis Castor

Using Castor for marshalling and unmarshalling of the XML payloads in SOAP messages is not a trivial process, but I've found it can be scripted to work in a reasonably consistent manner. The approach I took for this test application was to first run the Axis WSDL2Java tool with a WSDL file that uses a simplified form of the schema. This simplified schema defines dummy "query" and "results" elements that WSDL2Java turns into simple bean classes. I then run Castor code generation from the full XML schema to generate the real data classes, using a customization to generate class names for the root request and response objects that match what Axis generated. Next I separate out the classes into client and server directory structures, and use text substitution to replace the references to the normal serializer and deserializer used by Axis with the Castor equivalents. This is a much cleaner approach than was outlined in previous articles and discussions of using Castor with Axis.

Castor has very good support for schema features and types, and is able to handle the simple schema used by the test application without any problems. This makes it an excellent alternative to the default doc/lit handling in Axis, as long as performance is not a major concern (see the performance results to see why this may be an issue).

The Ant build.xml for this example handles the details of running first the WSDL2Java tool and then the Castor code generation to generate code in the /build/generate directory tree, then copies the appropriate generated classes to the /build/client and /build/server directory trees and merges in prebuilt code from the /src/client and /src/server directory trees. The prebuilt server code includes the com.sosnoski.seismic.axiscastor.SeismicBindingImpl class that actually implements the service, which replaces the null server implementation generated each time by WSDL2Java.

Axis rpc/enc

The easiest way to implement an rpc/enc service is generally by starting from the actual code, and this is what I did for my example service implementation on Axis 1.2. I start by running the Java2WSDL tool to generate an rpc/enc WSDL service description from a set of template classes for the web service, then run WSDL2Java to generate Java classes that match Axis' expectations. Then I merge my actual implementation code into the generated class structure, replacing the null server implementation generated by WSDL2Java.

As with the other versions of the code for Axis, the Ant build.xml for this example handles all the details of this process.

Deploying and Running

Rather than build deployable war files for each version of the test application using Axis, I just compile the server code for these into the appropriate /build/server/classes directory as part of the default Ant target in the supplied build.xml. If you deploy the Axis web application (supplied with Axis distributions as /webapps/axis) to your servlet engine, you can then copy the contents of the /build/server/classes directory created by running this Ant build to the /WEB-INF/classes directory of the Axis web application in order to prepare the service for deployment. You can use the same Axis instance for all three variations of the application, just ignore the duplicated data files.

After you've copied the files to your Axis application and started the servlet engine, you can deploy each service with the corresponding "deploy" Ant target. The "run" target will then run a simple test to verify that everything is working.

I've included the run.sh Linux shell script I used in the actual timing test runs (calling this one from a separate script that ran each set of command line arguments in sequence). Here again, you'll need to modify this script to match your installation in order to run the tests yourself.

The full code downloads as zip file are here: doc/lit version, Castor version, and rpc/enc version.