
WSDL (Web Services Description Language) is the W3C specification for the implementation of web services offered by servers to remote clients using the HTTP transport protocol.
A service is implemented starting with a WSDL document that defines the services offered by the server and how to access them.
SOAP (Simple Object Access Protocol) is the specification of the XML format that is used in the messages sent/received by clients and servers.
This post is a tutorial on the implementation of a simple example web service conformant to the SOAP/WSDL standard.
1. Defining the service – WSDL document
In our tutorial, we will be implementing a service “ArithmeticService”, that can be used by clients to request two operations: “add” and “subtract”.
A client will issue a request to the server, sending a message that specifies the desired operation, and the operands (two floating point numbers).
The server will send back the response, that will include the result of the operation as a single floating point number.
The first step in the implementation of the service is the elaboration of a WSDL document with the formal definition of the service described above.
1.1. Defining the structure of the messages exchanged between client and server
The first type of message is “ArithmeticRequest”. This is the mesage that the client will sent to the server to request an operation. In our sample service, the client must send two numeric operands “operand1” and “operand2”. In WSDL, this type of message is defined as:
1 2 3 4 5 6 |
<message name="ArithmeticRequest"> <part name="operand1" type="xsd:float" /> <part name="operand2" type="xsd:float" /> </message> |
The message that the server will send back to the client in response to the request must also be defined as a “ArithmeticResponse” message. The message will carry a single numeric value:
1 2 3 4 5 |
<message name="ArihtmeticResponse"> <part name="response" type="xsd:float" /> </message> |
1.2. Defining the request types accepted by the server
In our example service, the server will accept request for two operations “add” and “subtract”. These operations need also to be formally defined in WSDL. For each operation, the input and output message types are specified as follows:
1 2 3 4 5 6 7 8 9 10 11 12 |
<portType name="ArithmeticPort"> <operation name="add"> <input message="tns:ArithmeticRequest" /> <output message="tns:ArihtmeticResponse" /> </operation> <operation name="subtract"> <input message="tns:ArithmeticRequest" /> <output message="tns:ArithmeticResponse" /> </operation> </portType> |
1.3. Defining the format of the messages
For each of the operations in the service, the WSDL document must include the specification of the encoding format used in the messages.
In our example service, all input and output messages will use SOAP format.
This is specified in the document in a <binding> element, as shown:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<binding name="ArithmeticBinding" type="tns:ArithmeticPort"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> <operation name="add"> <soap:operation soapAction="urn:Arithmetic#sadd" /> <input> <soap:body use="encoded" namespace="urn:Arithmetic" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </input> <output> <soap:body use="encoded" namespace="urn:Arithmetic" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </output> </operation> <operation name="subtract"> <soap:operation soapAction="urn:Arithmetic#subtract" /> <input> <soap:body use="encoded" namespace="urn:Arithmetic" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </input> <output> <soap:body use="encoded" namespace="urn:Arithmetic" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </output> </operation> </binding> |
1.4. Defining the service access points
Finally, the URLs that the client will use to access the service must be specified in <port> elements inside a <service> element.
In our example, a single url “http://example.com/test/wsdl/arithmetic_server” will be used to issue requests to the server.
The definition in the WSDL document is:
1 2 3 4 5 6 7 |
<service name="ArithmeticService"> <port name="ArithmeticPort" binding="tns:ArithmeticBinding"> <soap:address location="http://example.com/test/wsdl/arithmetic_server" /> </port> </service> |
1.4. Complete WSDL document
All of the elements of the WSDL document that have been explained above must go inside a <definitions> element. A set of attributes in the <definitions> element point to the base XML, WSDL and SOAP specifications employed.
The final content of the WSDL document “ArithmeticService.wsdl” is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<?xml version="1.0"?> <definitions name="ArithmeticService" targetNamespace="urn:Arithmetic" xmlns:tns="urn:Arithmetic" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="ArithmeticRequest"> <part name="operand1" type="xsd:float" /> <part name="operand2" type="xsd:float" /> </message> <message name="ArihtmeticResponse"> <part name="response" type="xsd:float" /> </message> <portType name="ArithmeticPort"> <operation name="add"> <input message="tns:ArithmeticRequest" /> <output message="tns:ArihtmeticResponse" /> </operation> <operation name="subtract"> <input message="tns:ArithmeticRequest" /> <output message="tns:ArithmeticResponse" /> </operation> </portType> <binding name="ArithmeticBinding" type="tns:ArithmeticPort"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> <operation name="add"> <soap:operation soapAction="urn:Arithmetic#sadd" /> <input> <soap:body use="encoded" namespace="urn:Arithmetic" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </input> <output> <soap:body use="encoded" namespace="urn:Arithmetic" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </output> </operation> <operation name="subtract"> <soap:operation soapAction="urn:Arithmetic#subtract" /> <input> <soap:body use="encoded" namespace="urn:Arithmetic" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </input> <output> <soap:body use="encoded" namespace="urn:Arithmetic" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </output> </operation> </binding> <service name="ArithmeticService"> <port name="ArithmeticPort" binding="tns:ArithmeticBinding"> <soap:address location="http://example.com/test/wsdl/arithmetic_server" /> </port> </service> </definitions> |
2. Implementing the service
In most cases, the service is implemented inside a Java container (Tomcat, Jetty,…) running in a Apache web server.
In this post we will assume that a Tomcat/Apache environment to perform the installation of the WSDL/SOAP service is already available.
2.1. Installing AXIS2
AXIS2 is a Java library that implements all the functionality required for the development of a WSDL web service.
The installation packages can be downloaded from the AXIS downloads page. From that page, we download the standard binary distribution package axis2-1.6.2-bin.zip (20 MB), and extract the content under the directory /opt/axis2-1.6.2.
Next, the environment variable AXIS2_HOME is defined in the profile of the user that will be used for the development of the service, pointing to the installation directory:
1 2 3 |
AXIS2_HOME=/opt/axis2-1.6.2 |
Alternatively, the file /opt/axis2-1.6.2/bin/setenv.sh can be run to prepare the environment
Again, from the AXIS download page, the WAR installation package”axis2-1.6.2-war.zip” (18.2 MB) is downloaded, and extracted under the Tomcat webapps directory (/usr/share/tomcat7/webapps in a default Tomcat installation)
To verify that the AXIS application has been correctly installed, point the browser to the URL http://localhost:8080/axis2:
Optionally, we can click on the “Validate” link to access a page that displays the results of a set of validation tests of the installation.
2.2. Developing the ArithmeticService service
First, a directory “ArithmeticService” is created to contain the development of the service. Under it, the file “ArithmeticService.wsdl” is created with the content of the wsdl document as shown in point 1.4. of this post.
Next, the development environment is generated using the ‘wsdl2java’ utility included in the axis package:
(Note: You may need to define the environment variable JAVA_HOME pointing to the root of the Java JDK first)
1 2 3 4 5 6 7 |
$ /opt/axis2-1.6.2/bin/wsdl2java.sh -ss -sd -uri ArithmeticService.wsdl Using AXIS2_HOME: /opt/axis2-1.6.2/ Using JAVA_HOME: /opt/jdk1.8.0_20 Retrieving document at 'ArithmeticService.wsdl'. $ |
Next, “ant” is executed to compile the application
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$ ant Buildfile: /home/user/ArithmeticService/build.xml init: [mkdir] Created dir: /home/user/ArithmeticService/build [mkdir] Created dir: /home/user/ArithmeticService/build/classes [mkdir] Created dir: /home/user/ArithmeticService/build/lib pre.compile.test: [echo] Stax Availability= true [echo] Axis2 Availability= true compile.src: ... BUILD SUCCESSFUL Total time: 4 seconds $ |
“ant” generates a file “build/lib/ArithmeticService.aar”, that is moved under the axis2 “services” directory to deploy the service:
1 2 3 |
$ sudo mv build/lib/ArithmeticService.aar /usr/share/tomcat7/webapps/axis2/WEB-INF/services |
After moving the .aar file, the URL “http://localhost:8080/axis2/services/listServices” can be loaded in the browser, to verify that “ArithmeticService” appears in the list of available services:
2.3. Coding the functionality of the service
Naturally, the java code that implements the desired functionality of the “add” and “subtract” operations still needs to be coded.
The wsdl2java utility created a file “src/arithmetic/ArithmeticServiceSkeleton.java” with the definitions of the methods “add” and “subtract”. these methods need to be edited to include the code that implements the operations.
For instance, inside the skeleton, we can locate the definition of the method “add”:
1 2 3 4 5 6 7 8 9 10 11 |
public arithmetic.AddResponse add ( arithmetic.Add add ) { //TODO : fill this with the necessary business logic throw new java.lang.UnsupportedOperationException( "Please implement " + this.getClass().getName() + "#add"); } |
As can be seen, the return value of method “add” is of class “AddResponse”. This class is defined in the file “src/arithmetic/AddResponse.java” that has been also generated by wsdl2java. In the same way, the argument of the method “add” is of class “arithmetic.Add”. The definition of that class can be found in the file “src/arithmetic/Add.java”.
After looking at the method definitions in those files, we can proceed to write the code that implements the desired functionality (adding the two operands) inside the “add” method:
1 2 3 4 5 6 7 8 9 10 11 |
public arithmetic.AddResponse add (arithmetic.Add operands) { arithmetic.AddResponse result = new arithmetic.AddResponse(); result.setResponse( operands.getOperand1() + operands.getOperand2() ); return result; } |
The “subtract” method in the skeleton can be edited in the same way.
After the skeleton has been edited, the “.aar” file can be generated again and copied to the Tomcat container:
1 2 3 4 5 |
$ ant ... $ sudo mv build/lib/ArithmeticService.aar /usr/share/tomcat7/webapps/axis2/WEB-INF/services |
2.4. Testing the functionality of the service
To verify that the service is operational, we need to write a client that calls the service, and check that the responses are as expected.
To develop the client, we can use again the wsdl2java utility, passing the “-s” option to the call:
1 2 3 |
$ /opt/axis2-1.6.2/bin/wsdl2java.sh -uri ArithmeticService.wsdl -s |
Option “-s” tells wsdl2java to create a file “src/arithmetic/ArithmeticServiceStub.java”, that can be used as a base to write the client.
Next, the client itself is written in a file “src/arithmetic/ArithmeticClient.java”, with the following content:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package arithmetic; import arithmetic.ArithmeticServiceStub.Add; import arithmetic.ArithmeticServiceStub.AddResponse; public class ArithmeticClient{ public static void main(java.lang.String args[]){ try{ ArithmeticServiceStub stub = new ArithmeticServiceStub ("http://localhost:8080/axis2/services/ArithmeticService"); addTwoNumbers(stub); } catch(Exception e){ e.printStackTrace(); System.out.println("\n\n\n"); } } public static void addTwoNumbers(ArithmeticServiceStub stub){ try{ Add params = new Add(); params.setOperand1((float)23.75); params.setOperand2((float)1.63); AddResponse res = stub.add(params); System.out.println("The result of the addition is: " + res.getRespuesta()); } catch(Exception e){ e.printStackTrace(); System.out.println("\n\n\n"); } } } |
Next, the client is compiled with “ant”, and executed with “axis2.sh” (axis2.sh is an utility included in the axis package that adds to the CLASSPATH all the required libraries, before running the client on the java VM).
1 2 3 4 5 6 7 8 9 |
$ ant $ cd build/classes $ /opt/axis2-1.6.2/bin/axis2.sh arithmetic/ArithmeticClient Using AXIS2_HOME: /opt/axis2-1.6.2/ Using JAVA_HOME: /opt/jdk1.8.0_20 ... The result of the addition is: 25.38 |
In the generated output we can verify that the service works as expected, returning the result of the addition of the two operands.
—
References
—