Warning |
---|
This tutorial is a work in progress. Any additions, corrections or feedback very much appreciated. Please use the comment box if making a correction explaining the mistake. |
Preface
This tutorial aims to guide the reader through the stages of creating a project which uses Camel to facilitate the routing of messages from a JMS queue to a Spring service. The route works in a synchronous fashion returning a response to the client.
Table of Contents |
---|
TODOs
- Embellish the tutorial with more detail, explaining at each stage what is happening.
- Link to specific sections of Camel documentation when referring to components.
- Attach completed example project.
- Explain in more detail what is happening when the JMS component is being defined in camel-server.xml
- Show how logging can be introduced to monitor exchange body contents.
- Detail how time-outs can be configured.
- Show how to catch lost messages.
- Show how to use a wiretap.
- Can we make this ActiveMQ embedded so that it does not require the reader to download and start it manually?
Prerequisites
This tutorial uses ActiveMQ as the JMS broker. Download and extract it, then start the broker using script in the bin directory.
It is assumed that the reader is familiar with Spring (including v2.5 features) and Maven.
Create the Camel Project
Info |
---|
For the purposes of the tutorial a single Maven project will be used for both the client and server. Ideally you would break your application down into the appropriate components. |
Code Block |
---|
Wiki Markup |
{warning}This tutorial is a work in progress. Any additions, corrections or feedback very much appreciated. Please use the comment box if making a correction explaining the mistake.{warning} h1. Preface This tutorial aims to guide the reader through the stages of creating a project which uses Camel to facilitate the routing of messages from a JMS queue to a [Spring|http://www.springramework.org] service. The route works in a synchronous fashion returning a response to the client. {toc} h1. TODOs * Embellish the tutorial with more detail, explaining at each stage what is happening. * Link to specific sections of Camel documentation when referring to components. * -Attach completed example project.- * Explain in more detail what is happening when the JMS component is being defined in camel-server.xml * Show how logging can be introduced to monitor exchange body contents. * Detail how time-outs can be configured. * Show how to catch lost messages. * Show how to use a wiretap. * Can we make this ActiveMQ embedded so that it does not require the reader to download and start it manually? h1. Prerequisites This tutorial uses ActiveMQ as the JMS broker. [Download|http://activemq.apache.org/download.html] and extract it, then start the broker using script in the bin directory. It is assumed that the reader is familiar with Spring (including v2.5 features) and Maven. h1. Create the Camel Project {info} For the purposes of the tutorial a single Maven project will be used for both the client and server. Ideally you would break your application down into the appropriate components. {info} {code} mvn archetype:create -DgroupId=org.example -DartifactId=CamelWithJmsAndSpring {code} h2. Update the POM with Dependencies {code}.example -DartifactId=CamelWithJmsAndSpring |
Update the POM with Dependencies
Code Block |
---|
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
</dependencies>
{code}
h1. Writing the Server
h2. Create the Spring Service
For this example the Spring service on the server will be a simple multiplier which trebles in the received value. The classes should reside in the package {{ |
Writing the Server
Create the Spring Service
For this example the Spring service on the server will be a simple multiplier which trebles in the received value. The classes should reside in the package org.example.server
...
.
Code Block | ||||
---|---|---|---|---|
| =
| |||
} public interface Multiplier { /** * Multiplies the given number by a pre-defined constant. * * @param originalNumber The number to be multiplied * @return The result of the multiplication */ int multiply(int originalNumber); } {code} {code:title= |
Code Block | ||
---|---|---|
| ||
} @Service(value="multiplier") public class Treble implements Multiplier { /* (non-Javadoc) * @see org.example.server.Multiplier#multiply(int) */ public int multiply(final int originalNumber) { return originalNumber * 3; } } {code} |
Using
...
Spring
...
annotations
...
the
...
bean
...
is
...
defined
...
with
...
the
...
name
...
multiplier
...
.
...
Define
...
the
...
Camel
...
Routes
Code Block | ||||
---|---|---|---|---|
| =
| |||
} public class ServerRoutes extends RouteBuilder { /* (non-Javadoc) * @see org.apache.camel.builder.RouteBuilder#configure() */ @Override public void configure() throws Exception { from("jms:queue:numbers").beanRef("multiplier", "multiply"); } } {code} |
This
...
defines
...
a
...
Camel
...
route
...
from
...
the
...
JMS
...
queue
...
named
...
numbers
...
to
...
the
...
Spring
...
bean
...
named
...
multiplier
...
.
...
Camel
...
will
...
create
...
a
...
consumer
...
to
...
the
...
JMS
...
queue
...
which
...
forwards
...
all
...
received
...
messages
...
onto
...
the
...
the
...
Spring
...
bean,
...
using
...
the
...
method
...
named multiply.
Configure Spring
The Spring config file is placed under META-INF/spring
...
as
...
this
...
is
...
the
...
default
...
location
...
used
...
by
...
the
...
...
...
...
,
...
which
...
we
...
will
...
later
...
use
...
to
...
run
...
our
...
server.
Code Block | |||||||
---|---|---|---|---|---|---|---|
|
| ||||||
} <?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:context="http://www.springframework.org/schema/context" xmlns:camel="http://activemq.apache.org/camel/schema/spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/context http://schemas.leadx.com/spring/spring-context-2.5.xsd http://activemq.apache.org/camel/schema/spring http://activemq.apache.org/camel/schema/spring/camel-spring-1.3.0.xsd"> <context:component-scan base-package="org.example.server" /> <camel:camelContext id="camel"> <camel:package>org.example.server</camel:package> </camel:camelContext> <bean id="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory"> <bean class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://localhost:61616" /> </bean> </property> </bean> </beans> {code} | |
component-scan |
...
Defines |
...
the |
...
package |
...
to |
...
be |
...
scanned |
...
for |
...
Spring |
...
stereotype |
...
annotations, |
...
in |
...
this |
...
case, |
...
to |
...
load |
...
the |
...
"multiplier" |
...
bean |
...
camel-context |
...
Defines |
...
the |
...
package |
...
to |
...
be |
...
scanned |
...
for |
...
Camel |
...
routes. |
...
Will |
...
find |
...
the |
...
|
...
class |
...
and |
...
create |
...
the |
...
routes |
...
contained |
...
within |
...
it |
...
jms |
...
bean |
...
Creates |
...
the |
...
Camel |
...
JMS component |
Run the Server
Code Block | |||
---|---|---|---|
|
| ||
} public class CamelServer { public static void main(final String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("camel-server.xml"); } } {code} The {{main}} method can then be executed to start the server. h1. Creating the Client We will initially create a client by directly using {{CamelTemplate}}. We will later create a client which uses Spring remoting to hide the fact that messaging is being used. {code:title=camel-client.xml|xml} |
The main
method can then be executed to start the server.
Creating the Client
We will initially create a client by directly using CamelTemplate
. We will later create a client which uses Spring remoting to hide the fact that messaging is being used.
Code Block | ||||
---|---|---|---|---|
| ||||
<?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:camel="http://activemq.apache.org/camel/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://activemq.apache.org/camel/schema/spring
http://activemq.apache.org/camel/schema/spring/camel-spring-1.3-SNAPSHOT.xsd">
<camel:camelContext id="camel" />
<camel:template id="camelTemplate" />
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
</property>
</bean>
</beans>
{code}
|
The
...
client
...
will
...
not
...
use
...
the
...
...
...
...
so
...
the
...
Spring
...
XML
...
has
...
been
...
placed
...
in
...
src/main/resources
...
so
...
not
...
to
...
conflict
...
with
...
the
...
server
...
configs.
camelContext | The Camel context is defined but does not contain any routes |
tempate | The |
jms bean | This initialises the Camel JMS component, allowing us to place messages onto the queue |
Code Block | |||
---|---|---|---|
|
| ||
} public class CamelClient { public static void main(final String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("camel-client.xml"); CamelTemplate<JmsExchange> camelTemplate = (CamelTemplate) context.getBean("camelTemplate"); int response = (Integer)camelTemplate.sendBody("jms:queue:numbers", ExchangePattern.InOut, 22 ); Assert.assertEquals(66, response); System.out.println(response); } } {code} The {{CamelTemplate}} is retrieved from a Spring {{ApplicationContext}} and used to manually place a message on the "numbers" JMS queue. The exchange pattern (*ExchangePattern.InOut*) states that the call should be synchronous, and that we will receive a response. We then assert that the response is three times the value of the original. Before running the client be sure that both the ActiveMQ broker and the {{CamelServer}} are running. h1. Using Spring Remoting [Spring Remoting] "eases the development of remote-enabled services". It does this by allowing you to invoke remote services through your regular Java interface, masking that a remote service is being called. {code:title= |
The CamelTemplate
is retrieved from a Spring ApplicationContext
and used to manually place a message on the "numbers" JMS queue. The exchange pattern (ExchangePattern.InOut) states that the call should be synchronous, and that we will receive a response. We then assert that the response is three times the value of the original.
Before running the client be sure that both the ActiveMQ broker and the CamelServer
are running.
Using Spring Remoting
Spring Remoting "eases the development of remote-enabled services". It does this by allowing you to invoke remote services through your regular Java interface, masking that a remote service is being called.
Code Block | ||||
---|---|---|---|---|
| ||||
|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:camel="http://activemq.apache.org/camel/schema/spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://activemq.apache.org/camel/schema/spring http://activemq.apache.org/camel/schema/spring/camel-spring-1.3-SNAPSHOT.xsd"> <camel:camelContext id="camel" /> <camel:proxy id="multiplier" serviceInterface="org.example.server.Multiplier" serviceUrl="jms:queue:numbers" /> <bean id="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory"> <bean class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://localhost:61616" /> </bean> </property> </bean> </beans> {code} |
First
...
we
...
create
...
a
...
new
...
Spring
...
config
...
file.
...
This
...
has
...
a
...
few
...
changes
...
made
...
from
...
camel-client.xml
...
.
...
Firstly
...
the
...
Camel
...
template
...
has
...
been
...
removed,
...
as
...
it
...
will
...
not
...
be
...
used.
...
Secondly
...
a
...
proxy
...
is
...
defined.
...
This
...
will
...
create
...
a
...
proxy
...
service
...
bean
...
for
...
you
...
to
...
use
...
to
...
make
...
the
...
remote
...
invocations.
...
The
...
serviceInterface
...
property
...
details
...
which
...
Java
...
interface
...
is
...
to
...
be
...
implemented
...
by
...
the
...
proxy.
...
serviceUrl
...
defines
...
where
...
messages
...
sent
...
to
...
this
...
proxy
...
bean
...
will
...
be
...
directed.
...
Here
...
we
...
define
...
the
...
JMS
...
endpoint
...
with
...
the
...
"numbers"
...
queue
...
we
...
used
...
when
...
working
...
with
...
Camel
...
template
...
directly.
...
The
...
value
...
of
...
the
...
id
...
property
...
is
...
the
...
name
...
that
...
will
...
be
...
the
...
given
...
to
...
the
...
bean
...
when
...
it
...
is
...
exposed
...
through
...
the
...
Spring
...
ApplicationContext
...
.
...
We
...
will
...
use
...
this
...
name
...
to
...
retrieve
...
the
...
service
...
in
...
our
...
client.
...
I
...
have
...
named
...
the
...
bean
...
multiplierProxy
...
simply
...
to
...
highlight
...
that
...
it
...
is
...
not
...
the
...
same
...
multiplier
...
bean
...
as
...
is
...
being
...
used
...
by
...
CamelServer
...
.
...
They
...
are
...
in
...
completely
...
independent
...
contexts
...
and
...
have
...
no
...
knowledge
...
of
...
each
...
other.
...
As
...
you
...
are
...
trying
...
to
...
mask
...
the
...
fact
...
that
...
remoting
...
is
...
being
...
used
...
in
...
a
...
real
...
application
...
you
...
would
...
generally
...
not
...
include
...
proxy
...
in
...
the
...
name.
Code Block | ||||
---|---|---|---|---|
| =
| |||
} public class CamelClientRemoting { public static void main(final String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("camel-client-remoting.xml"); Multiplier multiplier = (Multiplier) context.getBean("multiplierProxy"); int response = multiplier.multiply(22); Assert.assertEquals(66, response); System.out.println(response); } } {code} |
Again,
...
the
...
client
...
is
...
similar
...
to
...
the
...
original
...
client,
...
but
...
with
...
some
...
important
...
differences.
...
- The
...
- Spring
...
- context
...
- is
...
- created
...
- with
...
- the
...
- new
...
- camel-client-remoting.xml
...
- We
...
- retrieve
...
- the
...
- proxy
...
- bean
...
- instead
...
- of
...
- a
...
CamelTemplate
...
- .
...
- In
...
- a
...
- non-trivial
...
- example
...
- you
...
- would
...
- have
...
- the
...
- bean
...
- injected
...
- as
...
- in
...
- the
...
- standard
...
- Spring
...
- manner.
...
- The
...
- multiply
...
- method
...
- is
...
- then
...
- called
...
- directly.
...
- In
...
- the
...
- client
...
- we
...
- are
...
- now
...
- working
...
- to
...
- an
...
- interface.
...
- There
...
- is
...
- no
...
- mention
...
- of
...
- Camel
...
- or
...
- JMS
...
- inside
...
- our Java code.
Using the Camel Maven Plugin
Note |
---|
Require an explanation here about the deployment options of Camel based projects Java code. h1. Using the Camel Maven Plugin {note} Require an explanation here about the deployment options of Camel based projects(e.g. running through Maven, creating a host application, deploying into ActiveMQ) and the pros/cons of each. |
The Camel Maven Plugin allows you to run your Camel routes directly from Maven. This negates the need to create a host application, as we did with Camel server, simply to start up the container. This can be very useful during development to get Camel routes running quickly.
Code Block | ||
---|---|---|
| ||
{note} The [Camel Maven Plugin] allows you to run your Camel routes directly from Maven. This negates the need to create a host application, as we did with Camel server, simply to start up the container. This can be very useful during development to get Camel routes running quickly. {code|title=pom.xml} <build> <plugins> <plugin> <groupId>org.apache.camel</groupId> <artifactId>camel-maven-plugin</artifactId> </plugin> </plugins> </build> {code} |
All
...
that
...
is
...
required
...
is
...
a
...
new
...
plugin
...
definition
...
in
...
your
...
Maven
...
POM.
...
As
...
we
...
have
...
already
...
placed
...
our
...
Camel
...
config
...
in
...
the
...
default
...
location
...
(camel-server.xml
...
has
...
been
...
placed
...
in
...
META-INF/spring/)
...
we
...
do
...
not
...
need
...
to
...
tell
...
the
...
plugin
...
where
...
the
...
route
...
definitions
...
are
...
located.
...
Simply
...
run
...
mvn
...
camel:run
...
.
TODO:
...
Testing
...
TODO:
...
Detail
...
how
...
to
...
unit
...
and
...
integration
...
test
...
this
...
example.