Chapter 12. Spring Integration and web services

 

This chapter covers

  • POX- and SOAP-based gateways
  • Simple HTTP-based integration

 

In the previous chapter, we saw Spring Integration’s support for integration through the exchange of files. Although file-based exchanges between systems are still common, enabling two systems to interact through the filesystem can be painful for a number of reasons. Most systems, for example, don’t share a filesystem because they’re likely to be on separate hardware, potentially in different parts of the world. With separate hardware in remote locations, file transfers over the network would have to facilitate this form of communication. Differences in file format and character encoding may create additional challenges.

Using the network directly for message exchange is an appealing alternative. TCP networks offer a ubiquitous transport layer over which calls can be made between systems without many of the downsides of using the filesystem. Because of this capability, web service use has grown to the point where it’s now the default approach for many forms of intersystem communication. This chapter discusses the support offered by Spring Integration for both exposing and consuming web services and the different flavors of web services supported (see figure 12.1).

Figure 12.1. Integration over HTTP is simple because the network exists and HTTP traffic passes relatively easily in and out of enterprise networks.

Let’s first make clear what we mean when we talk about web services. There’s no consensus on a concise definition. The W3C does offer one emphasizing the role of SOAP and WSDL,[1] but they preface that with a disclaimer that it’s “for the purpose of this Working Group... without prejudice toward other definitions.” Those on the REST side of the perennial SOAP versus REST debate would certainly argue that SOAP and WSDL aren’t essential to the definition. Furthermore, even SOAP isn’t exclusively tied to HTTP as the underlying transport.

1http://www.w3.org/TR/2004/NOTE-ws-gloss-20040211/#webservice

With Spring Web Services (Spring WS), Arjen Poutsma followed the good practice of decoupling transport and message. Spring Integration follows in this tradition. Before Spring Integration was released, there was support for web services over Java Message Services (JMS), email, and Extensible Messaging and Presence Protocol (XMPP) built on top of Spring WS. In this book, separate transport mechanisms are addressed in separate chapters.

Most people think of web services as communication using XML messages sent with HTTP. Even though the definition is much broader, this is the form of web service that we focus on in this chapter.

Many people also equate web services with SOAP (Simple Object Access Protocol). SOAP provides a standard for web services defined as follows: “A Web Service is a software component that is described via WSDL and is capable of being accessed via standard network protocols such as but not limited to SOAP over HTTP.”[2] WSDL (Web Service Description Language) provides a standard mechanism to describe a web service, but its use is by no means universal, so this definition doesn’t reflect the reality of web services even when considering only those using HTTP.

2 See http://www.oasis-open.org/committees/wsia/glossary/wsia-draft-glossary-03.htm.

Attempts to standardize web services gained great popularity in the 1990s. Most large software vendors were happily selling a broad range of tools and generating an increasing number of add-ons to the specs. Known as the WS-* specifications, these add-ons covered everything from security to business activities.

The relatively heavyweight and complex approach to web services dictated by SOAP left many people looking for alternatives. One popular alternative is to resort to plain XML, commonly called plain old XML or POX. POX payloads are typically exchanged over HTTP. An increasingly popular option today is to use simpler formats that can be customized for the task at hand. Simpler forms of web services can use HTTP as more than just a transport. The biggest growth in this form of web service has come through the popularity of RESTful web services, which apply Representational State Transfer (REST) principles.

Spring Integration provides support for exchanging XML-based web service messages over HTTP by building on the Spring WS project for both SOAP-based and POX-based web services. We look at POX support in the first section of this chapter.

Spring Integration provides adapters for working with HTTP directly as well, which can be useful for non-XML or RESTful services. We look at the HTTP adapters in the second section of this chapter. Let’s first look at the most common case using XML.

12.1. XML web services with Spring WS

Spring WS is a Spring portfolio project that focuses on contract-first web services with XML payloads. As mentioned before, not all XML web services use SOAP. Spring WS provides support for POX-based web services, among others. One of the strongest points of Spring WS is that it decouples application code from the relatively complex requirements of SOAP. Developers can code agnostic to the fact that SOAP is being used except where the application requires control over those details. Without the use of an abstraction like Spring WS, the creation of even a simple SOAP message, as in the following example, is relatively complex; it requires a good understanding of XML APIs and namespace usage:

