50
Apache Camel Taking Camel for a ride Hands on Xke Alexis Kinsella June 11, 2010

Xke - Introduction to Apache Camel

Embed Size (px)

DESCRIPTION

Introduction to Apache Camel

Citation preview

Page 1: Xke - Introduction to Apache Camel

Apache CamelTaking Camel for a ride

Hands on XkeAlexis KinsellaJune 11, 2010

Page 2: Xke - Introduction to Apache Camel

www.xebia.fr / blog.xebia.fr 2

What is camel ?

Page 3: Xke - Introduction to Apache Camel

What is camel ?

www.xebia.fr / blog.xebia.fr 3

It stands for :▶ Concise Application Message

Exchange Language (i.e. the Java DSL for routing)

▶ Its is a routing and mediation framework

Some people say that :▶ A camel is a horse designed by

committee (Not in that case ...)

Page 4: Xke - Introduction to Apache Camel

What is camel ?

A powerful Spring based Integration Framework

It implements Enterprise Integration Patterns

Routing and mediation rules configured using :▶ Java DSL (or Fluent API)▶ Spring Xml Configuration files.

www.xebia.fr / blog.xebia.fr 4

Page 5: Xke - Introduction to Apache Camel

What is camel ?

Apache Camel uses URIs▶ Works with any kind of transport or messaging such as:

» HTTP, ActiveMQ, JMS, MINA or CXF Bus API, …» Working with pluggable Data Format options

▶ Works with the same API regardless which kind of Transport used.

A Java library with minimal dependencies:▶ easy embedding in any Java application.

www.xebia.fr / blog.xebia.fr 5

Page 6: Xke - Introduction to Apache Camel

www.xebia.fr / blog.xebia.fr 6

Some informations before you start ...

Page 7: Xke - Introduction to Apache Camel

About the authors (Camel Riders)

James Strachan▶ Technical director at FuseSource▶ Blog: http://macstrac.blogspot.com/▶ Co-founder: Scalate, ActiveMQ, Camel, ServiceMix,

Lingo, Jencks, Groovy, dom4j▶ Committer: jaxen, taglibs, commons

Claus Ibsen▶ Software Engineer employed by Progress Software

working in The FUSE team▶ Blog: http://davsclaus.blogspot.com/▶ Leader: Camel

www.xebia.fr / blog.xebia.fr 7

Page 8: Xke - Introduction to Apache Camel

About the authors (Camel Riders)

Jon Anstey▶ Senior Engineer at Progress Software▶ Blog: http://janstey.blogspot.com/▶ Committer: ActiveMQ, Camel, ServiceMix

Hiram Chirino▶ A Software Architect at FuseSource▶ Blog: http://hiramchirino.com/blog/▶ Co-founder: ActiveMQ, Camel▶ Committer: ServiceMix,Geronimo

www.xebia.fr / blog.xebia.fr 8

Page 9: Xke - Introduction to Apache Camel

Camel and friends

ActiveMQ▶ Open source messaging provider (JMS provider).▶ Web site: http://activemq.apache.org▶ Current version: 5.3.2

CXF▶ Open Source Service Framework (WebServices)▶ Web site: http://cxf.apache.org▶ Current version: 2.2.9

ServiceMix▶ Open source ESB (Enterprise Service Bus)▶ Web site: http://servicemix.apache.org▶ Current versions: 3.3.2 / 4.2.0 (OSGI Based)

Apache Mina ...

www.xebia.fr / blog.xebia.fr 9

Page 10: Xke - Introduction to Apache Camel

Professionnal Camel Support

FuseSource – Open Source SOA▶ Get supported and fixed versions for:

» ActiveMQ, Camel, Cxf, ServiceMix, FuseHQ

▶ Subscribe production and development support, Consulting, Virtual Training

▶ Provide first class support: Emploies many Apache project co-founders and commiters

▶ Provides Open Maven repositories (No need to contract support to gain access to supported and fixed versions)

www.xebia.fr / blog.xebia.fr 10

Page 11: Xke - Introduction to Apache Camel

Competitors and Families of products

