Web services have emerged as a key technology for communication between web-based applications over the network. Web services typically leverage HTTP protocol for communication over the network, and use XML as the message payload format


Using web-related standards allows for application interoperability even between disparate applications and technologies


Spring Integration’s support for Standard Object Access Protocol (SOAP) services using the Web Services Definition Language (WSDL) as a method of describing the service for external clients


Spring Integration provides two components for supporting web services: invoking a web service by sending a message to a channel using an outbound web service gateway, and sending a message to a channel upon receiving a web service invocation using an inbound web service gateway. Both the inbound and outbound gateways include support for adding an XML marshaller


XML Schema

The standard message payload format for a web service is XML. XML is a plain-text format designed for data transfer and can be read by most application technologies. To ensure that both the web services client and server agree to the message payload format, a contract is usually enforced for the XML data using an XML schema. An XML schema is a description of the XML documents in terms of the constraints on the structure and the content.



XML Schema Ticket.xsd


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0"
attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://prospringintegration.com/tk/schemas"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="TicketRequest">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="description"/>
<xs:element type="priorityType" name="priority"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="TicketResponse">
<xs:complexType>
<xs:sequence>
<xs:element type="ticketType" name="ticket"/>
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:complexType name="ticketType">
<xs:sequence>
<xs:element name="description" type="xs:string" minOccurs="0"/>
<xs:element name="issueDateTime" type="xs:dateTime" minOccurs="0"/>
<xs:element name="priority" type="priorityType" minOccurs="0"/>
<xs:element name="ticketId" type="xs:long"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="priorityType">
<xs:restriction base="xs:string">
<xs:enumeration value="low"/>
<xs:enumeration value="medium"/>
<xs:enumeration value="high"/>
<xs:enumeration value="emergency"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

Configuring a Web Services Inbound Gateway


There are two Spring Integration implementations for an inbound web services gateway:
org.springframework.integration.ws.SimpleWebServiceInboundGateway and
org.springframework.integration.ws.MarshallingWebServiceInboundGateway.


SimpleWebServiceInboundGateway will extract a javax.xml.tranform.Source from the
org.springframework.ws.WebServiceMessage and set it as the message payload.


The MarshallingServiceInboundGateway provides support for defining an implementation of the org.springframework.oxm.Marshaller and org.springframework.oxm.Unmarshaller interfaces


Both gateway implementations implement the Spring Web Services
org.springframework.ws.server.endpoint.MessageEndpoint interface, so they can be configured using an org.springframework.ws.transport.http.MessageDispatcherServlet, similar to a standard Spring Web Services configuration.


