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:
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.
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:
- JDK 1.4 and above
- Eclipse any version which supports J2EE development(I suggest Eclipse Galileo or Helio)
- 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)
- Spring WebServices 1.5.9 (Download here)
- Apache Tomcat 5.5 or 6.0
- 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
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>
<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 . import java.math.BigDecimal;
public interface AdderInterface {
public BigDecimal add(BigDecimal num1, BigDecimal num2);
}
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:import java.math.BigDecimal;
public class Adder implements AdderInterface {
@Override
public BigDecimal add(BigDecimal num1, BigDecimal num2) {
BigDecimal result = num1.add(num2);
return result;
}
}
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 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.public void setAddNumber(Adder addNumber) {
this.addNumber = addNumber;
}
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.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;
Below is the full listing of AdderEndpoint.java.newInstance();
AddResponse addResponse = addResponseDocument.addNewAddResponse();
addResponse.setResult(result);
addResponseDocument.setAddResponse(addResponse);
return addResponseDocument;
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.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;
}
}
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)<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>
x<servlet-mapping>
<servlet-name>adder</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
The complete listing of web.xml<servlet-name>adder</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<?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:<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>
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<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>
<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.<property name="addNumber" ref="addNumber" />
<property name="marshaller" ref="calcMarshaller" />
<property name="unmarshaller" ref="calcMarshaller" />
</bean>
<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.<property name="addNumber" ref="addNumber" />
<property name="marshaller" ref="calcMarshaller" />
<property name="unmarshaller" ref="calcMarshaller" />
</bean>
<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.<property name="addNumber" ref="addNumber" />
<property name="marshaller" ref="calcMarshaller" />
<property name="unmarshaller" ref="calcMarshaller" />
</bean>
<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<property name="xsd" value="/WEB-INF/adder.xsd" />
</bean>
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


nice, but can u help me regarding the implementing faults in the same web services.
ReplyDelete