POST /InStock HTTP/1.1
Host: www.example.org
Content-Type: application/soap+xml; charset=utf-8
Content-Length: nnn

<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">

  <soap:Body xmlns:m="http://www.example.org/stock">
    <m:GetStockPrice>
      <m:StockName>IBM</m:StockName>
    </m:GetStockPrice>
  </soap:Body>

</soap:Envelope>

This example (borrowed from W3 schools)[3] shows both the HTTP headers and XML payload for a simple SOAP request. We already need to define a minimum of two elements in the SOAP namespace before we get to the message we want to pass. It’s also worth noting that SOAP always uses the POST HTTP method to make requests even in the case of a read-only request for data that arguably is better suited to the use of the HTTP GET method. This is because SOAP uses HTTP as a mechanism for passing data and makes no real use of the HTTP protocol. You’ll see later in this chapter that this contrasts with the more HTTP-centric alternatives to SOAP.

3http://www.w3schools.com/soap/soap_example.asp

The Spring WS project provides a simple programming model that insulates the developer from much of the complexity of web service development. This is achieved by combining Spring configuration with simple interface-based or annotated endpoints.

Spring Integration extends the simple programming model offered by Spring WS. It adds the power and simplicity of messaging combined with the established enterprise integration patterns (EIP) implementations.

Web service implementation can be complex, but using EIP and messaging generally produces a simpler, easier-to-implement solution. For example, an insurance quote comparison site might need to split the quote request into a number of requests in different formats, invoke a number of different quote providers using different technologies, and then process a number of responses into a single web service response. This can be achieved by using Spring WS alone, but it’s much less work to implement using a combination of the two, and that’s what the web service support in Spring Integration is intended to do.

To get started, you need to make sure the application can send and receive external messages through Spring WS. In the next section, we look into wiring the beans needed to expose an inbound gateway to do this.

12.1.1. Exposing a Spring WS–based inbound gateway

The inbound web service gateway allows for a POX- or SOAP-based endpoint to be exposed for handling requests, resulting in the creation of Spring Integration messages that are then published to a channel. When receiving web service requests over HTTP, a front controller servlet must be deployed and configured to pass requests to the Spring Integration inbound gateway. Just as when using Spring WS directly, the front controller is an instance of org.springframework.ws.transport.http.MessageDispatcherServlet mapped to a URI on which requests will be received using a standard web.xml configuration file:

<servlet>
    <servlet-name>si-ws-gateway</servlet-name>
    <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/si-ws-gateway-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
     <servlet-name>si-ws-gateway</servlet-name>
     <url-pattern>/quoteservice</url-pattern>
</servlet-mapping>

The MessageDispatcherServlet requires a bean implementing the Spring WS strategy interface org.springframework.ws.server.EndpointMapping to be provided by the application context configured via the contextConfigLocation parameter name. This strategy interface provides support for mapping a given request received by the servlet to a particular endpoint. Spring WS provides built-in support for mapping on a variety of characteristics of the request from the URI invoked by the caller to the name of the root payload element in the request payload. When using the Spring Integration inbound gateway, it’s more common to delegate all received requests to one gateway instance with additional routing being carried out by using the built-in Spring Integration support, for example, the XPath routing capabilities. The following configuration delegates all received requests to a channel named ws-requests:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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:int-ws="http://www.springframework.org/schema/integration/ws"
  xsi:schemaLocation="http://www.springframework.org/schema/integration/ws
  http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd
  http://www.springframework.org/schema/integration
  http://www.springframework.org/schema/integration/spring-integration.xsd
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd">


  <bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
    <property name="defaultEndpoint" ref="ws-inbound-gateway"/>
  </bean>

  <int-ws:inbound-gateway id="ws-inbound-gateway"
           request-channel="ws-requests"/>

  <int:channel id="ws-requests" />