As with a Spring Web Services, the inbound web services gateway must be deployed within a servlet container with the standard directory structure and configuration files. The web.xml file The servlet class is set to the MessageDispacherServlet, and all
requests with the URL pattern /ticketservice/* will be directed to the servlet.

Inbound Web Services Gateway 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>Pro Spring Integration Inbound SOAP Gateway Example</display-name>
<servlet>
<servlet-name>ticket-ws</servlet-name>

<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-
class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ticket-ws</servlet-name>
<url-pattern>/ticketservice/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>


By convention, the Spring configuration file should have the name <servlet name>-servlet.xml and be placed in the webapp/WEB-INF directory. In our example, the name will be ticket-ws-servlet.xml,


The component-scanning element is used to create the references to the Java configuration and component beans, which will be discussed following

Base Spring Configuration for Applying a Web Service Inbound Gateway service.xml


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:ws="http://www.springframework.org/schema/integration/ws"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/integration/ws
http://www.springframework.org/schema/integration/ws/spring-integration-ws-2.0.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-2.0.xsd">

<context:component-scan
base-package="com.apress.prospringintegration.webservice.web"/>

<int:channel id="inboundDOMTicketRequest"/>

<ws:inbound-gateway id="wsInboundGateway"
request-channel="inboundDOMTicketRequest"/>

<int:service-activator input-channel="inboundDOMTicketRequest"
ref="ticketIssuerEndpoint"/>

</beans>


We will leverage the Spring Integration ws namespace to create the inbound web services gateway.

The inbound-gateway element is configured to create a web services endpoint that forwards the web service invocation Source object containing the XML message to the inboundDomTicketRequest message channel defined by the request-channel attribute. The beauty of this example is that the underlying Spring Web Services libraries handle the SOAP protocol

Another option for the inbound-gateway is the reply-channel. By default, an anonymous channel is created and set through the REPLY_CHANNEL message
header. Also, the extract-payload attribute can be set to false (it defaults to true) to pass the entire WebServicesMessage as the message payload sent to the request channel. Finally, the marshaller and unmarshaller can be set


A ticketIssuerEndpoint service activator is configured to receive the incoming XML message and to create a reply XML message.


Configuring Web Services Endpoints

The web services endpoint is configured to send all incoming SOAP request invocations that match the URL pattern set in the web.xml file to the Spring Integration inbound gateway using the Java configuration file

Java Configuration for the Web Services Endpoint


package com.apress.prospringintegration.webservice.web;
import com.apress.prospringintegration.webservice.CommonConfiguration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.server.endpoint.mapping.UriEndpointMapping;

@Configuration
public class TicketIssuerConfiguration extends CommonConfiguration {

//the ws:inbound-gateway is in fact a reference to this base Spring WS object
@Value("#{wsInboundGateway}")
private MessageEndpoint wsInboundGateway;

@Bean
public UriEndpointMapping uriEndpointMapping() {
UriEndpointMapping uriEndpointMapping = new UriEndpointMapping();
uriEndpointMapping.setDefaultEndpoint(wsInboundGateway);
return uriEndpointMapping;
}
}


org.springframework.ws.server.endpoint.mapping.UriEndpointMapping instance is created, and the default endpoint is set to the Spring Integration gateway wsInboundGateway.


Payload Extraction with DOM

Spring Web Services uses the org.springframework.ws.soap.saaj.SaajSoapMessageFactory to extract the XML payload from the incoming SOAP request. The request payload must be parsed with an XML parser. As shown in the service activator code


the XML payload is parsed using the Java default DOM parser. The description and priority are extracted from the incoming XML request and used to create the reply XML message. In this example, the XML reply payload is created by hand. A parser can be used to create the XML reply; however, this code is presented in contrast to the simplicity of using a marshaller

Service Activator Handling an Incoming Web Services Request


package com.apress.prospringintegration.webservice.web;
import com.apress.prospringintegration.webservice.CommonConfiguration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.xml.source.DomSourceFactory;
import org.springframework.stereotype.Component;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import java.util.Date;
import java.util.Random;

@Component
public class TicketIssuerEndpoint {

private String replyTemplate =
"<TicketResponse xmlns=\"" + CommonConfiguration.NAMESPACE + "\">" +
"<ticket>" +
"<description>%s</description>" +
"<priority>%s</priority>" +
"<ticketId>%d</ticketId>" +
"<issueDateTime>%tc</issueDateTime>" +
"</ticket>" +
"</TicketResponse>";

@ServiceActivator
public Source handleRequest(DOMSource source)
throws Exception {
NodeList nodeList = source.getNode().getChildNodes();
String description = "";
String priority = "";
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeName().equals("priority")) {
priority = node.getFirstChild().getNodeValue();
} else if (node.getNodeName().equals("description")) {
description = node.getFirstChild().getNodeValue();
}
}
// transfer properties to an XML document
String xml = String.format(replyTemplate, description, priority,
new Random().nextLong() * 1000, new Date());
return new DomSourceFactory().createSource(xml);
}
}



This Spring Integration example can be built and then deployed to a servlet container such as Tomcat or Jetty. To build the war, simply execute mvn install, and copy the resulting war file within the target directory to the servlet container’s webapps directory.


Invoking Web Services Using an Outbound Gateway

Spring Integration has two outbound web services gateway implementations:
org.springframework.integration.ws.SimpleWebServiceOutboundGateway and
org.springframework.integration.ws.MarshallingWebServiceOutboundGateway.


SimpleWebServiceOutboundGateway takes either a String or a Source an inbound message payload. MarshallingWebServiceOutboundGateway provides support for any implementation of the Marshaller and Unmarshaller interfaces. Both gateways require a Spring Web Services


org.springframework.ws.client.support.destination.DestinationProvider for determining the URI of the web service to be invoked.

Spring Configuration for Outbound Gateway 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"
xmlns:ws="http://www.springframework.org/schema/integration/ws"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
http://www.springframework.org/schema/integration/ws
http://www.springframework.org/schema/integration/ws/spring-integration-ws-2.0.xsd">

<context:property-placeholder location="client.properties"/>

<int:channel id="ticketRequests"/>

<ws:outbound-gateway id="ticketIssueGateway" request-channel="ticketRequests"
uri="http://${ws.host}:${ws.port}/${ws.context}/ticketservice/tickets"/>

</beans>


Note that a property-placeholder element is used to leverage the client.properties properties file

Client Properties File client.properties


ws.host=127.0.0.1
ws.port=8080
ws.context=ticket-service-gateway-1.0


The gateway is configured using the outbound-gateway element. The gateway will respond
to the message channel ticketRequest, which is set through the request-channel attribute. The outbound gateway requires that the URL for the web service endpoint be specified using the url attribute. In this example, the reply-channel attribute is not set. If the web service were to return a nonempty response, it would be returned to the request message’s REPLY_CHANNEL header. A specific reply channel can be set using the reply-channel attribute.


To construct an XML request message, either create a DOMSource instance or simply create a string representation of the XML structure. This example uses the latter approach, since is requires less code, and the XML request payload is rather short. The XML document is created to conform to the previous Ticket.xsd schema. The XML message is sent as a message payload to the ticketRequest message channel. The response message payload is logged to the console

Client for Invoking Standard Web Services Endpoints


package com.apress.prospringintegration.webservice.client;
import com.apress.prospringintegration.webservice.CommonConfiguration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.support.MessageBuilder;
public class TicketWebServiceDomClient {
private static String bodyTemplate =
"<TicketRequest xmlns=\"" + CommonConfiguration.NAMESPACE + "\">" +
"<description>%s</description>" +
"<priority>%s</priority>" +
"</TicketRequest>";
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("client.xml");
MessageChannel channel = context.getBean("ticketRequests", MessageChannel.class);
String body = String.format(bodyTemplate, "Message Broker Down", "emergency");
System.out.println(body);
MessagingTemplate messagingTemplate = new MessagingTemplate();
Message<?> message = messagingTemplate.sendAndReceive(
channel, MessageBuilder.withPayload(body).build());
System.out.println(message.getPayload());
}
}

The results of running the web services gateway example are The request
XML message is shown, followed by the response message. Note the addition of the ticket ID and issue date time.

Results of Running the Web Services Gateway Example


<TicketRequest xmlns="http://prospringintegration.com/tk/schemas"><description>Message
Broker Down</description><priority>emergency</priority></TicketRequest>
<?xml version="1.0" encoding="UTF-8"?><TicketResponse xmlns="http://prospringintegration.com/tk/schemas"><ticket><description>Message Broker
Down</description><priority>emergency</priority><ticketId>-
7242698475708198496</ticketId><issueDateTime>Sun Feb 27 00:21:30 PST
2011</issueDateTime></ticket></TicketResponse>

Leave a Reply

Subscribe to Posts | Subscribe to Comments

About This Site

Howdy! My name is Suersh Rohan and I am the developer and maintainer of this blog. It mainly consists of my thoughts and opinions on the technologies I learn,use and develop with.

Blog Archive

Powered by Blogger.

- Copyright © My Code Snapshots -Metrominimalist- Powered by Blogger - Designed by Suresh Rohan -