Java Articles | Spring Articles

Wednesday, May 25, 2011

Spring Webservice Provider(Client) - Part 2

This tutorial is the continuation of the previous tutorial which I wrote to create a Spring based Web Service Provider. This is basically to write a Client which can send an AddRequest.xml document to the web service and recieves a AddResponse.xml document from the provider.


Step1:
Create a request xml document and store it in C:\Adder directory. This is the document which is sent to the web service as a request.
request.xml
<?xml version="1.0" encoding="UTF-8" ?>
<hr:AddRequest xmlns:hr="http://mycompany.com/calc/schemas"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mycompany.com/calc/schemas WEB-INF/calculator.xsd">
<hr:Number1>15.0</hr:Number1>
<hr:Number2>5.0</hr:Number2>
</hr:AddRequest>

Step2:
Create a java project AdderWSClient and write the client class.Create a lib directory in the project. Copy all the jars from the provider project and place them in a lib directory. Also add the jars in the classpath of the project.Create a class with the name AdderWSClient, in com.adder.client package, which extends a ebServiceGatewaySupport a class from the spring framework.

Write a method simpleSendAndRecieve which will send the request to the webservice by reading the xml from the specified loacation and writing the response.xml to the specified location.
public void simpleSendAndReceive() {

StreamSource requestMessage = new StreamSource(new File(
"C:\\Adder\\request.xml"));
StreamResult responseMessage = new StreamResult(new File(
"C:\\Adder\\response.xml"));
getWebServiceTemplate().sendSourceAndReceiveToResult(requestMessage,
responseMessage);
}
Write the main method to load the spring context.
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"client.xml");

AdderWSClient client = (AdderWSClient) context.getBean("webServiceClient");

client.simpleSendAndReceive();
}
Full listing of AdderWSClient.java
package com.adder.client;

import java.io.File;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;

public class AdderWSClient extends WebServiceGatewaySupport {

public void simpleSendAndReceive() {

StreamSource requestMessage = new StreamSource(new File(
"D:\\request.xml"));
System.out.print(requestMessage);
StreamResult responseMessage = new StreamResult(new File(
"D:\\response1.xml"));
getWebServiceTemplate().sendSourceAndReceiveToResult(requestMessage,
responseMessage);
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"client.xml");

AdderWSClient c = (AdderWSClient) context.getBean("webServiceClient");

c.simpleSendAndReceive();
}
}
Step 3:
We need the client.xml which is a spring context file. So we will also write a spring context file.Where we provide the client class with the default uri where we can locate the web service. Code for client.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean id="webServiceClient" class="com.adder.client.AdderWSClient">
<property name="defaultUri"
value="http://localhost:8080/AdderWS/AddNumberService/" />
</bean>

</beans>

Place the client.xml in the src directory of your project and execute the main method. A response.xml will appear in C:\Adder directory.

That was all for Spring Web Services. We have many other ways of creating a Spring Web Service and Client. This was one of the simpler ways and easy to learn.

Hope it helped you in learning. Happy Learning :)

Saturday, May 21, 2011

Spring Webservice Provider(Server) - Part 1

There is a lot on the web with the name Web Services. This is for those who want to create a Spring Web Service of their own.

Spring advocates contract first web services. So the basic perquisites for this tutorial is a working knowledge of XMLs and Java and of course a bit of Spring.

Requirements:
  1.  JDK 1.4 and above
  2.  Eclipse any version which supports J2EE development(I suggest Eclipse Galileo or Helio)
  3.  Spring 2.5 (Download it from here, if possible download Spring 2.5.6 with dependencies, you will find all the jars in the distribution)
  4.  Spring WebServices 1.5.9 (Download here)
  5.  Apache Tomcat 5.5 or 6.0
  6.  The following jars must be placed in the lib folder of your project:
  •  commons-logging.jar
  •  javax.wsdl_1.5.1.jar
  •  spring-beans.jar
  •  spring-context.jar
  •  spring-core.jar
  •  spring-web.jar
  •  spring-webmvc.jar
  •  spring-ws-1.5.9-all.jar
  •  xbean.jar
