Showing posts with label Spring Integration. Show all posts
Spring Integration Basics
Spring Integration Basics
Three components to the core Spring Framework:
messages,
message channels,
endpoints.
Messages
A message is a generic wrapper for any Java object combined with metadata used by Spring Integration to handle the object.
the Java object is the payload property, and the metadata is stored as a collection of message headers, which is in essence a Map with a String key and an Object value.
Headers
The org.springframework.integration.MessageHeaders object is a String/Object Map that typically maintains values for message housekeeping a rountine task . MessageHeaders are immutable and are usually created using the MessageBuilder API. There are a number of predefined entries (headers), including id, timestamp, correlation id, and priority. In addition, the headers can maintain values required by the adapter endpoints (e.g., the file name for the file adapter or the email address for the mail adapter).
Headers may be used any key/value pair required by the developer.
Payloads
The message payload can be any POJO. Spring Integration does not require message payloads to be in some sort of self-describing format. You can avail yourself of transformers to implement a canonical data model, as appropriate, but your hands aren’t tied if this isn’t appropriate for your application. Transformation support allows converting any payload into any type of format required by the message endpoint. This is in keeping with the noninvasive nature of Spring Integration.
Message Channels
A message channel is the component through which messages are moved. Message publishers send messages to the channel, and message consumers receive messages from the channel. The channel effectively decouples the producer and consumer. There are two types of messaging scenarios: point-topoint, in which a message is received only once, by a single consumer; and publish/subscribe, in which one or more consumers can attempt to receive a single message.
There are different ways to use a message channel, but generally your configuration will change according to whether you want messages on the channel to be published to you, or whether you want them queued.
Message Endpoints
A message endpoint is the abstraction layer between the application code and the messaging framework. An endpoint broadly defines all the types of components used in Spring Integration. It handles such tasks as producing and consuming messages, as well as interfacing with application code, external services, and applications. When data travels through a Spring Integration solution, it moves along channels from one endpoint to another. Data can come into the framework from external systems using a specific type of endpoint called an adapter. Spring Integration provides a number of adapters that interface with external applications and services; handling the interaction with the messaging infrastructure often only requires declarative configuration. Spring Integration provides a framework to build custom adapter endpoints in the (hopefully rare) event that the out-of-the-box adapters do not suffice.
The main endpoint types supported by Spring Integration are as follows:
• Transformer: Converts the message content or structure.
• Filter: Determines if the message should be passed to the message channel.
• Router: Can determine which channel to send a particular message based on its content.
• Splitter: Can break an incoming message into multiple messages and send them to the appropriate channel.
• Aggregator: Can combine multiple messages into one. An aggregator is more complex than a splitter often required to maintain state.
• Service activator: Is the interface between the message channel and a service instance, many times containing the application code for business logic.
• Channel adapter: Is used to connect the message channel to another system or transport.
First Steps for Spring Integration using Maven
We will start with creating a Maven project and show how to add the necessary library support. The simplest method to create a Maven project is to use an archetype, as follows:
1. For a command window, enter mvn archetype:generate.
2. Choose maven-archetype-quickstart from the list of options, which provides a sample Maven project.
3. Select the latest version of the archetype and enter com.equinox.springintegration for the groupId, firstproject for the artifactId, and the defaults for version and package . Then enter Return to create the project.
Maven Dependencies for Spring Integration
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jms</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
In addition, the Spring repositories may be needed, especially when using the
milestone and snapshot
<repositories>
<repository>
<id>repository.springframework.maven.release</id>
<name>Spring Framework Maven Release Repository</name>
<url>http://maven.springframework.org/release</url>
</repository>
<repository>
<id>org.springframework.maven.milestone</id>
<name>Maven Central Compatible Spring Milestone Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository>
<repository>
<id>org.springframework.maven.snapshot</id>
<name>Maven Central Compatible Spring Snapshot Repository</name>
<url>http://maven.springframework.org/snapshot</url>
</repository>
</repositories>
The following configuration must be added to ensure that the code compiles against Java SE 6, and that the resources directory isn’t filtered
pom.xml Build Element for Java SE 6
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
1. For a command window, enter mvn archetype:generate.
2. Choose maven-archetype-quickstart from the list of options, which provides a sample Maven project.
3. Select the latest version of the archetype and enter com.equinox.springintegration for the groupId, firstproject for the artifactId, and the defaults for version and package . Then enter Return to create the project.
Maven Dependencies for Spring Integration
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jms</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
In addition, the Spring repositories may be needed, especially when using the
milestone and snapshot
<repositories>
<repository>
<id>repository.springframework.maven.release</id>
<name>Spring Framework Maven Release Repository</name>
<url>http://maven.springframework.org/release</url>
</repository>
<repository>
<id>org.springframework.maven.milestone</id>
<name>Maven Central Compatible Spring Milestone Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository>
<repository>
<id>org.springframework.maven.snapshot</id>
<name>Maven Central Compatible Spring Snapshot Repository</name>
<url>http://maven.springframework.org/snapshot</url>
</repository>
</repositories>
The following configuration must be added to ensure that the code compiles against Java SE 6, and that the resources directory isn’t filtered
pom.xml Build Element for Java SE 6
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
Starting Your First Spring Integration Project
Each Spring Integration application is completely embedded, and needs no server infrastructure. In fact, a Spring Integration application can be deployed inside another application—for example, in your web application endpoint.
Spring Integration is deployed into your application; your application is not deployed into Spring Integration, as you might expect. There are no start and stop scripts and no ports to guard.
The simplest possible working Spring Integration application is a simple Java public static void main method to bootstrap a Spring context,
App.java
package com.apress.prospringintegration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("classpath:spring-context.xml");
context.start();
}
}
A standard Spring application context has been created and started.
The configuration file will be created for creating a simple input channel, a service activator to respond to a message published to the channel, and an output channel where the service activator sends it return value.
spring-context.xml integration graph
spring-context.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:si="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/integration
http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.apress.prospringintegration"/>
<int:channel id="input"/>
<int:channel id="output">
<int:queue capacity="10"/>
</int:channel>
<int:service-activator input-channel="input" output-channel="output" ref="messageHandler"/>
</beans>
A point-to-point direct channel input is created using the channel element, and a queue channel output is created by adding the queue element. In addition, a service activator messageHandler is created using the service-activator element.
Spring Integration supports annotations for configuring Spring bean components. By adding the component-scan element of the context library, any Java class in the package com.apress.prospringintegration with the annotation @Cmponent will be configured as a Spring bean.
By convention, the bean named messageHandler will refer to the class MessageHandler, resolved by capitalizing the first letter of the bean name. Thus, if a message is sent the
channel input, it will be forwarded to the service activator class MessageHandler. Since no method has been configured in the Spring configuration class, the message will be directed to the method annotated with @ServiceActivator.
MessageHandler.java
package com.apress.prospringintegration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.stereotype.Component;
@Component
public class MessageHandler {
@ServiceActivator
public String handleMessage(String message) {
System.out.println("Received message: " + message);
return "MESSAGE:" + message;
}
}
Note that the MessageHandler class has the required annotations for component scanning and the service activator annotation that directs the input message to the handleMessage method.
This is a good time to describe the convention for mapping the Message object to the method signature. Typically, the method signature will either map to the Message payload or the Message object itself.
the method signature maps to the String payload. The message payload will be logged and forwarded to the output channel, and prefixed with MESSAGE:.
App.java
package com.apress.prospringintegration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.support.MessageBuilder;
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("classpath:spring-context.xml");
context.start();
MessageChannel input =
(MessageChannel) context.getBean("input", MessageChannel.class );
PollableChannel output =
(PollableChannel) context.getBean("output", PollableChannel.class );
input.send(MessageBuilder.withPayload("Pro Spring Integration Example").build());
Message<?> reply = output.receive();
System.out.println("received: " + reply);
}
}
Maven Project Structure
Run application in Eclipse
Results of Running the Example Code
Received message: Pro Spring Integration Example
received: [Payload=MESSAGE:Pro Spring Integration Example][Headers={timestamp=1296618370609,id=d4c9fac6-655b-45f3-aa4e-e02c1167eb74}]
Creating a Spring Integration Application Using STS
STS has a number of starting templates for creating a Spring application. The templates create a Mavenbased application that includes unit test support
To create a Spring project, select New ➤ Spring Template Project from the File menu
which will create a basic Spring project including an integration test to load the Spring context.
Next, specify sts-project as the project name and com.apress.prospringintegration as the package name. This will build a Maven project called sts-project with the base package
com.apress.prospringintegration
A basic Maven project will be created with the project structure, All of the basic classes and configuration files will be created, including the root Maven pom.xml file, the Spring configuration file app-context.xml, and the integration unit test file ExampleConfiguratio nTests.java,which leverages the Spring testing harness that loads the Spring context.
Next, we will create an example similar to the first Spring project using STS, in which a message will published to a channel. An outbound JMS adapter will forward the message to the ActiveMQ JMS broker. A message-driven JMS channel adapter will receive the message and forward it to a service activator, which will log the message.
The first step is to add the Maven dependencies to the pom.xml file, Add the
Spring Integration core and JMS dependencies to support our example. Also, add the ActiveMQ client and the CGLIB library to support context scanning to simplify the XML configuration
STS pom.xml Maven Confiuration File
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jms</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.4.1</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
Creating the Integration
One of the best features of using STS with Spring Integration is the design editor for wiring up the channels and endpoints used in the application. The design editor supports two-way round-tripping between the XML source file and the graphic design editor. Any changes in either the design or Spring XML configuration file will be synchronized with the other representation. The design editor also supports importing Spring configuration files created by other editors or IDEs. In order to use the STS integration design editor, the required Spring Integration namespaces must be added. You can do this by first double-clicking the app-context.xml Spring configuration file in the Project Explorer. Then select
the Namespaces tab
select the int and int-jms Spring Integration namespaces, as well as the Spring context, in order to support context scanning. This will result in some additional tabs appearing in the design editor, including integration-graph, which is the Spring Integration design editor.
The next step is to add the JMS outbound channel adapter and the JMS message-driven channel adapter. Select the jms tab on the left side to bring up the JMS components. Drag and drop the outbound and message-driven JMS channel adapters onto the design pane. Name the outbound adapter jmsOut and the message-driven adapter jmsIn. In addition, set the destination-name properties to test.queue for both of the components so they will use the same JMS queue.
The last component to add for this example is the service activator used to receive the incoming JMS message and log it. Select the Endpoints tab on the left, and drag and drop the service-activator endpoint to the design pane. Name the service-activator endpoint messageHandler. In addition, set the ref property to jmsHandler to reference the Spring service activator, which we will created shortly.
The last step is to wire up the channels to the endpoints. Select the connection icon on the left side. This will allow creating connections between the channels and endpoints. Drag a connection between the input channel and the jmsOut outbound channel adapter. Then drag a connection between the jmsIn message-driven adapter and the output channel. Finally, drag a connection between the output channel and the messageHandler service activator.
You will need to make some modifications to the app-context.xml file. First, remove the service bean since it is not being used. Then add component scanning to support annotations for the service activator class by setting the base package to com.apress.prospringintegration. This will allow any class in this package to be scanned for annotation support. Component scanning will be used for the service activator and the JMS connection factory.
Spring Integration Configuration file app-context.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:int="http://www.springframework.org/schema/integration"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms-2.0.xsd
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">
<description>Example configuration to get you started.</description>
<context:component-scan
base-package="com.apress.prospringintegration"></context:component-scan>
<int:channel id="input"></int:channel>
<int:channel id="output"></int:channel>
<int-jms:outbound-channel-adapter id="jmsOut" channel="input"
destination-name="test.queue">
</int-jms:outbound-channel-adapter>
<int-jms:message-driven-channel-adapter id="jmsIn" channel="output"
destination-name="test.queue"/>
<int:service-activator id="messageHandler" input-channel="output"
ref="jmsHandler"> </int:service-activator>
</beans>
The ActiveMQ configuration will be done using the Spring Java configuration support. Using a Java class, annotations, and component scanning, you can configure the ActiveMQ connection factory
The Spring bean is named connectionFactory, which is the default connection
factory bean name for the JMS channel adapters. The broker URL is set to vm://localhost to enable the embedded ActiveMQ JMS broker. This is done to simplify the example.
ActiveMQ Connection Factory Configuration
package com.apress.prospringintegration;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.stereotype.Component;
import javax.jms.ConnectionFactory;
@Component
public class JmsConfiguration {
@Bean(name = "connectionFactory")
public ConnectionFactory getConnectionFactory() {
ActiveMQConnectionFactory targetConnectionFactory = new ActiveMQConnectionFactory();
targetConnectionFactory.setBrokerURL("vm://localhost");
CachingConnectionFactory connectionFactory =
new CachingConnectionFactory(targetConnectionFactory);
connectionFactory.setSessionCacheSize(10);
connectionFactory.setCacheProducers(false);
return connectionFactory;
}
}
The final piece of the message chain is to create the service activator class. This class will receive the message from the output channel and log it to the console. Again, component scanning and annotations are used to identify the Spring bean and service activator method.
Service Activator Class
package com.apress.prospringintegration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.stereotype.Component;
@Component
public class JmsHandler {
@ServiceActivator
public void handleMessage(String message) {
System.out.println("Received message: " + message);
}
}
Testing the Integration
In order to test the Spring Integration example, the Spring test harness created by the STS Spring template will be used , The input channel is autowired and the MessageBuilder utility class is used to send a message to the input channel. The test harness loads the Spring context, runs the test cases, and then exits. A delay is added to ensure that the JMS message is received by the messagedriven adapter.
Spring Integration Test Class
package com.apress.prospringintegration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class ExampleConfigurationTests {
@Autowired
private MessageChannel input;
@Test
public void testSendingMessage() throws Exception {
input.send(MessageBuilder.withPayload("Pro Spring Integration Example")
.build());
Thread.sleep(5000);
}
}
You can execute the text code by right-clicking the ExampleConfigurationTest class in the Package Explorer window and selecting Run As ➤ JUnit Test. The unit test will run and the message payload “Pro Spring Integration Example” will be logged in the console window.
Spring Integration Channels
According to Enterprise Integration Patterns,message channel is a virtual data pipe that connects a sender to one or more receivers. The message channel decouples the sender and the receivers so the sender does not necessary know who will receive the messages.
There are two major types of message channels: point-to-point channels and publisher-subscriber channels.
EAI Message Channel Patterns
The message channel design pattern is very simple. The message contains a piece of information that needs to be passed between different components, which can either be in a process or across different applications in different servers. For example, a chain retail store inventory system can send a message with the string “Inventory is running low with Item #12345” to the corporate warehouse so it can send more inventory back to the store. Besides strings, a message can contain any data type that the applications can understand.
The message endpoints are the components that interact with the messages. The endpoint that sends messages to the message channel is called the sender or producer. The endpoint that receives message from the message channel is called the receiver or consumer
The sender puts the data into a message and the receiver takes the data out from the message. As a result, the sender and receiver need to understand the data that they are exchanging. Besides sender and receiver, the message endpoint can filter messages within a channel or route the messages to the other channel. Some message endpoints can even split a message into multiple messages and route them into different channels.
Point-to-Point Channel
The point-to-point channel guarantees that there is only one receiver that receives the same message from the sender at any given time. Spring Integration provides several types of point-topoint channel implementations: QueueChannel, PriorityChannel, RendezvousChannel, DirectChannel, ExecutorChannel, and NullChannel.
Publish-Subscribe Channel
The publish-subscribe channel allows one-to-many relationship between the producer
and consumer, such that multiple consumers may receive the same message. The message is marked as “received” and removed from the channel when all the subscribed receivers have consumed the message. Spring Integration currently provides a publish-subscribe–style message channel implementation, which is PublishSubscribeChannel.
Invalid Message Channel
When the application receives a message from the channel, the application may decide not to process the incoming message because the data within the message may not pass validation or the application may not support the incoming message data type. The message will be routed into the invalid message channel , allowing further handling by the other process/application
Dead Letter Channel
When an application fails to deliver a message to the message channel after all the retry attempts, the message will be sent to the dead letter channel and will be handled further by the another process or application listening for messages on that channel
Channel Adapter
The channel adapter allows an application to connect to the messaging system. Most applications are not designed to communicate with a messaging system in the first place. By using a common interface or application programming interface (API), applications can be easily integrated with different messaging system implementations.
Messaging Bridge
A messaging bridge is a relatively trivial endpoint that simply connects two message channels or channel adapters . For example, the developer may want to connect a PollableChannel to a SubscribableChannel so that the subscribing endpoints don’t have to worry about any polling configuration. Instead, the messaging bridge provides the polling support
Web Service using Spring Integration Part - 1
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>
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>
WSDL Options in Spring Integration
A WSDL is a service contract between the web services provider (server) and service requestor (client), and is primarily used for SOAP services. It is similar to the contract created by an interface for a Java class.
Spring Web Services provides support for exposing a WSDL using an instance of org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition
DefaultWsdl11Definition, which autogenerates the WSDL based an instance of
org.springframework.xml.xsd.SimpleXsdSchema.
SimpleXsdSchema is used to expose Ticket.xsd as source schema for WSDL generation,
Generating a WSDL File Using an XML Schema
package com.apress.prospringintegration.webservice.web;
import com.apress.prospringintegration.webservice.domain.TicketRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.castor.CastorMarshaller;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor;
import org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@SuppressWarnings("unused")
@Configuration
public class TicketIssuerServiceConfiguration {
public static String NAMESPACE = "http://prospringintegration.com/tk/schemas";
// the ws:inbound-gateway is in fact a reference to this base Spring WS object
@Value("#{wsInboundGateway}")
private MessageEndpoint wsInboundGateway;
@Bean
public XsdSchema schema() {
SimpleXsdSchema xsdSchema = new SimpleXsdSchema();
xsdSchema.setXsd(new ClassPathResource("Ticket.xsd"));
return xsdSchema;
}
@Bean
public DefaultWsdl11Definition tickets() throws Throwable {
DefaultWsdl11Definition defaultWsdl11Definition =
new DefaultWsdl11Definition();
defaultWsdl11Definition.setSchema(schema());
defaultWsdl11Definition.setPortTypeName("TicketRequest");
defaultWsdl11Definition.setLocationUri("/tickets");
defaultWsdl11Definition.setTargetNamespace(NAMESPACE);
return defaultWsdl11Definition;
}
@Bean
public PayloadRootQNameEndpointMapping payloadRootQNameEndpointMapping() {
String fqn = String.format("{%s}%s", NAMESPACE, "TicketRequest");
Map<String, MessageEndpoint> endpoints = new HashMap<String, MessageEndpoint>();
endpoints.put(fqn, wsInboundGateway);
PayloadRootQNameEndpointMapping payloadRootQNameEndpointMapping =
new PayloadRootQNameEndpointMapping();
payloadRootQNameEndpointMapping.setEndpointMap(endpoints);
payloadRootQNameEndpointMapping.setInterceptors(
new EndpointInterceptor[]{new PayloadLoggingInterceptor()});
return payloadRootQNameEndpointMapping;
}
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleHandlerMapping = new SimpleUrlHandlerMapping();
simpleHandlerMapping.setDefaultHandler(soapMessageDispatcher());
Properties urlMap = new Properties();
urlMap.setProperty("*.wsdl", "tickets");
simpleHandlerMapping.setMappings(urlMap);
return simpleHandlerMapping;
}
@Bean
public SoapMessageDispatcher soapMessageDispatcher() {
return new SoapMessageDispatcher();
}
}
org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping is
used to map the incoming request to the service endpoints. In addition,
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping is used to specifically expose the WSDL file through the URI /tickets.wsdl.
To test the inbound web services gateway example using Castor marshalling, the ticket-servicemarshaller project must be built and 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.
Use a browser and go to the URL http://localhost:8080/ticketservice-marshalling-1.0/ticketservice/tickets.wsdl.
The WSDL shown will appear, describing the inbound gateway endpoint. You can also use this WSDL to create a client using one of the WSDL-to-Java tools available from projects such as Axis, CXF, or XFire.
Ouput of WSDL Generation tickets.wsdl
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:sch="http://prospringintegration.com/tk/schemas"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://prospringintegration.com/tk/schemas"
targetNamespace="http://prospringintegration.com/tk/schemas">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://prospringintegration.com/tk/schemas"
version="1.0">
<xs:element name="TicketRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="priority" type="priorityType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="TicketResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="ticket" type="ticketType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="ticketType">
<xs:sequence>
<xs:element minOccurs="0" name="description" type="xs:string"/>
<xs:element minOccurs="0" name="issueDateTime" type="xs:dateTime"/>
<xs:element minOccurs="0" name="priority" type="priorityType"/>
<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>
</wsdl:types>
<wsdl:message name="TicketRequest">
<wsdl:part element="tns:TicketRequest" name="TicketRequest">
</wsdl:part>
</wsdl:message>
<wsdl:message name="TicketResponse">
<wsdl:part element="tns:TicketResponse" name="TicketResponse">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="TicketRequest">
<wsdl:operation name="Ticket">
<wsdl:input message="tns:TicketRequest" name="TicketRequest">
</wsdl:input>
<wsdl:output message="tns:TicketResponse" name="TicketResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TicketRequestSoap11" type="tns:TicketRequest">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="Ticket">
<soap:operation soapAction=""/>
<wsdl:input name="TicketRequest">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="TicketResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TicketRequestService">
<wsdl:port binding="tns:TicketRequestSoap11" name="TicketRequestSoap11">
<soap:address
location="http://localhost:8080/ticket-service-marshalling-1.0/tickets"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Outbound Web Services Gateway with XML Marshalling
The Castor marshaller can also be used with the outbound web services gateway. This example will use the same domain and descriptor mapping classes from the inbound gateway example. Similar to the inbound-gateway configuration, the Castor marshaller is set through the marshaller and unmarshaller attributes of the outbound-gateway element
Spring Configuration for Gateway Client Using the Castor Marshaller 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:component-scan base-package="com.apress.prospringintegration.webservice.client"/>
<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"
marshaller="castorMarshaller" unmarshaller="castorMarshaller"/>
</beans>
The Java configuration for the Castor marshaller Since the TicketRequest
instance is sent first to the marshaller, Castor is able to get the reference to this instance and the related domain and descriptor mapping classes.
Java Configuration for the Outbound Gateway Client Using the Castor Marshaller
package com.apress.prospringintegration.webservice.client;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.castor.CastorMarshaller;
@Configuration
public class TicketWebServiceMarshallingConfiguration {
@Bean
public CastorMarshaller castorMarshaller() {
CastorMarshaller castorMarshaller = new CastorMarshaller();
return castorMarshaller;
}
}
The client code is similar to the first outbound gateway example, However, in this case XML document isn’t created by hand; instead, all the interaction with the gateway
occurs through the domain objects
Outbound Gateway Using the Castor Marshaller Client Class
package com.apress.prospringintegration.webservice.client;
import com.apress.prospringintegration.webservice.domain.Ticket;
import com.apress.prospringintegration.webservice.domain.TicketRequest;
import com.apress.prospringintegration.webservice.domain.TicketResponse;
import com.apress.prospringintegration.webservice.domain.types.PriorityType;
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;
import org.springframework.stereotype.Component;
@Component
public class TicketWebServiceMarshallingClient {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("client.xml");
MessageChannel channel =
context.getBean("ticketRequests", MessageChannel.class);
MessagingTemplate messagingTemplate = new MessagingTemplate();
TicketRequest tr = new TicketRequest();
tr.setDescription("Message Broker Down");
tr.setPriority(PriorityType.EMERGENCY);
System.out.printf("Ticket Request: %s [priority: %s] %n", tr.getDescription(),
tr.getPriority());
Message<TicketRequest> ticketRequestMessage =
MessageBuilder.withPayload(tr).build();
@SuppressWarnings("unchecked")
Message<TicketResponse> message =
(Message<TicketResponse>) messagingTemplate.sendAndReceive(
channel, ticketRequestMessage);
Ticket ticket = message.getPayload().getTicket();
System.out.printf("Ticket Response: %s [id: %d] [priority: %s] [date: %s]%n",
ticket.getDescription(), ticket.getTicketId(),
ticket.getPriority(), ticket.getIssueDateTime());
}
}
The results of running the outbound gateway client code, TicketRequest object is created and sent to the outbound gateway. Castor marshalling handles parsing
the XML. The gateway invokes the web service endpoint and returns the TicketResponse object with the new ticket issued.
Web Services Gateway Example Results Using the Castor Marshaller
Ticket Request: Message Broker Down [priority: emergency]
Ticket Response: Message Broker Down [id: 5433537107850368600] [priority: emergency] [date:Sun Feb 27 12:18:01 PST 2011]
Spring Web Services provides support for exposing a WSDL using an instance of org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition
DefaultWsdl11Definition, which autogenerates the WSDL based an instance of
org.springframework.xml.xsd.SimpleXsdSchema.
SimpleXsdSchema is used to expose Ticket.xsd as source schema for WSDL generation,
Generating a WSDL File Using an XML Schema
package com.apress.prospringintegration.webservice.web;
import com.apress.prospringintegration.webservice.domain.TicketRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.castor.CastorMarshaller;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor;
import org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@SuppressWarnings("unused")
@Configuration
public class TicketIssuerServiceConfiguration {
public static String NAMESPACE = "http://prospringintegration.com/tk/schemas";
// the ws:inbound-gateway is in fact a reference to this base Spring WS object
@Value("#{wsInboundGateway}")
private MessageEndpoint wsInboundGateway;
@Bean
public XsdSchema schema() {
SimpleXsdSchema xsdSchema = new SimpleXsdSchema();
xsdSchema.setXsd(new ClassPathResource("Ticket.xsd"));
return xsdSchema;
}
@Bean
public DefaultWsdl11Definition tickets() throws Throwable {
DefaultWsdl11Definition defaultWsdl11Definition =
new DefaultWsdl11Definition();
defaultWsdl11Definition.setSchema(schema());
defaultWsdl11Definition.setPortTypeName("TicketRequest");
defaultWsdl11Definition.setLocationUri("/tickets");
defaultWsdl11Definition.setTargetNamespace(NAMESPACE);
return defaultWsdl11Definition;
}
@Bean
public PayloadRootQNameEndpointMapping payloadRootQNameEndpointMapping() {
String fqn = String.format("{%s}%s", NAMESPACE, "TicketRequest");
Map<String, MessageEndpoint> endpoints = new HashMap<String, MessageEndpoint>();
endpoints.put(fqn, wsInboundGateway);
PayloadRootQNameEndpointMapping payloadRootQNameEndpointMapping =
new PayloadRootQNameEndpointMapping();
payloadRootQNameEndpointMapping.setEndpointMap(endpoints);
payloadRootQNameEndpointMapping.setInterceptors(
new EndpointInterceptor[]{new PayloadLoggingInterceptor()});
return payloadRootQNameEndpointMapping;
}
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleHandlerMapping = new SimpleUrlHandlerMapping();
simpleHandlerMapping.setDefaultHandler(soapMessageDispatcher());
Properties urlMap = new Properties();
urlMap.setProperty("*.wsdl", "tickets");
simpleHandlerMapping.setMappings(urlMap);
return simpleHandlerMapping;
}
@Bean
public SoapMessageDispatcher soapMessageDispatcher() {
return new SoapMessageDispatcher();
}
}
org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping is
used to map the incoming request to the service endpoints. In addition,
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping is used to specifically expose the WSDL file through the URI /tickets.wsdl.
To test the inbound web services gateway example using Castor marshalling, the ticket-servicemarshaller project must be built and 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.
Use a browser and go to the URL http://localhost:8080/ticketservice-marshalling-1.0/ticketservice/tickets.wsdl.
The WSDL shown will appear, describing the inbound gateway endpoint. You can also use this WSDL to create a client using one of the WSDL-to-Java tools available from projects such as Axis, CXF, or XFire.
Ouput of WSDL Generation tickets.wsdl
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:sch="http://prospringintegration.com/tk/schemas"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://prospringintegration.com/tk/schemas"
targetNamespace="http://prospringintegration.com/tk/schemas">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://prospringintegration.com/tk/schemas"
version="1.0">
<xs:element name="TicketRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="priority" type="priorityType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="TicketResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="ticket" type="ticketType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="ticketType">
<xs:sequence>
<xs:element minOccurs="0" name="description" type="xs:string"/>
<xs:element minOccurs="0" name="issueDateTime" type="xs:dateTime"/>
<xs:element minOccurs="0" name="priority" type="priorityType"/>
<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>
</wsdl:types>
<wsdl:message name="TicketRequest">
<wsdl:part element="tns:TicketRequest" name="TicketRequest">
</wsdl:part>
</wsdl:message>
<wsdl:message name="TicketResponse">
<wsdl:part element="tns:TicketResponse" name="TicketResponse">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="TicketRequest">
<wsdl:operation name="Ticket">
<wsdl:input message="tns:TicketRequest" name="TicketRequest">
</wsdl:input>
<wsdl:output message="tns:TicketResponse" name="TicketResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TicketRequestSoap11" type="tns:TicketRequest">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="Ticket">
<soap:operation soapAction=""/>
<wsdl:input name="TicketRequest">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="TicketResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TicketRequestService">
<wsdl:port binding="tns:TicketRequestSoap11" name="TicketRequestSoap11">
<soap:address
location="http://localhost:8080/ticket-service-marshalling-1.0/tickets"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Outbound Web Services Gateway with XML Marshalling
The Castor marshaller can also be used with the outbound web services gateway. This example will use the same domain and descriptor mapping classes from the inbound gateway example. Similar to the inbound-gateway configuration, the Castor marshaller is set through the marshaller and unmarshaller attributes of the outbound-gateway element
Spring Configuration for Gateway Client Using the Castor Marshaller 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:component-scan base-package="com.apress.prospringintegration.webservice.client"/>
<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"
marshaller="castorMarshaller" unmarshaller="castorMarshaller"/>
</beans>
The Java configuration for the Castor marshaller Since the TicketRequest
instance is sent first to the marshaller, Castor is able to get the reference to this instance and the related domain and descriptor mapping classes.
Java Configuration for the Outbound Gateway Client Using the Castor Marshaller
package com.apress.prospringintegration.webservice.client;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.castor.CastorMarshaller;
@Configuration
public class TicketWebServiceMarshallingConfiguration {
@Bean
public CastorMarshaller castorMarshaller() {
CastorMarshaller castorMarshaller = new CastorMarshaller();
return castorMarshaller;
}
}
The client code is similar to the first outbound gateway example, However, in this case XML document isn’t created by hand; instead, all the interaction with the gateway
occurs through the domain objects
Outbound Gateway Using the Castor Marshaller Client Class
package com.apress.prospringintegration.webservice.client;
import com.apress.prospringintegration.webservice.domain.Ticket;
import com.apress.prospringintegration.webservice.domain.TicketRequest;
import com.apress.prospringintegration.webservice.domain.TicketResponse;
import com.apress.prospringintegration.webservice.domain.types.PriorityType;
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;
import org.springframework.stereotype.Component;
@Component
public class TicketWebServiceMarshallingClient {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("client.xml");
MessageChannel channel =
context.getBean("ticketRequests", MessageChannel.class);
MessagingTemplate messagingTemplate = new MessagingTemplate();
TicketRequest tr = new TicketRequest();
tr.setDescription("Message Broker Down");
tr.setPriority(PriorityType.EMERGENCY);
System.out.printf("Ticket Request: %s [priority: %s] %n", tr.getDescription(),
tr.getPriority());
Message<TicketRequest> ticketRequestMessage =
MessageBuilder.withPayload(tr).build();
@SuppressWarnings("unchecked")
Message<TicketResponse> message =
(Message<TicketResponse>) messagingTemplate.sendAndReceive(
channel, ticketRequestMessage);
Ticket ticket = message.getPayload().getTicket();
System.out.printf("Ticket Response: %s [id: %d] [priority: %s] [date: %s]%n",
ticket.getDescription(), ticket.getTicketId(),
ticket.getPriority(), ticket.getIssueDateTime());
}
}
The results of running the outbound gateway client code, TicketRequest object is created and sent to the outbound gateway. Castor marshalling handles parsing
the XML. The gateway invokes the web service endpoint and returns the TicketResponse object with the new ticket issued.
Web Services Gateway Example Results Using the Castor Marshaller
Ticket Request: Message Broker Down [priority: emergency]
Ticket Response: Message Broker Down [id: 5433537107850368600] [priority: emergency] [date:Sun Feb 27 12:18:01 PST 2011]