Taking Apache Camel For A Ride

Post on 07-Nov-2014

6,239 views 1 download

Tags:

description

Presentation from ApacheCon US 2008

transcript

Taking Apache Camel

For A RideBruce Snyderbsnyder@apache.org7 Nov 2008 New Orleans, Louisiana

Protocol Integration is Common

Data Format Integration is Common

Integration is Messy!

SOA = Spaghetti Oriented Architecture

Options For Integration

1 2

3

Too Many Choices!

The Easiest Solution - Apache Camel

http://activemq.apache.org/camel/

What is Apache Camel?

Enterprise Integration Patterns

http://enterpriseintegrationpatterns.com/

Message Routing

Patterns

History of Apache Camel

Camel Components

http://activemq.apache.org/camel/components.html

Camel Components

Simple Routing

More Simple Routing

Pipeline Routing

Multicast Routing

Multicast-to-Many Pipeline Routes

Language Support For Message Processing

• BeanShell• Javascript• Groovy• Python• PHP• Ruby

• JSP EL• OGNL• SQL• XPath• XQuery

Getting Started - The Camel Context

<camelContext xmlns="http://activemq.apache.org/camel/schema/spring"> <package>com.acme.quotes</package></camelContext>

CamelContext context = new DefaultCamelContext();context.addRoutes(new MyRouteBuilder());context.start();

PatternExamples

Patterns

Content Based Router

RouteBuilder builder = new RouteBuilder() { public void configure() { from("seda:a").choice().when(header("foo") .isEqualTo("bar")).to("seda:b") .when(header("foo").isEqualTo("cheese")) .to("seda:c").otherwise().to("seda:d"); } };

<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>

Content Based Router

Message Filter

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("activemq:topic:Quotes). filter().xpath("/quote/product = ‘widget’"). to("mqseries:WidgetQuotes"); }}

Message Filter

<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>

Splitter

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("file://orders").

splitter(body().tokenize("\n")). to("activemq:Order.Items"); }}

Splitter Using XQuery

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("file://orders").

splitter().xquery("/order/items"). to("activemq:Order.Items"); }}

Aggregator

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("activemq:Inventory.Items"). aggregator(header("symbol").isEqualTo("IBM"). to("activemq:Inventory.Order"); }}

Message Translator

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("file://incoming”).

to("xslt:com/acme/mytransform.xsl"). to("http://outgoing.com/foo"); }}

Resequencer

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("direct:a”).

resequencer(header("customerRank")). to("seda:b"); }}

Routing Slip

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("direct:a”).routingSlip();

}}

Throttler

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("seda:a”).

throttler(3).timePeriodMillis(30000). to("seda:b"); }}

Delayer

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("seda:a”).

delayer(header("JMSTimestamp", 3000). to("seda:b"); }}

Load Balancerpublic class MyRouteBuilder extends RouteBuilder { public void configure() { from("file:/path/to/file"). loadBalance().roundRobin(). to("seda:a", "seda:b", "seda:c"); }}

Policy Description

Round Robin Balance the exchange load across the available endpoints

Random Randomly choose an endpoint to send the exchange

Sticky Sticky load balancing of exchanges using an expression

Topic Send exchange to all endpoints (like a JMS topic)

Multicast

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("direct:a"). multicast(). to("direct:x?x=y&amp;1=2", "direct:y", "direct:z");

}}

Demo

MorePatterns

Wire Tap

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("direct:a"). to("log:com.mycompany.messages?level=info"). to("mock:foo");

}}

Content Enricher

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("activemq:My.Queue"). to("velocity:com/acme/MyResponse.vm"). to("activemq:Another.Queue");

}}

More Content Enricher

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("activemq:My.Queue"). beanRef("myBeanName", "myMethodName"). to("activemq:Another.Queue");

}}

Content Filter

