Apache Camel Taking Camel for a ride Hands on Xke Alexis Kinsella June 11, 2010
www.xebia.fr / blog.xebia.fr What is camel ?
What is camel ? www.xebia.fr / blog.xebia.fr It stands for : C oncise A pplication M essage E xchange L anguage (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 ...)
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
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
www.xebia.fr / blog.xebia.fr Some informations before you start ...
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
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
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
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
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
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
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
www.xebia.fr / blog.xebia.fr The basics
Message Routing www.xebia.fr / blog.xebia.fr Endpoint 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 A Message
Camel Components www.xebia.fr / blog.xebia.fr
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
Simple Routing www.xebia.fr / blog.xebia.fr Endpoint 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 A Message File Jms
Pipeline www.xebia.fr / blog.xebia.fr Endpoint 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 A Message Endpoint 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 D Message Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed magna urna, varius a facilisis nec, sagittis eget
Multicast www.xebia.fr / blog.xebia.fr Endpoint 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 A Message Endpoint B Endpoint B File IBatis SMTP SFTP
Message filter: Spring XML www.xebia.fr / blog.xebia.fr <? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?> < beans xmlns = &quot;http://www.springframework.org/schema/beans&quot; xmlns:xsi = &quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:schemaLocation = &quot;…&quot; > < camelContext xmlns = &quot;http://activemq.apache.org/camel/schema/spring&quot; > < route > < from uri = &quot;activemq:topic:Quotes&quot; /> < filter > < xpath > /quote/product = ‘widget’ </ xpath > < to uri = &quot;mqseries:WidgetQuotes&quot; /> </ filter > </ route > </ camelContext > </ beans >
Message filter: Java DSL www.xebia.fr / blog.xebia.fr package com.acme.quotes; import org.apache.camel.builder.RouteBuilder; public class MyRouteBuilder extends RouteBuilder { public void configure() { // forward widget quotes to MQSeries from( &quot;activemq:topic:Quotes&quot; ). filter().xpath( &quot;/quote/product = ‘widget’&quot; ). to( &quot;mqseries:WidgetQuotes&quot; ); } }
Content Based Router: Java www.xebia.fr / blog.xebia.fr from( &quot;activemq:NewOrders&quot; ). choice().when().xpath( &quot;/quote/product = 'widget'&quot; ). to( &quot;activemq:Orders.Widgets&quot; ). choice().when().xpath( &quot;/quote/product = 'gadget'&quot; ). to( &quot;activemq:Orders.Gadgets&quot; ). otherwise(). to( &quot;activemq:Orders.Bad&quot; );
Content Based Router: Spring XML www.xebia.fr / blog.xebia.fr <? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?> < beans xmlns = &quot;http://www.springframework.org/schema/beans&quot; xmlns:xsi = &quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:schemaLocation = &quot;...&quot; > < camelContext xmlns = &quot;http://activemq.apache.org/camel/schema/spring&quot; > < route > < from uri = &quot;activemq:NewOrders&quot; /> < choice > < when > < xpath > /order/product = 'widget' </ xpath > < to uri = &quot;activemq:Orders.Widgets&quot; /> </ when > < when > < xpath > /order/product = 'gadget' </ xpath > < to uri = &quot;activemq:Orders.Gadgets&quot; /> </ when > < otherwise > < to uri = &quot;activemq:Orders.Bad&quot; /> </ otherwise > </ choice > </ route > </ camelContext > </ beans >
How camel do this routing work ? Camel Components Camel Endpoints Camel Consumer Camel Producer Camel-Core www.xebia.fr / blog.xebia.fr
Message processors www.xebia.fr / blog.xebia.fr from( &quot;direct:start&quot; ).process( new Processor() { public void process(Exchange exchange) { Message in = exchange.getIn(); in.setBody(in.getBody(String. class ) + &quot; World!&quot; ); } }).to( &quot;mock:result&quot; ); < bean id = &quot;myProcessor&quot; class = &quot;com.acme.MyProcessor&quot; /> from( &quot;activemq:myQueue&quot; ).to( &quot;myProcessor&quot; ); The Processor interface is used to implement: Consumers of message exchanges A Message Translator
Expressions www.xebia.fr / blog.xebia.fr 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
Predicates www.xebia.fr / blog.xebia.fr 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.
Predicates examples www.xebia.fr / blog.xebia.fr from( &quot;jms:queue:order&quot; ) .choice() .when(header( &quot;type&quot; ).isEqualTo( &quot;widget&quot; )).to( &quot;bean:widgetOrder&quot; ) .when(header( &quot;type&quot; ).isEqualTo( &quot;wombat&quot; )).to( &quot;bean:wombatOrder&quot; ) .otherwise() .to( &quot;bean:miscOrder&quot; ) .end(); Predicate isWidget = header( &quot;type&quot; ).isEqualTo( &quot;widget&quot; ); from( &quot;jms:queue:order&quot; ) .choice() .when( isWidget ).to( &quot;bean:widgetOrder&quot; ) .when( isWombat ).to( &quot;bean:wombatOrder&quot; ) .otherwise() .to( &quot;bean:miscOrder&quot; ) .end();
Transaction Oriented Endpoints www.xebia.fr / blog.xebia.fr Transaction Manager < bean id = &quot;jmsTransactionManager&quot; class = &quot;org.springframework.jms.connection.JmsTransactionManager&quot; > < property name = &quot;connectionFactory&quot; ref = &quot;jmsConnectionFactory&quot; /> </ bean > < bean id = &quot;jmsConnectionFactory&quot; class = &quot;org.apache.activemq.ActiveMQConnectionFactory&quot; > < property name = &quot;brokerURL&quot; value = &quot;tcp://localhost:61616&quot; /> </ bean > Transaction Policies < bean id = &quot;PROPAGATION_REQUIRED&quot; class = &quot;org.apache.camel.spring.spi.SpringTransactionPolicy&quot; > < property name = &quot;transactionManager&quot; ref = &quot;jmsTransactionManager&quot; /> </ bean > < bean id = &quot;PROPAGATION_REQUIRES_NEW&quot; class = &quot;org.apache.camel.spring.spi.SpringTransactionPolicy&quot; > < property name = &quot;transactionManager&quot; ref = &quot;jmsTransactionManager&quot; /> < property name = &quot;propagationBehaviorName&quot; value = &quot;PROPAGATION_REQUIRES_NEW&quot; /> </ bean >
Transaction Oriented Endpoints www.xebia.fr / blog.xebia.fr Using policies in Java DSL (1) public void configure() { ... Policy requried = bean ( SpringTransactionPolicy . class , &quot;PROPAGATION_REQUIRED&quot; ) ) ; Policy requirenew = bean ( SpringTransactionPolicy . class , &quot;PROPAGATION_REQUIRES_NEW&quot; )); ... } // Send to bar in a new transaction from( &quot;activemq:queue:foo&quot; ) .policy(requirenew).to( &quot;activemq:queue:bar&quot; ) ; // Send to bar without a transaction. from( &quot;activemq:queue:foo&quot; ).policy(notsupported).to( &quot;activemq:queue:bar&quot; );
Transaction Oriented Endpoints www.xebia.fr / blog.xebia.fr Using policies in Java DSL (2) from( &quot;direct:mixed&quot; ) // using required .transacted( &quot;PROPAGATION_REQUIRED&quot; ) // all these steps will be okay .setBody(constant( &quot;Tiger in Action&quot; )).beanRef( &quot;bookService&quot; ) .setBody(constant( &quot;Elephant in Action&quot; )).beanRef( &quot;bookService&quot; ) .setBody(constant( &quot;Lion in Action&quot; )).beanRef( &quot;bookService&quot; ) // continue on route 2 .to( &quot;direct:mixed2&quot; ) ; from( &quot;direct:mixed2&quot; ) // using a different propagation which is requires new .transacted( &quot;PROPAGATION_REQUIRES_NEW&quot; ) // 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( &quot;Giraffe in Action&quot; )).beanRef( &quot;bookService&quot; ) // this step will fail with donkey .setBody(constant( &quot;Donkey in Action&quot; )).beanRef( &quot;bookService&quot; );
Transaction Oriented Endpoints www.xebia.fr / blog.xebia.fr Using policies in Spring XML (1) <!-- here we define our camel context --> < camel:camelContext id = &quot;myroutes&quot; > <!-- 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 = &quot;transactionErrorHandler&quot; > <!-- 1: from the jms queue --> < camel:from uri = &quot;activemq:queue:okay&quot; /> <!-- 2: setup the transactional boundaries to require a transaction --> < camel:transacted ref = &quot;required&quot; /> <!-- 3: call our business logic that is myProcessor --> < camel:process ref = &quot;myProcessor&quot; /> <!-- 4: if success then send it to the mock --> < camel:to uri = &quot;mock:result&quot; /> </ 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 = &quot;noErrorHandler&quot; > < camel:from uri = &quot;activemq:queue:bad&quot; /> < camel:to uri = &quot;log:bad&quot; /> </ camel:route > </ camel:camelContext >
Transaction Oriented Endpoints www.xebia.fr / blog.xebia.fr Using policies in Spring XML (2) <!-- camel policy we refer to in our route --> < bean id = &quot;required&quot; class = &quot;org.apache.camel.spring.spi.SpringTransactionPolicy&quot; > < property name = &quot;transactionTemplate&quot; ref = &quot;PROPAGATION_REQUIRED&quot; /> </ bean > <!-- the standard spring transaction template for required --> < bean id = &quot;PROPAGATION_REQUIRED&quot; class = &quot;org.springframework.transaction.support.TransactionTemplate&quot; > < property name = &quot;transactionManager&quot; ref = &quot;jmsTransactionManager&quot; /> </ bean > <!-- the transaction error handle we refer to from the route --> < bean id = &quot;transactionErrorHandler&quot; class = &quot;org.apache.camel.spring.spi.TransactionErrorHandlerBuilder&quot; > < property name = &quot;transactionTemplate&quot; ref = &quot;PROPAGATION_REQUIRED&quot; /> </ bean > <!-- the no error handler --> < bean id = &quot;noErrorHandler&quot; class = &quot;org.apache.camel.builder.NoErrorHandlerBuilder&quot; />
Transaction Oriented Endpoints www.xebia.fr / blog.xebia.fr TransactionErrorHandler onException ( ValidationException . class ).handled( true ).transform(body( constant ( &quot;INVALID ORDER&quot; ))); from ( &quot;jetty: http://localhost/myservice/order &quot; ) .transacted() .to( &quot;bean:validateOrder&quot; ) .to( &quot;jms:queue:order&quot; ); e rrorHandler( transactionErrorHandler() . maximumRedeliveries(6) ) ; onException(IllegalArgumentException. class ).maximumRedeliveries(4); from( &quot;direct:okay&quot; ) .transacted() .setBody(constant( &quot;Tiger in Action&quot; )).beanRef( &quot;bookService&quot; ) .setBody(constant( &quot;Elephant in Action&quot; )).beanRef( &quot;bookService&quot; );
DefaultErrorHandler & DeadLetterChannel www.xebia.fr / blog.xebia.fr Client notified (Default DLC behavior, not DEH ) errorHandler(deadLetterChannel( &quot;jms:queue:dead&quot; ). maximumRedeliveries(3).redeliverDealy(5000)); Client not notified errorHandler(deadLetterChannel( &quot;jms:queue:dead&quot; ). maximumRedeliveries(3).redeliverDealy(5000).handled( false )); Use original message errorHandler(deadLetterChannel( &quot;jms:queue:dead&quot; ) .useOriginalMessage().mamimumRedeliveries(5).redeliverDelay(5000 ); Using default error handler onException(ValidationException. class ).handled( true ).transform(body(constant( &quot;INVALID ORDER&quot; )));
Annotation support www.xebia.fr / blog.xebia.fr Camel supports annotations public class RouterBean { @Consume (uri = &quot;activemq:foo&quot; ) @RecipientList public String[] route(String body) { return new String[]{ &quot;activemq:bar&quot; , &quot;activemq:whatnot&quot; }; } } public class Foo { @ MessageDriven ( uri = &quot;activemq:my.queue&quot; ) public void doSomething( @XPath ( &quot;/foo/bar/text()&quot; ) String correlationID, @Body String body) { // process the inbound message here } }
@Bean annotation www.xebia.fr / blog.xebia.fr public class Foo { @ MessageDriven ( uri = &quot;activemq:my.queue&quot; ) public void doSomething( @Bean ( &quot;myCorrelationIdGenerator&quot; ) String correlationID, @Body String body) { // process the inbound message here } } public class MyIdGenerator { private UserManager userManager ; public String generate( @ Header ( name = &quot;user&quot; ) String user, @Body String payload) throws Exception { User user = userManager .lookupUser(user); String id = user.getPrimaryId() + generateHashCodeForPayload (payload); return id; } }
Groovy support www.xebia.fr / blog.xebia.fr Using Java DSL // lets route if a line item is over $100 from( &quot;queue:foo&quot; ).filter( groovy ( &quot;request.lineItems.any { i -> i.value > 100 }&quot; )).to( &quot;queue:bar&quot; ); Using Spring XML < route > < from uri = &quot;queue:foo&quot; /> < filter > < groovy > request.lineItems.any { i -> i.value > 100 } </ groovy > < to uri = &quot;queue:bar&quot; /> </ filter > </ route >
Testing with camel www.xebia.fr / blog.xebia.fr 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 >
Testing with camel www.xebia.fr / blog.xebia.fr public class FilterTest extends CamelTestSupport { @EndpointInject (uri = &quot;mock:result&quot; ) protected MockEndpoint resultEndpoint ; @Produce (uri = &quot;direct:start&quot; ) protected ProducerTemplate template ; public void testSendMatchingMessage() throws Exception { String expectedBody = &quot;<matched/>&quot; ; resultEndpoint .expectedBodiesReceived(expectedBody); template .sendBodyAndHeader(expectedBody, &quot;foo&quot; , &quot;bar&quot; ); resultEndpoint .assertIsSatisfied(); } public void testSendNotMatchingMessage() throws Exception { resultEndpoint .expectedMessageCount(0); template .sendBodyAndHeader( &quot;<notMatched/>&quot; , &quot;foo&quot; , &quot;notMatchedHeaderValue&quot; ); resultEndpoint .assertIsSatisfied(); } @Override protected RouteBuilder createRouteBuilder() { return new RouteBuilder() { public void configure() { from( &quot;direct:start&quot; ).filter(header( &quot;foo&quot; ).isEqualTo( &quot;bar&quot; )).to( &quot;mock:result&quot; ); } }; } }
Spring Test with Java Config www.xebia.fr / blog.xebia.fr @ ContextConfiguration ( locations = &quot;org.apache.camel.spring.javaconfig.patterns.FilterTest$ContextConfig&quot; , loader = JavaConfigContextLoader . class ) public class FilterTest extends AbstractJUnit4SpringContextTests { @EndpointInject (uri = &quot;mock:result&quot; ) protected MockEndpoint resultEndpoint ; @Produce (uri = &quot;direct:start&quot; ) protected ProducerTemplate template ; @ DirtiesContext @Test public void testSendMatchingMessage() throws Exception { String expectedBody = &quot;<matched/>&quot; ; resultEndpoint .expectedBodiesReceived(expectedBody); template .sendBodyAndHeader(expectedBody, &quot;foo&quot; , &quot;bar&quot; ); resultEndpoint .assertIsSatisfied(); } @ Configuration public static class ContextConfig extends SingleRouteCamelConfiguration { @Bean public RouteBuilder route() { return new RouteBuilder() { public void configure() { from( &quot;direct:start&quot; ).filter(header( &quot;foo&quot; ).isEqualTo( &quot;bar&quot; )).to( &quot;mock:result&quot; ); } }; } } }
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
Camel & Maven mvn camel:run, camel:dot Maven declaration: www.xebia.fr / blog.xebia.fr <? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?> < 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 >  
Maven site report Result of report plugin (Dot & GraphViz) www.xebia.fr / blog.xebia.fr
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
www.xebia.fr / blog.xebia.fr Going further with 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
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
www.xebia.fr / blog.xebia.fr Twitter: @alexiskinsella Thank You

Xke - Introduction to Apache Camel

  • 1.
    Apache Camel TakingCamel for a ride Hands on Xke Alexis Kinsella June 11, 2010
  • 2.
  • 3.
    What is camel? www.xebia.fr / blog.xebia.fr It stands for : C oncise A pplication M essage E xchange L anguage (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 ...)
  • 4.
    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
  • 5.
    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
  • 6.
    www.xebia.fr / blog.xebia.frSome informations before you start ...
  • 7.
    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
  • 8.
    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
  • 9.
    Camel and friendsActiveMQ 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
  • 10.
    Professionnal Camel SupportFuseSource – 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
  • 11.
    Competitors and Familiesof 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
  • 12.
    Camel compared toMule ... 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
  • 13.
    Camel compared toMule ... 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
  • 14.
  • 15.
    Message Routing www.xebia.fr/ blog.xebia.fr Endpoint 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 A Message
  • 16.
  • 17.
    Kick Ass featuresIntegrates 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
  • 18.
    Simple Routing www.xebia.fr/ blog.xebia.fr Endpoint 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 A Message File Jms
  • 19.
    Pipeline www.xebia.fr /blog.xebia.fr Endpoint 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 A Message Endpoint 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 D Message Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed magna urna, varius a facilisis nec, sagittis eget
  • 20.
    Multicast www.xebia.fr /blog.xebia.fr Endpoint 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 A Message Endpoint B Endpoint B File IBatis SMTP SFTP
  • 21.
    Message filter: SpringXML www.xebia.fr / blog.xebia.fr <? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?> < beans xmlns = &quot;http://www.springframework.org/schema/beans&quot; xmlns:xsi = &quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:schemaLocation = &quot;…&quot; > < camelContext xmlns = &quot;http://activemq.apache.org/camel/schema/spring&quot; > < route > < from uri = &quot;activemq:topic:Quotes&quot; /> < filter > < xpath > /quote/product = ‘widget’ </ xpath > < to uri = &quot;mqseries:WidgetQuotes&quot; /> </ filter > </ route > </ camelContext > </ beans >
  • 22.
    Message filter: JavaDSL www.xebia.fr / blog.xebia.fr package com.acme.quotes; import org.apache.camel.builder.RouteBuilder; public class MyRouteBuilder extends RouteBuilder { public void configure() { // forward widget quotes to MQSeries from( &quot;activemq:topic:Quotes&quot; ). filter().xpath( &quot;/quote/product = ‘widget’&quot; ). to( &quot;mqseries:WidgetQuotes&quot; ); } }
  • 23.
    Content Based Router:Java www.xebia.fr / blog.xebia.fr from( &quot;activemq:NewOrders&quot; ). choice().when().xpath( &quot;/quote/product = 'widget'&quot; ). to( &quot;activemq:Orders.Widgets&quot; ). choice().when().xpath( &quot;/quote/product = 'gadget'&quot; ). to( &quot;activemq:Orders.Gadgets&quot; ). otherwise(). to( &quot;activemq:Orders.Bad&quot; );
  • 24.
    Content Based Router:Spring XML www.xebia.fr / blog.xebia.fr <? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?> < beans xmlns = &quot;http://www.springframework.org/schema/beans&quot; xmlns:xsi = &quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:schemaLocation = &quot;...&quot; > < camelContext xmlns = &quot;http://activemq.apache.org/camel/schema/spring&quot; > < route > < from uri = &quot;activemq:NewOrders&quot; /> < choice > < when > < xpath > /order/product = 'widget' </ xpath > < to uri = &quot;activemq:Orders.Widgets&quot; /> </ when > < when > < xpath > /order/product = 'gadget' </ xpath > < to uri = &quot;activemq:Orders.Gadgets&quot; /> </ when > < otherwise > < to uri = &quot;activemq:Orders.Bad&quot; /> </ otherwise > </ choice > </ route > </ camelContext > </ beans >
  • 25.
    How camel dothis routing work ? Camel Components Camel Endpoints Camel Consumer Camel Producer Camel-Core www.xebia.fr / blog.xebia.fr
  • 26.
    Message processors www.xebia.fr/ blog.xebia.fr from( &quot;direct:start&quot; ).process( new Processor() { public void process(Exchange exchange) { Message in = exchange.getIn(); in.setBody(in.getBody(String. class ) + &quot; World!&quot; ); } }).to( &quot;mock:result&quot; ); < bean id = &quot;myProcessor&quot; class = &quot;com.acme.MyProcessor&quot; /> from( &quot;activemq:myQueue&quot; ).to( &quot;myProcessor&quot; ); The Processor interface is used to implement: Consumers of message exchanges A Message Translator
  • 27.
    Expressions www.xebia.fr /blog.xebia.fr 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
  • 28.
    Predicates www.xebia.fr /blog.xebia.fr 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.
  • 29.
    Predicates examples www.xebia.fr/ blog.xebia.fr from( &quot;jms:queue:order&quot; ) .choice() .when(header( &quot;type&quot; ).isEqualTo( &quot;widget&quot; )).to( &quot;bean:widgetOrder&quot; ) .when(header( &quot;type&quot; ).isEqualTo( &quot;wombat&quot; )).to( &quot;bean:wombatOrder&quot; ) .otherwise() .to( &quot;bean:miscOrder&quot; ) .end(); Predicate isWidget = header( &quot;type&quot; ).isEqualTo( &quot;widget&quot; ); from( &quot;jms:queue:order&quot; ) .choice() .when( isWidget ).to( &quot;bean:widgetOrder&quot; ) .when( isWombat ).to( &quot;bean:wombatOrder&quot; ) .otherwise() .to( &quot;bean:miscOrder&quot; ) .end();
  • 30.
    Transaction Oriented Endpointswww.xebia.fr / blog.xebia.fr Transaction Manager < bean id = &quot;jmsTransactionManager&quot; class = &quot;org.springframework.jms.connection.JmsTransactionManager&quot; > < property name = &quot;connectionFactory&quot; ref = &quot;jmsConnectionFactory&quot; /> </ bean > < bean id = &quot;jmsConnectionFactory&quot; class = &quot;org.apache.activemq.ActiveMQConnectionFactory&quot; > < property name = &quot;brokerURL&quot; value = &quot;tcp://localhost:61616&quot; /> </ bean > Transaction Policies < bean id = &quot;PROPAGATION_REQUIRED&quot; class = &quot;org.apache.camel.spring.spi.SpringTransactionPolicy&quot; > < property name = &quot;transactionManager&quot; ref = &quot;jmsTransactionManager&quot; /> </ bean > < bean id = &quot;PROPAGATION_REQUIRES_NEW&quot; class = &quot;org.apache.camel.spring.spi.SpringTransactionPolicy&quot; > < property name = &quot;transactionManager&quot; ref = &quot;jmsTransactionManager&quot; /> < property name = &quot;propagationBehaviorName&quot; value = &quot;PROPAGATION_REQUIRES_NEW&quot; /> </ bean >
  • 31.
    Transaction Oriented Endpointswww.xebia.fr / blog.xebia.fr Using policies in Java DSL (1) public void configure() { ... Policy requried = bean ( SpringTransactionPolicy . class , &quot;PROPAGATION_REQUIRED&quot; ) ) ; Policy requirenew = bean ( SpringTransactionPolicy . class , &quot;PROPAGATION_REQUIRES_NEW&quot; )); ... } // Send to bar in a new transaction from( &quot;activemq:queue:foo&quot; ) .policy(requirenew).to( &quot;activemq:queue:bar&quot; ) ; // Send to bar without a transaction. from( &quot;activemq:queue:foo&quot; ).policy(notsupported).to( &quot;activemq:queue:bar&quot; );
  • 32.
    Transaction Oriented Endpointswww.xebia.fr / blog.xebia.fr Using policies in Java DSL (2) from( &quot;direct:mixed&quot; ) // using required .transacted( &quot;PROPAGATION_REQUIRED&quot; ) // all these steps will be okay .setBody(constant( &quot;Tiger in Action&quot; )).beanRef( &quot;bookService&quot; ) .setBody(constant( &quot;Elephant in Action&quot; )).beanRef( &quot;bookService&quot; ) .setBody(constant( &quot;Lion in Action&quot; )).beanRef( &quot;bookService&quot; ) // continue on route 2 .to( &quot;direct:mixed2&quot; ) ; from( &quot;direct:mixed2&quot; ) // using a different propagation which is requires new .transacted( &quot;PROPAGATION_REQUIRES_NEW&quot; ) // 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( &quot;Giraffe in Action&quot; )).beanRef( &quot;bookService&quot; ) // this step will fail with donkey .setBody(constant( &quot;Donkey in Action&quot; )).beanRef( &quot;bookService&quot; );
  • 33.
    Transaction Oriented Endpointswww.xebia.fr / blog.xebia.fr Using policies in Spring XML (1) <!-- here we define our camel context --> < camel:camelContext id = &quot;myroutes&quot; > <!-- 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 = &quot;transactionErrorHandler&quot; > <!-- 1: from the jms queue --> < camel:from uri = &quot;activemq:queue:okay&quot; /> <!-- 2: setup the transactional boundaries to require a transaction --> < camel:transacted ref = &quot;required&quot; /> <!-- 3: call our business logic that is myProcessor --> < camel:process ref = &quot;myProcessor&quot; /> <!-- 4: if success then send it to the mock --> < camel:to uri = &quot;mock:result&quot; /> </ 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 = &quot;noErrorHandler&quot; > < camel:from uri = &quot;activemq:queue:bad&quot; /> < camel:to uri = &quot;log:bad&quot; /> </ camel:route > </ camel:camelContext >
  • 34.
    Transaction Oriented Endpointswww.xebia.fr / blog.xebia.fr Using policies in Spring XML (2) <!-- camel policy we refer to in our route --> < bean id = &quot;required&quot; class = &quot;org.apache.camel.spring.spi.SpringTransactionPolicy&quot; > < property name = &quot;transactionTemplate&quot; ref = &quot;PROPAGATION_REQUIRED&quot; /> </ bean > <!-- the standard spring transaction template for required --> < bean id = &quot;PROPAGATION_REQUIRED&quot; class = &quot;org.springframework.transaction.support.TransactionTemplate&quot; > < property name = &quot;transactionManager&quot; ref = &quot;jmsTransactionManager&quot; /> </ bean > <!-- the transaction error handle we refer to from the route --> < bean id = &quot;transactionErrorHandler&quot; class = &quot;org.apache.camel.spring.spi.TransactionErrorHandlerBuilder&quot; > < property name = &quot;transactionTemplate&quot; ref = &quot;PROPAGATION_REQUIRED&quot; /> </ bean > <!-- the no error handler --> < bean id = &quot;noErrorHandler&quot; class = &quot;org.apache.camel.builder.NoErrorHandlerBuilder&quot; />
  • 35.
    Transaction Oriented Endpointswww.xebia.fr / blog.xebia.fr TransactionErrorHandler onException ( ValidationException . class ).handled( true ).transform(body( constant ( &quot;INVALID ORDER&quot; ))); from ( &quot;jetty: http://localhost/myservice/order &quot; ) .transacted() .to( &quot;bean:validateOrder&quot; ) .to( &quot;jms:queue:order&quot; ); e rrorHandler( transactionErrorHandler() . maximumRedeliveries(6) ) ; onException(IllegalArgumentException. class ).maximumRedeliveries(4); from( &quot;direct:okay&quot; ) .transacted() .setBody(constant( &quot;Tiger in Action&quot; )).beanRef( &quot;bookService&quot; ) .setBody(constant( &quot;Elephant in Action&quot; )).beanRef( &quot;bookService&quot; );
  • 36.
    DefaultErrorHandler & DeadLetterChannelwww.xebia.fr / blog.xebia.fr Client notified (Default DLC behavior, not DEH ) errorHandler(deadLetterChannel( &quot;jms:queue:dead&quot; ). maximumRedeliveries(3).redeliverDealy(5000)); Client not notified errorHandler(deadLetterChannel( &quot;jms:queue:dead&quot; ). maximumRedeliveries(3).redeliverDealy(5000).handled( false )); Use original message errorHandler(deadLetterChannel( &quot;jms:queue:dead&quot; ) .useOriginalMessage().mamimumRedeliveries(5).redeliverDelay(5000 ); Using default error handler onException(ValidationException. class ).handled( true ).transform(body(constant( &quot;INVALID ORDER&quot; )));
  • 37.
    Annotation support www.xebia.fr/ blog.xebia.fr Camel supports annotations public class RouterBean { @Consume (uri = &quot;activemq:foo&quot; ) @RecipientList public String[] route(String body) { return new String[]{ &quot;activemq:bar&quot; , &quot;activemq:whatnot&quot; }; } } public class Foo { @ MessageDriven ( uri = &quot;activemq:my.queue&quot; ) public void doSomething( @XPath ( &quot;/foo/bar/text()&quot; ) String correlationID, @Body String body) { // process the inbound message here } }
  • 38.
    @Bean annotation www.xebia.fr/ blog.xebia.fr public class Foo { @ MessageDriven ( uri = &quot;activemq:my.queue&quot; ) public void doSomething( @Bean ( &quot;myCorrelationIdGenerator&quot; ) String correlationID, @Body String body) { // process the inbound message here } } public class MyIdGenerator { private UserManager userManager ; public String generate( @ Header ( name = &quot;user&quot; ) String user, @Body String payload) throws Exception { User user = userManager .lookupUser(user); String id = user.getPrimaryId() + generateHashCodeForPayload (payload); return id; } }
  • 39.
    Groovy support www.xebia.fr/ blog.xebia.fr Using Java DSL // lets route if a line item is over $100 from( &quot;queue:foo&quot; ).filter( groovy ( &quot;request.lineItems.any { i -> i.value > 100 }&quot; )).to( &quot;queue:bar&quot; ); Using Spring XML < route > < from uri = &quot;queue:foo&quot; /> < filter > < groovy > request.lineItems.any { i -> i.value > 100 } </ groovy > < to uri = &quot;queue:bar&quot; /> </ filter > </ route >
  • 40.
    Testing with camelwww.xebia.fr / blog.xebia.fr 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 >
  • 41.
    Testing with camelwww.xebia.fr / blog.xebia.fr public class FilterTest extends CamelTestSupport { @EndpointInject (uri = &quot;mock:result&quot; ) protected MockEndpoint resultEndpoint ; @Produce (uri = &quot;direct:start&quot; ) protected ProducerTemplate template ; public void testSendMatchingMessage() throws Exception { String expectedBody = &quot;<matched/>&quot; ; resultEndpoint .expectedBodiesReceived(expectedBody); template .sendBodyAndHeader(expectedBody, &quot;foo&quot; , &quot;bar&quot; ); resultEndpoint .assertIsSatisfied(); } public void testSendNotMatchingMessage() throws Exception { resultEndpoint .expectedMessageCount(0); template .sendBodyAndHeader( &quot;<notMatched/>&quot; , &quot;foo&quot; , &quot;notMatchedHeaderValue&quot; ); resultEndpoint .assertIsSatisfied(); } @Override protected RouteBuilder createRouteBuilder() { return new RouteBuilder() { public void configure() { from( &quot;direct:start&quot; ).filter(header( &quot;foo&quot; ).isEqualTo( &quot;bar&quot; )).to( &quot;mock:result&quot; ); } }; } }
  • 42.
    Spring Test withJava Config www.xebia.fr / blog.xebia.fr @ ContextConfiguration ( locations = &quot;org.apache.camel.spring.javaconfig.patterns.FilterTest$ContextConfig&quot; , loader = JavaConfigContextLoader . class ) public class FilterTest extends AbstractJUnit4SpringContextTests { @EndpointInject (uri = &quot;mock:result&quot; ) protected MockEndpoint resultEndpoint ; @Produce (uri = &quot;direct:start&quot; ) protected ProducerTemplate template ; @ DirtiesContext @Test public void testSendMatchingMessage() throws Exception { String expectedBody = &quot;<matched/>&quot; ; resultEndpoint .expectedBodiesReceived(expectedBody); template .sendBodyAndHeader(expectedBody, &quot;foo&quot; , &quot;bar&quot; ); resultEndpoint .assertIsSatisfied(); } @ Configuration public static class ContextConfig extends SingleRouteCamelConfiguration { @Bean public RouteBuilder route() { return new RouteBuilder() { public void configure() { from( &quot;direct:start&quot; ).filter(header( &quot;foo&quot; ).isEqualTo( &quot;bar&quot; )).to( &quot;mock:result&quot; ); } }; } } }
  • 43.
    Camel riding fromJava /META-INF/spring/camelContext.xml Set the CLASSPATH Run Camel context from : java org.apache.camel.spring.Main www.xebia.fr / blog.xebia.fr
  • 44.
    Camel & Mavenmvn camel:run, camel:dot Maven declaration: www.xebia.fr / blog.xebia.fr <? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?> < 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 >  
  • 45.
    Maven site reportResult of report plugin (Dot & GraphViz) www.xebia.fr / blog.xebia.fr
  • 46.
    Where would Iuse 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
  • 47.
    www.xebia.fr / blog.xebia.frGoing further with Apache Camel …
  • 48.
    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
  • 49.
    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
  • 50.
    www.xebia.fr / blog.xebia.frTwitter: @alexiskinsella Thank You

Editor's Notes