ESB (Entreprise Service Bus):▶ ServiceMix (JBI compliant, integrates Apache Camel)▶ JbossESB▶ WebSphereESB (SCA compliant) ▶ SonicESB, OpenESB, Petals...

Lightweight Enterprise Integration Patterns Frameworks:▶ Camel▶ MuleESB▶ Spring Integration

Process Servers, EAI, …▶ WPS (Websphere Process Server)▶ Biztalk Server

www.xebia.fr / blog.xebia.fr 11

Page 12: Xke - Introduction to Apache Camel

Camel compared to Mule ...

Both based on Spring + POJO They can run in standalone mode or embedded in

an OSGI server, application server They are not based on based on JBI specification

▶ Where the messages send over the bus are XML normalized messages

Camel has more components than Mule now Camel proposes a DSL Language Mule has better monitoring & management tools

www.xebia.fr / blog.xebia.fr 12

Page 13: Xke - Introduction to Apache Camel

Camel compared to Mule ...

You don't need to create a lot of XML config files with inbound/outbound stuff like you have to do in Mule.

The routing in Mule is not so intuitive and not appear directly in the XML or DSL

www.xebia.fr / blog.xebia.fr 13

Page 14: Xke - Introduction to Apache Camel

www.xebia.fr / blog.xebia.fr 14

The basics

Page 15: Xke - Introduction to Apache Camel

Message Routing

www.xebia.fr / blog.xebia.fr 15

Endpoint BEndpoint B

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed magna urna, varius a

facilisis nec, sagittis eget eros. Mauris scelerisque justo et ipsum scelerisque

aliquam. In at auctor diam. Suspendisse ut justo sed diam

Endpoint AEndpoint A

Message

Page 16: Xke - Introduction to Apache Camel

Camel Components

www.xebia.fr / blog.xebia.fr 16

Page 17: Xke - Introduction to Apache Camel

Kick Ass features

Integrates with almost everything … Support for:

▶ Scripting languages» Groovy» Scala

▶ Google App Engine & Google APIs▶ …

Built-in BAM Features

Extendable

www.xebia.fr / blog.xebia.fr 17

Page 18: Xke - Introduction to Apache Camel

Simple Routing

www.xebia.fr / blog.xebia.fr 18

Endpoint BEndpoint B

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed magna urna, varius a

facilisis nec, sagittis eget eros. Mauris scelerisque justo et ipsum scelerisque

aliquam. In at auctor diam. Suspendisse ut justo sed diam

Endpoint AEndpoint A

Message FileJms

Page 19: Xke - Introduction to Apache Camel

Pipeline

www.xebia.fr / blog.xebia.fr 19

Endpoint BEndpoint B

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed magna urna, varius a

facilisis nec, sagittis eget eros. Mauris scelerisque justo et ipsum scelerisque

aliquam. In at auctor diam. Suspendisse ut justo sed diam

Endpoint AEndpoint A

Message

Endpoint CEndpoint C

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed magna urna, varius a

facilisis nec, sagittis eget eros. Mauris scelerisque justo et ipsum scelerisque

aliquam. In at auctor diam. Suspendisse ut justo sed diam

Endpoint DEndpoint D

Message

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed

magna urna, varius a facilisis nec, sagittis eget

Page 20: Xke - Introduction to Apache Camel

Multicast

www.xebia.fr / blog.xebia.fr 20

Endpoint BEndpoint B

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed magna urna, varius a

facilisis nec, sagittis eget eros. Mauris scelerisque justo et ipsum scelerisque

aliquam. In at auctor diam. Suspendisse ut justo sed diam

Endpoint AEndpoint A

Message

Endpoint BEndpoint B

Endpoint BEndpoint B

File

IBatis

SMTP

SFTP

Page 21: Xke - Introduction to Apache Camel

Message filter: Spring XML

www.xebia.fr / blog.xebia.fr 21

<?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:schemaLocation="…">

<camelContext xmlns="http://activemq.apache.org/camel/schema/spring"><route>

<from uri="activemq:topic:Quotes" /><filter>

<xpath>/quote/product = ‘widget’</xpath><to uri="mqseries:WidgetQuotes" />

