.
Windows / Web Services with Axis and XMLBeans Example

< Web Services using Tomcat, Axis, and XMLBeans | Working With Windows | Getting rid of Nero Scout >

Web Services Example
Using Tomcat, Axis, XMLBeans, and Ant

Page Contents
The Contract
The Service
The Client
Deployment Configuration
Build, Deploy and Test

This is an adjunct to the Web Services using Tomcat, Axis, and XMLBeans page.

For this example, I will demonstrate a simplistic method for creating a web service for a bookstore. Given a list of books and a zip code for the shipping destination, the service should return a price for each book and the shipping charges. Our service will be called createInvoice. If this were a more in-depth example, we would probably look up the books in a database to determine availability and weight, and then figure shipping charges based on the book’s weight and our shipper’s rate charts; but this is just a proof of concept and we will simply generate random numbers in our Business Logic.

All the files I wrote that are needed for this project are included in bookstore-example.zip. Simply download that file and extract it somewhere using 7-Zip (or your favorite ZIP program). You may need to edit the init target of the Ant build file build.xml (in the top example directory) to adjust for your configuration.

That ZIP file provides the files for use directly in the Windows environment. If you will be using Cygwin and have it configured for Unix line terminators, then download bookstore-example-nl.zip instead.

Both ZIP files provide the following files:

example/

 |-- build.xml
 |-- contract/
 |   |-- basket.xsd
 |   `-- invoice.xsd
 |-- data/
 |   `-- test_basket.xml
 |-- deployment/
 |   |-- deploy.wsdd
 |   `-- undeploy.wsdd
 `-- src/
     `-- com/
         `-- mybookstore/
             |-- client/
             |   `-- BookstoreClient.java
             |-- service/
             |   `-- BookstoreService.java
             `-- test/
                 `-- BookstoreServiceTest.java

I use Cygwin and emacs as my development environment. If you prefer using the Command Window and Notepad (or some other Windows editors or IDEs for Java and XML), remember to use %ENVIRONMENT_VARIABLE% instead of $ENVIRONMENT_VARIABLE and to switch your slashes around backward.

For more information about Tomcat, Axis, and XMLBeans, including the procedure for installing them all correctly under Windows, see the Web Services using Tomcat, Axis, and XMLBeans page. For more information about Ant (a Java-based build tool) including installation instructions, see the apache.org Ant project website.

The Contract

This is a high-level contract, not the SOA service contract --- we let Axis handle that.

We want to send the createInvoice service enough information about the books desired to uniquely specify them --- actually, we will overspecify, otherwise we could just pass an integer (the ISBN) and miss out on all the XMLBeans fun. We want to be able to buy more than one book at a time, to hopefully save on S&H. In order to figure out the shipping costs, we need the destination zip code.

What we want back are (at least) the retail price for each book and a total S&H charge. We will ignore sales tax until Congress passes more laws to screw up the Internet commerce. It would be helpful to have a subtotal and a grand total provided as well, because our client program would like to be lazy.

We could use class instances to pass all this data back and forth; but, that quickly gets ugly if not downright impossible via Axis. A much simpler, cleaner way to pass this data is via XML; specifically a string containing XML-formatted data. This is where XMLBeans makes life really easy; at the price of learning XML Schema. XML Schema is a “means for defining the structure, content and semantics of XML documents” --- see the W3C (World Wide Web Consortium) XML Schema project page for more details. A good website providing understandable reference pages and tutorials for XML Schema is www.w3schools.com/schema.

The Request

The XML request might look something like this, with two books in our shopping basket:

<basket zipcode="46835" xmlns="http://mybookstore.com/basket">
  <book isbn="0201700735">
    <title>The C++ Programming Language: Special Edition</title>
    <author>Bjarne Stroustrup</author>
    <year>2000</year>
  </book>
  <book isbn="0072226846">
    <title>Java 2: Sun Certified Programmer &amp; Developer for Java 2</title>
    <author>Kathy Sierra</author>
    <author>Bert Bates</author>
    <publisher>Osborne Certification Press</publisher>
    <year>2003</year>
  </book>
</basket>