In this tutorial we will create a web service which will accept two integers as parameters and return an integer as the sum.

Steps involved.

Step 1: Creating the contract, i.e. a xsd(XML Schema Document) for the web service. The contract defines the type of request which the web service expects and the type of response which would be sent to the client.

adder.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:hr="http://mycompany.com/calc/schemas" elementFormDefault="qualified"
targetNamespace="http://mycompany.com/calc/schemas">
<xs:element name="AddRequest">
<xs:complexType>
<xs:all>
<xs:element name="Number1" type="xs:decimal" />
<xs:element name="Number2" type="xs:decimal" />
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="AddResponse">
<xs:complexType>
<xs:all>
<xs:element name="Result" type="xs:decimal" />
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>

Step 2:
Generating required classes from adder.xsd. You can use any XML parser to generate the classes used in the web service. For eg: Here we will use the Apache xmlbeans 2.0.0 which can be downloaded from xmlbeans

Create a folder Adder in C drive and place adder.xsd in the folder.
Open the command window, navigate to java bin directory and run type the following command : scomp -out C:\Adder\adder.jar -src C:\Adder C:\Adder\adder.xsd

adder.jar is created in C:\Adder folder. Also the source code for the jar is created there.

Step 3:
Create a new Dynamic Web project in Eclipse and name it AdderWS.
Copy adder.xsd to WebContent\WEB-INF and adder.jar to WebContent\WEB-INF\lib folder.
Also add adder.jar into the build path.

Step 4:
Create com.adder.service package in the src folder of the project and create an interface AdderInterface.java
package com.adder.service;

import java.math.BigDecimal;

public interface AdderInterface {
public BigDecimal add(BigDecimal num1, BigDecimal num2);
}
Create a concrete implementation of the Interface .
Adder.java
package com.adder.service;

import java.math.BigDecimal;

public class Adder implements AdderInterface {

@Override
public BigDecimal add(BigDecimal num1, BigDecimal num2) {
BigDecimal result = num1.add(num2);
return result;
}
}
Step 5:
Creating the service endpoint
Create com.adder.endpoint package in the src folder of the project and create a class AdderEndpoint.java
Explanation: An endpoint is used for the following purpose at the provider end of a web service:
  •  To receive a request(here a soap message).
  •  Retrieve the request message(which is a xml document).
  •  Unmarshall it, i.e. convert xml into a request object.
  •  Process the request object by calling the business layer.
  •  Create a response object and marshall it into a xml document.
  •  Send back the xml document as the body of a soap message.
We create an AdderEndpoint which extends AbstractMarshallingPayloadEndpoint and override its invokeInternal().
We need to invoke the service layer methods i.e. the Adder class methods to process the business logic and retrieve a result. Hence the following code.
private Adder addNumber;

public void setAddNumber(Adder addNumber) {
this.addNumber = addNumber;
}
The invokeInternal() method retrieves the AddRequestDocument from the request and fetches the numbers which we want the service to add.
AddRequestDocument addRequest = (AddRequestDocument) request;
BigDecimal num1 = addRequest.getAddRequest().getNumber1();
BigDecimal num2 = addRequest.getAddRequest().getNumber2();
BigDecimal result = addNumber.add(num1, num2);
After the processing, it creates a AddResponseDocument and sets the result into it. After that it returns the AddResponse Document.
AddResponseDocument addResponseDocument = (AddResponseDocument) AddResponseDocument.Factory
.newInstance();
AddResponse addResponse = addResponseDocument.addNewAddResponse();
addResponse.setResult(result);
addResponseDocument.setAddResponse(addResponse);
return addResponseDocument;
Below is the full listing of AdderEndpoint.java
package com.adder.endpoint;

import java.math.BigDecimal;

import org.springframework.ws.server.endpoint.AbstractMarshallingPayloadEndpoint;

