blob: 951c656151b61210bac71c4d95f1edce2ad52973 [file] [log] [blame]
= Walk through another example
== Introduction
Continuing the walk from our first
xref:walk-through-an-example.adoc[example], we take a closer look at the
routing and explain a few pointers - so you won't walk into a bear trap,
but can enjoy an after-hours walk to the local pub for a large beer.
First we take a moment to look at the
xref:enterprise-integration-patterns.adoc[Enterprise Integration
Patterns] - the base pattern catalog for integration scenarios. In
particular we focus on http://www.enterpriseintegrationpatterns.com/PipesAndFilters.html[Pipes and Filters] -
a central pattern. This is used to route messages through a sequence of
processing steps, each performing a specific function - much like the
Java Servlet Filters.
== Pipes and filters
In this sample we want to process a message in a sequence of steps where
each steps can perform their specific function. In our example we have a
xref:components::jms-component.adoc[JMS] queue for receiving new orders. When an order is
received we need to process it in several steps:
* validate
* register
* send confirm email
This can be created in a route like this:
[source,xml]
----
<route>
<from uri="jms:queue:order"/>
<pipeline>
<bean ref="validateOrder"/>
<bean ref="registerOrder"/>
<bean ref="sendConfirmEmail"/>
</pipeline>
</route>
----
**Pipeline is default**
In the route above we specify `pipeline` but it can be omitted as its
default, so you can write the route as:
[source,xml]
----
<route>
<from uri="jms:queue:order"/>
<bean ref="validateOrder"/>
<bean ref="registerOrder"/>
<bean ref="sendConfirmEmail"/>
</route>
----
This is commonly used not to state the pipeline.
An example where the pipeline needs to be used, is when using a
multicast and "one" of the endpoints to send to (as a logical group) is
a pipeline of other endpoints. For example.
[source,xml]
----
<route>
<from uri="jms:queue:order"/>
<multicast>
<to uri="log:org.company.log.Category"/>
<pipeline>
<bean ref="validateOrder"/>
<bean ref="registerOrder"/>
<bean ref="sendConfirmEmail"/>
</pipeline>
</multicast>
</route>
----
The above sends the order (from `jms:queue:order`) to two locations at
the same time, our log component, and to the "pipeline" of beans which
goes one to the other. If you consider the opposite, sans the
`<pipeline>`
[source,xml]
----
<route>
<from uri="jms:queue:order"/>
<multicast>
<to uri="log:org.company.log.Category"/>
<bean ref="validateOrder"/>
<bean ref="registerOrder"/>
<bean ref="sendConfirmEmail"/>
</multicast>
</route>
----
you would see that multicast would not "flow" the message from one bean
to the next, but rather send the order to all 4 endpoints (1x log, 3x
bean) in parallel, which is not (for this example) what we want. We need
the message to flow to the validateOrder, then to the registerOrder,
then the sendConfirmEmail so adding the pipeline, provides this
facility.
Where as the `bean ref` is a reference for a spring bean id, so we
define our beans using regular Spring XML as:
[source,xml]
----
<bean id="validateOrder" class="com.mycompany.MyOrderValidator"/>
----
Our validator bean is a plain POJO that has no dependencies to Camel
what so ever. So you can implement this POJO as you like. Camel uses
rather intelligent xref:bean-binding.adoc[Bean Binding] to invoke your
POJO with the payload of the received message. In this example we will
*not* dig into this how this happens. You should return to this topic
later when you got some hands on experience with Camel how it can easily
bind routing using your existing POJO beans.
So what happens in the route above. Well when an order is received from
the xref:components::jms-component.adoc[JMS] queue the message is routed like
pipes and filters:
1. payload from the xref:components::jms-component.adoc[JMS] is sent as input to the
validateOrder bean +
2. the output from validateOrder bean is sent as input to the
registerOrder bean +
3. the output from registerOrder bean is sent as input to the
sendConfirmEmail bean
== Using Camel Components
In the route lets imagine that the registration of the order has to be
done by sending data to a TCP socket that could be a big mainframe. As
Camel has many xref:components::index.adoc[Components] we will use the
camel-mina component that supports xref:components::mina-component.adoc[TCP] connectivity. So
we change the route to:
[source,syntaxhighlighter-pre]
----
<route>
<from uri="jms:queue:order"/>
<bean ref="validateOrder"/>
<to uri="mina:tcp://mainframeip:4444?textline=true"/>
<bean ref="sendConfirmEmail"/>
</route>
----
What we now have in the route is a `to` type that can be used as a
direct replacement for the bean type. The steps is now:
1. payload from the xref:components::jms-component.adoc[JMS] is sent as input to the
validateOrder bean
2. the output from validateOrder bean is sent as text to the mainframe
using TCP
3. the output from mainframe is sent back as input to the
sendConfirmEmai bean
What to notice here is that the `to` is not the end of the route (the
world) in this example it's used in the middle of the
xref:pipeline-eip.adoc[Pipes and filters]. In fact we can change
the `bean` types to `to` as well:
[source,syntaxhighlighter-pre]
----
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="mina:tcp://mainframeip:4444?textline=true"/>
<to uri="bean:sendConfirmEmail"/>
</route>
----
As the `to` is a generic type we must state in the uri scheme which
component it is. So we must write *bean:* for the xref:components::bean-component.adoc[Bean]
component that we are using.
== Conclusion
This example was provided to demonstrate the Spring DSL (XML based) as
opposed to the pure Java DSL from the
xref:walk-through-an-example.adoc[first example]. And as well to point
about that the `to` doesn't have to be the last node in a route graph.
This example is also based on the *in-only* message exchange pattern.
What you must understand as well is the *in-out* message exchange
pattern, where the caller expects a response. We will look into this in
another example.