Here is the schema for the createInvoice request. The top-level element is a basket, which contains one or more book elements and has a required zipcode attribute. Each book contains:

  1. exactly one title element, whose value can be any string;
  2. one or more author elements, each whose value can be any string;
  3. an optional publisher element, whose value can be any string;
  4. an optional year element, whose value must be a 4 digit number in the range 1956--2007 (inclusive); and
  5. a required isbn attribute, whose value must be a 10 digit number, with leading zeros if necessary (e.g. 0072226846).

The value for the zipcode attribute must be a 5 digit number, with leading zeros if necessary (e.g. 01804).

example/contract/basket.xsd

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema
   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
   xmlns:bb="http://mybookstore.com/basket"
   targetNamespace="http://mybookstore.com/basket"
   elementFormDefault="qualified">

  <xs:element name="basket">
    <xs:annotation>
      <xs:documentation>
        A basket is a non-empty set of books destined for a specific zipcode.
      </xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element name="book" type="bb:book" maxOccurs="unbounded" />
      </xs:sequence>
      <xs:attribute name="zipcode" type="bb:zipcode" use="required" />
    </xs:complexType>
  </xs:element>

  <xs:complexType name="book">
    <xs:annotation>
      <xs:documentation>
        A book has to have a title and one or more authors. However, the
        publisher and year are optional.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="title" type="xs:string" />
      <xs:element name="author" type="xs:string" maxOccurs="unbounded" />
      <xs:element name="publisher" type="xs:string" minOccurs="0" />
      <xs:element name="year" type="bb:year" minOccurs="0" />
    </xs:sequence>
    <xs:attribute name="isbn" type="bb:isbn" use="required" />
  </xs:complexType>

  <xs:simpleType name="zipcode">
    <xs:annotation>
      <xs:documentation>
        A 5 digit number with leading zeroes
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9]{5}"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="isbn">
    <xs:annotation>
      <xs:documentation>
        A 10 digit number with leading zeroes
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9]{10}"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="year">
    <xs:annotation>
      <xs:documentation>
        We don't sell really old books or books from the future.
        Note that at least the maxInclusive value must be updated each year!
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:integer">
      <xs:minInclusive value="1956" />
      <xs:maxInclusive value="2007" />
    </xs:restriction>
  </xs:simpleType>

</xs:schema>

The Response

What we want back is an invoice: a list of items with the price listed for each, a subtotal, the S&H charge, and the grand total. Something like this:

<invoice zipcode="46835" xmlns="http://mybookstore.com/invoice">
  <book isbn="0201700735">
    <title>The C++ Programming Language: Special Edition</title>
    <author>Bjarne Stroustrup</author>
    <price>69.68</price>
  </book>
  <book isbn="0072226846">
    <title>Java 2: Sun Certified Programmer &amp; Developer for Java 2</title>
    <author>Kathy Sierra</author>
    <price>11.34</price>
  </book>
  <subtotal>81.02</subtotal>
  <charges>15.35</charges>
  <total>96.37</total>
</invoice>

I know a real bookstore would need a lot more than this (what about discounts, what if something is out of stock, etc.); but this is all we want for our example. Anyway, here is the schema for the createInvoice response. The top-level element is an invoice, which contains one or more book elements and pricing elements.

The invoice has a required zipcode attribute which must be a 5 digit number, with leading zeros if necessary (e.g. 01804).

For the invoice, each book contains:

  1. exactly one title element, whose value can be any string;
  2. exactly one author element, whose value can be any string (we just need the first author when printing our invoice);
  3. exactly one price element, whose value must be something called “money” (which I will explain shortly); and
  4. a required isbn attribute, whose value must be a 10 digit number, with leading zeros if necessary (e.g. 0072226846).

Finally, the invoice contains three required pricing elements, subtotal, charges (shipping and handling charges), and total, all of whose values must be that something called “money”. We define money as a non-negative number which includes a decimal point and two digits after the decimal, just like we typically express dollars and cents in the United States.