</beans>

By default, the inbound gateway publishes an instance of Spring Integration Message, the payload of which will be the payload of the web service request in the form of an instance of javax.xml.transform.Source. In some cases, it may be desirable to publish the whole web service message rather than just the payload. This is achieved by setting the extract-payload flag to false, as follows:

<int-ws:inbound-gateway id="ws-inbound-gateway"
                        request-channel="ws-requests"
                        extract-payload="false" />

12.1.2. Calling a web service with the outbound gateway

Invoking a web service from Spring Integration is also extremely simple. The following snippet shows how to configure an example in which the payload of the message received on the requests channel becomes the payload of the message sent to the w3schools temperature-conversion service. The payload of the web service response is then published to the configured reply channel:

<int-ws:outbound-gateway
   uri="http://www.w3schools.com/webservices/tempconvert.asmx"
   request-channel="requests" reply-channel="responses" />

12.1.3. Marshalling support

Marshalling versions of both the inbound and outbound gateways are provided and are enabled by configuring the inbound or outbound gateway with a marshaller and/ or unmarshaller to allow automatic conversion between Java and XML for both the request and reply messages.

12.2. Simple HTTP endpoints

SOAP- and POX-based endpoints aren’t the only form of web service supported by Spring Integration. It has become increasingly popular to provide web services that don’t conform to web service standards such as SOAP and the plethora of additional WS-* specifications. Of particular interest to many is the use of the architectural style known as REST, which stands for Representational State Transfer. In a RESTful approach, HTTP is used as the service protocol. The term REST originates from the doctoral dissertation of Roy Fielding,[4] one of the authors of the HTTP specification—hence the close relationship between RESTful services and HTTP.

4http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

A REST request works as follows: on receipt of an HTTP request using, for example, the DELETE HTTP method and a URI of http://www.example.org/books/123, the request would be interpreted as a request to delete book number 123:

DELETE /books/123 HTTP/1.1
Host: www.example.org

But receiving a GET request as follows, where only the HTTP method is different, would result in retrieval of a representation of book 123:

GET /books/123 HTTP/1.1
Host: www.example.org

In HTTP-based communication, it’s common not to make use of all the HTTP methods and instead to use GET or POST for a multitude of purposes, including requests which are really deletions of some sort. This is technically not REST, but sometimes tricks are used to stay as close as possible to the intent of REST without blocking browsers that only support GET and POST.

Spring 3.0 brought in extensive support for RESTful web services as an extension to the existing Model-View-Controller (MVC) framework for web applications. This support focused on mapping controller methods to requests using both the URI and the HTTP methods while also making it easy to map parts of the URI to controller method parameters. The following code shows an example controller configured to process requests for the retrieval of books:

@RequestMapping(value="/library/*/books/{book}",
     method=RequestMethod.GET)
public ModelAndView getBook(@PathVariable("book") long bookId) {
   ...
}

Spring Integration 2.0 uses Spring 3.0 REST support through a set of HTTP adapters that provide inbound and outbound support for HTTP-based services. Because REST is a style rather than a specification, HTTP-based services may or may not conform to the REST style. Therefore, although it’s possible to use Spring Integration to expose services in a RESTful fashion, HTTP can also be used to expose services that aren’t considered RESTful. Support for all HTTP methods is something that may not exist in some technologies, such as Asynchronous JavaScript + XML (Ajax), that use, almost exclusively, GET and POST HTTP methods and rarely use URI schemes that reference resources.

12.2.1. Processing HTTP inbound requests

The HTTP inbound gateway and channel adapter endpoints allow for the consumption of an HTTP message, which is then used to construct a Spring Integration message for processing. The inbound endpoints, by default, attempt to convert the received message according to a strategy. The default strategy for conversion is based on the content type of the request and converts the received payload to an appropriate Java message. To start processing inbound HTTP requests, you first need a servlet to act as the entry point for requests. You configure an instance of Spring’s HttpRequestHandlerServlet mapped to the appropriate URL via the standard web.xml. You configure it with a Spring application context containing the Spring Integration inbound gateway:

<servlet>
    <servlet-name>httpTripInboundGateway</servlet-name>
    <servlet-class>org.springframework.web.context.support.
                   HttpRequestHandlerServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/http-ws-servlet.xml
        </param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>httpTripInboundGateway</servlet-name>
    <url-pattern>/httpquote</url-pattern>
</servlet-mapping>

The contents of the file http-ws-servlet.xml would then use the Spring Integration HTTP namespace as follows, defining which Spring Integration channel should be used for received HTTP requests in the form of Spring Integration messages. In this example, a reply channel is provided, but it isn’t required, and when it’s not provided, a temporary channel is used to receive responses:

<int-http:inbound-gateway id="httpTripInboundGateway"
                          request-channel="tripQuoteRequestsChannel"
                          reply-channel="tripQuoteResponseChannel"/>

The inbound gateway element will produce an instance of either HttpRequestHandlingMessagingGateway or HttpRequestHandlingController. Which one is instantiated at runtime depends on whether the Spring MVC view technology is being used to render the response. If an attribute specifying a view name is provided, then the controller version is created; otherwise, the gateway implementation with its own response-rendering logic is used. When the controller-based gateway is used, the HTTP response can be rendered by one of the large number of view technologies supported by Spring MVC, including Java Server Pages, FreeMarker, or a custom implementation of the View interface.

Apart from specifying the view, several other attributes can be set. Table 12.1 shows an overview of the attributes and their functions.

Table 12.1. Additional configuration attributes for the HTTP inbound gateway element

Attribute

Description

view-name Name of the view to use to render responses. If view-name is provided, a controller class is used to provide the inbound request processing functionality. If not, the gateway class is used.
extract-reply-payload Boolean flag indicating whether the type of the reply should be a Spring Integration message or the payload of the message should be extracted. Default is true. Supported by gateway and controller.
reply-key Key to use for the response message when adding it to the model map that will be passed to the view. Supported by controller.
reply-timeout Timeout for waiting on a response. Supported by controller and gateway.
message-converters List of HttpMessageConverters used to convert the HTTP message.
supported-methods HTTP methods allowable for this gateway. Supported by controller and gateway.
convert-exceptions Indicates whether the provided message converters should be used to convert any exception thrown to an HTTP message. Defaults to false. Supported by gateway.
request-payload-type Indicates to the message converters the desired Java type to convert the request to. Supported by controller and gateway.
error-code Code to be used to indicate failure in any Errors object passed to the view. Supported by controller.
errors-key Key to use for an Errors instance containing binding errors if an exception is thrown during request processing. Supported by controller.
header-mapper Optional reference to a bean implementing HeaderMapper <HttpHeaders>. This strategy converts the HTTP headers to and from Message headers. If not specified, the default strategy is used. This maps all standard HTTP headers. Supported by controller and gateway.
name For example, /getQuote. When used with a Spring Dispatcher-Servlet and the BeanNameUrlHandlerMapping, this attribute provides the path prefix for requests that this endpoint will handle. Supported by controller and gateway.

The ability to provide a view gives a great deal of flexibility in generating a response.

12.2.2. Inbound-only messages using inbound-channel-adapter

For processing HTTP requests which require only confirmation that the request was successfully accepted, Spring Integration provides an inbound channel adapter. The implementation for the channel adapter uses exactly the same classes, HttpRequestHandlingMessagingGateway and HttpRequestHandlingController, but they are configured not to wait for a reply message. Internally, this is done using MessagingTemplate.send() for the channel adapter as opossed to MessagingTemplate.send-AndReceive() for the gateway.

Here’s an example of using an inbound channel adapter. The view-name attribute is specified, so the resolution of the view and the creation of the response is handled as usual in Spring MVC:

<int-http:inbound-channel-adapter
  channel="smsSubscriptionsChannel"
  supported-methods="GET,POST"
  name="/subscribe"
  view-name="confirmReceived" />

