Tuesday, February 8, 2011

Building a contract-first webservice with JAX-WS

In this tutorial, we'll be building a webservice contract-first. This means we build the webservice based on a contract that already exists. This contract is the WSDL file that describes the webservice formally.

The first step is to generate JAX-WS classes using wsgen that comes with the Java EE SDK. You can find the executable in your SDK/Glassfish installation directory. We'll be using the WSDL file of an earlier blogpost. Save this file as: ExampleWSService.wsdl. If you're using Eclipse, you might want to save the files in WebContent/WEB-INF/wsdl in the project directory.


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://javaeenotes.com/"
name="ExampleWSService"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://javaeenotes.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<types>
<xsd:schema>
<xsd:import namespace="http://javaeenotes.com/" schemaLocation="ExampleWSService.xsd"/>
</xsd:schema>
</types>
<message name="sum">
<part name="parameters" element="tns:sum"/>
</message>
<message name="sumResponse">
<part name="parameters" element="tns:sumResponse"/>
</message>
<message name="greet">
<part name="parameters" element="tns:greet"/>
</message>
<message name="greetResponse">
<part name="parameters" element="tns:greetResponse"/>
</message>
<message name="multiply">
<part name="parameters" element="tns:multiply"/>
</message>
<message name="multiplyResponse">
<part name="parameters" element="tns:multiplyResponse"/>
</message>
<portType name="ExampleWS">
<operation name="sum">
<input message="tns:sum"/>
<output message="tns:sumResponse"/>
</operation>
<operation name="greet">
<input message="tns:greet"/>
<output message="tns:greetResponse"/>
</operation>
<operation name="multiply">
<input message="tns:multiply"/>
<output message="tns:multiplyResponse"/>
</operation>
</portType>
<binding name="ExampleWSPortBinding" type="tns:ExampleWS">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="sum">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
<operation name="greet">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
<operation name="multiply">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="ExampleWSService">
<port name="ExampleWSPort" binding="tns:ExampleWSPortBinding">
<soap:address location="http://127.0.0.1:8080/webservice/ExampleWSService"/>
</port>
</service>
</definitions>


This WSDL file imports an XSD file. Make sure this is placed in the same directory as the WSDL file, and name it ExampleWSService.xsd. Also update the location/URL in the WSDL file. This example assumes the application is called webservice and the service name is ExampleWSService.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0"
targetNamespace="http://javaeenotes.com/"
xmlns:tns="http://javaeenotes.com/"
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="greet" type="tns:greet"/>

<xs:element name="greetResponse" type="tns:greetResponse"/>

<xs:element name="multiply" type="tns:multiply"/>

<xs:element name="multiplyResponse" type="tns:multiplyResponse"/>

<xs:element name="sum" type="tns:sum"/>

<xs:element name="sumResponse" type="tns:sumResponse"/>

<xs:complexType name="greet">
<xs:sequence>
<xs:element name="arg0" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="greetResponse">
<xs:sequence>
<xs:element name="return" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="sum">
<xs:sequence>
<xs:element name="arg0" type="xs:int"/>
<xs:element name="arg1" type="xs:int"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="sumResponse">
<xs:sequence>
<xs:element name="return" type="xs:int"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="multiply">
<xs:sequence>
<xs:element name="arg0" type="xs:int"/>
<xs:element name="arg1" type="xs:int"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="multiplyResponse">
<xs:sequence>
<xs:element name="return" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:schema>


Now use the wsgen command to generate the server stubs. I generally put the complete command in a Windows batch file, so I can easily rerun the command in the future if necessary. Now, execute the following command:

wsimport -p com.javaeenotes.ws -d build/classes -s src WebContent/WEB-INF/wsdl/ExampleWSService.wsdl


This will generate all classes needed to setup the webservice. Next is to create a class that implements the webservice.


package com.javaeenotes;

import javax.jws.WebService;

import com.javaeenotes.ws.ExampleWS;

@WebService(name = "ERSService",
targetNamespace = "http://javaeenotes.com/",
serviceName = "ExampleWSService",
portName = "ExampleWSPort",
endpointInterface = "com.javaeenotes.ws.ExampleWS",
wsdlLocation = "WEB-INF/wsdl/ExampleWSService.wsdl")
public class WsImplementation implements ExampleWS {

@Override
public int sum(int arg0, int arg1) {
return 0;
}

@Override
public String greet(String arg0) {
return null;
}

@Override
public int multiply(int arg0, int arg1) {
return 0;
}
}


This class implements the webservice interface we generated from the WSDL file. Using simple annotations, we can easily deploy it without editting any deployment descriptors. Nothing more is needed for successful deployment. If you used the default URL in the WSDL file, you can now reach the webservice using this URL:

http://127.0.0.1:8080/webservice/ExampleWSService?wsdl

I recommend SOAP-UI to test the webservice.

1 comment:

  1. Thanks a lot for this tutorial, it was very useful.

    But what if I want to add multiple ports (with its distinct portType and binding) to the same WSDL service?

    ReplyDelete