Simple web service: Client manually invokes remote method described in WSDL

Objective

In this tutorial, we will study how to create a simple standalone web service application at the client side in which, the remote service from the server is manually invoked based on its description in the WSDL file

  • At the server side, we know only a WSDL file about the service.
  • At the client side, a simple console application is created to manually invoke the remote web service.

Understanding the wsdl file

At the server side, the service provider provides us only a wsdl file of the service as follow. Let’s analyze the content to understand the provided services:

  • The service description is presented in the tag <wsdl:service> (line 264), and the endpoint URL to access to the service is presented in the tag <wsdlsoap:address> (line 268).
  • All services are listed in the tag <wsdl:portType> (line 134).
  • A service (or method) is presented in a tag <wsdl:operation> (for instances, line 136, 148, 160, 172)
  • A service contains its description of input <wsdl:input> (i.e, line 138) and output <wsdl:ouput> (i.e, line 142).
  • Input or output refers to its respective message: The input in the line 138 refers to the message <wsdl:message> in the line 110, which contain some element, this element refers to the element <element> in the line 6 which presents two input parameters in order: a of type float, b of type float.
  • The same analyze helps us to understand the operation of minus, multiple, and division.
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://webservices" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://webservices" xmlns:intf="http://webservices" 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:types>
  <schema elementFormDefault="qualified" targetNamespace="http://webservices" xmlns="http://www.w3.org/2001/XMLSchema">
   <element name="sum">
    <complexType>
     <sequence>
      <element name="a" type="xsd:float"/>
      <element name="b" type="xsd:float"/>
     </sequence>
    </complexType>
   </element>
   <element name="sumResponse">
    <complexType>
     <sequence>
      <element name="sumReturn" type="xsd:float"/>
     </sequence>
    </complexType>
   </element>
   <element name="minus">
    <complexType>
     <sequence>
      <element name="a" type="xsd:float"/>
      <element name="b" type="xsd:float"/>
     </sequence>
    </complexType>
   </element>
   <element name="minusResponse">
    <complexType>
     <sequence>
      <element name="minusReturn" type="xsd:float"/>
     </sequence>
    </complexType>
   </element>
   <element name="multiple">
    <complexType>
     <sequence>
      <element name="a" type="xsd:float"/>
      <element name="b" type="xsd:float"/>
     </sequence>
    </complexType>
   </element>
   <element name="multipleResponse">
    <complexType>
     <sequence>
      <element name="multipleReturn" type="xsd:float"/>
     </sequence>
    </complexType>
   </element>
   <element name="division">
    <complexType>
     <sequence>
      <element name="a" type="xsd:float"/>
      <element name="b" type="xsd:float"/>
     </sequence>
    </complexType>
   </element>
   <element name="divisionResponse">
    <complexType>
     <sequence>
      <element name="divisionReturn" type="xsd:float"/>
     </sequence>
    </complexType>
   </element>
  </schema>
 </wsdl:types>

   <wsdl:message name="sumResponse">

      <wsdl:part element="impl:sumResponse" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="divisionRequest">

      <wsdl:part element="impl:division" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="minusResponse">

      <wsdl:part element="impl:minusResponse" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="multipleResponse">

      <wsdl:part element="impl:multipleResponse" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="minusRequest">

      <wsdl:part element="impl:minus" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="sumRequest">

      <wsdl:part element="impl:sum" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="multipleRequest">

      <wsdl:part element="impl:multiple" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="divisionResponse">

      <wsdl:part element="impl:divisionResponse" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:portType name="Calculator">

      <wsdl:operation name="sum">

         <wsdl:input message="impl:sumRequest" name="sumRequest">

       </wsdl:input>

         <wsdl:output message="impl:sumResponse" name="sumResponse">

       </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="minus">

         <wsdl:input message="impl:minusRequest" name="minusRequest">

       </wsdl:input>

         <wsdl:output message="impl:minusResponse" name="minusResponse">

       </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="multiple">

         <wsdl:input message="impl:multipleRequest" name="multipleRequest">

       </wsdl:input>

         <wsdl:output message="impl:multipleResponse" name="multipleResponse">

       </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="division">

         <wsdl:input message="impl:divisionRequest" name="divisionRequest">

       </wsdl:input>

         <wsdl:output message="impl:divisionResponse" name="divisionResponse">

       </wsdl:output>

      </wsdl:operation>

   </wsdl:portType>

   <wsdl:binding name="CalculatorSoapBinding" type="impl:Calculator">

      <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>

      <wsdl:operation name="sum">

         <wsdlsoap:operation soapAction=""/>

         <wsdl:input name="sumRequest">

            <wsdlsoap:body use="literal"/>

         </wsdl:input>

         <wsdl:output name="sumResponse">

            <wsdlsoap:body use="literal"/>

         </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="minus">

         <wsdlsoap:operation soapAction=""/>

         <wsdl:input name="minusRequest">

            <wsdlsoap:body use="literal"/>

         </wsdl:input>

         <wsdl:output name="minusResponse">

            <wsdlsoap:body use="literal"/>

         </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="multiple">

         <wsdlsoap:operation soapAction=""/>

         <wsdl:input name="multipleRequest">

            <wsdlsoap:body use="literal"/>

         </wsdl:input>

         <wsdl:output name="multipleResponse">

            <wsdlsoap:body use="literal"/>

         </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="division">

         <wsdlsoap:operation soapAction=""/>

         <wsdl:input name="divisionRequest">

            <wsdlsoap:body use="literal"/>

         </wsdl:input>

         <wsdl:output name="divisionResponse">

            <wsdlsoap:body use="literal"/>

         </wsdl:output>

      </wsdl:operation>

   </wsdl:binding>

   <wsdl:service name="CalculatorService">

      <wsdl:port binding="impl:CalculatorSoapBinding" name="Calculator">

         <wsdlsoap:address location="http://localhost:8080/wsCalculator/services/Calculator"/>

      </wsdl:port>

   </wsdl:service>