import com.adder.service.Adder;
import com.mycompany.calc.schemas.AddRequestDocument;
import com.mycompany.calc.schemas.AddResponseDocument;
import com.mycompany.calc.schemas.AddResponseDocument.AddResponse;

public class AdderEndpoint extends AbstractMarshallingPayloadEndpoint{
private Adder addNumber;

public void setAddNumber(Adder addNumber) {
this.addNumber = addNumber;
}

@Override
protected Object invokeInternal(Object request) throws Exception {

AddRequestDocument addRequest = (AddRequestDocument) request;
BigDecimal num1 = addRequest.getAddRequest().getNumber1();
BigDecimal num2 = addRequest.getAddRequest().getNumber2();
BigDecimal result = addNumber.add(num1, num2);
AddResponseDocument addResponseDocument = (AddResponseDocument) AddResponseDocument.Factory
.newInstance();
AddResponse addResponse = addResponseDocument.addNewAddResponse();
addResponse.setResult(result);
addResponseDocument.setAddResponse(addResponse);
return addResponseDocument;
}
}
The invokeInternal() method is called by the spring container once it receives a request for the specific endpoint.

Step 6:

Configuring web container for the web service.
Edit the web.xml located in WebContent\WEB-INF directory
Declare a servlet in the web.xml which will handle any incoming request for the webservice.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:hr="http://mycompany.com/calc/schemas" elementFormDefault="qualified"
targetNamespace="http://mycompany.com/calc/schemas">
<xs:element name="AddRequest">
<xs:complexType>
<xs:all>
<xs:element name="Number1" type="xs:decimal" />
<xs:element name="Number2" type="xs:decimal" />
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="AddResponse">
<xs:complexType>
<xs:all>
<xs:element name="Result" type="xs:decimal" />
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
Now map all coming request urls with the servlet. Any request to use the webservice will be directed to this particular servlet(here adder)
x<servlet-mapping>
<servlet-name>adder</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
The complete listing of web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>AdderWS</display-name>
<servlet>
<servlet-name>adder</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>adder</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Step 7:
Configuring spring for the web service.
Create a adder-servlet.xml in WebContent\WEB-INF directory
Add the beans namespace declarations as needed and after that we will wire up the beans and inject one into the other as per requirements.
First we declare the endpoint mapping which resolves the mapping and chooses an endpoint from several endpoints.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>AdderWS</display-name>
<servlet>
<servlet-name>adder</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>adder</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

This mapping requires an endpoint, adderEndPoint so we need to declare another bean with the name adderEndPoint
<bean id="adderEndPoint" class="com.adder.endpoint.AdderEndpoint">
<property name="addNumber" ref="addNumber" />
<property name="marshaller" ref="calcMarshaller" />
<property name="unmarshaller" ref="calcMarshaller" />
</bean>
This endpoint requires an addNumber object, a marshaller to marshall the response document into xml, and an unmarshaller to unmarshal xml into request document.
<bean id="adderEndPoint" class="com.adder.endpoint.AdderEndpoint">
<property name="addNumber" ref="addNumber" />
<property name="marshaller" ref="calcMarshaller" />
<property name="unmarshaller" ref="calcMarshaller" />
</bean>
Now we must declare the dynamic generation of wsdl document. Declare a bean with the name adder so that the wsdl can be generated with the same name.
<bean id="adderEndPoint" class="com.adder.endpoint.AdderEndpoint">
<property name="addNumber" ref="addNumber" />
<property name="marshaller" ref="calcMarshaller" />
<property name="unmarshaller" ref="calcMarshaller" />
</bean>
Declare a bean addSchema as we need to tell the spring container where the contract(xsd) could be find.
<bean id="addSchema" class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="/WEB-INF/adder.xsd" />
</bean>
Below is the full listing of adder-servlet.xml























Step 8:
Publishing the Web Service
Start the tomcat server, and run the project.
In the browser address bar type the url http://localhost:8080/AdderWS/adder.wsdl

If a wsdl document appears, it confirms that the webservice is successfully hosted.

Screenshot of Project directory