</filter></route>

</camelContext>

</beans>

Page 22: Xke - Introduction to Apache Camel

Message filter: Java DSL

www.xebia.fr / blog.xebia.fr 22

package com.acme.quotes;

import org.apache.camel.builder.RouteBuilder;

public class MyRouteBuilder extends RouteBuilder {

public void configure() {// forward widget quotes to MQSeriesfrom("activemq:topic:Quotes").

filter().xpath("/quote/product = ‘widget’").to("mqseries:WidgetQuotes");

}}

Page 23: Xke - Introduction to Apache Camel

Content Based Router: Java

www.xebia.fr / blog.xebia.fr 23

from("activemq:NewOrders").choice().when().xpath("/quote/product = 'widget'").

to("activemq:Orders.Widgets").choice().when().xpath("/quote/product = 'gadget'").

to("activemq:Orders.Gadgets").otherwise().

to("activemq:Orders.Bad");

Page 24: Xke - Introduction to Apache Camel

Content Based Router: Spring XML

www.xebia.fr / blog.xebia.fr 24

<?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:schemaLocation="...">

<camelContext xmlns="http://activemq.apache.org/camel/schema/spring"><route>

<from uri="activemq:NewOrders" /><choice>

<when><xpath>/order/product = 'widget'</xpath><to uri="activemq:Orders.Widgets" />

</when><when>

<xpath>/order/product = 'gadget'</xpath><to uri="activemq:Orders.Gadgets" />

</when><otherwise>

<to uri="activemq:Orders.Bad" /></otherwise>

</choice></route>

</camelContext>

</beans>

Page 25: Xke - Introduction to Apache Camel

How camel do this routing work ?

Camel Components▶ Camel Endpoints

» Camel Consumer» Camel Producer

Camel-Core

www.xebia.fr / blog.xebia.fr 25

Page 26: Xke - Introduction to Apache Camel

Message processors

www.xebia.fr / blog.xebia.fr 26

from("direct:start").process(new Processor() {

public void process(Exchange exchange) {

Message in = exchange.getIn();

in.setBody(in.getBody(String.class) + " World!");

}

}).to("mock:result");

<bean id="myProcessor" class="com.acme.MyProcessor"/>

from("activemq:myQueue").to("myProcessor");

The Processor interface is used to implement:▶ Consumers of message exchanges▶ A Message Translator

Page 27: Xke - Introduction to Apache Camel

Expressions

www.xebia.fr / blog.xebia.fr 27

Camel supports pluggable Expression strategies using a variety of different Languages (Dynamic rules):▶ Bean Language for using Java for expressions▶ The unified EL from JSP and JSF▶ JXPath, Mvel, OGNL▶ Scala DSL, Groovy▶ Python, PHP, Ruby, JavaScript▶ Simple, Constant▶ Xpath, Xquery, SQL

Page 28: Xke - Introduction to Apache Camel

Predicates

www.xebia.fr / blog.xebia.fr 28

Camel supports a pluggable interface called Predicate▶ Can be used to integrate a dynamic predicate into

Enterprise Integration Patterns such as when using: » Message Filter» Content Based Router.

A Predicate is being evaluated to a boolean value so the result is either true or false. ▶ This makes Predicate so powerful as it is often used to

control the routing of message in which path they should be routed.

Page 29: Xke - Introduction to Apache Camel

Predicates examples

www.xebia.fr / blog.xebia.fr 29

from("jms:queue:order")

.choice()

.when(header("type").isEqualTo("widget")).to("bean:widgetOrder")

.when(header("type").isEqualTo("wombat")).to("bean:wombatOrder")

.otherwise()

.to("bean:miscOrder")

.end();

Predicate isWidget = header("type").isEqualTo("widget");

from("jms:queue:order")

.choice()

.when(isWidget).to("bean:widgetOrder")

.when(isWombat).to("bean:wombatOrder")

.otherwise()

.to("bean:miscOrder")

.end();

Page 30: Xke - Introduction to Apache Camel

Transaction Oriented Endpoints

www.xebia.fr / blog.xebia.fr 30

Transaction Manager

<bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager">