</wsdl:definitions>

Create client web service application

In order to manually invoke the operation provided in the wsdl file, for instance, the sum method that we have analyzed: the name of method if sum, input parameters are two float numbers, the output parameter is a float number. We need to manually prepare a call as follow:

  • Config the first input parameter as a float number (line 13-15)
  • Config the second input parameter as a float number (line 17-19)
  • Set the output parameter as a float number (line 21-23)
  • Set the name of the operation is sum (line 27)
  • Manually invoke the remote method (line 30)
  • Cast the return value to return (line 33-39)
  • Repeat this process for each remote operation we need to invoke.
/**
	 * remote call for sum method
	 * @param a
	 * @param b
	 * @return
	 */
	public float remoteSum(float x, float y){
		float result=0;
		try{
			//prepare the operation
			OperationDesc oper = new OperationDesc();
			//first parameter
			ParameterDesc param = new ParameterDesc(new QName("http://webservices", "a"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//second parameter
			param = new ParameterDesc(new QName("http://webservices", "b"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//return parameter
			oper.setReturnType(new QName("http://www.w3.org/2001/XMLSchema", "float"));
			oper.setReturnClass(float.class);
			oper.setReturnQName(new QName("http://webservices", "sumReturn"));

			//create Call object
			call.setOperation(oper);
			call.setOperationName(new QName("http://webservices", "sum"));

			//invoke the call
			Object resp = call.invoke(new Object[] {new Float(x), new Float(y)});

			//extract the result
			if (!(resp instanceof java.rmi.RemoteException) ){
				try {// convert by java.lang
					result = ((Float) resp).floatValue();
				} catch (Exception e) {//convert by axis
					result = ((Float)JavaUtils.convert(resp, float.class)).floatValue();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
  • Now, in Eclipse, create a java project as wsClientTuto
  • in the /src folder, create two packages: control and view
  • Create a class CalculatorWS.java in the control package
  • Create a class ClientConsole.java in the view package

Code: CalculatorWS.java

package control;

import java.net.URL;
import javax.xml.namespace.QName;
import org.apache.axis.client.Call;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.description.ParameterDesc;
import org.apache.axis.utils.JavaUtils;


public class CalculatorWS {
	private Call call;
	
	public CalculatorWS(){
		try{
			call = new Call(new URL("http://localhost:8080/wsCalculator/services/Calculator"));
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	/**
	 * remote call for minus method
	 * @param a
	 * @param b
	 * @return
	 */
	public float remoteMinus(float x, float y){
		float result=0;
		try{
			//prepare the operation
			OperationDesc oper = new OperationDesc();
			//first parameter
			ParameterDesc param = new ParameterDesc(new QName("http://webservices", "a"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//second parameter
			param = new ParameterDesc(new QName("http://webservices", "b"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//return parameter
			oper.setReturnType(new QName("http://www.w3.org/2001/XMLSchema", "float"));
			oper.setReturnClass(float.class);
			oper.setReturnQName(new QName("http://webservices", "minusReturn"));

			//create Call object
			call.setOperation(oper);
			call.setOperationName(new QName("http://webservices", "minus"));

			//invoke the call
			Object resp = call.invoke(new Object[] {new Float(x), new Float(y)});

			//extract the result
			if (!(resp instanceof java.rmi.RemoteException) ){
				try {// convert by java.lang
					result = ((Float) resp).floatValue();
				} catch (Exception e) {//convert by axis
					result = ((Float)JavaUtils.convert(resp, float.class)).floatValue();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	

	/**
	 * remote call for sum method
	 * @param a
	 * @param b
	 * @return
	 */
	public float remoteSum(float x, float y){
		float result=0;
		try{
			//prepare the operation
			OperationDesc oper = new OperationDesc();
			//first parameter
			ParameterDesc param = new ParameterDesc(new QName("http://webservices", "a"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//second parameter
			param = new ParameterDesc(new QName("http://webservices", "b"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//return parameter
			oper.setReturnType(new QName("http://www.w3.org/2001/XMLSchema", "float"));
			oper.setReturnClass(float.class);
			oper.setReturnQName(new QName("http://webservices", "sumReturn"));

			//create Call object
			call.setOperation(oper);
			call.setOperationName(new QName("http://webservices", "sum"));

			//invoke the call
			Object resp = call.invoke(new Object[] {new Float(x), new Float(y)});

			//extract the result
			if (!(resp instanceof java.rmi.RemoteException) ){
				try {// convert by java.lang
					result = ((Float) resp).floatValue();
				} catch (Exception e) {//convert by axis
					result = ((Float)JavaUtils.convert(resp, float.class)).floatValue();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	

	/**
	 * remote call for multiple method
	 * @param a
	 * @param b
	 * @return
	 */
	public float remoteMultiple(float x, float y){
		float result=0;
		try{
			//prepare the operation
			OperationDesc oper = new OperationDesc();
			//first parameter
			ParameterDesc param = new ParameterDesc(new QName("http://webservices", "a"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//second parameter
			param = new ParameterDesc(new QName("http://webservices", "b"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//return parameter
			oper.setReturnType(new QName("http://www.w3.org/2001/XMLSchema", "float"));
			oper.setReturnClass(float.class);
			oper.setReturnQName(new QName("http://webservices", "multipleReturn"));

			//create Call object
			call.setOperation(oper);
			call.setOperationName(new QName("http://webservices", "multiple"));

			//invoke the call
			Object resp = call.invoke(new Object[] {new Float(x), new Float(y)});

			//extract the result
			if (!(resp instanceof java.rmi.RemoteException) ){
				try {// convert by java.lang
					result = ((Float) resp).floatValue();
				} catch (Exception e) {//convert by axis
					result = ((Float)JavaUtils.convert(resp, float.class)).floatValue();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	

	/**
	 * remote call for divide method
	 * @param a
	 * @param b
	 * @return
	 */
	public float remoteDivide(float x, float y){
		if(y==0){
			System.out.print("Division by zero error!");
			return 0;
		}
		float result=0;
		try{
			//prepare the operation
			OperationDesc oper = new OperationDesc();
			//first parameter
			ParameterDesc param = new ParameterDesc(new QName("http://webservices", "a"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//second parameter
			param = new ParameterDesc(new QName("http://webservices", "b"), ParameterDesc.IN, 
					new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class, false, false);
			oper.addParameter(param);
			//return parameter
			oper.setReturnType(new QName("http://www.w3.org/2001/XMLSchema", "float"));
			oper.setReturnClass(float.class);
			oper.setReturnQName(new QName("http://webservices", "divisionReturn"));

			//create Call object
			call.setOperation(oper);
			call.setOperationName(new QName("http://webservices", "division"));

			//invoke the call
			Object resp = call.invoke(new Object[] {new Float(x), new Float(y)});

			//extract the result
			if (!(resp instanceof java.rmi.RemoteException) ){
				try {// convert by java.lang
					result = ((Float) resp).floatValue();
				} catch (Exception e) {//convert by axis
					result = ((Float)JavaUtils.convert(resp, float.class)).floatValue();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}	
}

Code: ClientConsole.java

package view;

import control.CalculatorWS;

public class ClientConsole {

	public static void main(String[] args) {		
		CalculatorWS cws = new CalculatorWS();
		System.out.println("Minus: " + cws.remoteMinus(10, 2));
		System.out.println("Sum: " + cws.remoteSum(10, 2));
		System.out.println("Multiple: " + cws.remoteMultiple(10, 2));
		System.out.println("Divide: " + cws.remoteDivide(10, 2));		
	}
}