Saturday, 5 April 2014

SOAP webservice using Spring-ws

Spring-ws API works on the principal of contract first SOAP webservice. In this type of webservice implementation the wsdl is created first. In contract last SOAP webservice the JAVA code is created first which inturns creates the wsdl. The contract first webservice is a bit difficult to implement as compared to contract last webservice as the xsd and wsdl needs to be created manually. Contract first webservice is more advantageous though as it eliminates the impedance mismatch problem. Below code snippets explains how to use spring-ws to implement the SOAP based webservice.


The first thing to do is to identify the request and response xml and to create the XSD. The xsd can be created using any online tools.
Since Spring-ws is a contract first API we have to come up with the xsd.
The XSD will be used to generate the wsdl in later sections.

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:login="http://mycompany.com/login/schemas" elementFormDefault="qualified"
 targetNamespace="http://mycompany.com/login/schemas">
 <xs:element name="LoginRequest">
  <xs:complexType>
   <xs:sequence>
    <xs:element type="xs:string" name="username" />
    <xs:element type="xs:string" name="password" />
   </xs:sequence>
  </xs:complexType>
 </xs:element>

 <xs:element name="Response">
  <xs:complexType>
   <xs:sequence>
    <xs:element type="xs:string" name="message" />
   </xs:sequence>
  </xs:complexType>
 </xs:element>
</xs:schema>

Next create a Maven web application with dependencies as mentioned below

<dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.ws</groupId>
   <artifactId>spring-ws-core</artifactId>
   <version>2.1.3.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.16</version>
  </dependency>
</dependencies>

The next thing is to create the web.xml file.
web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <display-name>Live Restaurant</display-name>
 <context-param>
  <param-name>log4jConfigLocation</param-name>
  <param-value>/WEB-INF/log4j.properties</param-value>
 </context-param>
 <context-param>
  <param-name>log4jRefreshInterval</param-name>
  <param-value>1000</param-value>
 </context-param>
 <listener>
  <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
 </listener>
    <servlet>
        <servlet-name>spring-ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <init-param>
            <param-name>transformWsdlLocations</param-name>
            <param-value>true</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring-ws</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

Above here MessageDispatcherServlet is defined which is the entry point of the SOAP webservice. As in Spring MVC the servlet looks for spring-ws-servlet.xml file.

spring-ws-servlet.xml
This file below dynamic-wsdl tag which uses the xsd to create the wsdl. Also 2 interceptors are mentioned. One to validate the request/response messages and the other one to print the request/response on console.

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:sws="http://www.springframework.org/schema/web-services"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

 <context:component-scan base-package="com.login" />

 <sws:annotation-driven />



 <sws:dynamic-wsdl id="login" portTypeName="SocialNetwork"
  locationUri="/loginService/" targetNamespace="http://mycompany.com/login/definitions"> <sws:xsd location="/WEB-INF/login.xsd" 
  /></sws:dynamic-wsdl>



  <sws:interceptors>
   <bean
    class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
    <property name="schema" value="/WEB-INF/login.xsd" />
    <property name="validateRequest" value="true" />
    <property name="validateResponse" value="true" />
   </bean>
   <bean
    class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor">
   </bean>

  </sws:interceptors>

</beans>




Next is to create the request and response classes. This can be done by using the xjc command in JAVA_HOME\bin folder. What it needs is just the xsd. Go to the folder where the xsd is saved and type the below command.

C:\Softwares\xsd>xjc .
parsing a schema...
compiling a schema...
com\mycompany\login\schemas\LoginRequest.java
com\mycompany\login\schemas\ObjectFactory.java
com\mycompany\login\schemas\Response.java
com\mycompany\login\schemas\package-info.java


Now finally we create the endpoint class. The actual webservice. This class used JAXB marshaller to marshall and unmarshall the request/response objects.

package com.login;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.util.JAXBSource;
import javax.xml.transform.Source;

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
@Endpoint
public class LoginEndpoint {
 private static final String NAMESPACE_URI = "http://mycompany.com/login/schemas";
 

 @PayloadRoot(namespace = NAMESPACE_URI, localPart = "LoginRequest") 
 public @ResponsePayload
 Source handleHolidayRequest(@RequestPayload Source source)
   throws Exception {
  
  System.out.println("in here called");
  LoginRequest loginRequest =  (LoginRequest)unmarshal(source,LoginRequest.class);
  Response response = new Response();
  
  response.setMessage("welcome user " + loginRequest.getUsername());
  
  return marshal(response);

 }
    private Source marshal(Object obj) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(obj.getClass());
        return new JAXBSource(context, obj);
    }
 private Object unmarshal(Source source, Class clazz) throws JAXBException {
        JAXBContext context;
        try {
            context = JAXBContext.newInstance(clazz);
            Unmarshaller um = context.createUnmarshaller();
            return um.unmarshal(source);
        } catch (JAXBException e) {
            e.printStackTrace();
            throw e;
        }
    }
}
After the webapplication is deployed correctly, you can view the wsdl by hitting the below URL on browser:

http://localhost:8080/Login_Simple/login.wsdl

Once the services is UP, you can test the webservice using any webservice client like jax-ws or any other tool.
Below is the sample request and response tested in SOAPUI

SOAP Request

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://mycompany.com/login/schemas">
   <soapenv:Header/>
   <soapenv:Body>
      <sch:LoginRequest>
         <sch:username>Hunaid</sch:username>
         <sch:password>password@123</sch:password>
      </sch:LoginRequest>
   </soapenv:Body>
</soapenv:Envelope>

SOAP Response
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <Response xmlns="http://mycompany.com/login/schemas">
         <message>welcome user Hunaid</message>
      </Response>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


Below is the structure of the application for your reference



For Web Service Introduction click here

Below are some posts that explain how to implement and test SOAP/REST Webservices

Host
SOAP REST
JAX-WS JAX-RS
Spring-ws Spring-MVC-REST
Client
SOAP REST
JAX-WS(wsimport) Google REST APP
SOAP UI Apache REST

Share the post