example/contract/invoice.xsd

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema
   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
   xmlns:bi="http://mybookstore.com/invoice"
   targetNamespace="http://mybookstore.com/invoice"
   elementFormDefault="qualified">

  <xs:element name="invoice">
    <xs:annotation>
      <xs:documentation>
        A invoice is an itemized list of books purchased, a subtotal, the 
        shipping charge, and the grand total.
      </xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element name="book" type="bi:book" maxOccurs="unbounded" />
        <xs:element name="subtotal" type="bi:money" />
        <xs:element name="charges" type="bi:money" />
        <xs:element name="total" type="bi:money" />
      </xs:sequence>
      <xs:attribute name="zipcode" type="bi:zipcode" use="required" />
    </xs:complexType>
  </xs:element>

  <xs:complexType name="book">
    <xs:annotation>
      <xs:documentation>
        For the invoice, we only need a title and the first listed author.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="title" type="xs:string" />
      <xs:element name="author" type="xs:string" />
      <xs:element name="price" type="bi:money" />
    </xs:sequence>
    <xs:attribute name="isbn" type="bi:isbn" use="required" />
  </xs:complexType>

  <xs:simpleType name="zipcode">
    <xs:annotation>
      <xs:documentation>
        A 5 digit number with leading zeroes
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9]{5}"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="isbn">
    <xs:annotation>
      <xs:documentation>
        A 10 digit number with leading zeroes
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9]{10}"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="money">
    <xs:annotation>
      <xs:documentation>
        Must be positive and no fractional pennies.
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:decimal">
      <xs:minInclusive value="0.00" />
      <xs:fractionDigits value="2" />
    </xs:restriction>
  </xs:simpleType>

</xs:schema>

I realize there are a few elements in common between these two schemas and I could have put those common elements in a third schema, and included that third schema in these two. But I didn’t.

These schemas will need to be processed by the XMLBeans program scomp. If one were to do this by hand, the equivalent command to what we have in the contract target in the build.xml Ant build script (see below) is:

scomp -src contract/src -out build/lib/contract.jar contract

This command processes the schemas in the contract directory (basket.xsd and invoice.xsd) into several classes, which are stored in build/lib/contract.jar. This command also instructs scomp to output into the contract/src directory all the Java source code for those classes (just because we are curious, not because it is needed). Note that scomp will create the src directory if one does not exist in contract; however, it will not create the lib directory in build. Go figure.

The Service

Here is the code for the BookstoreService class, which has only one method, createInvoice. createInvoice receives the basket XML as a string.

The XMLBeans paradigm is essentially that for a given top-level element, there is a “Document” class which represents the full schema instance. Contained in that “Document” class is a class representing the top-level element. So, for our basket schema, there is a BasketDocument class containing a Basket class. We can only get and set information from the Basket class; the BasketDocument class is just (to us) some necessary holder.

So in the createInvoice method, we use a BasketDocument.Factory.parse method to extract the basket document from the input XML string; and then we use the BasketDocument.getBasket method to get a Basket we can use.

Similarly, we use the InvoiceDocument.Factory.newInstance method to create a blank invoice document (which we will eventually return ); and then we use the InvoiceDocument.addNewInvoice method to create an Invoice we can use.

Remember, the XMLBeans scomp program has created all these basket and invoice classes and methods for us from our two schemas.

Next, the createInvoice method simply copies the zip code from the Basket to our new Invoice.

Then, we need to access all the books placed in the basket. We use the undocumented getBookList method instead of the getBookArray described in the XMLBeans documentation. This List method is a new feature of XMLBeans which (according to the comments in the source code generated by scomp) deprecates the Array method. I discovered it only because I was curious to see the source code scomp generated.

For each book in the basket, the createInvoice method simply copies the title, the first author specified, and the ISBN into a new book item in the invoice. We come up with a price and add that to the invoice book item. Notice that XMLBeans uses BigDecimal when dealing with numeric values in the schema. This is mentioned somewhere in the XMLBeans documentation, but was not readily apparent to me and tripped me up at first.

Finally, we compute and add to the invoice the subtotal, shipping charges, and grand total. Finally, we use the InvoiceDocument.toString method to serialize our invoice XML document so the createInvoice method can return it.

example/src/com/mybookstore/service/BookstoreService.java

package com.mybookstore.service;

import com.mybookstore.basket.BasketDocument;
import com.mybookstore.basket.BasketDocument.Basket;

import com.mybookstore.invoice.InvoiceDocument;
import com.mybookstore.invoice.InvoiceDocument.Invoice;

import org.apache.xmlbeans.*;

import java.util.*;
import java.math.BigDecimal;