Note that in this example, the name of the bean is assigned as a path. This allows the bean to be used with the default behavior of Spring’s DispatcherServlet, as configured in the following snippet:

<servlet>
    <servlet-name>sms-update</servlet-name>
    <servlet-class>org.springframework.
             web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:http-applicationContext.xml
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>sms-update</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

Now you know how to receive incoming messages over HTTP, but that’s only one side of the story. Next up is the outbound part of it.

12.2.3. Outbound HTTP requests

In addition to processing inbound HTTP requests, Spring Integration provides an outbound HTTP gateway capable of transforming a Spring Integration message and optionally publishing the HTTP response as a Spring Integration message. Following is a simple example using the HTTP namespace support. This example uses the URI variable capabilities of the REST template that performs the HTTP request, allowing the evaluation of an expression on the message to provide a value for insertion into the URI used for the HTTP request. In other words, the URL can contain a variable, which is filled at runtime. In this case, we expect a location to be contained within the message payload, and it’s used to request the weather for that location from Google:

<int-http:outbound-gateway
               url="http://www.google.com/ig/api?weather={location}"
               request-channel="weatherRequests"
               http-method="GET"
               expected-response-type="java.lang.String">
            <int-http:uri-variable name="location" expression="payload" />
</int-http:outbound-gateway>

<int:channel id="weatherRequests" />

The HTTP response is provided as a String even though the content type of the response is text/xml. Changing the gateway to specify the response type as a Source will facilitate processing as XML:

<int-http:outbound-gateway
                url="http://www.google.com/ig/api?weather={location}"
                request-channel="weatherRequests"
                http-method="GET"
                expected-response-type="javax.xml.transform.Source">
            <int-http:uri-variable name="location" expression="payload" />
</int-http:outbound-gateway>

In the previous two sections, we’ve talked about synchronous messaging. This is natural because HTTP is an inherently synchronous protocol. But there’s no reason why we can’t use a synchronous protocol for asynchronous communication architectures. The next section discusses the outbound channel adapter that can be used to do this.

12.2.4. Outbound channel adapter

An outbound channel adapter is much like an outbound gateway except that it doesn’t send a response on a reply channel. Behind the scenes, the HTTP outbound channel adapter uses the RestTemplate from the Spring Framework. Therefore, the ResponseErrorHandler interface is implemented to determine what is an error. The error handler can be provided by setting an attribute on the outbound channel adapter element. If no custom error handler is provided, then an instance of DefaultResponseErrorHandler is used. This error handler may not give you the expected behavior. It treats only HTTP response codes of 4xx and 5xx as exceptional. This can lead to problems, for example, with a POST request for which the response is 301 (moved permanently). Such a response won’t be treated as exceptional, and messages will be silently dropped as the HTTP server discards them without any indication of a problem at the Spring Integration end. Following is an example configuration that posts messages to the configured URL:

<int-http:outbound-channel-adapter id="blogAdapter"
          url="http://www.blogger.com/feeds/5800805938651950760/posts/default"
          channel="flightUpdates"
          http-method="POST"
          charset="UTF-8" />

12.3. Summary

Integration over the internet is becoming increasingly important, allowing use of content and services from a wide variety of sources and supporting a large number of different consumers of that content with different format requirements. Although standards such as SOAP are still favored in large corporations, many people are moving to more flexible approaches to web services. The de facto standard on the web is REST because it fits so well with the HTTP paradigm. To integrate systems that take different approaches to web services, you need flexibility in your integration solution. Spring Integration provides this flexibility.

In this chapter, you learned that Spring Integration provides a number of options for web service integration. Spring Integration covers common forms of web service, such as SOAP, REST, and POX, as well as other HTTP-based forms of integration. The namespaces simplify the development of applications that expose or consume web services. Combining Spring Integration with Spring WS and the REST support provided by Spring MVC helps the developer to use EIP patterns within those applications.

Now that we’ve covered the mainstream enterprise types of service integration, we can spend the next chapter looking at emerging integration options. As with email, Spring Integration supports other messaging systems suitable for human interaction, such as Twitter and XMPP.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.52.188