Generating a Web Service Client using Axis2 and JiBX

This document explains how to generate a Web service client using Axis2 and JiBX data binding. The service has the following WSDL:

Code Listing 1: The WSDL file

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
   xmlns:apachesoap="http://xml.apache.org/xml-soap"
   xmlns:impl="http://apache.org/axis2/Axis2UserGuide"
   xmlns:intf="http://apache.org/axis2/Axis2UserGuide"
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
   xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   targetNamespace="http://apache.org/axis2/Axis2UserGuide">

  <wsdl:types>
    <schema
       elementFormDefault="qualified"
       targetNamespace="http://apache.org/axis2/Axis2UserGuide"
       xmlns="http://www.w3.org/2001/XMLSchema">
      
      <!-- ELEMENTS -->
      
      <element name="DoInOnlyRequest">
        <complexType>
          <sequence>
            <element name="messageString" type="xsd:string"/>
          </sequence>
        </complexType>
      </element>
      
      <element name="TwoWayOneParameterEchoRequest">
        <complexType>
          <sequence>
            <element name="echoString" type="xsd:string"/>
          </sequence>
        </complexType>
      </element>
      <element name="TwoWayOneParameterEchoResponse">
        <complexType>
          <sequence>
            <element name="echoString" type="xsd:string"/>
          </sequence>
        </complexType>
      </element>
      
      <element name="NoParametersRequest">
        <complexType/>
      </element>
      <element name="NoParametersResponse">
        <complexType/>
      </element>
      
      <element name="MultipleParametersAddItemRequest">
        <complexType>
          <sequence>
            <element name="itemId" type="xsd:int"/>
            <element name="itemName" type="xsd:string"/>
            <element name="price" type="xsd:float"/>
            <element name="description" type="xsd:string"/>
          </sequence>
        </complexType>
      </element>

      <element name="MultipleParametersAddItemResponse">
        <complexType>
          <sequence>
          <element name="itemId" type="xsd:int"/>
          <element name="successfulAdd" type="xsd:boolean"/>
          </sequence>
        </complexType>
      </element>

    </schema>
  </wsdl:types>

  
  <!-- MESSAGES -->

  <wsdl:message name="DoInOnlyRequestMessage">
    <wsdl:part name="input" element="impl:DoInOnlyRequest"/>
  </wsdl:message>

  <wsdl:message name="TwoWayOneParameterEchoRequestMessage">
    <wsdl:part name="input" element="impl:TwoWayOneParameterEchoRequest"/>
  </wsdl:message>
  <wsdl:message name="TwoWayOneParameterEchoResponseMessage">
    <wsdl:part name="output" element="impl:TwoWayOneParameterEchoResponse"/>
  </wsdl:message>

  <wsdl:message name="NoParametersRequestMessage">
    <wsdl:part name="input" element="impl:NoParametersRequest"/>
  </wsdl:message>
  <wsdl:message name="NoParametersResponseMessage">
    <wsdl:part name="output" element="impl:NoParametersResponse"/>
  </wsdl:message>

  <wsdl:message name="MultipleParametersAddItemRequestMessage">
    <wsdl:part name="input" element="impl:MultipleParametersAddItemRequest"/>
  </wsdl:message>
  <wsdl:message name="MultipleParametersAddItemResponseMessage">
    <wsdl:part name="output" element="impl:MultipleParametersAddItemResponse"/>
  </wsdl:message>


  <!-- Port type (operations) -->

  <wsdl:portType name="Axis2UserGuidePortType">

    <wsdl:operation name="DoInOnly" parameterOrder="input">
      <wsdl:input name="DoInOnlyRequestMessage"
                  message="impl:DoInOnlyRequestMessage"/>
    </wsdl:operation>

    <wsdl:operation name="TwoWayOneParameterEcho" parameterOrder="input">
      <wsdl:input name="TwoWayOneParameterEchoRequestMessage"
                  message="impl:TwoWayOneParameterEchoRequestMessage"/>
      <wsdl:output name="TwoWayOneParameterEchoResponseMessage"
                  message="impl:TwoWayOneParameterEchoResponseMessage"/>
    </wsdl:operation>

    <wsdl:operation name="NoParameters" parameterOrder="input">
      <wsdl:input name="NoParametersRequestMessage"
                  message="impl:NoParametersRequestMessage"/>
      <wsdl:output name="NoParametersResponseMessage"
                   message="impl:NoParametersResponseMessage"/>
    </wsdl:operation>

    <wsdl:operation name="MultipleParametersAddItem" parameterOrder="input">
      <wsdl:input name="MultipleParametersAddItemRequestMessage"
                  message="impl:MultipleParametersAddItemRequestMessage"/>
      <wsdl:output name="MultipleParametersAddItemResponseMessage"
                  message="impl:MultipleParametersAddItemResponseMessage"/>
    </wsdl:operation>

  </wsdl:portType>


  <!-- BINDING (bind operations) -->
  <wsdl:binding
     name="Axis2UserGuideSoapBinding"
     type="impl:Axis2UserGuidePortType">
    <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>

    <wsdl:operation name="DoInOnly">
      <wsdlsoap:operation soapAction="DoInOnly"/>
      <wsdl:input>
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
    </wsdl:operation>

    <wsdl:operation name="TwoWayOneParameterEcho">
      <wsdlsoap:operation soapAction="TwoWayOneParameterEcho"/>
      <wsdl:input>
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="NoParameters">
      <wsdlsoap:operation soapAction="NoParameters"/>
      <wsdl:input>
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="MultipleParametersAddItem">
      <wsdlsoap:operation soapAction="MultipleParametersAddItem"/>
      <wsdl:input>
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>


  <!-- SERVICE -->

  <wsdl:service name="Axis2UserGuideService">
    <wsdl:port binding="impl:Axis2UserGuideSoapBinding"
               name="Axis2UserGuide">
      <wsdlsoap:address location="http://localhost:8080/axis2/services/Axis2UserGuide"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Note that the document defines four operations, DoInOnly, NoParameters, TwoWayOneParameterEcho, and MultipleParametersAddItem. Each client will include methods for calling each of these operations.

