In this chapter, we will cover:
Setting up a Web-Service client development environment within Eclipse
Setting up a Web-Service client development environment using Maven
Creating a Web-Service client on HTTP transport
Creating a Web-Service client on JMS transport
Creating a Web-Service client on E-mail transport
Creating a Web-Service client on XMPP transport
Creating a Web-Service client using XPath expression
Creating a Web-Service client for WS-Addressing endpoint
Transforming a Web-Service message using XSLT
Using Java API, such as SAAJ
, client-side SOAP messages can be generated and transmitted to/from a Web-Service. However, it requires an extra amount of coding and knowledge about SOAP messages.
The package org.springframework.ws.client.core
contains the core functionality of the client-side API, which facilitates calling the server-side Web-Service.
APIs in this package provide template classes like WebServiceTemplate
that simplifies the use of Web-Services. Using these templates, you will be able to create a Web-Service client over various transport protocols (HTTP, JMS, e-mail, XMPP, and so on) and send/receive XML messages as well as marshal objects to XML before sending them. Spring also provides classes, such as StringSource
and Result
, which simplify passing and retrieving XML messages while using WebServiceTemplate
.
In this chapter, the first two recipes explain how to set up the environment for calling a Web-Service client using Eclipse and Maven.
Then we will discuss the usage of WebServiceTemplate
to create a Web-Service client over various transport protocols (HTTP, JMS, e-mail, XMPP, and so on). In addition to this, the recipe Setting up a Web-Service client using an XPath expression explains how to retrieve data from an XML message. Finally, in the last recipe, Transforming a Web-Service message using XSLT, how to convert the XML messages into different formats between the client and server is presented. To set up a Web-Service server, some recipes from Chapter 1, Building SOAP Web-Services, are used and a separate client project is created that calls the server-side Web-Service.
A Web-Service client in the simplest form is a Java class that calls a server-side Web-Service. In this recipe, setting up the environment to call a server-side Web-Service is presented. Here, a client-side Java class calls a Web-Service on the server in two forms. The first one is a Java class that calls a Web-Service in the main method of the class. The second one uses the JUnit test class to call the server-side Web-Service.
This recipe is similar to the recipe Using Maven for building and running a Spring-WS, discussed in Chapter 1,Building SOAP Web-Services.
Download and install the Eclipse IDE for Java EE developers Helios.
In this recipe, the project's name is LiveRestaurant_R-2.1
(for server-side Web-Service), with the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
jdom-1.0.jar
log4j-1.2.9.jar
jaxen-1.1.jarb
xalan-2.7.0.jar
The LiveRestaurant_R-2.1-Client
(for the client side) has the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
jdom-1.0.jar
log4j-1.2.9.jar
jaxen-1.1.jar
xalan-2.7.0.jar
junit-4.7.jar
Run the following Maven command to be able to import the client projects into Eclipse (for the client side):
mvn eclipse:eclipse -Declipse.projectNameTemplate="LiveRestaurant_R-2.1-Client"
This recipe uses the recipe Handling the incoming XML messages using JDOM, discussed in Chapter 1, Building SOAP Web-Services, as the server-side project.
Run a Java class that calls a Web-Service in the main method.
Import LiveRestaurant_R-2.1-Client
into the Eclipse workspace by going to File | Import | General | Existing projects into workspace | LiveRestaurant_R-2..1-Client.
Go to the folder LiveRestaurant_R-2.1
in the command prompt and run the server using the following command:
mvn clean package tomcat:run
Select the class OrderServiceClient
in the folder src/main/java
from the package com.packtpub.liverestaurant.client
and select Run As | Java Application.
The following is the console output on running the Java class on the client side:
Received response ....
<tns:placeOrderResponse xmlns:tns=".."> <tns:refNumber>order-John_Smith_9999</tns:refNumber>
</tns:placeOrderResponse>
for request...
<tns:placeOrderRequest xmlns:tns="...">
<tns:order>
<tns:refNumber>9999</tns:refNumber>
<tns:customer>
.......
</tns:customer>
<tns:dateSubmitted>2008-09-29T05:49:45</tns:dateSubmitted>
<tns:orderDate>2014-09-19T03:18:33</tns:orderDate>
<tns:items>
<tns:type>Snacks</tns:type>
<tns:name>Pitza</tns:name>
<tns:quantity>2</tns:quantity>
</tns:items>
</tns:order>
</tns:placeOrderRequest>....
Run a JUnit test case using Eclipse.
Select the class OrderServiceClientTest
in the folder src/test/java
from the package com.packtpub.liverestaurant.client
and select Run As | Junit Test.
The following is the console output on running the JUnit test case (you can click on the JUnit tab, adjacent to the Console tab, to see whether the test case has succeeded or not):
Received response ..
<tns:placeOrderResponse xmlns:tns="...">
<tns:refNumber>order-John_Smith_9999</tns:refNumber>
</tns:placeOrderResponse>..
......
<tns:placeOrderRequest xmlns:tns=".....">
<tns:order>
<tns:refNumber>9999</tns:refNumber>
<tns:customer>
......
</tns:customer>
<tns:dateSubmitted>2008-09-29T05:49:45</tns:dateSubmitted>
<tns:orderDate>2014-09-19T03:18:33</tns:orderDate>
<tns:items>
<tns:type>Snacks</tns:type>
<tns:name>Pitza</tns:name>
<tns:quantity>2</tns:quantity>
</tns:items>
</tns:order>
</tns:placeOrderRequest>
When a Java class that calls a Web-Service in the main method is run, Eclipse runs the following command internally using the following Java class path:
java -classpath com.packtpub.liverestaurant.client.OrderServiceClient
When a JUnit test case is run, Eclipse runs a test case using the JUnit framework by internally calling the following command:
java -classpath com.packtpub.liverestaurant.client.OrderServiceClientTest
The recipes Using Maven for building and running a Spring-WS project and Handling the incoming XML messages using JDOM, discussed in Chapter 1,
The recipe Creating a Web-Service client on HTTP transport, discussed in this chapter.
Maven supports running the main method of a class using command prompt as well as a JUnit test case.
In this recipe, setting up a Maven environment to call a client-side Web-Service is explained. Here, a client-side Java code calls a Web-Service on the server in two forms. The first one is a Java class that calls a Web-Service in the main method of the class. The second one uses JUnit to call a server-side Web-Service.
In this recipe, the project's name is LiveRestaurant_R-2.2
(for a server-side Web-Service) with the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
log4j-1.2.9.jar
The following are the Maven dependencies for LiveRestaurant_R-2.2-Client
(for the client-side Web-Service):
spring-ws-core-2.0.1.RELEASE.jar
junit-4.7.jar
This recipe uses the recipe Handling the incoming XML messages using DOM, discussed in Chapter 1, Building SOAP Web-Services, as the server-side project.
Run a Java class that calls a Web-Service in the main method.
Go to the folder LiveRestaurant_R-2.2
in the command prompt and run the server using the following command:
mvn clean package tomcat:run
Go to the folder LiveRestaurant_R-2.2-Client
and run the following command:
mvn clean package exec:java
The following is the output when the Maven command is run on the client side:
Received response ....
<placeOrderResponse xmlns="...">
<refNumber>order-John_Smith_9999</refNumber>
</placeOrderResponse>....
<tns:placeOrderRequest xmlns:tns="...">
<tns:order>
<tns:refNumber>9999</tns:refNumber>
<tns:customer>
.....
</tns:customer>
<tns:dateSubmitted>2008-09-29T05:49:45</tns:dateSubmitted>
<tns:orderDate>2014-09-19T03:18:33</tns:orderDate>
<tns:items>
<tns:type>Snacks</tns:type>
<tns:name>Pitza</tns:name>
<tns:quantity>2</tns:quantity>
</tns:items>
</tns:order>
</tns:placeOrderRequest>
Run a JUnit test case using Maven.
Go to the folder LiveRestaurant_R-2.2
from the command prompt and run the server using the following command:
mvn clean package tomcat:run
Go to the folder LiveRestaurant_R-2.2-Client
and run the following command:
mvn clean package
Here is the output after running the JUnit test case using Maven on the client side:
Received response ...
<placeOrderResponse xmlns="...">
<refNumber>order-John_Smith_9999</refNumber>
</placeOrderResponse>...
for request ...
<tns:placeOrderRequest xmlns:tns="...">
<tns:order>
<tns:refNumber>9999</tns:refNumber>
<tns:customer>
.....
</tns:customer>
<tns:dateSubmitted>2008-09-29T05:49:45</tns:dateSubmitted>
<tns:orderDate>2014-09-19T03:18:33</tns:orderDate>
<tns:items>
<tns:type>Snacks</tns:type>
<tns:name>Pitza</tns:name>
<tns:quantity>2</tns:quantity>
</tns:items>
</tns:order>
</tns:placeOrderRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.702 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
Run a Java class that calls a Web-Service in the main method, exec-maven-plugin
, set in the pom.xml
file. The Java class tells Maven to run mainClass
of OrderServiceClient:
<build> <finalName>LiveRestaurant_Client</finalName> <plugins> ....... </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.2.1</version> <executions> <execution> <goals> <goal>java</goal> </goals> </execution> </executions> <configuration> <mainClass>com.packtpub.liverestaurant.client.OrderServiceClient</mainClass> </configuration> </plugin> </plugins> </build>
Maven runs the following command internally using the project class path:
java -classpath com.packtpub.liverestaurant.client.OrderServiceClient
To set up and run a JUnit test case in Maven, the test class OrderServiceClientTest
should be included in the folder src/test/java
and the test class name should end with Test
(OrderServiceClientTest)
. The command mvn clean package
runs all the test cases in the src/test/java
folder (internal Maven calls):
java -classpath ...;junit.jar.. junit.textui.TestRunner com.packtpub.liverestaurant.client.OrderServiceClientTest ) .
The recipes Using Maven for building and running a Spring-WS project and Handling the incoming XML messages using JDOM, discussed in Chapter 1,Building SOAP Web-Services.
The recipe Creating a Web-Service client on HTTP transport, discussed in this chapter.
In this recipe, WebServiceTemplate
is used to send/receive simple XML messages from the client side over the HTTP transport.
In this recipe, the project's name is LiveRestaurant_R-2.3
(for server-side Web-Service) with the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
log4j-1.2.9.jar
The following are the Maven dependencies for LiveRestaurant_R-2.3-Client
(for the client-side Web-Service):
spring-ws-core-2.0.1.RELEASE.jar
junit-4.7.jar
This recipe uses the recipe Setting up an endpoint by annotating the payload-root, discussed in Chapter 1, Building SOAP Web-Services, as the server-side project. Here is how you set up the client side:
Create a class that calls the Web-Service server using WebServiceTemplate
in src/test
.
Configure WebServiceTemplate
in the applicationContext.xml
file.
From the folder Liverestaurant_R-2.3
, run the following command:
mvn clean package tomcat:run
Open a new command window to Liverestaurant_R-2.3-Client
and run the following command:
mvn clean package
The following is the client-side output:
Received response ....
<tns:placeOrderResponse xmlns:tns="...">
<tns:refNumber>order-John_Smith_1234</tns:refNumber>
</tns:placeOrderResponse>...
<tns:placeOrderRequest xmlns:tns="....">
<tns:order>
<tns:refNumber>9999</tns:refNumber>
<tns:customer>
......
</tns:customer>
<tns:dateSubmitted>2008-09-29T05:49:45</tns:dateSubmitted>
<tns:orderDate>2014-09-19T03:18:33</tns:orderDate>
<tns:items>
<tns:type>Snacks</tns:type>
<tns:name>Pitza</tns:name>
<tns:quantity>2</tns:quantity>
</tns:items>
</tns:order>
</tns:placeOrderRequest>
.....
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.749 sec
Results :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
Liverestaurant_R-2.3
is a server-side project that reuses the recipe Setting up an endpoint by annotating the payload-root, discussed in Chapter 1,Building SOAP Web-Services.
The applicationContext.xml
file of the configured client WebServiceTemplate
(id="webServiceTemplate")
is used for sending and receiving XML messages. The instance of this bean can be fetched from the client-side program to send and receive XML messages.
messageFactory
is an instance of SaajSoapMessageFactory
, which is referenced inside WebServiceTemplate. messageFactory
is used to create a SOAP packet from the XML messages. The default service URI is the URI that WebServiceTemplate
uses by default to send/receive all requests/responses:
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" /> <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"> <constructor-arg ref="messageFactory" /> <property name="defaultUri" value="http://localhost:8080/LiveRestaurant/spring-ws/OrderService" /> </bean>
OrderServiceClientTest.java
is a simple JUnit test case that is used to fetch and initialize WebServiceTemplate
from applicationContext.xml
in the method setUpBeforeClass()
(marked by @BeforeClass)
. In the methods testCancelOrderRequest
and testPlaceOrderRequest
(marked by @Test), WebServiceTemplate
sends a simple XML message (created by a StringSource
object from an existing input XML file) and receives a response from the server wrapped inside the Result
object:
private static WebServiceTemplate wsTemplate = null; private static InputStream isPlace; private static InputStream isCancel; @BeforeClass public static void setUpBeforeClass() throws Exception { ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("/applicationContext.xml"); wsTemplate = (WebServiceTemplate) appContext.getBean("webServiceTemplate"); isPlace = new OrderServiceClientTest().getClass().getResourceAsStream("placeOrderRequest.xml"); isCancel = new OrderServiceClientTest().getClass().getResourceAsStream("cancelOrderRequest.xml"); } @Test public final void testPlaceOrderRequest() throws Exception { Result result = invokeWS(isPlace); Assert.assertTrue(result.toString().indexOf("placeOrderResponse")>0); } @Test public final void testCancelOrderRequest() throws Exception { Result result = invokeWS(isCancel); Assert.assertTrue(result.toString().indexOf("cancelOrderResponse")>0); } private static Result invokeWS(InputStream is) { StreamSource source = new StreamSource(is); StringResult result = new StringResult(); wsTemplate.sendSourceAndReceiveToResult(source, result); return result; }
The recipe Setting up an endpoint by annotating the payload-root, discussed in Chapter 1, Building SOAP Web-Services and the recipe Setting up a Web-Service client development environment using Maven, discussed in this chapter.
JMS (Java message Service) was introduced in 1999 by Sun Microsystems as part of Java 2, J2EE. The systems that use JMS can communicate synchronously or asynchronously and are based on point-to-point and publish-subscribe models. Spring Web-Services provide features to set up a Web-Service over the JMS protocol that is built upon the JMS functionality in the Spring framework. Spring Web-Service over JMS protocol provides the following communication features:
The client and server could be disconnected and can be connected only when sending/receiving messages
The client doesn't need to wait until the server replies (in case the server needs a lot of time to process, for example, while doing complex mathematical calculations)
JMS provides features that guarantee the delivery of messages between the client and server
In this recipe, WebServiceTemplate
is used to send/receive simple XML messages on the client side over JMS transport. A JUnit test case class is used to set up as on server side and send and receive messages using WebServiceTemplate
.
In this recipe, the project's name is LiveRestaurant_R-2.4
, with the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
spring-ws-support-2.0.1.RELEASE.jar
spring-test-3.0.5.RELEASE.jar
spring-jms-3.0.5.RELEASE.jar
junit-4.7.jar
xmlunit-1.1.jar
log4j-1.2.9.jar
jms-1.1.jar
activemq-core-4.1.1.jar
This recipe uses the recipe Setting up a Web-Service on JMS transport, discussed in Chapter 1, Building SOAP Web-Services, as a server-side project.
Received response ..
<tns:placeOrderResponse xmlns:tns="...">
<tns:refNumber>order-John_Smith_1234</tns:refNumber>
</tns:placeOrderResponse>....
<tns:placeOrderRequest xmlns:tns="...">
<tns:order>
<tns:refNumber>9999</tns:refNumber>
<tns:customer>
.....
</tns:customer>
<tns:dateSubmitted>2008-09-29T05:49:45</tns:dateSubmitted>
<tns:orderDate>2014-09-19T03:18:33</tns:orderDate>
<tns:items>
<tns:type>Snacks</tns:type>
<tns:name>Pitza</tns:name>
<tns:quantity>2</tns:quantity>
</tns:items>
</tns:order>
</tns:placeOrderRequest>
In this project, we set up a Web-Service server, over JMS transport, using a JUnit class. The server uses PayloadEndpoint
to receive the XML request message and returns a simple XML message as the response (the server is already described in the recipe Setting up a Web-Service on JMS transport, discussed in Chapter 1,Building SOAP Web-Services).
The applicationContext.xml
file of the configured client WebServiceTemplate
(id="webServiceTemplate")
is used for sending and receiving XML messages. The instance of this bean can be fetched from the client-side program to send and receive XML messages. messageFactory
is an instance of SaajSoapMessageFactory
, referenced inside WebServiceTemplate. messageFactory
is used to create a SOAP packet from the XML messages. The default service URI is the JMS URI that WebServiceTemplate
uses by default to send/receive all requests/responses. JmsMessageSender
, configured inside WebServiceTemplate
, is used to send JMS messages. To use the JmsMessageSender
, the defaultUri
or JMS URI
should contain the jms:
prefix and a destination name. Some examples of JMS URI
are jms:SomeQueue, jms:SomeTopic?priority=3&deliveryMode=NON_PERSISTENT, jms:RequestQueue?replyToName=ResponseName
, and so on. By default, the JmsMessageSender
sends JMS BytesMessage
, but this can be overridden to use TextMessages
by using the messageType
parameter on the JMS URI. For example, jms:Queue?messageType=TEXT_MESSAGE
.
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"> <constructor-arg ref="messageFactory"/> <property name="messageSender"> <bean class="org.springframework.ws.transport.jms.JmsMessageSender"> <property name="connectionFactory" ref="connectionFactory"/> </bean> </property> <property name="defaultUri" value="jms:RequestQueue?deliveryMode=NON_PERSISTENT"/> </bean>
JmsTransportWebServiceIntegrationTest.java
is a JUnit test case that fetches and injects WebServiceTemplate
from the applicationContext.xml
file (marked by @ContextConfiguration("applicationContext.xml"))
. In the method testSendReceive()
(marked by @Test), WebServiceTemplate
sends a simple XML message (created by a StringSource
object from a simple input string) and receives a response from the server wrapped inside the Result
object. In the method testSendReceive()
(marked by @Test)
, sending and receiving of messages is similar to the HTTP client and uses WebServiceTemplate.sendSourceAndReceiveToResult
to send/receive messages:
@Test public void testSendReceive() throws Exception { InputStream is = new JmsTransportWebServiceIntegrationTest().getClass().getResourceAsStream("placeOrderRequest.xml"); StreamSource source = new StreamSource(is); StringResult result = new StringResult(); webServiceTemplate.sendSourceAndReceiveToResult(source, result); XMLAssert.assertXMLEqual("Invalid content received", expectedResponseContent, result.toString()); }
The recipe Setting up a Web-Service on JMS transport, discussed in Chapter 1,Building SOAPWeb-Services.
Unit testing a Web-Service using Spring Junit
In this recipe, WebServiceTemplate
is used to send/receive simple XML messages on the client side, over E-mail transport. The Setting up a Web-Service on E-mail transport recipe from Chapter 1, Building SOAP Web-Services, is used to set up a Web-Service. A JUnit test case class is used to set up a Web-Service on the server side and messages are sent/received using WebServiceTemplate
.
In this recipe, the project's name is LiveRestaurant_R-2.5
, with the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
spring-ws-support-2.0.1.RELEASE.jar
spring-test-3.0.5.RELEASE.jar
mail-1.4.1.jar
mock-javamail-1.6.jar
junit-4.7.jar
xmlunit-1.1.jar
This recipe uses the recipe Setting up a Web-Service on E-mail transport, discussed in Chapter 1, Building SOAP Web-Services, as the server-side project.
Create a test class that calls the Web-Service server using WebServiceTemplate
.
Configure WebServiceTemplate
in applicationContext
to send messages over the e-mail protocol.
Run the command mvn clean package
. The following is the output of this command:
Received response
<tns:placeOrderResponse xmlns:tns="...">
<tns:refNumber>order-John_Smith_1234</tns:refNumber>
</tns:placeOrderResponse>....
<tns:placeOrderRequest xmlns:tns="...">
<tns:order>
<tns:refNumber>9999</tns:refNumber>
<tns:customer>
.....
</tns:customer>
<tns:dateSubmitted>2008-09-29T05:49:45</tns:dateSubmitted>
<tns:orderDate>2014-09-19T03:18:33</tns:orderDate>
<tns:items>
<tns:type>Snacks</tns:type>
<tns:name>Pitza</tns:name>
<tns:quantity>2</tns:quantity>
</tns:items>
</tns:order>
</tns:placeOrderRequest>
This project sets up a Web-Service server over the E-mail transport, using a JUnit class. This class uses Spring JUnit that loads the application context, sets up the server first, and then runs the client unit test to verify that it functions as expected. The server is already explained in the recipe Setting up a Web-Service on E-mail transport, discussed in Chapter 1,Building SOAP Web-Services.
The applicationContext.xml
file of the configured client WebServiceTemplate (id="webServiceTemplate")
is used for sending and receiving XML messages. The instance of this bean can be fetched from the client-side program to send and receive XML messages. messageFactory
is an instance of SaajSoapMessageFactory
, referenced inside WebServiceTemplate. messageFactory
is used to create a SOAP packet from XML messages. transportURI
is a URI used by WebServiceTemplate
and indicates the server to use for sending requests. storeURI
is a URI, configured inside WebServiceTemplate
, and indicates the server to poll for responses (typically, a POP3 or IMAP server). The default URI is the e-mail address URI that WebServiceTemplate
uses by default to send/receive all requests/responses:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"> <constructor-arg ref="messageFactory"/> <property name="messageSender"> <bean class="org.springframework.ws.transport.mail.MailMessageSender"> <property name="from" value="[email protected]"/> <property name="transportUri" value="smtp://smtp.packtpubtest.com"/> <property name="storeUri" value="imap://[email protected]/INBOX"/> <property name="receiveSleepTime" value="1500"/> <property name="session" ref="session"/> </bean> </property> <property name="defaultUri" value="mailto:[email protected]"/> </bean> <bean id="session" class="javax.mail.Session" factory-method="getInstance"> <constructor-arg> <props/> </constructor-arg> </bean>
MailTransportWebServiceIntegrationTest.java
is a JUnit test case that fetches and injects WebServiceTemplate
from applicationContext.xml
(marked by @ContextConfiguration("applicationContext.xml"))
. In the method testWebServiceOnMailTransport()(marked
by @Test), WebServiceTemplate
sends a simple XML message (created by a StringSource
object from an input XML file) and receives a response from the server wrapped inside the Result
object.
@Test public void testWebServiceOnMailTransport() throws Exception { InputStream is = new MailTransportWebServiceIntegrationTest().getClass().getResourceAsStream("placeOrderRequest.xml"); StreamSource source = new StreamSource(is); StringResult result = new StringResult(); webServiceTemplate.sendSourceAndReceiveToResult(source, result); applicationContext.close(); XMLAssert.assertXMLEqual("Invalid content received", expectedResponseContent, result.toString()); }
The recipe Setting up a Web-Service on E-mail transport, discussed in Chapter 1,Building SOAP Web-Services.
Unit testing a Web-Service using Spring Junit
XMPP (The Extensible Messaging and Presence Protocol) is an open and decentralized XML routing technology on which systems can send XMPP messages to each other. The XMPP network consists of XMPP servers, clients, and services. Each system using XMPP is recognized by a unique ID known as the Jabber ID (JID) . XMPP servers publish XMPP services to offer connected to a client remote service.
In this recipe, WebServiceTemplate
is used to send/receive simple XML messages on the client side over XMPP transport. The recipe Setting up a Web-Service on XMPP transport from Chapter 1, Building SOAP Web-Services, is used to set up a Web-Service. A JUnit test case class is used to set up a Web-Service on the server side and send and receive messages using WebServiceTemplate
.
In this recipe, the project's name is LiveRestaurant_R-2.6
, with the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
spring-ws-support-2.0.1.RELEASE.jar
spring-test-3.0.5.RELEASE.jar
junit-4.7.jar
xmlunit-1.1.jar
smack-3.1.0.jar
This recipe uses the recipe Setting up a Web-Service on XMPP transport, discussed in Chapter 1, Building SOAP Web-Services, as the server-side project.
Create a test class that calls the Web-Service server using WebServiceTemplate
.
Configure WebServiceTemplate
in applicationContext
to send messages over the XMPP protocol.
Run the command mvn clean package
. You will see the following output:
Received response ..
<tns:placeOrderResponse xmlns:tns="...">
<tns:refNumber>order-John_Smith_1234</tns:refNumber>
</tns:placeOrderResponse>....
<tns:placeOrderRequest xmlns:tns="...">
<tns:order>
<tns:refNumber>9999</tns:refNumber>
<tns:customer>
.....
</tns:customer>
<tns:dateSubmitted>2008-09-29T05:49:45</tns:dateSubmitted>
<tns:orderDate>2014-09-19T03:18:33</tns:orderDate>
<tns:items>
<tns:type>Snacks</tns:type>
<tns:name>Pitza</tns:name>
<tns:quantity>2</tns:quantity>
</tns:items>
</tns:order>
</tns:placeOrderRequest>
This project sets up a Web-Service server over the XMPP transport using a JUnit class. The server is already explained in the recipe Setting up a Web-Service on e-mail transport, discussed in Chapter 1,Building SOAP Web-Services.
The applicationContext.xml
file of the configured client WebServiceTemplate
(id="webServiceTemplate")
is used for sending and receiving XML messages. The instance of this bean can be fetched from the client-side program to send and receive XML messages. messageFactory
is an instance of SaajSoapMessageFactory
, referenced inside WebServiceTemplate. messageFactory
is used to create a SOAP packet from XML messages. WebServiceTemplate
uses XmppMessageSender
to send messages to the server. The default URI is a XMPP address URI that WebServiceTemplate
uses by default to send/receive all requests/responses:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"> <constructor-arg ref="messageFactory"/> <property name="messageSender"> <bean class="org.springframework.ws.transport.xmpp.XmppMessageSender"> <property name="connection" ref="connection"/> </bean> </property> <property name="defaultUri" value="xmpp:[email protected]"/> </bean>
XMPPTransportWebServiceIntegrationTest.java
is a JUnit test case that fetches and injects WebServiceTemplate
from applicationContext.xml
(marked by @ContextConfiguration("applicationContext.xml"))
. In the method testWebServiceOnXMPPTransport()(marked
by @Test), WebServiceTemplate
sends an XML message (created by a StringSource
object from a simple input XML file ) and receives a response from the server wrapped inside the Result
object.
@Autowired private GenericApplicationContext applicationContext; @Test public void testWebServiceOnXMPPTransport() throws Exception { StringResult result = new StringResult(); StringSource sc=new StringSource(requestContent); webServiceTemplate.sendSourceAndReceiveToResult(sc, result); XMLAssert.assertXMLEqual("Invalid content received", requestContent, result.toString()); applicationContext.close(); }
The recipe Setting up a Web-Service on XMPP transport, discussed in Chapter 1,Building SOAP Web-Services.
Unit testing a Web-Service using Spring JUnit
Using XPath in Java programming is one of the standard ways of extracting data from XML messages. However, it mixes the XPath address of XML nodes/attributes (that might eventually turn out to be very long) with Java code.
Spring provides a feature to extract these addresses from Java and shift them into the Spring configuration file. In this recipe, the Setting up an endpoint by annotating the payload-root recipe from Chapter 1, Building SOAP Web-Services, is used to set up a Web-Service server.
In this recipe, the project's name is LiveRestaurant_R-2.7
(for the server-side Web-Service), with the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
log4j-1.2.9.jar
The following are the Maven dependencies for LiveRestaurant_R-2.7-Client
(for the client-side Web-Service):
spring-ws-core-2.0.1.RELEASE.jar
junit-4.7.jar
log4j-1.2.9.jar
This recipe uses the Setting up an endpoint by annotating the payload-root recipe discussed in Chapter 1, Building SOAP Web-Services, as the server-side project.
Configure the XPath expression inside applicationContext.xml
.
Configure WebServiceTemplate
in applicationContext
to send messages over the HTTP protocol, as described in the recipe Creating a Web-Service client on HTTP transport.
Create a test class that calls the Web-Service server using WebServiceTemplate
and uses the XPath expression in Java code to extract the desired values.
From the folder Liverestaurant_R-2.7
, run the command mvn clean package tomcat:run
.
Open a new command window to Liverestaurant_R-2.7-Client
and run the following command:
mvn clean package.
--Request
<tns:placeOrderRequest xmlns:tns="http://www.packtpub.com/liverestaurant/OrderService/schema">
<tns:order>
<tns:refNumber>9999</tns:refNumber>
<tns:customer>
<tns:addressPrimary>
<tns:doorNo>808</tns:doorNo>
<tns:building>W8</tns:building>
<tns:street>St two</tns:street>
<tns:city>NY</tns:city>
<tns:country>US</tns:country>
<tns:phoneMobile>0018884488</tns:phoneMobile>
<tns:phoneLandLine>0017773366</tns:phoneLandLine>
<tns:email>[email protected]</tns:email>
</tns:addressPrimary>
<tns:addressSecondary>
<tns:doorNo>409</tns:doorNo>
<tns:building>W2</tns:building>
<tns:street>St one</tns:street>
<tns:city>NY</tns:city>
<tns:country>US</tns:country>
<tns:phoneMobile>0018882244</tns:phoneMobile>
<tns:phoneLandLine>0019991122</tns:phoneLandLine>
<tns:email>[email protected]</tns:email>
</tns:addressSecondary>
<tns:name>
<tns:fName>John</tns:fName>
<tns:mName>Paul</tns:mName>
<tns:lName>Smith</tns:lName>
</tns:name>
</tns:customer>
<tns:dateSubmitted>2008-09-29T05:49:45</tns:dateSubmitted>
<tns:orderDate>2014-09-19T03:18:33</tns:orderDate>
<tns:items>
<tns:type>Snacks</tns:type>
<tns:name>Pitza</tns:name>
<tns:quantity>2</tns:quantity>
</tns:items>
</tns:order>
</tns:placeOrderRequest>
<!--Received response-->
<tns:placeOrderResponse xmlns:tns="...">
<tns:refNumber>order-John_Smith_1234</tns:refNumber></tns:placeOrderResponse>
...Request
<tns:cancelOrderRequest xmlns:tns="http://www.packtpub.com/liverestaurant/OrderService/schema">
<tns:refNumber>9999</tns:refNumber>
</tns:cancelOrderRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>]
...Received response..
<tns:cancelOrderResponse xmlns:tns="http://www.packtpub.com/liverestaurant/OrderService/schema">
<tns:cancelled>true</tns:cancelled></tns:cancelOrderResponse>
Setting up the client and server and using WebserviceTemplate
are done in the same way as we did in the recipe Creating a Web-Service client on HTTP transport. xpathExpPlace
and xpathExpCancel
are configured in the client applicationContext.xml
and it creates an instance of XPathExpressionFactoryBean
that gets a property of expression
as the XPath of the required data and namespaces
of the XML messages:
<bean id="xpathExpCancel" class="org.springframework.xml.xpath.XPathExpressionFactoryBean"> <property name="expression" value="/tns:cancelOrderResponse/tns:cancelled" /> <property name="namespaces"> <props> <prop key="tns">http://www.packtpub.com/liverestaurant/OrderService/schema</prop> </props> </property> </bean> <bean id="xpathExpPlace" class="org.springframework.xml.xpath.XPathExpressionFactoryBean"> <property name="expression" value="/tns:placeOrderResponse/tns:refNumber" /> <property name="namespaces"> <props> <prop key="tns">http://www.packtpub.com/liverestaurant/OrderService/schema</prop> </props> </property> </bean>
In the class OrderServiceClientTest
, an instance of XPathExpressionFactoryBean
can be extracted from applicationContext. String message = xpathExp.evaluateAsString(result.getNode())
returns the required data using an XPath expression:
@Test public final void testPlaceOrderRequest() { DOMResult result=invokeWS(isPlace); String message = xpathExpPlace.evaluateAsString(result.getNode()); Assert.assertTrue(message.contains("Smith")); } @Test public final void testCancelOrderRequest() { DOMResult result= invokeWS(isCancel); Boolean cancelled = xpathExpCancel.evaluateAsBoolean(result.getNode()); Assert.assertTrue(cancelled); }
The recipe Setting up an endpoint using an XPath expression, discussed in Chapter 1,Building SOAP Web-Services.
The recipe Creating a Web-Service client on HTTP transport, discussed in this chapter.
Unit testing a Web-Service using Spring JUnit.
As described in the recipe Setting up a transport-neutral WS-Addressing endpoint, discussed in Chapter 1, Building SOAP Web-Services, WS-Addressing is an alternative way for routing. Instead of including the routing data within the body of the SOAP messages, WS-Addressing separates the routing data from the messages and includes it with the SOAP headers. Here is a sample of the WS-Addressing style of a SOAP message, sent from the client side:
<SOAP-ENV:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>server_uri</wsa:To>
<wsa:Action>action_uri</wsa:Action>
<wsa:From>client_address </wsa:From>
<wsa:ReplyTo>client_address</wsa:ReplyTo>
<wsa:FaultTo>admen_uri </wsa:FaultTo>
<wsa:MessageID>..</wsa:MessageID>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<tns:placeOrderRequest>....</tns:placeOrderReques>
</SOAP-ENV:Body></SOAP-ENV:Envelope>]
While using WS-Addressing, the client or server can access more features when compared to the other methods (including routing data within a message). For example, here the client side can set ReplyTo
to its own and FaultTo
to the admin endpoint address. Then the server sends successful messages to the client and fault messages to the admin address.
Spring-WS supports client-side WS-Addressing as well as on the server side. To create WS-Addressing headers for the client side, org.springframework.ws.soap.addressing.client.ActionCallback
can be used. This callback keeps the Action
header as a parameter. It also uses the WS-Addressing version and a To
header.
In this recipe, the Setting up a transport-neutral WS-Addressing endpoint recipe, discussed in Chapter 1, Building SOAP Web-Services, is used to set up a WS-Addressing Web-Service. A client application is used here to call the server and return the response object.
In this recipe, the project's name is LiveRestaurant_R-2.8
(for server-side Web-Service), with the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
log4j-1.2.9.jar
The following are the Maven dependencies for LiveRestaurant_R-2.8-Client
(for the client-side Web-Service):
spring-ws-core-2.0.1.RELEASE.jar
junit-4.7.jar
log4j-1.2.9.jar
This recipe uses the recipe Setting up a transport-neutral WS-Addressing endpoint, discussed in Chapter 1, Building SOAP Web-Services, as the server-side project. Creating a client for WS-Addressing is done in the same way as described in the recipe Creating a Web-Service client on HTTP transport, without using WebServiceTemplate. To add a WS-Addressing header on the client side, the method sendSourceAndReceiveToResult
of WebServiceTemplate
gets an ActionCallBack
instance.
From the folder LiveRestaurant_R-2.8
, run the following command:
mvn clean package tomcat:run
Open a new command window to LiveRestaurant_R-2.8-Client
and run the following command:
mvn clean package
The following is the client-side output:
Received response [<SOAP-ENV:Envelope xmlns:SOAP-ENV="..../">
<SOAP-ENV:Header xmlns:wsa="...">
<wsa:To SOAP-ENV:mustUnderstand="1">....</wsa:To><wsa:Action>http://www.packtpub.com/OrderService/CanOrdReqResponse</wsa:Action>
<wsa:MessageID>....</wsa:MessageID>
<wsa:RelatesTo>...</wsa:RelatesTo>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<tns:cancelOrderResponse xmlns:tns="http://www.packtpub.com/liverestaurant/OrderService/schema">
<tns:cancelled>true</tns:cancelled></tns:cancelOrderResponse>
</SOAP-ENV:Body></SOAP-ENV:Envelope>]
for request ...
<SOAP-ENV:Envelope xmlns:SOAP
-ENV=".."><SOAP-ENV:Header xmlns:wsa="..">
<wsa:To SOAP-ENV:mustUnderstand="1">http://www.packtpub.com/liverestaurant/OrderService/schema</wsa:To>
<wsa:To SOAP-ENV:mustUnderstand="1">http://www.packtpub.com/liverestaurant/OrderService/schema</wsa:To>
<wsa:Action>http://www.packtpub.com/OrderService/CanOrdReq</wsa:Action>
<wsa:MessageID>..</wsa:MessageID>
</SOAP-ENV:Header><SOAP-ENV:Body/>
</SOAP-ENV:Envelope>]
<?xml version="1.0" encoding="UTF-8"?>
<tns:cancelOrderResponse xmlns:tns="http://www.packtpub.com/liverestaurant/OrderService/schema">
<tns:cancelled>true</tns:cancelled></tns:cancelOrderResponse>
The Liverestaurant_R-2.8
project is a server-side Web-Service that supports the WS-Addressing endpoint.
The applicationContext.xml
file of the configured client WebServiceTemplate
(id="webServiceTemplate")
is used for sending and receiving XML messages, as described in the recipe Creating a Web-Service client on HTTP transport, except for the implementation of the Java class that used WebServiceTemplate
.
WS-Addressing client passes an instance of ActionCallBack
to the method sendSourceAndReceiveToResult
of WebServiceTemplate
. Using ActionCallBack
, the client adds a custom header that contains the Action
URI, for example, http://www.packtpub.com/OrderService/OrdReq and the To
URI, for example, http://www.packtpub.com/liverestaurant/OrderService/schema.
@Test public final void testPlaceOrderRequest() throws URISyntaxException { invokeWS(isPlace,"http://www.packtpub.com/OrderService/OrdReq"); } @Test public final void testCancelOrderRequest() throws URISyntaxException { invokeWS(isCancel,"http://www.packtpub.com/OrderService/CanOrdReq"); } private static Result invokeWS(InputStream is,String action) throws URISyntaxException { StreamSource source = new StreamSource(is); StringResult result = new StringResult(); wsTemplate.sendSourceAndReceiveToResult(source, new ActionCallback(new URI(action),new Addressing10(),new URI("http://www.packtpub.com/liverestaurant/OrderService/schema")), result); return result; }
Using this header, the server side will be able to find the method in the endpoint (using the @Action
annotation).
The recipe Setting up a transport-neutral WS-Addressing endpoint, discussed in Chapter 1,Building SOAP Web-Services.
The recipe Creating a Web-Service client on HTTP transport, discussed in this chapter.
Unit testing a Web-Service using Spring JUnit
Eventually, clients of a Web-Service may use different versions of XML messages and the requirement is to use the same Web-Service on the server side.
Spring Web-Services provide PayloadTransformingInterceptor
. This endpoint interceptor uses XSLT stylesheets and is useful when you need multiple versions of a Web-Service. Using this interceptor, you can transform the old format of the message to a newer one.
In this recipe, the Setting up a simple endpoint mapping for the Web-Service recipe from Chapter 1, Building SOAP Web-Services, is used to set up a Web-Service and the client application here calls the server and returns the response message.
In this recipe, the project's name is LiveRestaurant_R-2.9
(for a server-side web service), with the following Maven dependencies:
spring-ws-core-2.0.1.RELEASE.jar
log4j-1.2.9.jar
The following are the Maven dependencies for LiveRestaurant_R-2.9-Client
(for the client-side Web-Service):
spring-ws-core-2.0.1.RELEASE.jar
junit-4.7.jar
log4j-1.2.9.jar
This recipe uses the Setting up a simple endpoint mapping for the Web-Service recipe, discussed in Chapter 1, Building SOAP Web-Services, as a server-side project. The client side is the same as discussed in the recipe Creating a Web-Service client on HTTP transport, except for the XSLT files and their configuration in the server-side application context file:
Create the XSLT files(oldResponse.xslt, oldRequest.xslt)
.
Modify the file spring-ws-servlet.xml
in LiveRestaurant_R-2.9
to include the XSLT files
From the folder Liverestaurant_R-2.9
, run the following command:
mvn clean package tomcat:run
Open a new command window to Liverestaurant_R-2.9-Client
and run the following command:
mvn clean package
The following is the client-side output:
Received response...
<ns:OrderResponse xmlns:ns="http://www.packtpub.com/LiveRestaurant/OrderService/schema" message="Order Accepted!"/>...
for request ....
<OrderRequest xmlns="http://www.packtpub.com/LiveRestaurant/OrderService/schema" message="This is a sample Order Message"/>
The following is the server-side output:
actual request ..
<ns:OrderRequest xmlns:ns="...">
<ns:message>This is a sample Order Message</ns:message></ns:OrderRequest>
actual response = <ns:OrderResponse xmlns:ns="..">
<ns:message>Order Accepted!</ns:message></ns:OrderResponse>
The server side is the same as that described in the recipe Setting up a simple endpoint mapping for the Web-Service from Chapter 1, Building SOAP Web-Services. On the client side, WebServiceTemplate
and OrderServiceClientTest.java
are the same as those described in the recipe Creating a Web-Service client on HTTP transport.
The only difference is the server application context file. The transformingInterceptor
bean in spring-servlet.xml
uses oldRequests.xslt
and oldResponse.xslt
to convert the old request XML message to the server's newer version and vice versa, respectively:
. <bean class="org.springframework.ws.server.endpoint.mapping.SimpleMethodEndpointMapping"> <property name="endpoints"> <ref bean="OrderServiceEndpoint" /> </property> <property name="methodPrefix" value="handle"></property> <property name="interceptors"> <list> <bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"> <property name="logRequest" value="true" /> <property name="logResponse" value="true" /> </bean> <bean id="transformingInterceptor" class="org.springframework.ws.server.endpoint.interceptor.PayloadTransformingInterceptor"> <property name="requestXslt" value="/WEB-INF/oldRequests.xslt" /> <property name="responseXslt" value="/WEB-INF/oldResponse.xslt" /> </bean> </list> </property> </bean>
The recipe Setting up a simple endpoint mapping for the Web-Service, discussed in Chapter 1,Building SOAP Web-Services.
Unit testing a Web-Service using Spring JUnit.