<property name="connectionFactory" ref="jmsConnectionFactory" /> </bean> <bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://localhost:61616"/> </bean>

Transaction Policies

<bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="jmsTransactionManager"/> </bean>

<bean id="PROPAGATION_REQUIRES_NEW" class="org.apache.camel.spring.spi.SpringTransactionPolicy">

<property name="transactionManager" ref="jmsTransactionManager"/> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRES_NEW"/>

</bean>

Page 31: Xke - Introduction to Apache Camel

Transaction Oriented Endpoints

www.xebia.fr / blog.xebia.fr 31

Using policies in Java DSL (1)

public void configure() { ... Policy requried = bean(SpringTransactionPolicy.class, "PROPAGATION_REQUIRED")); Policy requirenew = bean(SpringTransactionPolicy.class, "PROPAGATION_REQUIRES_NEW")); ... }

// Send to bar in a new transaction from("activemq:queue:foo").policy(requirenew).to("activemq:queue:bar");

// Send to bar without a transaction. from("activemq:queue:foo").policy(notsupported).to("activemq:queue:bar");

Page 32: Xke - Introduction to Apache Camel

Transaction Oriented Endpoints

www.xebia.fr / blog.xebia.fr 32

Using policies in Java DSL (2)

from("direct:mixed") // using required .transacted("PROPAGATION_REQUIRED") // all these steps will be okay .setBody(constant("Tiger in Action")).beanRef("bookService") .setBody(constant("Elephant in Action")).beanRef("bookService") .setBody(constant("Lion in Action")).beanRef("bookService") // continue on route 2 .to("direct:mixed2");

from("direct:mixed2") // using a different propagation which is requires new .transacted("PROPAGATION_REQUIRES_NEW") // tell Camel that if this route fails then only rollback this last route // by using (rollback only *last*) .onException(Exception.class).markRollbackOnlyLast().end() // this step will be okay .setBody(constant("Giraffe in Action")).beanRef("bookService") // this step will fail with donkey .setBody(constant("Donkey in Action")).beanRef("bookService");

Page 33: Xke - Introduction to Apache Camel

Transaction Oriented Endpoints

www.xebia.fr / blog.xebia.fr 33

Using policies in Spring XML (1) <!-- here we define our camel context --><camel:camelContext id="myroutes">

<!-- first route with transaction error handler --> <!-- here we refer to our transaction error handler we define in this Spring XML file --> <!-- in this route the transactionErrorHandler is used --> <camel:route errorHandlerRef="transactionErrorHandler"> <!-- 1: from the jms queue --> <camel:from uri="activemq:queue:okay"/> <!-- 2: setup the transactional boundaries to require a transaction --> <camel:transacted ref="required"/> <!-- 3: call our business logic that is myProcessor --> <camel:process ref="myProcessor"/> <!-- 4: if success then send it to the mock --> <camel:to uri="mock:result"/> </camel:route>

<!-- 2nd route with no error handling --> <!-- this route doens't use error handler, in fact the spring bean with id noErrorHandler --> <camel:route errorHandlerRef="noErrorHandler"> <camel:from uri="activemq:queue:bad"/> <camel:to uri="log:bad"/> </camel:route>

</camel:camelContext>

Page 34: Xke - Introduction to Apache Camel

Transaction Oriented Endpoints

www.xebia.fr / blog.xebia.fr 34

Using policies in Spring XML (2)

<!-- camel policy we refer to in our route --><bean id="required" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionTemplate" ref="PROPAGATION_REQUIRED"/></bean>

<!-- the standard spring transaction template for required --><bean id="PROPAGATION_REQUIRED"

class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="jmsTransactionManager"/></bean>

<!-- the transaction error handle we refer to from the route --><bean id="transactionErrorHandler"

class="org.apache.camel.spring.spi.TransactionErrorHandlerBuilder"> <property name="transactionTemplate" ref="PROPAGATION_REQUIRED"/></bean>

<!-- the no error handler --><bean id="noErrorHandler" class="org.apache.camel.builder.NoErrorHandlerBuilder"/>

Page 35: Xke - Introduction to Apache Camel