(You can get more information on WSDL at http://www.w3.org/2002/ws/desc/ .)

JiBX

JiBX is not part of the Apache project, so in order to use it to generate your clients, you will need to do some setting up to start with. To generate your client, execute the following steps:

The short story:

  1. Download the latest JiBX package (tested with JiBX v1.1) from http://sourceforge.net/projects/jibx/ . Extract the zip file, and copy the JARs in the lib directory to the AXIS2_HOME/lib directory. (Delete the stax-api.jar file; it's superseded by the version that comes with Axis2.)
  2. Download xsd2jibx version beta2a from SourceForge. Create a directory called xsd2jibx in your working directory and extract the files into it. This utility does not work with the latest release (v1.1) of JiBX, so download jibx-1.0RC1 from SourceForge. Extract the files from this archive and copy the *.jar files in the lib directory into the xsd2jibx/lib directory.
  3. Create a schema based on the data structures of your WSDL file and save it in your working directory.
  4. Make sure that only the xsd2jibx jar files are in the classpath and execute the following command to create the basic binding file: java -jar xsd2jibx\lib\xsd2jibx.jar Axis2UserGuide.xsd
  5. Copy the org directory to the src directory to place the generated classes into the project so that the compiler will see them.
  6. Remove the xsd2jibx-related *.jar files from your CLASSPATH and add the Axis2 .jar files back into it. Execute the following command to generate the stubs:
    %AXIS2_HOME%\bin\WSDL2Java -uri Axis2UserGuide.wsdl -p org.apache.axis2.axis2userguide -d jibx -Ebindingfile org\apache\axis2\axis2userguide\binding.xml -s
    
  7. Create the client file in the org/apache/axis2/axis2userguide directory.
  8. Copy the org directory and all its contents to the src directory.
  9. Compile the first set of classes by typing:ant jar.client
  10. Go to the build/classes directory and run the JiBX compiler:
    java -jar C:\apps\axis2\lib\jibx-bind.jar 
    ..\..\org\apache\axis2\axis2userguide\binding.xml
    
  11. Run Ant again to package the new auto-generated JiBX classes into the client jar by typing: ant jar.client
  12. Add the build/lib/Axis2UserGuideService-test-client.jar file to the CLASSPATH and run the client by typing:
    java org.apache.axis2.axis2userguide.Client
    

The long story:

To use JiBX to generate your client, you first need to use it in two different functions. You have to generate a binding file that maps objects to the XML elements, and then use JiBX to generate the stubs that your client will use. To generate a binding file, you'll need the xsd2jibx utility, which creates a binding file from an XML Schema document. Once you have the binding file, you can run JiBX to create the actual object. In order to do all that you'll need to have the appropriate versions of the JiBX software.

Download the latest JiBX package (tested with JiBX v1.1) from http://sourceforge.net/projects/jibx/. Extract the zip file, and copy the JARs in the lib directory to the AXIS2_HOME/lib directory. (Delete the stax-api.jar file; it's superseded by the version that comes with Axis2.) These files pertain to the main JiBX application.

Download xsd2jibx version beta2a from Sourceforge. Create a directory called xsd2jibx in your working directory and extract the files into it. Unfortunately, this utility does not work with the latest release of JiBX, so you will need to download jibx-1.0RC1 from Sourceforge. Extract the files from this archive and place the *.jar files in the lib directory into the xsd2jibx/lib directory. This way, you can use them exclusively with the xsd2jibx utility.

You'll need an XML schema from which to generate the binding file, which links XML elements to the Java classes. As defined in the sample WSDL file, its content should be as shown in Code Listing 2.

Code Listing 2: XML Schema

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
   elementFormDefault="qualified"
   targetNamespace="http://apache.org/axis2/Axis2UserGuide"
   xmlns="http://www.w3.org/2001/XMLSchema"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  
  <!-- ELEMENTS -->
  <xsd:element name="DoInOnlyRequest">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="messageString" type="xsd:string"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
  
  <xsd:element name="TwoWayOneParameterEchoRequest">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="echoString" type="xsd:string"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
  <xsd:element name="TwoWayOneParameterEchoResponse">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="echoString" type="xsd:string"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
  
  <xsd:element name="NoParametersRequest">
    <xsd:complexType/>
  </xsd:element>
  <xsd:element name="NoParametersResponse">
    <xsd:complexType/>
  </xsd:element>
  
  <xsd:element name="MultipleParametersAddItemRequest">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="itemId" type="xsd:int"/>
        <xsd:element name="itemName" type="xsd:string"/>
        <xsd:element name="price" type="xsd:float"/>
        <xsd:element name="description" type="xsd:string"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="MultipleParametersAddItemResponse">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="itemId" type="xsd:int"/>
        <xsd:element name="successfulAdd" type="xsd:boolean"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

</xsd:schema>

Save the above XML schema file as Axis2UserGuide.xsd.

In order to map this schema into a JiBX binding file, you'll need to use the xsd2jibx utility. Clear your CLASSPATH and add only the .jar files in the xsd2jibx/lib directory. Execute the following command to create the basic binding file:

java -jar xsd2jibx\lib\xsd2jibx.jar Axis2UserGuide.xsd

This operation creates the basic class files, as well as the mapping file, called binding.xml. You'll use this file to do the actual WSDL-to-Java conversion.

Remove the xsd2jibx .jar files from your CLASSPATH and add the Axis2 .jar files back into it. Execute the command in Code Listing 3 to generate the stubs.

Code Listing 3: Generating the stubs

%AXIS2_HOME%\bin\WSDL2Java -uri Axis2UserGuide.wsdl -p org.apache.axis2.axis2userguide -d jibx -Ebindingfile org\apache\axis2\axis2userguide\binding.xml -s

Create the client file, Client.java, in the org/apache/axis2/axis2userguide directory. Add the following code in Code Listing 4.

Code Listing 4: Creating Client.java

package org.apache.axis2.axis2userguide;

public class Client{
    public static void main(java.lang.String args[]){
        try{
            Axis2UserGuideServiceStub stub =
                new Axis2UserGuideServiceStub
              ("http://localhost:8080/axis2/services/Axis2UserGuideService");

            doInOnly(stub);
            twoWayOneParameterEcho(stub);
            noParameters(stub);
            multipleParameters(stub);
        } catch(Exception e){
            e.printStackTrace();
            System.out.println("\n\n\n");
        }
    }

    public static void doInOnly(Axis2UserGuideServiceStub stub){
        try{
            DoInOnlyRequest req = 
                new DoInOnlyRequest();

            req.setMessageString("fire and forget it!");

            stub.DoInOnly(req);
        } catch(Exception e){
            e.printStackTrace();
            System.out.println("\n\n\n");
        }
    }

    public static void twoWayOneParameterEcho(Axis2UserGuideServiceStub stub){
        try{
            TwoWayOneParameterEchoRequest req = 
                new TwoWayOneParameterEchoRequest();

            req.setEchoString("echo! ... echo!");
        System.out.println(stub.TwoWayOneParameterEcho(req).getEchoString());
        } catch(Exception e){
            e.printStackTrace();
            System.out.println("\n\n\n");
        }
    }

    public static void noParameters(Axis2UserGuideServiceStub stub){
        try{
            NoParametersRequest req =
                new NoParametersRequest();

            System.out.println(stub.NoParameters(req));
        } catch(Exception e){
            e.printStackTrace();
            System.out.println("\n\n\n");
        }
    }

    public static void multipleParameters(Axis2UserGuideServiceStub stub){
        try{
            MultipleParametersAddItemRequest req =
                new MultipleParametersAddItemRequest();

            req.setPrice((float)1.99);
            req.setItemId((int)23872983);
            req.setDescription("Must have for cooking");
            req.setItemName("flour");

            MultipleParametersAddItemResponse res =
                stub.MultipleParametersAddItem(req);

            System.out.println(res.getItemId());
            System.out.println(res.getSuccessfulAdd());
        } catch(Exception e){
            e.printStackTrace();
            System.out.println("\n\n\n");
        }
    }
}

Now it's time to compile the client. For the generated files to be found, they need to be in the source directory, so copy the org file to the src directory.

Compile the first set of classes by typing: ant jar.client

This action compiles most of the available classes, but not everything. Fortunately, it does compile the classes needed by the JiBX compiler, so you can now generate the actual JiBX resources. Change to the build/classes directory and run the JiBX compiler:

java -jar C:\apps\axis2\lib\jibx-bind.jar ..\..\org\apache\axis2\axis2userguide\binding.xml

Now that you have the new files in place, re-run the Ant task to generate the client: ant jar.client

This action adds all the appropriate files to the build/lib/Axis2UserGuideService-test-client.jar file, so add that .jar file to your CLASSPATH and run the client by typing: java org.apache.axis2.axis2userguide.Client