public class BookstoreService
{
    public String createInvoice( String request_xml )
    {
       Random generator = new Random();
       String response_xml = new String();

       try {

          // Parse the input request (BASKET)
          BasketDocument basket_doc = BasketDocument.Factory.parse( request_xml );
          Basket mybasket = basket_doc.getBasket();

          // Initialize our response (INVOICE)
          InvoiceDocument invoice_doc = InvoiceDocument.Factory.newInstance();
          Invoice myinvoice = invoice_doc.addNewInvoice();

          // Copy the zip code from the basket to the invoice
          String zipcode = mybasket.getZipcode();
          myinvoice.setZipcode( zipcode );

          // Get the list of books from the basket 
          List<com.mybookstore.basket.Book> book_list = mybasket.getBookList();
          if (book_list.isEmpty()) {
             return "<error>The basket is empty</error>";
          }

          // For each book in the basket
          // 1. copy the title, first author, and ISBN to the invoice book list
          // 2. determine the price of the book (a random price under $100)
          int book_count = 0;
          double subtotal = 0.0;
          Iterator<com.mybookstore.basket.Book> i = book_list.iterator();
          while (i.hasNext()) {
             com.mybookstore.basket.Book basket_book  = i.next();
             com.mybookstore.invoice.Book invoice_book = myinvoice.addNewBook();

             invoice_book.setTitle( basket_book.getTitle() );
             invoice_book.setAuthor( basket_book.getAuthorArray( 0 ) );
             invoice_book.setIsbn( basket_book.getIsbn() );

             int price_cents = generator.nextInt( 10000 );
             double price = price_cents;
             price /= 100.0;
             BigDecimal book_price = 
                new BigDecimal( price ).setScale( 2, BigDecimal.ROUND_HALF_UP );

             invoice_book.setPrice( book_price );
             subtotal += price;
             ++book_count;
          }

          // Set the subtotal price in the invoice
          BigDecimal subtotal_price = 
             new BigDecimal( subtotal ).setScale( 2, BigDecimal.ROUND_HALF_UP );
          myinvoice.setSubtotal( subtotal_price );

          // Calculate the shipping charge and set it in the invoice
          // 1. Estimate the distance based on zip code
          // 2. Determine the shipping charge per book
          // 3. Multiply that by number of books to get total shipping charge
          double shipping = Double.parseDouble( zipcode );
          shipping = 1.00 + (Math.abs( 80207.0 - shipping )/5000.0);
          shipping *= book_count;
          BigDecimal shipping_price = 
             new BigDecimal( shipping ).setScale( 2, BigDecimal.ROUND_HALF_UP );
          myinvoice.setCharges( shipping_price );

          // Determine the grand total and set it in the invoice
          subtotal += shipping;
          BigDecimal total_price = 
             new BigDecimal( subtotal ).setScale( 2, BigDecimal.ROUND_HALF_UP );
          myinvoice.setTotal( total_price );

          // Serialize the invoice into a response string
          response_xml = invoice_doc.toString();
       }
       catch (Exception e) {
          response_xml = e.toString();
       }

       return response_xml;
    }
}

The Client

Here is the code for the BookstoreClient class. It simply reads the basket from an XML file specified on the command line, sends that to the BookstoreService.createInvoice method, and then looks at the invoice returned to report the subtotal (cost of the books), shipping, and total cost. As you look at this Java code, please remember I am a C/C++ programmer --- I am just bluffing my way through Java.

