Spring Web Services is a product from Spring community to develop the web services in easier manner. Spring Web Services is following the strategy of contract-first web services. It focus more on XML and lesser on Java implementation. In this article, we will learn how to write a simple web service application using Spring Web Services. It is expected that the reader has a fair amount of knowledge on Web services concepts before continuing with the article along with the basics of Spring Framework like Dependency Injection and Inversion of Control. For more information on the per-requisites, refer Spring Introduction and Web Services on JavaBeat. The below list has some of the popular spring framework articles published in JavaBeat.
also read:
What is Contract First Web Services?
When developing web services, there are two approaches:Contract Last and Contract First. Whan using the contract-last approach, you first write the Java code and let web service contract(WSDL) to be genereated for that. When using the contract-first approach, you start with the web services contract (XML files) and let Java impletement the web service contract. Spring Web Services only supports the contract-first development style.
Spring Web Services Example
In this article, we will design a simple utility that reverses a given string using Spring Web Service. This article will provide the content in a tutorial fashion in a step-by-step manner and parallely giving relevant details to that section. Generally speaking, developing web services involves writing artifacts in the server and the client tier. We will look into the details about those artifacts in the subsequent sections. Given below are the pre-requisite softwares to develop and run the application
- Java Development Kit
- Spring Web Service Framework
- Web Server
Server-side artifacts
The following steps are provided in building up the various server-side artifacts.
- Contract Design
- Defining the service interface
- Implementing the service interface
- Defining Spring Web-Service endpoints
- Configuring deployment descriptor.
- Configuring Spring’s Application Context.
Remember to build the server tier as a web application so that it can be made runnable in any web server.
Contract design
We will design the contract for the service through xml. The contract defines the input and the output messages that a service expects. Since we wanted to enforce restriction on the input and output, we will provide an XSD. In our case, the request and the response messages will be simple string objects. The following definition defines the XSD file:
reversalService.xsd
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="qualified" targetNamespace="https://javabeat.net/spring /spring-ws/articles/reversal-service" xmlns:tns="https://javabeat.net/spring /spring-ws/articles/reversal-service"> <element name="stringReveralRequest" type="string"/> <element name="stringReveralResponse" type="string"/> </schema>
Defining the service interface
The service interface represents the client-facing interface for invoking the service by passing in the required inputs. Note that the interface will be a simple POJO, the interface doesn’t need to extend or implement any of the spring web-service related APIs. In this example, the input will be a simple java string object.
StringReveralService.java
package net.javabeat.spring.springws.articles.stringreversal; public interface StringReveralService { String reverse(String anyString); }
Implementing the service interface
Writing the implementation for the above service interface will be fairly straight-forward. It reverses the input string by using Java built-in API and returns the result to the caller. The following code will just do that.
StringReversalServiceImpl.java
package net.javabeat.spring.springws.articles.stringreversal; public class StringReversalServiceImpl implements StringReveralService{ @Override public String reverse(String anyString) { if (anyString == null || anyString.trim().length() == 0){ return ""; } return new StringBuilder(anyString).reverse().toString(); } }
Defining endpoints
Endpoints are components for processing the input request messages and are usually responsible for invoking the desired service by passing in the required details. Spring Web Services implementation comes with two flavors of endpoints – message endpoints and payload endpoints. Message endpoints provide access to the raw input XML message including the XML header along with the XML body. On the other hand, Payload endpoints are useful in dealing with the XML body alone.
In our simple application, we will define a Payload endpoint for parsing the input XML message for invoking the StringReversalService service.
StringReversalServiceEndPoint.java
package net.javabeat.spring.springws.articles .stringreversal.endpoint; import net.javabeat.spring.springws.articles.stringreversal .StringReveralService; import org.springframework.ws.server.endpoint .AbstractDomPayloadEndpoint; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; public class StringReversalServiceEndPoint extends AbstractDomPayloadEndpoint { public static final String NAMESPACE = "https://javabeat.net/spring/spring-ws /articles/reversal-service"; private StringReveralService stringReversalService; public void setStringReveralService( StringReveralService stringReveralService) { this.stringReversalService = stringReveralService; } protected Element invokeInternal(Element requestElement, Document document) throws Exception { String requestString = findRequestString(requestElement); String reversedString = invokeServiceAndReturnResponse(requestString); Element responseXml = prepareResponseXml(document, reversedString); return responseXml; } private static String findRequestString(Element requestElement){ NodeList childNodes = requestElement.getChildNodes(); String requestString = null; for (int i = 0; i < childNodes.getLength(); i++) { if (childNodes.item(i).getNodeType() == Node.TEXT_NODE) { Text tempText = (Text) childNodes.item(i); requestString = tempText.getNodeValue(); break; } } return requestString; } private String invokeServiceAndReturnResponse(String requestString){ String reversedString = stringReversalService.reverse(requestString); return reversedString; } private static Element prepareResponseXml( Document document, String responseString){ Element responseElement = document.createElementNS( NAMESPACE, "stringReveralResponse"); Text responseText = document.createTextNode(responseString); responseElement.appendChild(responseText); return responseElement; } }
The method invokeInternal will be called when an XML request is received by the framework and the whole xml content will be available in the requestElement. The rest of the code does the job of finding the request string from the input XML, invoke the string reversal service for reversing the string and then constructs the appropriate XML response.
Note that this class is dependent on StringReversalService: in the later section, we will see how to inject this dependency.
Configuring the web application context
The web application’s deployment descriptor must be configured with a servlet that is capable of dispatching web service message to the appropriate handler. This happens to be the MessageDispatcherServlet servlet.
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name> String Reversal Service Demo using Spring WebService </display-name> <servlet> <servlet-name>spring-ws-service</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-service</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
In the above XML, we have routed all requests to the servlet spring-ws-service which in-turns maps to MessageDispatcherServlet. The above dispatcher servlet will search for a configuration file representing the spring application context for looking up the definition for various spring beans. By default, the name of the configuration file will be derived from the servlet name. If the name of the servlet is xyz, then the name of the configuration file will be xyz-servlet.xml. In our case, the configuration file will be spring-ws-service-servlet.xml. We will look into more details of the configuration file in the following section.
Spring Application Configuration file
The minimal requirement of the spring application configuration file that resides in a web server is to contain the following entries:
- Endpoints definition
- Endpoint mappings definition
- WSDL Definition
Endpoint definition
Remember that endpoints in Spring Web Service are used to process the input XML request and then to invoke the appropriate service and it is necessary to declare them in the spring’s application context. The following code snippet will just do that.
<bean id="stringReversalService"> </bean> <bean id="stringReversalServiceEndpoint"> <property name="stringReversalService" ref="stringReversalService"/> </bean>
Endpoint mapping definition
Endpoint mapping definitions are used to map the incoming XML message to the appropriate endpoints. For an application dealing with multiple namespaces, there must be some way to route certain set of namespace definitions to an endpoint and to route the other set of namespace definitions to some other endpoint.
<bean id="payloadMapping"> <property name="defaultEndpoint" ref="stringReversalServiceEndpoint"/> </bean>
WSDL Definition
There are multiple ways of generating and subsequently publishing the WSDL to the client. One of the simpler approaches is used generate the WSDL file directly from the XML schema. Refer the following code snippet,
<bean id="stringReversalSchema"> <property name="xsd" value="/WEB-INF/reversalService.xsd"/> </bean> <bean id="stringReversal"> <property name="schema" ref="stringReversalSchema"/> <property name="portTypeName" value="stringReversal"/> <property name="locationUri" value="http://localhost:8080/string-reversal/services"/> </bean>
The first bean declaration defines an instance of the string reversal XML schema that we had defined for getting referenced in the WSDL definition bean ‘stringReversal’. Note that in this bean declaration, we have specified the port-type and the URI where the service is located, which are the minimal requirements for the framework to generate the WSDL file. Other properties for the WSDL file will have sensible defaults, however it is absolutely possible to override the default values here. The important thing to note is the bean identifier stringReversal. Clients will be referencing only this bean identifier in the client code and not the name of the WSDL file in this case.
Note that these artifacts have to be wriiten as a web project with the standard directory layout. Assuming that the web project module is built as a war and is deployed in a web sever, we can start concentrating on writing the client-side artifacts.
Client-side artifacts
There is not too much work to be done in the client end as the client-side artifact represents a plain java application that is capable of contacting the web service that is residing on top of the web server. Writing the client code is fairly simple. Spring Template classes for web services simplify the process of writing the client side. Take a look at the following client code,
StringReversalClient.java
package net.javabeat.spring.sprringws.stringreversal.client; import java.io.StringReader; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.springframework.ws.client.core.WebServiceTemplate; public class StringReversalClient { public static void main(String[] args) throws Exception{ String xmlRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<stringReveralRequest xmlns=\"https://javabeat.net /spring/spring-ws/articles/reversal-service\">Hello</stringReveralRequest>"; String wsdlUrl = "http://localhost:8080/string-reversal/stringReversal.wsdl"; StreamSource requestMessage = new StreamSource(new StringReader(xmlRequest)); StreamResult responseMessage = new StreamResult(System.out); WebServiceTemplate template = new WebServiceTemplate(); template.sendSourceAndReceiveToResult(wsdlUrl, requestMessage, responseMessage); } }
The code constructs input XML message containing the string to be reversed. Then it defines the URL of the WSDL file. Remember that in the URL containing the WSDL file name stringReversal.wsdl, stringReversal represents the bean id. For sending and receiving a web service XML message, WebServiceTemplate class can be used with the configuration done for the request and the response objects. The request comes from string reader object encapsulating the XML string and the response is the standard output meaning that the response will be displayed in the standard output – usually the console.
also read:
Conclusion
This article provided step-by-step details in writing a simple web service using Spring Web Services framework. With the invent of this framework, developer doesn’t have to worry too much in spending time for understanding the low-level details that are often involved in developing any web service application and can concentrate only on the core business logic.
Spring Framework Reference.