public class MyRouteBuilder extends RouteBuilder { public void configure() { 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"); }}

Combine Patterns

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("seda:a”). resequencer(header("JMSGroupSeq")).

delayer(3000). to("mock:x"); }}

Configure Error Handling

Global Error Handler:

RouteBuilder builder = new RouteBuilder() { public void configure() { errorHandler(deadLetterChannel("file:errors")); from("bean:foo").to("seda:b"); }};

Configure Error Handling

Local Error Handler: RouteBuilder builder = new RouteBuilder() { public void configure() { from("seda:a"). errorHandler(loggingErrorHandler("FOO.BAR")). to("seda:b");

from("seda:b").to("seda:c"); }};

Configure Exception Policies

RouteBuilder builder = new RouteBuilder() { public void configure() { exception(IOException.class) .initialRedeliveryDelay(5000L) .maximumRedeliveries(3) .maximumRedeliveryDelay(30000L) .backOffMultiplier(1.0) .useExponentialBackOff() .setHeader(MESSAGE_INFO, constant("Damned IOException!")) .to("activemq:errors");

from("seda:a").to("seda:b"); }};

Beans

Make Context Discover Beans

package com.mycompany.beans;

public class MyBean {

public void someMethod(String name) { ... }}

<camelContext xmlns="http://activemq.apache.org/camel/schema/spring"> <package>com.mycompany.beans</package></camelContext>

Bean as a Message Translator

public class MyRouteBuilder extends RouteBuilder { public void configure() {

from("activemq:Incoming”). beanRef("myBean"). to("activemq:Outgoing"); }}

Bean as a Message Translator

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("activemq:Incoming”). beanRef("myBean", "someMethod"). to("activemq:Outgoing"); }}

*With Method Name

Binding Beans to Camel Endpoints

public class Foo {

@MessageDriven(uri="activemq:cheese") public void onCheese(String name) { ... }}

Binding Method Arguments

public class Foo {

public void onCheese( @XPath("/foo/bar") String name, @Header("JMSCorrelationID") String id) { ... }}

Injecting Endpoints Into Beans

public class Foo { @EndpointInject(uri="activemq:foo.bar") ProducerTemplate producer;

public void doSomething() { if (whatever) { producer.sendBody("<hello>world!</hello>"); } }}

Type Conversion

Type Conversion

@Converterpublic class IOConverter {

@Converter public static InputStream toInputStream(File file) throws FileNotFoundException { return new BufferedInputStream(

new FileInputStream(file)); }}

Type Convertors

public class MyRouteBuilder extends RouteBuilder { public void configure() { 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"); }}

Support for the following types: • File• String• byte[] and ByteBuffer • InputStream and OutputStream • Reader and Writer • Document and Source

Message Mapper

Message Translator

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("file://incoming”).

to("xslt:com/acme/mytransform.xsl"). to("http://outgoing.com/foo"); }}

Another Message Translator

public class MyRouteBuilder extends RouteBuilder { public void configure() { from("activemq:FOO.TEST”). transform(body().append(getDynamicText())). to("http://outgoing.com/foo"); }}

Business Activity Monitoring (BAM)

Business Activity Monitoring (BAM)

public class MyActivities extends ProcessBuilder {

public void configure() throws Exception {

// lets define some activities, correlating on an // XPath query of the message body ActivityBuilder purchaseOrder = activity("activemq:PurchaseOrders") .correlate(xpath("/purchaseOrder/@id").stringResult());

ActivityBuilder invoice = activity("activemq:Invoices") .correlate(xpath("/invoice/@purchaseOrderId").stringResult());

// now lets add some BAM rules invoice.starts().after(purchaseOrder.completes()) .expectWithin(seconds(1)) .errorIfOver(seconds(2)).to("activemq:FailedProcesses"); }}

Complex Routing is Easier from(“http://localhost:8080/requests/”). tryBlock(). to(“activemq:queue:requests”). setOutBody(constant(“<ack/>”)). handle(Throwable.class). setFaultBody(constant(“<nack/>”));

from((“activemq:queue:requests?transacted=true”). process(requestTransformer). to(“http://host:8080/Request”). filter(xpath(“//nack”)). process(nackTransformer). to(“jdbc:store”);

from(“http://localhost:8080/responses/”). tryBlock(). to(“activemq:queue:responses”). setOutBody(constant(“<ack/>”)). handle(Throwable.class). setFaultBody(constant(“<nack/>”));

from(“activemq:queue:responses?transacted=true”). process(responseTransformer). to(“jdbc:store”);

from(“http://localhost:8080/pull/”). to(“jdbc:load”);

Finally, the Camel Truck!

Ride the Camel!

http://activemq.apache.org/camel/

Ride the Camel!