First, the client uses org.apache.axis.utils.Options to extract the Axis-specific arguments from the command line arguments. I have not yet been able to find any documentation for a full list of command line arguments supported by Options; however, I do know (from examples in various Axis documentation and tutorials) that there is a -lURL argument which specifies the URL for the service to call (in our case, http://localhost/axis/services/BookstoreService).

The remaining argument is supposed to be the path and name of an XML file containing the basket to be processed. We use java.io.File to open the file, and then use a BasketDocument.Factory.parse method which validates the XML while it parses it. Next, we check that the basket is not empty, though this is probably unnecessary since the schema requires at least one book element within the basket. Now we can serialize the BasketDocument into a string that we will send to the BookstoreService.

This client was hand-coded; I did not use the WSDL2Java capability of Axis. Doing that would hide all the nitty-gritty Service and Call stuff from us. For now, however, I just used the example from the tutorial and did it “the hard way.” I don’t really understand why the OperationName uses http://com/mybookstore/service rather than http://mybookstore.com/service; but that’s the way the example showed it and it works.

Finally, we use the InvoiceDocument.Factory.parse method to deserialize the returned invoice XML string, and then print out the pricing summary.

example/src/com/mybookstore/client/BookstoreClient.java

package com.mybookstore.client;

import com.mybookstore.basket.BasketDocument;
import com.mybookstore.basket.BasketDocument.Basket;

import com.mybookstore.invoice.InvoiceDocument;
import com.mybookstore.invoice.InvoiceDocument.Invoice;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import org.apache.axis.utils.Options;

import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;

import java.io.*;
import java.util.List;

public class BookstoreClient
{
   public static void main( String [] args )
   {

      // Process the options, primarily to extract the "-lURL" argument
      Options options = null;
      String endpointURL = null;
      try {
         options = new Options(args);
         endpointURL = options.getURL();
      } catch (Exception e) {
         System.err.println( e.toString() );
         return;
      }

      // The remaining argument specifies the file containing the basket XML
      args = options.getRemainingArgs();
      if ((args == null) || (args.length < 1)) {
         System.err.println( "ERROR: no basket XML file specified" );
         return;
      }

      // Parse the specified file into a BASKET
      File basketXmlFile = new File( args[0] );
      if (! basketXmlFile.exists()) {
         System.err.println( "ERROR: " + args[0] + " does not exist" );
         return;
      }

      BasketDocument request_xml = null;
      try {
         request_xml = BasketDocument.Factory.parse( basketXmlFile );
      } catch (Exception e) {
         System.err.println( "ERROR: unable to parse " + args[0] );
         System.err.println( e.toString() );
         return;
      }
      Basket mybasket = request_xml.getBasket();

      // Make sure the basket isn't empty
      List<com.mybookstore.basket.Book> book_list = mybasket.getBookList();
      if (book_list.isEmpty()) {
         System.err.println( "ERROR: there are no books in the basket" );
         return;
      }

      // Serialize the basket into a request string
      String request = request_xml.toString();
      System.out.println( "REQUEST:" );
      System.out.println( request );

      // Call the BookstoreService createInvoice method with the request string
      String response = null;
      try {
         Service  service = new Service();
         Call     call    = (Call) service.createCall();

         call.setTargetEndpointAddress( new java.net.URL(endpointURL) );
         call.setOperationName( new QName( "http://com/mybookstore/service",
                                           "createInvoice" ) );
         call.addParameter( "arg1", XMLType.XSD_STRING, ParameterMode.IN );
         call.setReturnType( org.apache.axis.encoding.XMLType.XSD_STRING );

         response = (String) call.invoke( new Object[] { request } );
      } catch (Exception e) {
         System.err.println( e.toString() );
         return;
      }

      System.out.println( "RESPONSE: " );
      System.out.println( response );

      // Parse the INVOICE from the response string
      InvoiceDocument response_xml = null;
      try {
         response_xml = InvoiceDocument.Factory.parse( response );
      } catch (Exception e) {
         System.err.println( "ERROR: unable to parse response" );
         return;
      }

      Invoice invoice = response_xml.getInvoice();

      // I'm lazy here and just print out the subtotal, shipping, and total
      System.out.println( "Subtotal: " + invoice.getSubtotal().toString() );
      System.out.println( "     S&H: " + invoice.getCharges().toString() );
      System.out.println( "   Total: " + invoice.getTotal().toString() );

   }
}

Deployment Configuration

Here are the WSDD files I use to deploy and undeploy BookstoreService as an Axis service.

example/deployment/deploy.wsdd

<deployment xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

  <service name="BookstoreService" provider="java:RPC">
    <parameter name="className" value="com.mybookstore.service.BookstoreService" />
    <parameter name="allowedMethods" value="createInvoice" />
  </service>

</deployment>

example/deployment/undeploy.wsdd

<undeployment xmlns="http://xml.apache.org/axis/wsdd/">
  <service name="BookstoreService"/>
</undeployment>

Build, Deploy and Test

Here is my rather involved Ant build script.

  • To build everything, simply run ant.
  • To deploy the BookstoreService, run ant deploy; if anything needs building, that will be done as well. The deploy target also takes care of stopping and restarting the Axis service within Tomcat, so that the new BookstoreService is immediately available.
  • To do a test run of the BookstoreClient, run ant client-test. This makes sure everything is built, but it does not make sure the BookstoreService is deployed (after all, one might want to test what happens when that service isn’t deployed).
  • If things don’t work because Java cannot find a class, try ant path-debug; it displays the values of all the classpaths used.

example/build.xml

<?xml version="1.0" ?>
<project name="BookstoreExample" 
      basedir="." 
      default="build">
  <description>
The master ant build file for the Bookstore Example.

The following environment variables are required:
    CATALINA_HOME   where Tomcat is installed
    AXIS_HOME       where Axis is installed
    AXIS_WEBINF     where the Axis WEB-INF directory is located
    XMLBEANS_HOME   where XMLBeans is installed
  </description>

  <!-- init ======================================================== -->
  <target name="init">

    <property environment="env" />
    <echo>${ant.project.name} project</echo>
    <echo>${ant.version}</echo>
    <echo>Java version ${ant.java.version}</echo>

    <!-- project properties -->
    <property name="build"
          location="build" />
    <property name="build.lib"
          location="${build}/lib" />
    <property name="src" 
          location="src" />
    <property name="package.dir"  
             value="com/mybookstore" />
    <property name="package.spec"
             value="com.mybookstore" />

    <!-- Tomcat properties and tasks -->
    <available property="tomcat.home"
                  value="${env.CATALINA_HOME}"
                   file="${env.CATALINA_HOME}"
                   type="dir" />
    <fail message="Set CATALINA_HOME in your environment"
           unless="tomcat.home" />
    <echo>tomcat.home: ${tomcat.home}</echo>

    <available property="tomcat.lib"
                  value="${tomcat.home}/server/lib"
                   file="${tomcat.home}/server/lib/catalina-ant.jar" />
    <fail message="Cannot find catalina-ant.jar in your Tomcat installation"
           unless="tomcat.lib" />

    <property name="tomcat.url"
             value="http://localhost/manager" />
    <property name="tomcat.uname"
             value="admin" />
    <property name="tomcat.pword"
             value="secret" />
    <property name="tomcat.axis.path"
             value="/axis" />

    <path id="tomcat.classpath">
      <pathelement location="${tomcat.lib}/catalina-ant.jar" />      
    </path>

    <taskdef name="tomcat.start"
        classname="org.apache.catalina.ant.StartTask"
     classpathref="tomcat.classpath" />

    <taskdef name="tomcat.stop"
        classname="org.apache.catalina.ant.StopTask"
     classpathref="tomcat.classpath" />

    <!-- Axis properties -->
    <available property="axis.home" 
                  value="${env.AXIS_HOME}"
                   file="${env.AXIS_HOME}"
                   type="dir" />
    <fail message="Set AXIS_HOME in your environment"
           unless="axis.home" />
    <echo>axis.home: ${axis.home}</echo>

    <available property="axis.webinf" 
                  value="${env.AXIS_WEBINF}"
                   file="${env.AXIS_WEBINF}"
                   type="dir" />
    <fail message="Set AXIS_WEBINF in your environment"
           unless="axis.webinf" />
    <echo>axis.webinfo: ${axis.webinf}</echo>

    <property name="axis.web.classes" 
             value="${axis.webinf}/classes" />
    <property name="axis.web.lib" 
             value="${axis.webinf}/lib" />

    <path id="axis.classpath">
      <fileset dir="${axis.webinf}/lib">
        <include name="**/*.jar" />
      </fileset>
    </path>

    <taskdef resource="axis-tasks.properties"
         classpathref="axis.classpath" />

    <property name="axis.server.hostname"
             value="localhost" />
    <property name="axis.server.port"
             value="80" />
    <property name="axis.server.url"
             value="http://${axis.server.hostname}:${axis.server.port}" />
    <property name="axis.services.path"
             value="axis/services" />
    <property name="axis.services.url"
             value="${axis.server.url}/${axis.services.path}" />
    <property name="axis.admin.servlet" 
             value="${axis.services.path}/AdminService" />

    <!-- XMLBeans properties -->
    <available property="xmlbeans.home" 
                  value="${env.XMLBEANS_HOME}"
                   file="${env.XMLBEANS_HOME}"
                   type="dir" />
    <fail message="Set XMLBEANS_HOME in your environment."
           unless="xmlbeans.home" />
    <echo>xmlbeans.home: ${xmlbeans.home}</echo>

    <property name="xmlbeans.lib"
             value="${xmlbeans.home}/lib" />

    <path id="xmlbeans.path">
      <fileset dir="${xmlbeans.lib}" 
          includes="*.jar" />
    </path>

    <taskdef name="xmlbean"
        classname="org.apache.xmlbeans.impl.tool.XMLBean"
     classpathref="xmlbeans.path" />

    <!-- contract properties -->
    <property name="contract"
          location="contract" />
    <property name="contract.src"
             value="${contract}/src" />
    <property name="contract.jar"
             value="contract.jar" />
    <property name="contract.build.target"   
             value="${build.lib}/${contract.jar}" />
    <property name="contract.install.target" 
             value="${axis.web.lib}/${contract.jar}" />

    <!-- service properties -->
    <property name="service.name" 
             value="BookstoreService" />
    <property name="service.dir"  
             value="${package.dir}/service" />
    <property name="service.class" 
             value="${service.dir}/${service.name}.class" />
    <property name="service.build.target"   
             value="${build}/${service.class}" />
    <property name="service.install.target" 
             value="${axis.web.classes}/${service.class}" />
    <property name="deploy.config.dir" 
             value="deployment" />
    <property name="service.deploy.wsdd"   
             value="${deploy.config.dir}/deploy.wsdd" />
    <property name="service.undeploy.wsdd" 
             value="${deploy.config.dir}/undeploy.wsdd" />
    <property name="service.url"
             value="${axis.services.url}/${service.name}" />

    <!-- client properties -->
    <property name="client.name" 
             value="BookstoreClient" />
    <property name="client.dir"  
             value="${package.dir}/client" />
    <property name="client.class" 
             value="${client.dir}/${client.name}.class" />
    <property name="client.spec"
             value="${package.spec}.client" />
    <property name="client.classname"
             value="${client.spec}.${client.name}" />
    <property name="client.xmlfile"
             value="data/test_basket.xml" />

    <path id="client.classpath">
      <path path="${build}" />
      <path location="${contract.build.target}" />
      <path refid="xmlbeans.path" />
      <path refid="axis.classpath" />
    </path>

    <!-- service test program properties -->
    <property name="service.test.name"
             value="BookstoreServiceTest" />
    <property name="service.test.spec"
             value="${package.spec}.test" />
    <property name="service.test.classname"
             value="${service.test.spec}.${service.test.name}" />
    <property name="service.test.xmlfile"
             value="data/test_basket.xml" />

    <path id="service.test.classpath">
      <path location="${build}" />
      <path location="${contract.build.target}" />
      <path refid="xmlbeans.path" />
    </path>

    <!-- project directory setup -->
    <mkdir dir="${build}" />
    <mkdir dir="${build.lib}" />
    <mkdir dir="${contract.src}" />

  </target>

  <!-- clean ======================================================= -->
  <target name="clean" 
       depends="init" 
   description="Start from scratch">

    <delete dir="${build}" />
    <delete dir="${contract.src}" />

  </target>

  <!-- path-debug ================================================== -->
  <target name="path-debug"
       depends="init"
   description="Print out the classpaths defined in init">

    <property name="axis.classpath.value" 
             refid="axis.classpath" />
    <echo>
axis.classpath: 
${axis.classpath.value}
    </echo>

    <property name="xmlbeans.path.value" 
             refid="xmlbeans.path" />
    <echo>
xmlbeans.path: 
${xmlbeans.path.value}
    </echo>

    <property name="client.classpath.value" 
             refid="client.classpath" />
    <echo>
client.classpath:
${client.classpath.value}
    </echo>

    <property name="service.test.classpath.value" 
             refid="service.test.classpath" />
    <echo>
service.test.classpath: 
${service.test.classpath.value}
    </echo>

  </target>

  <!-- build ======================================================= -->
  <target name="build" 
       depends="init,contract,compile"
   description="Build the Bookstore Example service and client">

  </target>

  <!-- contract ==================================================== -->
  <target name="contract" 
       depends="init,contract.check,contract.jar"
   description="Use XMLBeans to process the contract XML Schemas" >

  </target>

  <target name="contract.check" 
       depends="init">

    <uptodate property="contract.notRequired"
            targetfile="${contract.build.target}">
      <srcfiles dir="${contract}" 
           includes="**/*.xsd" />
    </uptodate>

  </target>

  <target name="contract.jar" 
       depends="init,contract.check"
        unless="contract.notRequired">

    <xmlbean schema="contract"
           destfile="${contract.build.target}"
          srcgendir="${contract.src}"
       classpathref="xmlbeans.path"
         javasource="1.5" />

  </target>

  <!-- compile ===================================================== -->
  <target name="compile" 
       depends="init,contract"
   description="Compile the service and client">

    <javac srcdir="${src}"
          destdir="${build}">
      <classpath>
        <path location="${contract.build.target}" />
        <path refid="xmlbeans.path" />
        <path refid="axis.classpath" />
      </classpath>
    </javac>

  </target>

  <!-- deploy ====================================================== -->
  <target name="deploy"
       depends="init,contract,compile"
   description="Deploy the service to AXIS">
    <copy file="${service.build.target}"
        tofile="${service.install.target}" />
    <copy file="${contract.build.target}"
        tofile="${contract.install.target}" />
    <echo>xmlfile: ${service.deploy.wsdd}</echo>
    <axis-admin hostname="${axis.server.hostname}"
                    port="${axis.server.port}"
             failonerror="false"
             servletpath="${axis.admin.servlet}"
                 xmlfile="${service.deploy.wsdd}" />
    <tomcat.stop url="${tomcat.url}"
            username="${tomcat.uname}" 
            password="${tomcat.pword}"
                path="${tomcat.axis.path}" />
    <tomcat.start url="${tomcat.url}"
             username="${tomcat.uname}" 
             password="${tomcat.pword}"
                 path="${tomcat.axis.path}" />
  </target>

  <!-- undeploy ==================================================== -->
  <target name="undeploy" 
       depends="init" 
   description="Undeploy the service">
    <echo>xmlfile: ${service.undeploy.wsdd}</echo>
    <axis-admin hostname="${axis.server.hostname}"
                    port="${axis.server.port}"
             failonerror="false"
             servletpath="${axis.admin.servlet}"
                 xmlfile="${service.undeploy.wsdd}" />
    <tomcat.stop url="${tomcat.url}"
            username="${tomcat.uname}" 
            password="${tomcat.pword}"
                path="${tomcat.axis.path}" />
    <delete file="${service.install.target}"
     failonerror="false" />
    <delete file="${contract.install.target}"
     failonerror="false" />
    <tomcat.start url="${tomcat.url}"
             username="${tomcat.uname}" 
             password="${tomcat.pword}"
                 path="${tomcat.axis.path}" />
  </target>

  <!-- service-test ================================================ -->
  <target name="service-test"
       depends="init,compile"
   description="Runs the service test program">
    <echo>Attempting to run ${service.test.classname}</echo>
    <java classname="${service.test.classname}"
        failonerror="false"
       classpathref="service.test.classpath">
      <arg value="${service.test.xmlfile}" />
    </java>
  </target>

  <!-- client-test ================================================= -->
  <target name="client-test"
       depends="init,compile"
   description="Runs the client program with test data">
    <echo>Attempting to run ${client.classname}</echo>
    <java classname="${client.classname}"
        failonerror="false"
       classpathref="client.classpath">
      <arg value="-l${service.url}" />
      <arg value="${client.xmlfile}" />
    </java>
  </target>

</project>

< Web Services using Tomcat, Axis, and XMLBeans | Working With Windows | Getting rid of Nero Scout >


What we obtain too cheap, we esteem too lightly: it is dearness only that gives every thing its value.

Thomas Paine
The American Crisis, 1776

A2 Web Hosting
Creative Commons License
Get your Domain at GoDaddy.com
search engine by freefind advanced

loaded 2025-05-20 16:28:10 • last modified 2015-07-14 12:08:40
Privacy PolicyDisclaimer
• awcolley.com is powered by PmWiki
• all content (unless otherwise noted) © 2025 A W Colley