Hi All,
Here we start with our first instalment from Web Services Series. I am excited :) . So without wasting any time we will jump into the content.
There are typically two approaches of developing webservice.
Contract First - The contract(XSD/WSDL) is created first and then based on this the Service Implementation is provided.
Contract Last - The contract(WSDL) is generated at the end of Service Implementation.
Spring supports Contract First approach. I am going to show you the implementation of Spring web Services using contract first approach.
Steps for implementing Spring Web Service:
1-XML Schema and WSDL Development(Contract Creation)
2-Request/Response Mapping to Java Objects
3-Marshalling/Un-Marshalling of Messages
4-Endpoint configuration
5-Business Logic Implementation
6-Some more Application Configuration settings
I will create a simple Country Look up Web Service for explaining the implementation
Step-1 : Contract Creation
We can create XML contract using any of the following technologies:
DTDs
XML Schema Definations
Relax NG
Based on your requirement and comfort, you can select any of these to create WSDL.
There are some good tools to available to create and validate XSD and Contract.
countryLookUpService.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://springproject.webservice.example"
xmlns:orders="http://springproject.webservice.example">
<xs:element name="findCountryRequest">
<xs:complexType>
<xs:attribute name="countryCd" use="required" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="findCountryResponse">
<xs:complexType>
<xs:attribute name="countryCd" type="xs:integer"/>
<xs:attribute name="countryName" type="xs:String"/>
</xs:complexType>
</xs:element>
</xs:schema>
The above shows a simple XSD. If you want, you can add some validations and restrictions in your XSD.
Once you have created your XSD you can create WSDL based on the schema definitions. There are several ways you can generate WSDL. Using some WSDL generator tool( for example WSCF Tool) or can write build task to generate WSDL for you.
Spring web service project also comes with the facility to generate the WSDL using XSD. But we have to configure this properly so that the Spring container could pick it and do the required task.
Step-2
Now, we will create a ant task which will generate Pojo objects and other classes using JAXB tool
JAXB has inbuild complier which will convert these Java objects from the XSD schema that was created in first step.
The ant task will be as follows:
<project name="SpringWSProject" default="generate" basedir=".">
<property name="src.dir" location="src" />
<property name="java.dir" location="src/main/java" />
<property name="schema.dir"
location="${src.dir}/main/webapp/WEB-INF/serviceSchemas/xsd" />
<target name="generate">
<exec executable="xjc">
<arg line=" -d ${java.dir} -p springproject.webservice.example ${schema.dir}/countryLookUpService.xsd" />
</exec>
</target>
</project>
Once you run this ant task, you will be able to see the following Java files have been created there in the springproject.webservice.example folder:
FindCountryRequest.java
FindCountryResponse.java
Step-3
Now we are ready with XSD and Java Objects. Its time to go ahead and start implementing the Endpoints. The term marshalling and un-marshalling comes into the mind when we send/receive the message. Marshalling is nothing but constructing your message and sending them over wire and Un-Marshalling is the process of converting back the packaged messages into readable format at receiving end for further processing.
I am going to use Annotations for creating Endpoints. You can have the similar endpoint configured using XML configuration as well.
@Endpoint
// We are registering this class as a Component class so that the Spring container can recognize and treat //this a Endpoint.
public class CountryEndpoint{
@Autowired
private CountryService countryService;
@PayloadRoot(localPart="findCountryRequest", namespace="http://springproject.webservice.example")
//This annotation is used to register the endpoint method as request handler. This defines type of request message that //can be handled by the method. We have to be careful for assigning the same namespace that we have defined in XSD. //because it matches the namespace from payload root element with the XSD schema name space.
//@RequestPayload - Java object that contains the request message which has to be passed as a parameter to the //method. @ResponsePayload - Defines the response message.
public @ResponsePayload FindCountryResponse findCountry(@RequestPayload FindCountryRequest findCountryRequest) {
//Following code is going to call the business logic and return the result into an Object
CountryVO countryVO = countryService.countryLookup(findCountryRequest.getCountryCd);
FindCountryResponse searchResponse = new FindCountryResponse();
response.setConfirmationId(confirmation.getConfirmationId());
searchResponse.setCountryCd(countryVO.getCountryCd());
searchResponse.setCountryName(countryVO.getCountryName());
return searchResponse;
}
}
Step-4
Other Configurations:
First of all we shall change the web.xml as follows:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springproject/webservice/example/config/application-config.xml
</param-value>
</context-param>
Provide the listener which will load the application context to container
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Design the Controller Servlet. This will act as a Front Controller to handle all SOAP requests. So all the request XML will be going to their endpoint through this Controller.
<servlet>
<servlet-name>country</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springproject/webservice/example/config/ws-servlet-
config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>country</servlet-name>
<url-pattern>/country/*</url-pattern>
</servlet-mapping>
ws-servlet-config.xml
Defines webservices lounching details:
<context:component-scan base-package="springproject.webservice.example"/>
<!-- detects @PayloadRoot -->
<ws:annotation-driven/>
<ws:dynamic-wsdl id="countryLookup" portTypeName="country"
locationUri="http://localhost:8081/springproject">
<ws:xsd location="/WEB-INF/serviceSchemas/xsd/countryLookUpService.xsd"/>
</ws:dynamic-wsdl>
MessageDispatcherServlet handles the value of locationUri dynamically. Now I am running it locally so the WSDL will be available at:
http://localhost:8081/springproject/country/countryLookup.wsdl
Step-5
Now you can use this WSDL and call the service. Pass the required parameter and get the response. That's it :) !!!
I will try to conclude the above implementation in 10 Steps to show you the flow.
1.Client looks up the description of the Web Service using the WSDL.
2.Client sends a request for the Web Service which is handled by the MessageDispatcherServlet.
3.MessageDispatchServlet validates the Web Service request through the schema validator. This Validation Framework is implemented using Spring WS XML Schema Validation.
4.MessageDispatcherServlet sends the validated Web Service request to the EndPoint via Spring WS EndpointMapping.
5.At the Endpoint, the Marshaller unmarshalls the Web Service Request to a Java Request Object.
6.The Endpoint sends the Java Request Object to the Business Service.
7.The Business Service processes the response to a Java Response Object and sends it back to the Endpoint.
8.At the Endpoint, the Marshaller marshalls the Java Response Object to a Web Service Response.
9.The MessageDispatcher re-validates the Web Service Response through the schema.
10.The MessageDispatcher sends the Web Service Response back to the Client.
That's all :)
Comments
Post a Comment