Transaction Oriented Endpoints

www.xebia.fr / blog.xebia.fr 35

TransactionErrorHandler

onException(ValidationException.class).handled(true).transform(body(constant("INVALID ORDER")));

from("jetty:http://localhost/myservice/order").transacted().to("bean:validateOrder").to("jms:queue:order");

errorHandler(transactionErrorHandler().maximumRedeliveries(6));

onException(IllegalArgumentException.class).maximumRedeliveries(4);

from("direct:okay") .transacted() .setBody(constant("Tiger in Action")).beanRef("bookService") .setBody(constant("Elephant in Action")).beanRef("bookService");

Page 36: Xke - Introduction to Apache Camel

DefaultErrorHandler & DeadLetterChannel

www.xebia.fr / blog.xebia.fr 36

Client notified (Default DLC behavior, not DEH )

errorHandler(deadLetterChannel("jms:queue:dead").

maximumRedeliveries(3).redeliverDealy(5000));

Client not notified errorHandler(deadLetterChannel("jms:queue:dead").

maximumRedeliveries(3).redeliverDealy(5000).handled(false));

Use original message errorHandler(deadLetterChannel("jms:queue:dead") .useOriginalMessage().mamimumRedeliveries(5).redeliverDelay(5000);

Using default error handleronException(ValidationException.class).handled(true).transform(body(constant("INVALID ORDER")));

Page 37: Xke - Introduction to Apache Camel

Annotation support

www.xebia.fr / blog.xebia.fr 37

Camel supports annotations

public class RouterBean {

@Consume(uri = "activemq:foo")

@RecipientList

public String[] route(String body) {

return new String[]{"activemq:bar", "activemq:whatnot"};

}

}

public class Foo {

@MessageDriven(uri = "activemq:my.queue")

public void doSomething(@XPath("/foo/bar/text()") String correlationID, @Body String body) {

// process the inbound message here

}

}

Page 38: Xke - Introduction to Apache Camel

@Bean annotation

www.xebia.fr / blog.xebia.fr 38

public class Foo {

@MessageDriven(uri = "activemq:my.queue")

public void doSomething(@Bean("myCorrelationIdGenerator") String correlationID, @Body String body) {

// process the inbound message here

}

}

public class MyIdGenerator {

private UserManager userManager;

public String generate(@Header(name = "user") String user, @Body String payload) throws Exception {

User user = userManager.lookupUser(user);

String id = user.getPrimaryId() + generateHashCodeForPayload(payload);

return id;

}

}

Page 39: Xke - Introduction to Apache Camel

Groovy support

www.xebia.fr / blog.xebia.fr 39

Using Java DSL

// lets route if a line item is over $100

from("queue:foo").filter(groovy("request.lineItems.any { i -> i.value > 100 }")).to("queue:bar");

Using Spring XML

<route>

<from uri="queue:foo"/>

<filter>

<groovy>request.lineItems.any { i -> i.value > 100 }</groovy>

<to uri="queue:bar"/>

</filter>

</route>

Page 40: Xke - Introduction to Apache Camel

Testing with camel

www.xebia.fr / blog.xebia.fr 40

Testing of distributed and asynchronous processing is notoriously difficult

Camel provides helpers:▶ Test URIs▶ Datasets▶ Mocks

Maven dependency for tests: <dependency>

<groupId>org.apache.camel</groupId>

<artifactId>camel-test</artifactId>

<version>${camel-version}</version>

<scope>test</scope>

</dependency>

Page 41: Xke - Introduction to Apache Camel

Testing with camel

www.xebia.fr / blog.xebia.fr 41

public class FilterTest extends CamelTestSupport {

@EndpointInject(uri = "mock:result") protected MockEndpoint resultEndpoint;

@Produce(uri = "direct:start") protected ProducerTemplate template;

public void testSendMatchingMessage() throws Exception {

String expectedBody = "<matched/>";

resultEndpoint.expectedBodiesReceived(expectedBody);

template.sendBodyAndHeader(expectedBody, "foo", "bar");

resultEndpoint.assertIsSatisfied();

}

public void testSendNotMatchingMessage() throws Exception {

resultEndpoint.expectedMessageCount(0);

template.sendBodyAndHeader("<notMatched/>", "foo", "notMatchedHeaderValue");

resultEndpoint.assertIsSatisfied();

}

@Override

protected RouteBuilder createRouteBuilder() {

return new RouteBuilder() {

public void configure() {

from("direct:start").filter(header("foo").isEqualTo("bar")).to("mock:result");

}

};

}

}

Page 42: Xke - Introduction to Apache Camel

Spring Test with Java Config

www.xebia.fr / blog.xebia.fr 42

@ContextConfiguration( locations = "org.apache.camel.spring.javaconfig.patterns.FilterTest$ContextConfig", loader = JavaConfigContextLoader.class)

public class FilterTest extends AbstractJUnit4SpringContextTests {

@EndpointInject(uri = "mock:result") protected MockEndpoint resultEndpoint;

@Produce(uri = "direct:start") protected ProducerTemplate template;

@DirtiesContext

@Test

public void testSendMatchingMessage() throws Exception {

String expectedBody = "<matched/>";

resultEndpoint.expectedBodiesReceived(expectedBody);

template.sendBodyAndHeader(expectedBody, "foo", "bar");

resultEndpoint.assertIsSatisfied();

}

@Configuration

public static class ContextConfig extends SingleRouteCamelConfiguration {

@Bean

public RouteBuilder route() {

return new RouteBuilder() {

public void configure() {

from("direct:start").filter(header("foo").isEqualTo("bar")).to("mock:result");

}

};

}

}

}

Page 43: Xke - Introduction to Apache Camel

Camel riding from Java

/META-INF/spring/camelContext.xml

Set the CLASSPATH

Run Camel context from :▶ java org.apache.camel.spring.Main

www.xebia.fr / blog.xebia.fr 43

Page 44: Xke - Introduction to Apache Camel

Camel & Maven

mvn camel:run, camel:dot

Maven declaration:

www.xebia.fr / blog.xebia.fr 44

<?xml version="1.0" encoding="UTF-8"?>

<project><build>

<plugins><plugin>

<groupId>org.apache.camel</groupId><artifactId>camel-maven-plugin</artifactId>

</plugin></plugins>

</build><reporting>

<plugins><plugin>

<groupId>org.apache.camel</groupId><artifactId>camel-maven-plugin</artifactId>

</plugin></plugins>

</reporting></project> 

Page 45: Xke - Introduction to Apache Camel

Maven site report

Result of report plugin (Dot & GraphViz)

www.xebia.fr / blog.xebia.fr 45

Page 46: Xke - Introduction to Apache Camel

Where would I use Camel ?

Standalone or in any Spring application

Inside ActiveMQ’s JMS client or the broker

Inside your ESB such as ServiceMix via the servicemix-camel Service Unit

Inside CXF either as a transport or reusing CXF inside Camel

www.xebia.fr / blog.xebia.fr 46

Page 47: Xke - Introduction to Apache Camel

www.xebia.fr / blog.xebia.fr 47

Going further with Apache Camel …

Page 48: Xke - Introduction to Apache Camel

Books

Theme: ▶ This book is essentially the

Camel bible

Edition: ▶ Manning▶ Fall 2010 | 435 pages▶ ISBN: 9781935182368

Authors: ▶ Claus Ibsen, Committer and

lead▶ Jonathan Anstey, Committer▶ Hadrian Zbarcea, Committer,

Chair of PMC and Release Manager

www.xebia.fr / blog.xebia.fr 48

Page 49: Xke - Introduction to Apache Camel

Books

Theme: ▶ catalog of sixty-five patterns,

with real-world solutions

Edition: ▶ Addison-Wesley Professional▶ October 2003 | 736 pages▶ ISBN: 9780321200686

Authors: ▶ Gregor Hohpe, Software

engineer at Google.▶ Bobby Woolf, WebSphere

consultant at IBM.

www.xebia.fr / blog.xebia.fr 49

Page 50: Xke - Introduction to Apache Camel

www.xebia.fr / blog.xebia.fr 50

Twitter: @alexiskinsella

Thank You