The document discusses using Spring Integration and Enterprise Integration Patterns (EIP) to integrate the systems of an online retailer called WGRUS. It provides an overview of Spring Integration and EIPs, describing common patterns like channels, gateways, routers and how they address integration challenges. It then gives examples of implementing various EIP patterns with Spring Integration components to integrate WGRUS' order intake and processing across different channels.
3. Agenda
• Spring Integration – 10.000 foot view
• Enterprise Integration Patterns - WGRUS
– What is integration?
– How to address integration challenges
– Messaging / what are EIP Patterns ?
• EIP with Spring Integration (SI)
• WGRUS flows
• Study resources
4. Spring Integration – 10.000 foot view
• Enterprise Application Integration solution
– integration of systems and applications across an enterprise
• Spring Integration pillars (axioms):
– Spring programming model
● probably the most popular Java framework
– Enterprise Integration Patterns
● Gregor Hohpe , Bobby Woolf - 2003
● Foreward by Martin Fowler
(Patterns of Enterprise Application Architecture)
● Asynchronous, message-driven behavior
within a Spring-based application
● Intuitive, incremental adoption for existing Spring users
● Default integration with HTTP, JMS, AMQP, FTP, JDBC, JPA
Mail, Mongo, RMI, Web Services, Twitter, XMPP, File systems
5. EIP – What is integration?
Widgets & Gadgets ‘R Us (WGRUS) - an online retailer that buys widgets and gadgets from
manufacturers and resells them to customers on multiple channels (by phone, fax orders, web
interface).
WGRUS & external systems WGRUS's internal systems
• Call center:
C++ desktop application / Oracle database server – it allows customers to place orders via phone. Apps
sources cannot / may not be modified.
• Inbound fax:
The inbound fax system requires manual data entry into a small Microsoft Access application.
• Web Interface:
JEE custom built web app allowing customers to browse widgets & gadgets, place orders, monitor orders
status. Apps sources may / can be modified.
6. EIP – Why integration is necessary ?
What is needed
Take Orders
Customers can place orders on multiple
channels - via Web, phone or fax
Processing Orders
Processing an order involves multiple steps,
including verifying inventory, shipping the goods and
invoicing the customer (integrate all backend
systems)
New Catalog
The suppliers update their catalog
periodically. WGRUS needs to update its pricing and
availability based in the new catalogs.
Challenges
Networks are unreliable
Networks are slow
Any two applications are different
Change is inevitable
7. EIP – How to address integration challenges
1. File Transfer - the MS Office
database from the Inbound Fax System is
copied periodically to a specific network file
location; the Integration Solution will recover
it from that location, process it by importing
any new order and later delete it.
2. Shared Database - the Call Center
application's sources cannot / may not
changed. However, since it uses an Oracle
database server, the creation of new orders
might be monitored with a trigger on insert
(on the “orders” table). That trigger would
copy new order details into a new created
table “orders_si”. A separate application
would connect to these database,
monitoring the “orders_si” table and each
time a new record is created, it will notify the
Integration Solution with order details; later
on, that new “orders_si” record would be
deleted.
3. Remote Procedure Invocation - WGRUS needs to update its pricing
and availability based in the new catalogs by running some HTTP SOAP web
service calls to “Widget Co” and “Gadget Co” external systems; those systems
respond back with their current catalogs & prices.
8. EIP – How to address integration challenges
4. Messaging - after a new order is
placed, the web app detects that order
and publishes a new message on a specific
JMS queue. This message contains new
order's details. And that's it, the web app
'forgets' about that message returning to
its job.
The messaging system is notified by the
JMS queue with an event about the new
order. It can start processing that order.
10. EIP with Spring Integration - Message
public interface Message<T> {
MessageHeaders getHeaders();
T getPayload();
}
public final class MessageHeaders
implements Map<String, Object>, Serializable{
...
}
Message<String> message1 = MessageBuilder.withPayload("test").setHeader("foo", "bar").build();
Spring Integration Messages are immutable!
Best practice: the payload / headers would have to be immutable and serializable.
12. EIP with Spring Integration - Channel
• EIP name: Point-to-Point Channel
• Message consumer: Event-Driven Consumer
• A channel that invokes a single subscriber for
each sent Message. The invocation will occur in
the sender's thread. It uses an
UnicastingDispatcher without a thread executor.
Failover support.
<channel id=directChannel" />
<channel id=directChannel2">
<dispatcher failover="true" load-balancer="round-robin" />
</channel>
<transformer id="t1" input-channel="directChannel"
output-channel="outputChannel"
ref="myTransformerBean"/>
13. EIP with Spring Integration - Channel
• EIP name: Point-to-Point Channel
• Message consumer: Event-Driven Consumer
• A channel that invokes a single subscriber for
each sent Message. The invocation will occur on
executor's threads. It uses an
UnicastingDispatcher with a thread executor.
Failover support.
<channel id=”executorChannel”>
<dispatcher task-executor=”someExecutor”/>
</channel>
<transformer id="t2" input-channel="executorChannel"
output-channel="outputChannel"
ref="myTransformerBean"/>
14. EIP with Spring Integration - Channel
• EIP name: Publish-Subscribe Channel
• Message consumer: Event-Driven Consumer
• A channel that sends the Message to each one of its
subscribers. The invocation occurs on the sender's
thread (if no executor is specified) or on separate
threads for each receiver (if an executor is specified).
It uses an BroadcastingDispatcher with an optional
thread executor.
<publish-subscribe-channel id="pubSubChannel"
task-executor="someExecutor"/>
<transformer id="t1" input-channel="pubSubChannel"
output-channel="outputChannel1" ref="myTransformerBean1"/>
<transformer id="t2" input-channel="pubSubChannel"
output-channel="outputChannel2" ref="myTransformerBean2"/>
<filter id="f1" input-channel="pubSubChannel"
output-channel="outputChannel3"/>
15. EIP with Spring Integration - Channel
• EIP name: Point-to-Point Channel
• Message consumer: Polling Consumer
• Simple implementation of a message channel. Each
Message is placed in a BlockingQueue whose capacity
may be specified upon construction. By default, it uses
a LinkedBlockingQueue but a MessageGroupQueue
might be used to store messages on a persistent
context (like a relational database) – basically, using a
MessageStore
<channel id=”queueChannel”>
<queue capacity="25" />
</channel>
<channel id=”queueChannel” >
<queue message-store="myMessageStore" />
</channel>
<jdbc:message-store id="myMessageStore" data-source="mySqlDataSource"/>
16. EIP with Spring Integration - Channel
• Sending messages on a channel:
@Autowired
@Qualifier(“myChannelID”);
private DirectChannel channel;
public void sendMessage(String msgPayload) {
final MessagingTemplate mt = new MessagingTemplate();
final Message<String> msg =
MessageBuilder.withPayload(msgPayload).build();
mt.send(channel, msg);
}
17. EIP with SI – Polling Consumer
• Polling consumers: a consumer with a PollableChannel as its input channel
• Sync / Async polling consumers
• <channel id=”queueChannel”>
<queue message-store="myMessageStore" />
</channel>
<jdbc:message-store id="myMessageStore" data-source="mySqlDataSource" />
<transformer id="t3" input-channel="queueChannel"
output-channel="outputChannel" ref="myTransformerBean">
<poller fixed-rate="10" receive-timeout="60000"
task-executor="myTaskExecutor">
<transactional isolation="REPEATABLE_READ"
transaction-manager="txManager" propagation="REQUIRED" />
</poller>
</transformer>
18. EIP with SI – Event-driven Consumers
• Event driven consumers: a consumer with a SubscribableChannel as its input channel
• <channel id="directChannel" />
<transformer id="t3" input-channel="directChannel"
output-channel="outputChannel" ref="myTransformerBean" />
19. EIP with SI – Channel Adapter
• A Channel Adapter is a component that connects a single sender or receiver to a Message Channel.
(outside of the sender/receiver; one way communication)
• JMS inbound channel adapter:
<jms:message-driven-channel-adapter id="jmsIn" destination="requestQueue"
channel="jmsInChannel" />
<channel id="jmsInChannel" />
• JMS outbound channel adapter:
<channel id="stdinToJmsoutChannel"/>
<jms:outbound-channel-adapter id="jmsout" channel="stdinToJmsoutChannel"
destination="requestQueue"/>
• Predefined channel adapters: JMS, AMQP, JDBC, JPA, Mongo, Redis, FTP, Twitter
20. EIP with SI – Gateways
• A Gateway is a Message Endpoint that connects an application that is both a sender and receiver to a
Message Channel. (inside the application; two-way communication).
• The 'default' gateway allows Java code to call a Spring Integration flow as a Spring service:
<gateway id="myGateway" default-request-channel="inputChannel"
default-reply-channel="outputChannel" service-interface="fr.pentalog.si.MyGateway">
<method name="process">
<header name="configuredHeader" value="abc"/>
</method>
</gateway>
<channel id="inputChannel" />
<channel id="outputChannel" />
• Async gateways:
public interface MyGateway {
public String process(String thing,
<gateway id="myGateway" default-request-channel="inputChannel"
default-reply-channel="outputChannel" service-interface="fr.pentalog.si.MyGatewayy"
async-executor="myExecutor">
<method name="process" />
</gateway>
• Predefined gateways:
– JMS, AMQP, HTTP, Web Services, Redis, JDBC
@Header(FileHeaders.FILENAME)
String fileName);
}
public interface MyGateway {
public Feature<String> process(String thing,
@Header(FileHeaders.FILENAME)
String fileName);
}
21. EIP with SI – Service Activator
• A service activator in Spring Integration simply connects any existing Spring-managed bean to a channel.
These Spring service beans may or may not return a result.
• <service-activator id="myServiceActivator" input-channel="inputChannel" output-channel="outputChannel"
ref="barista" method="prepareHotDrink" />
@Service("barista")
public class Barista {
@Transactional
public Drink prepareHotDrink(OrderItem orderItem) {
...
}
}
22. EIP with SI – Transformer
<transformer input-channel="callCenterOrdersChannel" output-channel="canonicalOrdersChannel"
ref="transformer" method="transform"/>
<beans:bean id="transformer" class="fr.pentalog.si.CallCenterOrderTransformer" />
public class CallCenterOrderTransformer {
public CanonicalOrder transform(CallCenterOrder order) {
...;
}
}
<object-to-json-transformer
input-channel="newOrders"
output-channel="jsonNewOrders" />
24. EIP with SI – Filter
<filter input-channel="inputChannel2" output-channel="outputChannel"
discard-channel="discardChannel2"
ref="petFilter" method="dogsOnly" />
<beans:bean id="dogsOnly" class="fr.pentalog.fr.PetFilter"/>
public class PetFilter {
public boolean dogsOnly(String input) {
return input.toLowerCase().contains("dog");
}
}
<filter input-channel="inputChannel2" output-channel="outputChannel"
throw-exception-on-rejection="true"
ref="petFilter" method="dogsOnly" />
25. EIP with SI – Splitter
<channel id="ordersChannel" />
<channel id="itemsChannel" />
<splitter input-channel="ordersChannel" output-channel="itemsChannel" apply-sequence="true"
ref="ordersSplitter" method="splitOrder">
</splitter>
<beans:bean id="ordersSplitter" class="fr.pentalog.si.OrdersSplitter" />
public class OrdersSplitter {
public List<CanonicalItem> splitOrder(CanonicalOrder order) {
return null;
}
}
The Splitter adds following headers in Item messages (for an Order with 2 items):
{correlationId=d7c96f28-b9b5-1c8b-1881-8d4b09d83c6b, sequenceSize=2, sequenceNumber=1}
{ correlationId=d7c96f28-b9b5-1c8b-1881-8d4b09d83c6b, sequenceSize=2, sequenceNumber=2}
26. EIP with SI – Aggregator
<aggregator input-channel="itemsChannel" output-channel="ordersChannel"
ref="itemsAggregator" method="aggregate" message-store="myMessageStore">
</aggregator>
<beans:bean id="itemsAggregator" class="fr.pentalog.si.ItemsAggregator" />
public class ItemsAggregator {
public CanonicalOrder splitOrder(List<CanonicalItem> items) {
...
}
}
CorrelationId, SequenceSize, SequenceNumber
Statefull component - it might use a message store to keep messages upon completion.
Correlation Strategy – how to identify thow messages belong to the same group
ReleaseStrategy – how to detect that a group of messages is complete
Timeouts – time to wait a group of messages upon completion
Discard channel – where expired messages will be published
Partial Aggregation – if not all expected messages are to come
27. EIP with SI – Router
<channel id="itemInputChannel"/>
<router id="router1" input-channel="itemInputChannel" ref="orderRouter" method="route" />
<router id="router2" input-channel="itemInputChannel" ref="orderRouter" method="route">
<mapping value="widget" channel="widgetItemOrderChannel" />
<mapping value="gadget" channel="gadgetItemOrderChannel" />
</router>
<beans:bean class="fr.pentalog.si.OrderRouter"/>
public class OrderRouter {
public String route(CanonicalOrderItem order) {
...
}
}
28. Spring Integration – Error Handling
Default channels:
errorChannel
used internally for sending error messages and may be overridden with a custom configuration
nullChannel
acts like /dev/null, simply logging any Message sent to it at DEBUG level and returning immediately
31. Study resources
Spring Integration in Action – written by SI's creators
Enterprise Integration Patterns
32.
33. Please fill the online evaluation form after event
[Enterprise Integration Patterns with Spring Integration]
[Mihalache Catalin]
[Pentalog]
[25th of October 2014]