78
FUSE ESB Enterprise Integration Patterns (OSGi Container) Version 4.0 October 2008

Enterprise Integration Patterns (OSGi Container)

Embed Size (px)

Citation preview

Page 1: Enterprise Integration Patterns (OSGi Container)

FUSE™ ESBEnterprise Integration Patterns (OSGi Container)

Version 4.0October 2008

Page 2: Enterprise Integration Patterns (OSGi Container)

Enterprise Integration Patterns (OSGi Container)Progress Software

Version 4.0

Published 26 Jan 2009Copyright© 2008 IONA Technologies PLC , a wholly-owned subsidiary of Progress Software Corporation.

Legal Notices

Progress Software Corporation and/or its subsidiaries may have patents, patent applications, trademarks, copyrights, or otherintellectual property rights covering subject matter in this publication. Except as expressly provided in any written license agreementfrom Progress Software Corporation, the furnishing of this publication does not give you any license to these patents, trademarks,copyrights, or other intellectual property. Any rights not expressly granted herein are reserved.

Progress, IONA, IONA Technologies, the IONA logo, Orbix, High Performance Integration, Artix, FUSE, and Making SoftwareWork Together are trademarks or registered trademarks of Progress Software Corporation and/or its subsidiaries in the US andother countries.

Java and J2EE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.CORBA is a trademark or registered trademark of the Object Management Group, Inc. in the US and other countries. All othertrademarks that appear herein are the property of their respective owners.

While the information in this publication is believed to be accurate Progress Software Corporation makes no warranty of any kindto this material including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose.Progress Software Corporation shall not be liable for errors contained herein, or for incidental or consequential damages inconnection with the furnishing, performance or use of this material.

All products or services mentioned in this manual are covered by the trademarks, service marks, or product names as designatedby the companies who market those products.

No part of this publication may be reproduced, stored in a retrieval system or transmitted, in any form or by any means,photocopying, recording or otherwise, without prior written consent of IONA Technologies PLC. No third-party intellectual propertyright liability is assumed with respect to the use of the information contained herein. IONA Technologies PLC assumes noresponsibility for errors or omissions contained in this publication. This publication and features described herein are subject tochange without notice. Portions of this document may include Apache Foundation documentation, all rights reserved.

Page 3: Enterprise Integration Patterns (OSGi Container)

Table of ContentsDeploying Integration Patterns ................................................................................................. 11

What are the Enterprise Integration Patterns? ........................................................................ 12Architecture ................................................................................................................. 14Deploying an XML Route ................................................................................................. 17Running the camel-osgi Demonstration ............................................................................... 27Using the NMR Component .............................................................................................. 30Running the camel-nmr Demonstration ............................................................................... 36

Defining Routes in Java DSL .................................................................................................... 39Implementing a RouteBuilder Class .................................................................................... 40Basic Java DSL Syntax .................................................................................................... 42Processors ................................................................................................................... 46Languages for Expressions and Predicates ............................................................................ 51Transforming Message Content .......................................................................................... 56

Defining Routes in XML .......................................................................................................... 63Using the Router Schema in an XML File ............................................................................. 64Defining a Basic Route in XML .......................................................................................... 66Processors ................................................................................................................... 67Languages for Expressions and Predicates ............................................................................ 74Transforming Message Content .......................................................................................... 76

3

Page 4: Enterprise Integration Patterns (OSGi Container)

4

Page 5: Enterprise Integration Patterns (OSGi Container)

List of Figures1. FUSE Mediation Router Deployed into the OSGi Container ............. 142. Local Routing Rules .............................................................. 43

5

Page 6: Enterprise Integration Patterns (OSGi Container)

6

Page 7: Enterprise Integration Patterns (OSGi Container)

List of Tables1. Properties for Simple Language ............................................... 522. Transformation Methods from the ProcessorType Class .................. 573. Methods from the Builder Class ............................................... 584. Modifier Methods from the ValueBuilder Class ............................. 595. Elements for Expression and Predicate Languages ........................ 74

7

Page 8: Enterprise Integration Patterns (OSGi Container)

8

Page 9: Enterprise Integration Patterns (OSGi Container)

List of Examples1. Spring XML File Defining a Route ............................................. 182. Transformation Bean Example ................................................. 213. Manifest for the camel-osgi Demonstration ................................. 224. Configuration of Maven Bundle Plug-In in pom.xml File ................. 245. Spring XML Defining a Route with an NMR Endpoint .................... 326. Manifest for the camel-nmr Demonstration ................................. 347. Implementation of a RouteBuilder Class .................................... 408. Implementing a Custom Processor Class .................................... 509. Simple Transformation of Incoming Messages ............................. 5610. Using Artix Data Services to Marshal and Unmarshal .................. 6211. Specifying the Router Schema Location ................................... 6412. Router Schema in a Spring Configuration File ............................ 6513. Basic Route in XML ............................................................ 6614. Using Artix Data Services to Marshal and Unmarshal .................. 78

9

Page 10: Enterprise Integration Patterns (OSGi Container)

10

Page 11: Enterprise Integration Patterns (OSGi Container)

Deploying Integration PatternsThis chapter explains how to get started with enterprise integration patterns in the context of FUSE ESB's OSGicontainer. The fundamental task that you need to learn about is how to deploy a FUSE Mediation Router applicationinto the OSGi container (where FUSE Mediation Router provides the implementation of the enterprise integrationpatterns.

What are the Enterprise Integration Patterns? ................................................................................ 12Architecture ......................................................................................................................... 14Deploying an XML Route ......................................................................................................... 17Running the camel-osgi Demonstration ....................................................................................... 27Using the NMR Component ...................................................................................................... 30Running the camel-nmr Demonstration ....................................................................................... 36

11

Page 12: Enterprise Integration Patterns (OSGi Container)

What are the Enterprise Integration Patterns?Overview

The enterprise integration patterns are inspired by a book of the same namewritten by Gregor Hohpe and Bobby Woolf. The patterns described by theseauthors provide an excellent toolbox for developing enterprise integrationprojects. In addition to providing a common language for discussing integrationarchitectures, many of the patterns can be implemented directly using FUSEMediation Router's programming interfaces and XML configuration.

FUSE Mediation RouterThe FUSE Mediation Router product provides practical implementations formany of the patterns described in Hohpe and Woolf's book. FUSE MediationRouter applications are constructed from the following basic entities:

• Routes—a route is a set of instructions for processing messages. Each routestarts with a consumer endpoint (or source endpoint), which receivesincoming messages, and ends with one or more producer endpoints (ordestination endpoints), which send messages to external or localdestinations. If the message exchange pattern is InOut, a reply messagecan also pass back through the route.

Many of the enterprise integration patterns can be mapped to routes thatperform particular kinds of message processing. For example, most of themessage routing and message transformation patterns from Hohpe andWoolf's book can be implemented as routes in FUSE Mediation Router.

• Components—a component is an endpoint factory, where endpoints actas sources and sinks for messages in a route. Various component typescan be used either to connect routes together or to communicate with theoutside world. Frequently, a component represents a particular kind oftransport protocol: for example, the JMS component, the FTP component,or the Mail component.

Some of the enterprise integration patterns are implemented usingcomponents. In particular, the JMS component and the ActiveMQcomponent are relevant to many of the patterns, because the originalenterprise integration patterns are mainly concerned with messagingsystems.

12

Deploying Integration Patterns

Page 13: Enterprise Integration Patterns (OSGi Container)

For a more detailed introduction to the basic concepts in FUSE MediationRouter, see Defining Routes in Java DSL on page 39.

Example of an enterpriseintegration pattern To take a concrete example of an enterprise integration pattern, consider the

splitter pattern, which can be implemented by a simple route in Java, asfollows:

from("activemq:my.queue").splitter(xpath("/*")).to("file://some/directory")

Where the route is written in FUSE Mediation Router's Java DSL (see BasicJava DSL Syntax on page 42 for details). This route defines a consumerendpoint, activemq:my.queue, using the ActiveMQ component (where

Apache ActiveMQ is a JMS -compliant messaging system). The consumerendpoint is configured to receive messages from a queue called my.queue.

Messages pulled off the queue pass through the splitter processor,splitter(xpath("/*")), which applies an XPath expression to the incoming

message (presumed to be in XML format) in order to split it into multiplesmaller messages. In this example, the effect is to split off every root-levelelement into a separate message.

You can also define an equivalent route using XML configuration:

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

<route><from uri="activemq:my.queue"/><splitter><xpath>/*</xpath><to uri="file://some/directory"/>

</splitter></route>

</camelContext>

Further readingTo gain a fuller understanding of how to implement enterprise integrationpatterns using FUSE Mediation Router, we recommend that you supplementthis introductory guide by reading one or more of the following documentsfrom the FUSE Mediation Router library:

• FUSE Mediation Router Implementing Enterprise Integration Patterns.

• FUSE Mediation Router Component Reference.

• FUSE Mediation Router Programmer's Guide.

13

What are the Enterprise Integration Patterns?

Page 14: Enterprise Integration Patterns (OSGi Container)

ArchitectureOverview

Figure 1 on page 14 gives an overview of the architecture that forms thebasis of FUSE Mediation Router applications.

Figure 1. FUSE Mediation Router Deployed into the OSGi Container

OSGi containerThe OSGi container provides the overall framework for your FUSE MediationRouter applications. To start the OSGi container, open a command prompt,change directory to the FUSE ESB install directory, and enter the followingcommand:

bin/servicemix

After a few moments, the container initializes itself and you should see a shellprompt like the following:

ServiceMix>

14

Deploying Integration Patterns

Page 15: Enterprise Integration Patterns (OSGi Container)

For example, to list all of the bundles currently deployed in the OSGi container,enter the command osgi list.

OSGi bundlesAll parts of the application, including the FUSE ESB kernel and the FUSEMediation Router core, are deployed as OSGi bundles. In OSGi, everythingis a bundle.

At its simplest, a bundle is simply a JAR file that has a few additional entriesin its manifest, META-INF/MANIFEST.MF. These additional entries are known

as bundle headers (for more details, see Example 3 on page 22).

NMRThe FUSE ESB NMR is a general-purpose message bus used for transmittingmessages between bundles in the OSGi container. It is modelled on theNormalized Message Router (NMR) defined in the Java Business Integration(JBI) specification [http://www.jcp.org/en/jsr/detail?id=208]. Hence, theFUSE ESB NMR can be used to transmit XML messages, optionally augmentedwith properties and attachments. Unlike the standard NMR, however, theFUSE ESB NMR is not restricted to the JBI container. You can use the NMRto transmit messages inside the OSGi container or, if the JBI container is alsodeployed, to transmit messages between the two containers.

In Figure 1 on page 14, the NMR is represented as a horizontal graphicalelement in order to emphasize its role linking together various applicationbundles. In practice, however, the NMR is deployed as a collection of bundles,just like any other application in the OSGi container.

FUSE Mediation Router coreThe FUSE Mediation Router core provides the core functionality forimplementing the Enterprise Integration Patterns. This feature consists of thecamel-core bundle and a few other basic bundles.

For your FUSE Mediation Router applications, you will always require theFUSE Mediation Router core and possibly one or more FUSE Mediation Routercomponents as well.

Spring dynamic modules for OSGiThe Spring dynamic modules for OSGi service platforms[http://www.springframework.org/osgi] feature makes it relatively easy to useSpring configuration files in the context of OSGi. Spring dynamic modulesextends the OSGi framework, so that Spring configuration files areautomatically detected whenever you start an OSGi bundle.

When you start a bundle (for example, using the command, osgi start),

the Spring dynamic bundles extensor automatically checks to see whether

15

Architecture

Page 16: Enterprise Integration Patterns (OSGi Container)

there are any Spring configuration files matching *.xml under the

META-INF/spring directory. If any configuration files are found there, Spring

automatically instantiates and initializes the beans defined in these files. Byexploiting this mechanism, you can effectively use Spring configuration filesto bootstrap your application. This mechanism is particularly convenient forFUSE Mediation Router, because it is normal practice to use Springconfiguration files to initialize FUSE Mediation Router applications.

FUSE Mediation Routercomponents A FUSE Mediation Router component is essentially an endpoint factory. Thus

there are components for creating File endpoints, SEDA endpoints, HTTPendpoints, CXF endpoints, JMS endpoints, and so on. A few components arepart of the FUSE Mediation Router core (see ???), but many more of themare packaged separately as OSGi bundles. For details of how to installadditional components, see ???.

For a list of supported FUSE Mediation Router components, see Camelcomponents [http://activemq.apache.org/camel/components.html].

NMR componentThe NMR component is of particular interest, because it enables FUSEMediation Router applications to communicate with each other (and withother bundles) through the NMR. Additionally, the NMR makes it possibleto communicate with applications deployed into the JBI container.

For details about how to use the NMR component, see Using the NMRComponent on page 30.

FUSE Mediation Routerapplications FUSE Mediation Router applications are deployed as regular OSGi bundles.

To bootstrap your application, you normally define a Spring configuration filein the META-INF/spring directory. For detailed examples, see Deploying an

XML Route on page 17 and Using the NMR Component on page 30.

NMR endpointsIf a FUSE Mediation Router application needs to communicate over the NMR,it can create an NMR endpoint simply by specifying an NMR endpoint URIas the source or destination of a route. For details of how this is done, seeUsing the NMR Component on page 30.

16

Deploying Integration Patterns

Page 17: Enterprise Integration Patterns (OSGi Container)

Deploying an XML RouteOverview

This section explains how to create a simple FUSE Mediation Routerapplication and how to deploy it as an OSGi bundle into the FUSE ESB OSGicontainer. The examples in this section are taken from the camel-osgi

demonstration, which defines a simple route in a Spring XML configurationfile.

camel-osgi demonstrationThe camel-osgi demonstration is located in the following directory:

InstallDir/examples/camel-osgi

The demonstration shows how to define a route in XML, where the route isbuilt up from the following parts:

• At the start of the route is a timer endpoint, which generates a heartbeat

event every two seconds.

• Next comes a callout to a transformer bean (implemented in Java), whichtransforms the hearbeat into a message containing the current date andtime.

• At the end of the route is a log endpoint, which sends the transformed

message to Jakarta commons logger.

The route is deployed into the FUSE ESB container as an OSGi bundle.

Defining the route in a SpringXML file Relative to the CLASSPATH, the application's Spring XML file must be located

in the following directory:

META-INF/spring

When you start an application bundle in the FUSE ESB OSGi container, Springlooks for any files matching *.xml located in META-INF/spring and processes

all of the matched files. In effect, the Spring XML files located in this directorybootstrap the bundled application.

Example 1 on page 18 shows the routes for the camel-osgi demonstration,

taken from the Spring XML configuration file, META-INF/spring/beans.xml.

17

Deploying an XML Route

Page 18: Enterprise Integration Patterns (OSGi Container)

Example 1. Spring XML File Defining a Route

<?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:osgi="http://activemq.apache.org/camel/schema/osgi" ❸

xmlns:osgix="http://www.springframework.org/schema/osgi-compendium" ❹

xsi:schemaLocation="http://www.springframework.org/schema/beans ht

tp://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.xsd

http://activemq.apache.org/camel/schema/osgi http://activemq.apache.org/camel/schema/osgi/camel-osgi.xsd

http://www.springframework.org/schema/osgi-compendiumhttp://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd">

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

<route> ❻<from uri="timer://myTimer?fixedRate=true&amp;peri

od=2000"/><bean ref="myTransform" method="transform"/><to uri="log:ExampleRouter"/>

</route></osgi:camelContext>

<bean id="myTransform" class="org.apache.servicemix.examples.camel.MyTransform"> ❼

<property name="prefix" value="${prefix}"/> ❽</bean>

<osgix:property-placeholder persistent-id="org.apache.servicemix.examples"> ❾

<osgix:default-properties><prop key="prefix">MyTransform</prop>

</osgix:default-properties></osgix:property-placeholder>

</beans>

18

Deploying Integration Patterns

Page 19: Enterprise Integration Patterns (OSGi Container)

❶ The default namespace,http://www.springframework.org/schema/beans, is the Spring

XML namespace. This namespace provides access to the Springconfiguration schema, which is used to instantiate and configure Javaobjects. In particular, the beans element, which contains all of the

application's configuration, belongs to this namespace.❷ The XML schema namespace,

http://www.w3.org/2001/XMLSchema-instance, gets associated

with the xsi prefix. The XML schema provides access to standard XML

data types and enables you to define new XML types and elements (hereit is needed for the xsi:schemaLocation attribute).

❸ The Camel/OSGi namespace,http://activemq.apache.org/camel/schema/osgi, gets associated

with the osgi prefix. The Camel/OSGi schema is a simple schema that

is used to define FUSE Mediation Router routes inside an OSGi container.Currently, this schema defines just a single element,osgi:camelContext.

❹ The OSGi compendium namespace,http://www.springframework.org/schema/osgi-compendium,

gets associated with the osgix prefix. The OSGi compendium schema

provides additional features for Spring/OSGi integration, where thesefeatures are based on the OSGi Service Platform Service Compendiumspecification.

For more details, see Spring Compendium Services[http://tinyurl.com/52x3m5].

❺ The contents of the osgi:camelContext element are defined using the

regular Camel schema,http://activemq.apache.org/camel/schema/spring. The Camel

schema[http://activemq.apache.org/camel/schema/spring/camel-spring.xsd]enables you to define all of the routes for your FUSE Mediation Routerapplication. See Using the Router Schema in an XML File on page 64.

❻ Each route is defined using a route element and you can define multiple

route elements in an osgi:camelContext element. In this example,

the route starts with a FUSE Mediation Router timer component, whichgenerates a hearbeat event every 2000 ms. Each event message ispassed through a bean reference, which calls the transform()method

19

Deploying an XML Route

Page 20: Enterprise Integration Patterns (OSGi Container)

on the bean with ID, myTransform, in order to process the message.

Finally, the transformed message is sent to a Jakarta commons loggingendpoint, log:ExampleRouter, using the FUSE Mediation Router log

component.

For more details about how to define XML routes, see Defining Routesin XML on page 63.

❼ The bean element instantiates the transformer bean using standard

Spring syntax. When Spring parses this bean element, it creates a newinstance of the class,org.apache.servicemix.examples.camel.MyTransform, by calling

its default constructor. The property element is used to initialize the

value of a Java bean property. In this case, the effect is that Spring callsthe MyTransform.setPrefix() method, passing in the string,

MyTransform. Finally, Spring enters the newly instantiated bean in its

registry, using the ID value, myTransform. This enables other parts of

the configuration to access the bean (for example, using a tag like <bean

ref="IDValue" .../>).

For more details about how to instantiate Java classes using Spring, seeThe IoC Container[http://static.springframework.org/spring/docs/2.5.x/reference/beans.html]chapter in the Spring documentation.

❽ The prefix value is specified using a property placeholder, ${prefix},

which enables you to source bean property values from the OSGiConfiguration Admin service.

NoteUsing property placeholders is optional. You can specify theliteral value of the property here, if you prefer.

❾ The presence of the osgix:property-placeholder element in the

Spring XML file enables the property placeholder feature from the Springcompendium services. In particular, this feature enables you to specifyplaceholder values, like ${KeyName}, using the standard OSGi

20

Deploying Integration Patterns

Page 21: Enterprise Integration Patterns (OSGi Container)

Configuration Admin service. This example also specifies a default valuefor the property.

Definition of a transformationbean Example 2 on page 21 shows the definition of a transformation bean class,

org.apache.servicemix.examples.camel.MyTransform, which is

responsible for transforming the body of the In message in a route. TheMyTransform.transform() method from this class gets called by the

preceding XML route (see Example 1 on page 18).

Example 2. Transformation Bean Example

package org.apache.servicemix.examples.camel;

import java.util.Date;

import org.apache.commons.logging.Log; ❶import org.apache.commons.logging.LogFactory;

public class MyTransform {private static final transient Log LOG = LogFactory.get

Log(MyTransform.class);private boolean verbose = true;private String prefix = "MyTransform";

public Object transform(Object body) { ❷String answer = prefix + " set body: " + new Date();

if (verbose) {System.out.println(">>>> " + answer);

}LOG.info(">>>> " + answer);return answer; ❸

}

public String getPrefix() {return prefix;

}

public void setPrefix(String prefix) { ❹this.prefix = prefix;

}...

}

21

Deploying an XML Route

Page 22: Enterprise Integration Patterns (OSGi Container)

❶ The org.apache.commons.logging package is external to the

camel-osgi demonstration bundle. For details of how to access external

packages, see Configuring the bundle headers on page 22.❷ The transform() method is responsible for performing the message

transformation. The signature of this transformation method conformsto the following syntax:

• The method takes a single parameter of Object type, representing

the body of the In message.

• The method declares a return value of Object type, representing the

transformed body of the In message.

• The name of the method can be anything you like.

There are other ways of defining bean transformation methods—for moredetails, see Bean Integration[http://activemq.apache.org/camel/bean-integration.html].

❸ In this example, the body of the incoming message is ignored and thetransformed message, answer, is a simple string containing a date and

time stamp.❹ The setPrefix() method is a simple example of a bean property that

can be initialized from within a Spring XML file (seeExample 2 on page 21).

Configuring the bundle headersIn order to package the demonstration as an OSGi bundle (which is simply aJAR file), it is necessary to add a number of entries to the JAR's manifest file.Relative to the JAR root, the manifest file is stored in the following location:

META-INF/MANIFEST.MF

Where the pathname of this location is case-insensitive. For example,meta-inf/Manifiest.mf would work just as well. Example 3 on page 22

shows the manifest for the camel-osgi bundle, which includes some

OSGi-specific manifest entries, known as bundle headers.

Example 3. Manifest for the camel-osgi Demonstration

Manifest-Version: 1.0Built-By: YOURUSERNAMECreated-By: Apache Maven Bundle PluginBundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt

22

Deploying Integration Patterns

Page 23: Enterprise Integration Patterns (OSGi Container)

Import-Package: org.apache.camel.osgi,org.apache.commons.loggingBnd-LastModified: 1222079507224Bundle-Version: 4.0.0.fuseBundle-Name: Apache ServiceMix Example :: Camel OSGiBundle-Description: This pom provides project information thatis common to all ServiceMix branches.Build-Jdk: 1.5.0_08Private-Package: org.apache.servicemix.examples.camelBundle-DocURL: http://www.apache.org/Bundle-ManifestVersion: 2Bundle-Vendor: The Apache Software FoundationBundle-SymbolicName: camel-osgiTool: Bnd-0.0.255

Some of these manifest entries (for example, Bnd-LastModified, Build-Jdk,

Private-Package, and Tool) are generated by the Maven bundle plug-in

for information purposes only and they are thus not particularly important.Some of the OSGi bundle headers are also included for information only. Theimportant entries are the bundle headers that affect the interaction betweenthe bundle and the OSGi container and these are, as follows:

Bundle-Name:A human-readable name for the current bundle. For example, when youenter the command, osgi list, from the FUSE ESB console, the

installed bundles are listed with their bundle name.

Bundle-SymbolicName:A unique name for the current bundle. The bundle symbolic name is theprimary way of identifying a bundle. For example, you would use thebundle symbolic name to refer to a bundle from within a piece of codeor in a configuration file. The usual convention for a bundle symbolicname is to use a reverse URL format (the sample value shown here isunconventional in this respect).

Import-Package:The value of this header is a comma-separated list of Java packagenames for all of the packages needed by, but not included in this bundle.For example, the org.apache.commons.logging package is listed here

because it is used by the transformation bean code.

23

Deploying an XML Route

Page 24: Enterprise Integration Patterns (OSGi Container)

NoteThe syntax of the package list can be a bit more complicatedthan a comma-separated list (for example, you can optionallyselect particular package versions and so on). For full details ofthe syntax, consult the OSGi specification[http://www.osgi.org/Specifications/HomePage].

Export-Package:(Not used in the example) The value of this header is a comma-separatedlist of Java package names for packages contained in the current bundlethat you want to make available to other bundles. The Export-Package:

and Import-Package: headers are complementary: the Java packages

exported by one bundle using Export-Package: become available to

other bundles that import them using Import-Package:.

Creating the contents of these headers can be an annoying chore, if you haveto do it by hand. For example, a moderately complex piece of Java code mightneed to import dozens of different packages using the Import-Package:

header. For larger applications, it would be convenient to have some way ofautomatically generating bundle headers.

Maven bundle plug-inIf you are using the Apache Maven2 [http://maven.apache.org/] build systemto build your application, you have the option of using the Maven bundleplug-in [http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html]to generate all of the bundle headers automatically. As already noted, thisfeature can be extremely convenient for large, complex applications.Example 4 on page 24 shows how to modify the top-level Maven build file,pom.xml, in order to enable the bundle plug-in.

Example 4. Configuration of Maven Bundle Plug-In in pom.xml File

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

...<groupId>org.apache.servicemix.examples</groupId><artifactId>camel-osgi</artifactId><packaging>bundle</packaging> ❶<version>4.0.0.2-fuse</version><name>Apache ServiceMix Example :: Camel OSGi</name>

24

Deploying Integration Patterns

Page 25: Enterprise Integration Patterns (OSGi Container)

...<dependencies>

<dependency> ❷<groupId>org.apache.felix</groupId><artifactId>org.osgi.core</artifactId><version>1.0.0</version>

</dependency>...

</dependencies>...<build>

<plugins><plugin> ❸

<groupId>org.apache.felix</groupId><artifactId>maven-bundle-plugin</artifactId><configuration>

<instructions><Bundle-SymbolicName>${pom.artifact

Id}</Bundle-SymbolicName><Import-Pack

age>*,org.apache.camel.osgi</Import-Package><Private-Package>org.apache.service

mix.examples.camel</Private-Package></instructions>

</configuration></plugin>

</plugins>...

</build>...

</project>

❶ Change the packaging from jar to bundle.

❷ Add a dependency on the Apache Felix library, as shown.

NoteIn the POM file for the camel-osgi demonstration, this

dependency does not appear explicitly. It is actually includedin the parent POM.

❸ The plugin element is used to configure the Maven bundle plug-in.

There is no need to install the Maven bundle plug-in explicitly. Because theplug-in is archived in the default Maven2 repository (that is,http://repo1.maven.org/maven2/), Maven will automatically locate and

25

Deploying an XML Route

Page 26: Enterprise Integration Patterns (OSGi Container)

download the plug-in the first time you build your application (provided thatthe build machine is connected to the Internet). The preceding configurationdefines the following instructions for generating bundle headers:

<Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName><Import-Package>*,org.apache.camel.osgi</Import-Package><Private-Package>org.apache.servicemix.examples.camel</Private-Package>

The preceding elements can be explained as follows:

Bundle-SymbolicNameGenerates the Bundle-SymbolicName:manifest entry. In this example,

it is set to the project's artifact ID, which resolves to camel-osgi. If you

want to be sure to avoid a name clash, you could define the symbolicname as follows:

<Bundle-SymbolicName>$(pom.groupId).${pom.artifactId}</Bundle-SymbolicName>

Which would resolve toorg.apache.servicemix.examples.camel-osgi in the current

example.

Import-PackageGenerates the Import-Package:manifest entry. The wildcard character

, *, generates a list containing every referenced Java package not included

in the current Maven project. The org.apache.camel.osgi package

is listed explicitly, because it is not referenced in the source code, but itis needed at run time.

Private-PackageGenerates the Private-Package: manifest entry. This entry does not

correspond to a bundle header and is ignored by the OSGi container.The private package list contains the names of all the Java packagesthat are defined in the current bundle, but are not visible to other bundles.It is provided for information purposes only.

Because the bundle plug-in generates sensible defaults for most of the bundleheaders, the preceding plug-in configuration is normally adequate to get youstarted with most projects. For more details about configuring the Mavenbundle plug-in, see Maven bundle plug-in[http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html].

26

Deploying Integration Patterns

Page 27: Enterprise Integration Patterns (OSGi Container)

Running the camel-osgi DemonstrationRunning from a remote repository

To install and run the camel-osgi demonstration, where the demonstration

bundle is downloaded from a remote repository, perform the following steps:

1. Install and start the camel-osgi bundle—at the FUSE ESB console, enterthe following command:

servicemix> features install examples-camel-osgi

This command has the effect of both installing and starting the camel-osgi

bundle. After entering this command, you should soon see output like thefollowing being logged to the console screen:

>>>> MyTransform set body: Mon Sep 22 11:43:42 BST 2008>>>> MyTransform set body: Mon Sep 22 11:43:44 BST 2008>>>> MyTransform set body: Mon Sep 22 11:43:46 BST 2008

2. Stop the camel-osgi bundle—to stop the camel-osgi bundle, you first

need to discover the relevant bundle number. To find the bundle number,enter the following console command (this might look a bit confusing,because the text you are typing will intermingle with the output that isbeing logged to the screen):

servicemix> osgi list

At the end of the listing, you should see an entry like the following:

[ 126] [Active ] [ 50] Apache ServiceMix Example ::Camel OSGi (4.0.0.2-fuse)

Where, in this example, the bundle number is 126. To stop this bundle,enter the following console command:

servicemix> osgi stop 126

Running from a local buildTo install and run the camel-osgi demonstration, where the demonstration

bundle is built locally, perform the following steps:

27

Running the camel-osgi Demonstration

Page 28: Enterprise Integration Patterns (OSGi Container)

1. Build the demonstration—open a command prompt and change directoryto examples/camel-osgi. Use Maven to build the demonstration by

entering the following command:

mvn install

If this command runs successfully, the examples/camel-osgi/target

directory should contain the bundle file, camel-osgi-4.0.0.2-fuse.jar.

2. Install and start the camel-osgi bundle—at the FUSE ESB console, enterthe following command:

servicemix> osgi install -s file:InstallDir/examples/camel-osgi/target/camel-osgi-4.0.0.2-fuse.jar

Where InstallDir is the directory where you installed FUSE ESB and

the -s flag directs the container to start the bundle right away. For example,

if your install directory isC:\Programs\FUSE\apache-servicemix-4.0.0.2-fuse on a Windows

machine, you would enter the following command:

servicemix> osgi install -s file:C:/Programs/FUSE/apache-servicemix-4.0.0.2-fuse/examples/camel-osgi/target/camel-osgi-4.0.0-fuse-SNAPSHOT.jar

After entering this command, you should soon see output like the followingbeing logged to the console screen:

>>>> MyTransform set body: Mon Sep 22 11:43:42 BST 2008>>>> MyTransform set body: Mon Sep 22 11:43:44 BST 2008>>>> MyTransform set body: Mon Sep 22 11:43:46 BST 2008

NoteWhen specifying the location of a bundle to the osgi install

command, it is essential to use forward slashes, /, in the path

name, even on a Windows machine.

3. Stop the camel-osgi bundle—to stop the camel-osgi bundle, you first

need to discover the relevant bundle number. To find the bundle number,enter the following console command (this might look a bit confusing,

28

Deploying Integration Patterns

Page 29: Enterprise Integration Patterns (OSGi Container)

because the text you are typing will intermingle with the output that isbeing logged to the screen):

servicemix> osgi list

At the end of the listing, you should see an entry like the following:

[ 126] [Active ] [ 50] Apache ServiceMix Example ::Camel OSGi (4.0.0.2-fuse)

Where, in this example, the bundle number is 126. To stop this bundle,enter the following console command:

servicemix> osgi stop 126

29

Running the camel-osgi Demonstration

Page 30: Enterprise Integration Patterns (OSGi Container)

Using the NMR ComponentOverview

The NMR component is an adapter to the NMR, which is a general-purposemessage bus that applications can use in order to communicate within theFUSE ESB OSGi container. It is modelled on the Normalized Message Router(NMR) defined in the Java Business Integration (JBI) specification. Hence,the FUSE ESB NMR can be used to transmit XML messages, along withproperties and attachments. Unlike the standard NMR, however, the FUSEESB NMR is not restricted to the JBI container. You can use the NMR totransmit messages inside the OSGi container, even if JBI is not deployed.Moreover, if you do deploy the JBI container, you can use the NMR forcommunicating between the two containers.

Installing the NMR componentThe NMR component is installed in FUSE ESB as an OSGi bundle. The NMRcomponent gets installed along with the NMR feature, which you can installby entering the following command:

features install nmr

Normally, the NMR feature is pre-installed in the OSGi container. In additionto installing the NMR feature, however, you also need to edit your application'sSpring XML configuration file, META-INF/spring/*.xml, in order to

instantiate the NMR component. The following XML import inserts a chunkof XML that takes care of instantiating the NMR component:

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

<beans xmlns="http://www.springframework.org/schema/beans"... >...<import resource="classpath:org/apache/service

mix/camel/camel-nmr.xml" />...

</beans>

Because this import statement references the external package,

org.apache.servicemix.camel, you also need to import this package in

the Import-Package bundle header—see Example 6 on page 34 for details.

URI format for the NMRcomponent The NMR component enables you to create and to reference endpoints using

a JBI style of addressing. The general form of an NMR endpoint URI is asfollows:

30

Deploying Integration Patterns

Page 31: Enterprise Integration Patterns (OSGi Container)

nmr:JBIAddressingURI

Where JBIAddressingURI conforms to the URI format described in

ServiceMix URIs [http://servicemix.apache.org/uris.html].

Specifying an InOut messageexchange pattern By default, an NMR endpoint supports oneway exchanges (Inmessages only).

If you want to enable an NMR endpoint to send back a reply, you mustexplicitly enable this using the mep query option. To enable the InOutmessage

exchange protocol on an NMR endpoint, simply append ?mep="in-out" to

the URI. For example:

nmr:ExampleRouter?mep=in-out

camel-nmr demonstrationThe camel-nmr demonstration is located in the following directory:

InstallDir/examples/camel-nmr

The demonstration defines two routes in XML, where the routes are joinedtogether using an NMR endpoint. The first route is defined as follows:

• At the start of the route is a timer endpoint, which generates a heartbeat

event every two seconds.

• At the end of the route is an NMR endpoint, which transmits the messagesto the next route.

The second route is defined as follows:

• At the start of the second route is an NMR endpoint, which receives themessages sent by the first route.

• Next comes a callout to a transformer bean (implemented in Java), whichtransforms the hearbeat into a message containing the current date andtime.

• At the end of the route is a log endpoint, which sends the transformed

message to Jakarta commons logger.

The route is deployed into the FUSE ESB container as an OSGi bundle.

Defining the route in a SpringXML file Example 5 on page 32 shows the routes for the camel-nmr demonstration,

taken from the Spring XML configuration file, META-INF/spring/beans.xml.

31

Using the NMR Component

Page 32: Enterprise Integration Patterns (OSGi Container)

Example 5. Spring XML Defining a Route with an NMR Endpoint

<?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:osgi="http://act

ivemq.apache.org/camel/schema/osgi"xmlns:osgix="http://www.springframework.org/schema/osgi-

compendium"xsi:schemaLocation="http://www.springframework.org/schema/beans ht

tp://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.xsd

http://activemq.apache.org/camel/schema/osgi http://activemq.apache.org/camel/schema/osgi/camel-osgi.xsd

http://www.springframework.org/schema/osgi-compendiumhttp://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd">

<import resource="classpath:org/apache/servicemix/camel/camel-nmr.xml" /> ❶

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

<!-- Route periodically sent events into the NMR --><route><from uri="timer://myTimer?fixedRate=true&amp;peri

od=2000"/><to uri="nmr:ExampleRouter"/> ❷

</route><!-- Route exchange from the NMR endpoint to a log endpoint

--><route><from uri="nmr:ExampleRouter"/> ❸<bean ref="myTransform" method="transform"/><to uri="log:ExampleRouter"/>

</route></osgi:camelContext>

<bean id="myTransform" class="org.apache.servicemix.examples.camel.MyTransform">

<property name="prefix" value="MyTransform"/></bean>

</beans>

32

Deploying Integration Patterns

Page 33: Enterprise Integration Patterns (OSGi Container)

❶ This Spring import element imports a snippet of XML that instantiates

and initializes the NMR component. The NMR component is exceptionalin this respect: for most of the non-core components, you can put therelevant XML snippet directly into your Spring configuration file insteadof importing it—see ???.

The location of the XML snippet is specified using the classpath URI,classpath:org/apache/servicemix/camel/camel-nmr.xml, which

indicates that the XML file can be found on the current CLASSPATH. Asa matter of fact, the camel-nmr.xml file is located in a separate bundle:

that is, it is part of the org.apache.servicemix.camel.component

bundle. Hence, it is necessary to import theorg.apache.servicemix.camel bundle, in order to make this XML

file accessible (see Example 6 on page 34 for details of how this isdone).

❷ At the end of the first route, messages are sent to the NMR endpoint,nmr:ExampleRouter.

❸ When you specify an NMR endpoint in the uri attribute of the <from>

tag, a new NMR endpoint is created by the NMR component. In thisexample, the <from> tag implicitly creates the NMR endpoint,

nmr:ExampleRouter, which is then capable of receiving the messages

sent by the first route.

NoteThe NMR is a general purpose message bus that operatesindependently of the JBI container. Hence, it is possible tocreate NMR endpoints outside the JBI container, as is done inthis example.

Configuring the bundle headersThe bundle headers are defined in the JAR's manifest file, which is stored inthe following location:

META-INF/MANIFEST.MF

Example 6 on page 34 shows the manifest for the camel-nmr bundle (for a

more detailed explanation of these manifest entries, seeExample 3 on page 22).

33

Using the NMR Component

Page 34: Enterprise Integration Patterns (OSGi Container)

Example 6. Manifest for the camel-nmr Demonstration

Manifest-Version: 1.0Built-By: YOURUSERNAMECreated-By: Apache Maven Bundle PluginBundle-License: http://www.apache.org/licenses/LICENSE-2.0.txtImport-Package: org.apache.commons.logging,org.apache.servicemix.camel.nmr,org.apache.servicemix.nmr.apiBnd-LastModified: 1222082014067Bundle-Version: 4.0.0.fuseBundle-Name: Apache ServiceMix Example :: Camel NMRBundle-Description: This pom provides project information thatis common to all ServiceMix branches.Build-Jdk: 1.5.0_08Private-Package: org.apache.servicemix.examples.camelBundle-DocURL: http://www.apache.org/Bundle-ManifestVersion: 2Bundle-Vendor: The Apache Software FoundationBundle-SymbolicName: camel-nmrTool: Bnd-0.0.255

The important entries are the bundle headers that affect the interactionbetween the bundle and the OSGi container and these are, as follows:

Bundle-Name:A human-readable name for the current bundle.

Bundle-SymbolicName:A unique name for the current bundle.

Import-Package:A comma-separated list of Java package names for all of the packagesneeded by, but not included in this bundle. The following packages areimported into this bundle:

• org.apache.commons.logging—the Apache Commons logging API

is used in the MyTransform bean (see Example 2 on page 21).

• org.apache.servicemix.camel.nmr—this package contains the

camel-nmr.xml file, which is imported into the XML configuration in

order to initialize the NMR component bean (seeExample 5 on page 32).

34

Deploying Integration Patterns

Page 35: Enterprise Integration Patterns (OSGi Container)

• org.apache.servicemix.camel.nmr.api—this package contains

the NMR API.

35

Using the NMR Component

Page 36: Enterprise Integration Patterns (OSGi Container)

Running the camel-nmr DemonstrationRunning from a remote repository

To install and run the camel-nmr demonstration, where the demonstration

bundle is downloaded from a remote repository, perform the following steps:

1. Install and start the camel-nmr bundle—at the FUSE ESB console, enterthe following command:

servicemix> features install examples-camel-nmr

This command has the effect of both installing and starting the camel-nmr

bundle. After entering this command, you should soon see output like thefollowing being logged to the console screen:

>>>> MyTransform set body: Mon Sep 22 12:09:10 BST 2008>>>> MyTransform set body: Mon Sep 22 12:09:12 BST 2008>>>> MyTransform set body: Mon Sep 22 12:09:14 BST 2008

2. Stop the camel-nmr bundle—to stop the camel-nmr bundle, you first

need to discover the relevant bundle number. To find the bundle number,enter the following console command (this might look a bit confusing,because the text you are typing will intermingle with the output that isbeing logged to the screen):

servicemix> osgi list

At the end of the listing, you should see an entry like the following:

[ 129] [Active ] [ 50] Apache ServiceMix Example ::Camel NMR (4.0.0.2-fuse)

Where, in this example, the bundle number is 129. To stop this bundle,enter the following console command:

servicemix> osgi stop 129

Running from a local buildTo install and run the camel-nmr demonstration, where the demonstration

bundle is built locally, perform the following steps:

1. If you have not done so already, install the camel-nmr feature by entering

the following command at the FUSE ESB console:

36

Deploying Integration Patterns

Page 37: Enterprise Integration Patterns (OSGi Container)

servicemix> features install camel-nmr

2. Build the demonstration—open a command prompt and change directoryto examples/camel-nmr. Use Maven to build the demonstration by

entering the following command:

mvn install

If this command runs successfully, the examples/camel-nmr/target

directory should contain the bundle file, camel-nmr-4.0.0.2-fuse.jar.

3. Install and start the camel-nmr bundle—at the FUSE ESB console, enterthe following command:

servicemix> osgi install -s file:InstallDir/examples/camel-nmr/target/camel-nmr-4.0.0.2-fuse.jar

Where InstallDir is the directory where you installed FUSE ESB and

the -s flag directs the container to start the bundle right away. For example,

if your install directory isC:\Programs\FUSE\apache-servicemix-4.0.0.2-fuse on a Windows

machine, you would enter the following command:

servicemix> osgi install -s file:C:/Programs/FUSE/apache-servicemix-4.0.0.2-fuse/examples/camel-nmr/target/camel-nmr-4.0.0-fuse-SNAPSHOT.jar

After entering this command, you should soon see output like the followingbeing logged to the console screen:

>>>> MyTransform set body: Mon Sep 22 12:09:10 BST 2008>>>> MyTransform set body: Mon Sep 22 12:09:12 BST 2008>>>> MyTransform set body: Mon Sep 22 12:09:14 BST 2008

NoteWhen specifying the location of a bundle to the osgi install

command, it is essential to use forward slashes, /, in the path

name, even on a Windows machine.

4. Stop the camel-nmr bundle—to stop the camel-nmr bundle, you first

need to discover the relevant bundle number. To find the bundle number,

37

Running the camel-nmr Demonstration

Page 38: Enterprise Integration Patterns (OSGi Container)

enter the following console command (this might look a bit confusing,because the text you are typing will intermingle with the output that isbeing logged to the screen):

servicemix> osgi list

At the end of the listing, you should see an entry like the following:

[ 129] [Active ] [ 50] Apache ServiceMix Example ::Camel NMR (4.0.0.2-fuse)

Where, in this example, the bundle number is 129. To stop this bundle,enter the following console command:

servicemix> osgi stop 129

38

Deploying Integration Patterns

Page 39: Enterprise Integration Patterns (OSGi Container)

Defining Routes in Java DSLYou can define routing rules in Java, using a domain specific language (DSL). The routing rules represent thecore of a router application and Java DSL is currently the most flexible way to define them.

Implementing a RouteBuilder Class ............................................................................................ 40Basic Java DSL Syntax ............................................................................................................ 42Processors ........................................................................................................................... 46Languages for Expressions and Predicates .................................................................................... 51Transforming Message Content .................................................................................................. 56

39

Page 40: Enterprise Integration Patterns (OSGi Container)

Implementing a RouteBuilder ClassOverview

In , you define routes by implementing a RouteBuilder class. You must

override a single method, RouteBuilder.configure(), and in this method

define the routing rules you want to associate with the RouteBuilder. The

rules themselves are defined using a Domain Specific Language (DSL), whichis implemented as a Java API.

You can define as many RouteBuilder classes as you like in a router

application. Ultimately, each RouteBuilder class must get instantiated once

and registered with the CamelContext object. Normally, however, the lifecycle

of the RouteBuilder objects is managed automatically by the container in

which you deploy the router. The core task for a router developer is simplyto implement one or more RouteBuilder classes.

RouteBuilder classThe org.apache.camel.builder.RouteBuilder class is the base class

for implementing your own route builder types. It defines an abstract method,configure(), that you must override in your derived implementation class.

In addition, RouteBuilder also defines methods that are used to initiate the

routing rules (for example, from(), intercept(), and exception()).

Implementing a RouteBuilderExample 7 on page 40 shows an example of a simpler RouteBuilder

implementation. You need only define a single method, configure(), which

contains a list of routing rules (one Java statement for each rule).

Example 7. Implementation of a RouteBuilder Class

import org.apache.camel.builder.RouteBuilder;

public class MyRouteBuilder extends RouteBuilder {

public void configure() {// Define routing rules here:from("file:src/data?noop=true").to("file:target/mes

sages");

// More rules can be included, in you like.// ...

40

Defining Routes in Java DSL

Page 41: Enterprise Integration Patterns (OSGi Container)

}}

Where the rule of the form from(URL1).to(URL2) instructs the router to read

messages from the file system located in directory, src/data, and send them

to files located in the directory, target/messages. The option, ?noop=true,

specifies that the source messages are not to be deleted from the src/data

directory.

41

Implementing a RouteBuilder Class

Page 42: Enterprise Integration Patterns (OSGi Container)

Basic Java DSL SyntaxWhat is a DSL?

A Domain Specific Language (DSL) is essentially a mini-language designedfor a special purpose. The DSL is not required to be logically complete; itneed only have enough expressive power to describe problems adequately inthe chosen domain.

Typically, a DSL does not require a dedicated parser, interpreter, or compiler.You can piggyback a DSL on top of an existing object-oriented host languageby observing that it is possible to map an API in a host language to aspecialized language syntax: that is, a sequence of commands in the DSLmaps to a chain of method invocations in the host language. For example, asequence of commands in some hypothetical DSL that might look like this:

command01;command02;command03;

Can be mapped to a chain of Java invocations, like this:

command01().command02().command03()

You could even define blocks, for example:

command01().startBlock().command02().command03().endBlock()

The syntax of the DSL is implicitly defined by the type system of thespecialized API. For example, the return type of a method determines whichmethods can legally be invoked next (equivalent to the next command in theDSL).

Router rule syntaxThe defines a router DSL for defining routing rules. You can use this DSL todefine rules in the body of a RouteBuilder.configure() implementation.

Figure 2 on page 43 shows an overview of the basic syntax for defining localrouting rules.

42

Defining Routes in Java DSL

Page 43: Enterprise Integration Patterns (OSGi Container)

Figure 2. Local Routing Rules

A local rule always starts with a from("EndpointURL") method, which

specifies the source of messages for the routing rule. You can then add anarbitrarily long chain of processors to the rule (for example, filter()),

finishing off the rule with a to("EndpointURL") method, which specifies the

target for the messages that pass through the rule. It is not always necessaryto end a rule with to(), however. There are alternative ways of specifying

the message target in a rule.

NoteIt is also possible to define a global routing rule, by starting the rulewith a special processor type (such as intercept(), exception(),

errorHandler(), and so on). This kind of rule lies outside the scope

of the Getting Started guide.

Sources and targetsA local rule always starts by defining a source endpoint, usingfrom("EndpointURL"), and typically (but not always) ends by defining a

target endpoint, using to("EndpointURL"). The endpoint URLs,

EndpointURL, can use any of the components configured at deploy time. For

example, you could use a file endpoint, file:MyMessageDirectory, a CXF

endpoint, cxf:MyServiceName, or an ActiveMQ endpoint,

43

Basic Java DSL Syntax

Page 44: Enterprise Integration Patterns (OSGi Container)

activemq:queue:MyQName. For a complete list of component types, see

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

ProcessorsA processor is a method that can access and modify the stream of messagespassing through a rule. If a message is part of a remote procedure call (InOutcall), the processor can potentially act on the messages flowing in bothdirections: on the request messages, flowing from source to target, and onthe reply messages, flowing from target back to source (see Messageexchanges on page 44). Processors can take expression or predicatearguments, that modify their behavior. For example, the rule shown inFigure 2 on page 43 includes a filter() processor that takes an xpath()

predicate as its argument.

Expressions and predicatesExpressions (evaluating to strings or other data types) and predicates(evaluating to true or false) occur frequently as arguments to the built-inprocessor types. You do not have to worry much about which type to pass toan expression argument, because they are usually automatically converted tothe type you need. For example, you can usually just pass a string into anexpression argument. Predicate expressions are useful for defining conditionalbehaviour in a route. For example, the following filter rule propagates Inmessages, only if the foo header is equal to the value bar:

from("seda:a").filter(header("foo").isEqualTo("bar")).to("seda:b");

Where the filter is qualified by the predicate,header("foo").isEqualTo("bar"). To construct more sophisticated

predicates and expressions, based on the message content, you can use oneof the expression and predicate languages (see Languages for Expressionsand Predicates on page 51).

Message exchangesWhen a router rule is activated, it can process messages passing in eitherdirection: that is, from source to target or from target back to source. Forexample, if a router rule is mediating a remote procedure call (RPC), the rulewould process requests, replies, and faults. How do you manage messagecorrelation in this case? One of the most effective and straightforward waysis to use a message exchange object as the basis for processing messages.uses message exchange objects (of org.apache.camel.Exchange type) in

its API for processing router rules.

The basic idea of the message exchange is that, instead of accessing requests,replies, and faults separately, you encapsulate the correlated messages inside

44

Defining Routes in Java DSL

Page 45: Enterprise Integration Patterns (OSGi Container)

a single object (an Exchange object). Message correlation now becomes trivial

from the perspective of a processor, because correlated messages areencapsulated in a single Exchange object and processors gain access to

messages through the Exchange object.

Using an Exchange object makes it easy to generalize message processing

to different kinds ofmessage exchange pattern. For example, an asynchronousprotocol might define a message exchange pattern that consists of a singlemessage that flows from the source to the target (an In message). An RPCprotocol, on the other hand, might define a message exchange pattern thatconsists of a request message correlated with either a reply or fault message.Currently, supports the following message exchange patterns:

• InOnly

• RobustInOnly

• InOut

• InOptionalOut

• OutOnly

• RobustOutOnly

• OutIn

• OutOptionalIn

Where these message exchange patterns are represented by constants in theenumeration type, org.apache.camel.ExchangePattern.

45

Basic Java DSL Syntax

Page 46: Enterprise Integration Patterns (OSGi Container)

ProcessorsOverview

To enable the router to do something more interesting than simply connectinga source endpoint to a target endpoint, you can add processors to your route.A processor is a command you can insert into a routing rule in order to performarbitrary processing of the messages that flow through the rule. provides awide variety of different processors, as follows:

• Filter on page 46.

• Choice on page 46.

• Pipeline on page 47

• Recipient list on page 47.

• Splitter on page 47.

• Aggregator on page 48.

• Resequencer on page 48.

• Throttler on page 49.

• Delayer on page 49.

• Custom processor on page 50.

FilterThe filter() processor can be used to prevent uninteresting messages from

reaching the target endpoint. It takes a single predicate argument: if thepredicate is true, the message exchange is allowed through to the target; ifthe predicate is false, the message exchange is blocked. For example, thefollowing filter blocks a message exchange, unless the incoming messagecontains a header, foo, with value equal to bar:

from("SourceURL").filter(header("foo").isEqualTo("bar")).to("TargetURL");

ChoiceThe choice() processor is a conditional statement that is used to route

incoming messages to alternative targets. The alternative targets are eachpreceded by a when() method, which takes a predicate argument. If the

46

Defining Routes in Java DSL

Page 47: Enterprise Integration Patterns (OSGi Container)

predicate is true, the following target is selected, otherwise processing proceedsto the next when() method in the rule. For example, the following choice()

processor directs incoming messages to either Target1, Target2, or Target3,

depending on the values of Predicate1 and Predicate2:

from("SourceURL").choice().when(Predicate1).to("Target1").when(Predicate2).to("Target2").otherwise().to("Target3");

PipelineThe pipeline() processor is used to link together a chain of targets, where

the output of one target is fed into the input of the next target in the pipeline(analogous to the UNIX pipe command). The pipeline() method takes an

arbitrary number of endpoint arguments, which specify the sequence ofendpoints in the pipeline. For example, to pass messages from SourceURL

to Target1 to Target2 to Target3 in a pipeline, you could use the following

rule:

from("SourceURL").pipeline("Target1","Target2","Target3");

Recipient listIf you want the messages from a source endpoint, SourceURL, to be sent to

more than one target, there are two alternative approaches you can use. Oneapproach is to invoke the to() method with multiple target endpoints (static

recipient list), for example:

from("SourceURL").to("Target1","Target2","Target3");

The alternative approach is to invoke the recipientList() processor, which

takes a list of recipients as its argument (dynamic recipient list). The advantageof the recipientList() processor is that the list of recipients can be

calculated at runtime. For example, the following rule generates a recipientlist by reading the contents of the recipientListHeader from the incoming

message:

from("SourceURL").recipientList(header("recipientListHeader").tokenize(","));

SplitterThe splitter() processor is used to split a message into parts, which are

then processed as separate messages. The splitter() method takes a list

47

Processors

Page 48: Enterprise Integration Patterns (OSGi Container)

argument, where each item in the list represents a message part that is to bere-sent as a separate message. For example, the following rule splits the bodyof an incoming message into separate lines and then sends each line to thetarget in a separate message:

from("SourceURL").splitter(bodyAs(String.class).tokenize("\n")).to("TargetURL");

AggregatorThe aggregator() processor is used to aggregate related incoming messages

into a single message. In order to distinguish which messages are eligible tobe aggregated together, you need to define a correlation key for the aggregator.The correlation key is normally derived from a field in the message (forexample, a header field). Messages that have the same correlation key valueare eligible to be aggregated together. You can also optionally specify anaggregation algorithm to the aggregator() processor (the default algorithm

is to pick the latest message with a given value of the correlation key and todiscard the older messages with that correlation key value).

For example, if you are monitoring a data stream that reports stock prices inreal time, you might only be interested in the latest price of each stock symbol.In this case, you could configure an aggregator to transmit only the latestprice for a given stock and discard the older (out-of-date) price notifications.The following rule implements this functionality, where the correlation key isread from the stockSymbol header and the default aggregator algorithm is

used:

from("SourceURL").aggregator(header("stockSymbol")).to("TargetURL");

ResequencerA resequencer() processor is used to re-arrange the order in which incoming

messages are transmitted. The resequencer() method takes a sequence

number as its argument (where the sequence number is calculated from thecontents of a field in the incoming message). Naturally, before you can startre-ordering messages, you need to wait until a certain number of messageshave been received from the source. There are a couple of different ways tospecify how long the resequencer() processor should wait before attempting

to re-order the accumulated messages and forward them to the target, asfollows:

• Batch resequencing—(the default) wait until a specified number ofmessages have accumulated before starting to re-order and forward

48

Defining Routes in Java DSL

Page 49: Enterprise Integration Patterns (OSGi Container)

messages. This processing option is specified by invokingresequencer().batch(). For example, the following resequencing rule

would re-order messages based on the timeOfDay header, waiting until

at least 300 messages have accumulated or 4000 ms have elapsed sincethe last message received.

from("SourceURL").resequencer(header("timeOfDay").batch(newBatchResequencerConfig(300, 4000L)).to("TargetURL");

• Stream resequencing—transmit messages as soon as they arrive unlessthe resequencer detects a gap in the incoming message stream (missingsequence numbers), in which case the resequencer waits until the missingmessages arrive and then forwards the messages in the correct order. Toavoid the resequencer blocking forever, you can specify a timeout (defaultis 1000 ms), after which time the message sequence is transmitted withunresolved gaps. For example, the following resequencing rule detects gapsin the message stream by monitoring the value of the sequenceNumber

header, where the maximum buffer size is limited to 5000 and the timeoutis specified to be 4000 ms:

from("SourceURL").resequencer(header("sequenceNumber")).stream(new StreamResequencerConfig(5000,4000L)).to("TargetURL");

ThrottlerThe throttler() processor is used to ensure that a target endpoint does

not get overloaded. The throttler works by limiting the number of messagesthat can pass through per second. If the incoming messages exceed thespecified rate, the throttler accumulates excess messages in a buffer andtransmits them more slowly to the target endpoint. For example, to limit therate of throughput to 100 messages per second, you can define the followingrule:

from("SourceURL").throttler(100).to("TargetURL");

DelayerThe delayer() processor is used to hold up messages for a specified length

of time. The delay can either be relative (wait a specified length of time afterreceipt of the incoming message) or absolute (wait until a specific time). Forexample, to add a delay of 2 seconds before transmitting received messages,you can use the following rule:

49

Processors

Page 50: Enterprise Integration Patterns (OSGi Container)

from("SourceURL").delayer(2000).to("TargetURL");

To wait until the absolute time specified in the processAfter header, you

can use the following rule:

from("SourceURL").delayer(header("processAfter").to("TargetURL");

The delayer() method is overloaded, such that an integer is interpreted as

a relative delay and an expression (for example, a string) is interpreted as anabsolute delay.

Custom processorIf none of the standard processors described here provide the functionalityyou need, you can always define your own custom processor. To create acustom processor, define a class that implements theorg.apache.camel.Processor interface and override the process()

method in this class. For example, the following custom processor,MyProcessor, removes the header named foo from incoming messages:

Example 8. Implementing a Custom Processor Class

public class MyProcessor implements org.apache.camel.Processor{

public void process(org.apache.camel.Exchange exchange){

inMessage = exchange.getIn();if (inMessage != null) {

inMessage.removeHeader("foo");}

}};

To insert the custom processor into a router rule, invoke the process()

method, which provides a generic mechanism for inserting processors intorules. For example, the following rule invokes the processor defined inExample 8 on page 50:

org.apache.camel.Processor myProc = new MyProcessor();

from("SourceURL").process(myProc).to("TargetURL");

50

Defining Routes in Java DSL

Page 51: Enterprise Integration Patterns (OSGi Container)

Languages for Expressions and PredicatesOverview

To provide you with greater flexibility when parsing and processing messages,supports language plug-ins for various scripting languages. For example, ifan incoming message is formatted as XML, it is relatively easy to extract thecontents of particular XML elements or attributes from the message using alanguage such as XPath. The implements script builder classes, whichencapsulate the imported languages. Each languages is accessed through astatic method that takes a script expression as its argument, processes thecurrent message using that script, and then returns an expression or apredicate. In order to be usable as an expression or a predicate, the scriptbuilder classes implement the following interfaces:

org.apache.camel.Expression<E>org.apache.camel.Predicate<E>

In addition to this, the ScriptBuilder class (which wraps scripting languages

such as JavaScript, and so on) inherits from the following interface:

org.apache.camel.Processor

Which implies that the languages associated with the ScriptBuilder class

can also be used as message processors (see Custom processor on page 50).

SimpleThe simple language is a very limited expression language that is built intothe router core. This language can be useful, if you need to eliminatedependancies on third-party libraries whilst testing. Otherwise, you shoulduse one of the other languages. To use the simple language in your applicationcode, include the following import statement in your Java source files:

import static org.apache.camel.language.simple.SimpleLanguage.simple;

The simple language provides various elementary expressions that returndifferent parts of a message exchange. For example, the expression,simple("header.timeOfDay"), would return the contents of a header called

timeOfDay from the incoming message. You can also construct predicates

by testing expressions for equality. For example, the predicate,simple("header.timeOfDay = '14:30'"), tests whether the timeOfDay

header in the incoming message is equal to 14:30. Table 1 on page 52

shows the list of elementary expressions supported by the simple language.

51

Languages for Expressions and Predicates

Page 52: Enterprise Integration Patterns (OSGi Container)

Table 1. Properties for Simple Language

DescriptionElementary Expression

Access the body of the incoming message.body

Access the body of the outgoing message.out.body

Access the contents of the HeaderName header

from the incoming message.

header.HeaderName

Access the contents of the HeaderName header

from the outgoing message.

out.header.HeaderName

Access the PropertyName property on the

exchange.

property.PropertyName

XPathThe xpath() static method parses message content using the XPath language

(to learn about XPath, see the W3 Schools tutorial,http://www.w3schools.com/xpath/default.asp). To use the XPath language inyour application code, include the following import statement in your Javasource files:

import static org.apache.camel.builder.xml.XPathBuilder.xpath;

You can pass an XPath expression to xpath() as a string argument. The

XPath expression implicitly acts on the message content and returns a nodeset as its result. Depending on the context, the return value is interpretedeither as a predicate (where an empty node set is interpreted as false) or anexpression. For example, if you are processing an XML message with thefollowing content:

<person user="paddington"><firstName>Paddington</firstName><lastName>Bear</lastName><city>London</city>

</person>

You could choose which target endpoint to route the message to, based onthe content of the city element, using the following rule:

from("file:src/data?noop=true").choice().

when(xpath("/person/city = 'London'")).to("file:tar

52

Defining Routes in Java DSL

Page 53: Enterprise Integration Patterns (OSGi Container)

get/messages/uk").otherwise().to("file:target/messages/others");

Where the return value of xpath() is treated as a predicate in this example.

XQueryThe xquery() static method parses message content using the XQuery

language (to learn about XQuery, see the W3 Schools tutorial,http://www.w3schools.com/xquery/default.asp). XQuery is a superset of theXPath language; hence, any valid XPath expression is also a valid XQueryexpression. To use the XQuery language in your application code, include thefollowing import statement in your Java source files:

import static org.apache.camel.builder.saxon.XQueryBuilder.xquery;

You can pass an XQuery expression to xquery() in several different ways.

For simple expressions, you can pass the XQuery expressions as a string,java.lang.String. For longer XQuery expressions, on the other hand, you

might prefer to store the expression in a file, which you can then referenceby passing a java.io.File argument or a java.net.URL argument to the

overloaded xquery() method. The XQuery expression implicitly acts on the

message content and returns a node set as its result. Depending on thecontext, the return value is interpreted either as a predicate (where an emptynode set is interpreted as false) or an expression.

JoSQLThe sql() static method enables you to call on the JoSQL (SQL for Java

objects) language to evaluate predicates and expressions in . JoSQL employsa SQL-like query syntax to perform selection and ordering operations on datafrom in-memory Java objects—JoSQL is not a database, however. In theJoSQL syntax, each Java object instance is treated like a table row and eachobject method is treated like a column name. Using this syntax, it is possibleto construct powerful statements for extracting and compiling data fromcollections of Java objects. For details, see http://josql.sourceforge.net/.

To use the JoSQL language in your application code, include the followingimport statement in your Java source files:

53

Languages for Expressions and Predicates

Page 54: Enterprise Integration Patterns (OSGi Container)

import static org.apache.camel.builder.sql.SqlBuilder.sql;

OGNLThe ognl() static method enables you to call on OGNL (Object Graph

Navigation Language) expressions, which can then be used as predicates andexpressions in a router rule. For details, see http://www.ognl.org/.

To use the OGNL language in your application code, include the followingimport statement in your Java source files:

import static org.apache.camel.language.ognl.OgnlExpression.ognl;

ELThe el() static method enables you to call on the Unified Expression

Language (EL) to construct predicates and expressions in a router rule. TheEL was originally specified as part of the JSP 2.1 standard (JSR-245), butis now available as a standalone language. integrates with JUEL(http://juel.sourceforge.net/), which is an open source implementation of theEL language.

To use the EL language in your application code, include the following importstatement in your Java source files:

import static org.apache.camel.language.juel.JuelExpression.el;

GroovyThe groovy() static method enables you to call on the Groovy scripting

language to construct predicates and expressions in a route. To use the Groovylanguage in your application code, include the following import statement inyour Java source files:

import static org.apache.camel.builder.camel.script.ScriptBuilder.*;

JavaScriptThe javaScript() static method enables you to call on the JavaScript

scripting language to construct predicates and expressions in a route. To usethe JavaScript language in your application code, include the following importstatement in your Java source files:

54

Defining Routes in Java DSL

Page 55: Enterprise Integration Patterns (OSGi Container)

import static org.apache.camel.builder.camel.script.ScriptBuilder.*;

PHPThe php() static method enables you to call on the PHP scripting language

to construct predicates and expressions in a route. To use the PHP languagein your application code, include the following import statement in your Javasource files:

import static org.apache.camel.builder.camel.script.ScriptBuilder.*;

PythonThe python() static method enables you to call on the Python scripting

language to construct predicates and expressions in a route. To use the Pythonlanguage in your application code, include the following import statement inyour Java source files:

import static org.apache.camel.builder.camel.script.ScriptBuilder.*;

RubyThe ruby() static method enables you to call on the Ruby scripting language

to construct predicates and expressions in a route. To use the Ruby languagein your application code, include the following import statement in your Javasource files:

import static org.apache.camel.builder.camel.script.ScriptBuilder.*;

BeanYou can also use Java beans to evaluate predicates and expressions. Forexample, to evaluate the predicate on a filter using the isGoldCustomer()

method on the bean instance, myBean, you can use a rule like the following:

from("SourceURL").filter().method("myBean", "isGoldCustomer").to("TargetURL");

A discussion of bean integration in is beyond the scope of this Defining Routesguide. For details, see http://activemq.apache.org/camel/bean-language.html.

55

Languages for Expressions and Predicates

Page 56: Enterprise Integration Patterns (OSGi Container)

Transforming Message ContentOverview

supports a variety of approaches to transforming message content. In additionto a simple native API for modifying message content, supports integrationwith serveral different third-party libraries and transformation standards. Thefollowing kinds of transformation are discussed in this section:

• Simple transformations on page 56.

• Marshalling and unmarshalling on page 60.

• Artix Data Services on page 61.

Simple transformationsThe Java DSL has a built-in API that enables you to perform simpletransformations on incoming and outgoing messages. For example, the ruleshown in Example 9 on page 56 would append the text, World!, to the

end of the incoming message body.

Example 9. Simple Transformation of Incoming Messages

from("SourceURL").setBody(body().append(" World!")).to("TargetURL");

Where the setBody() command replaces the content of the incoming

message's body. You can use the following API classes to perform simpletransformations of the message content in a router rule:

• org.apache.camel.model.ProcessorType

• org.apache.camel.builder.Builder

• org.apache.camel.builder.ValueBuilder

ProcessorType classThe org.apache.camel.model.ProcessorType class defines the DSL

commands you can insert directly into a router rule—for example, thesetBody() command in Example 9 on page 56. Table 2 on page 57 shows

the ProcessorType methods that are relevant to transforming message

content:

56

Defining Routes in Java DSL

Page 57: Enterprise Integration Patterns (OSGi Container)

Table 2. Transformation Methods from the ProcessorType Class

DescriptionMethod

Converts the IN message body to the specified type.Type convertBodyTo(Class type)

Converts the FAULT message body to the specified type.Type convertFaultBodyTo(Class type)

Converts the OUT message body to the specified type.Type convertOutBodyTo(Class type)

Adds a processor which removes the header on theFAULT message.

Type removeFaultHeader(String name)

Adds a processor which removes the header on the INmessage.

Type removeHeader(String name)

Adds a processor which removes the header on the OUTmessage.

Type removeOutHeader(String name)

Adds a processor which removes the exchange property.Type removeProperty(String name)

Adds a processor which sets the body on the IN message.ExpressionClause<ProcessorType<Type>>

setBody()

Adds a processor which sets the body on the IN message.ExpressionClause<ProcessorType<Type>>

setBody()

Adds a processor which sets the body on the FAULTmessage.

Type setFaultBody(Expression expression)

Adds a processor which sets the header on the FAULTmessage.

Type setFaultHeader(String name, Expression

expression)

Adds a processor which sets the header on the INmessage.

ExpressionClause<ProcessorType<Type>>

setHeader(String name)

Adds a processor which sets the header on the INmessage.

Type setHeader(String name, Expression

expression)

Adds a processor which sets the body on the OUTmessage.

ExpressionClause<ProcessorType<Type>>

setOutBody()

Adds a processor which sets the body on the OUTmessage.

Type setOutBody(Expression expression)

Adds a processor which sets the header on the OUTmessage.

ExpressionClause<ProcessorType<Type>>

setOutHeader(String name)

57

Transforming Message Content

Page 58: Enterprise Integration Patterns (OSGi Container)

DescriptionMethod

Adds a processor which sets the header on the OUTmessage.

Type setOutHeader(String name, Expression

expression)

Adds a processor which sets the exchange property.ExpressionClause<ProcessorType<Type>>

setProperty(String name)

Adds a processor which sets the exchange property.Type setProperty(String name, Expression

expression)

Builder classThe org.apache.camel.builder.Builder class provides access to message

content in contexts where expressions or predicates are expected. In otherwords, Builder methods are typically invoked in the arguments of DSL

commands—for example, the body() command in Example 9 on page 56.

Table 3 on page 58 summarizes the static methods available in the Builder

class.

Table 3. Methods from the Builder Class

DescriptionMethod

Returns a predicate and value builder for the inboundbody on an exchange.

static <E extends Exchange> ValueBuilder<E>

body()

Returns a predicate and value builder for the inboundmessage body as a specific type.

static <E extends Exchange,T> ValueBuilder<E>

bodyAs(Class<T> type)

Returns a constant expression.static <E extends Exchange> ValueBuilder<E>

constant(Object value)

Returns a predicate and value builder for the fault bodyon an exchange.

static <E extends Exchange> ValueBuilder<E>

faultBody()

Returns a predicate and value builder for the faultmessage body as a specific type.

static <E extends Exchange,T> ValueBuilder<E>

faultBodyAs(Class<T> type)

Returns a predicate and value builder for headers on anexchange.

static <E extends Exchange> ValueBuilder<E>

header(String name)

58

Defining Routes in Java DSL

Page 59: Enterprise Integration Patterns (OSGi Container)

DescriptionMethod

Returns a predicate and value builder for the outboundbody on an exchange.

static <E extends Exchange> ValueBuilder<E>

outBody()

Returns a predicate and value builder for the outboundmessage body as a specific type.

static <E extends Exchange> ValueBuilder<E>

outBody()

Returns an expression for the given system property.static <E extends Exchange> ValueBuilder<E>

systemProperty(String name)

Returns an expression for the given system property.static <E extends Exchange> ValueBuilder<E>

systemProperty(String name, String

defaultValue)

ValueBuilder classThe org.apache.camel.builder.ValueBuilder class enables you to

modify values returned by the Buildermethods. In other words, the methods

in ValueBuilder provide a simple way of modifying message content.

Table 4 on page 59 summarizes the methods available in the ValueBuilder

class. That is, the table shows only the methods that are used to modify thevalue they are invoked on (for full details, see the API Referencedocumentation).

Table 4. Modifier Methods from the ValueBuilder Class

DescriptionMethod

Appends the string evaluation of this expression with thegiven value.

ValueBuilder<E> append(Object value)

Converts the current value to the given type using theregistered type converters.

ValueBuilder<E> convertTo(Class type)

Converts the current value a String using the registeredtype converters.

ValueBuilder<E> convertToString()

Replaces all occurrencies of the regular expression withthe given replacement.

ValueBuilder<E> regexReplaceAll(String regex,

Expression<E> replacement)

Replaces all occurrencies of the regular expression withthe given replacement.

ValueBuilder<E> regexReplaceAll(String regex,

String replacement)

59

Transforming Message Content

Page 60: Enterprise Integration Patterns (OSGi Container)

DescriptionMethod

Tokenizes the string conversion of this expression usingthe given regular expression.

ValueBuilder<E> regexTokenize(String regex)

ValueBuilder<E> tokenize()

Tokenizes the string conversion of this expression usingthe given token separator.

ValueBuilder<E> tokenize(String token)

Marshalling and unmarshallingYou can convert between low-level and high-level message formats using thefollowing commands:

• marshal()—convert a high-level data format to a low-level data format.

• unmarshal()—convert a low-level data format to a high-level data format.

supports marshalling and unmarshalling of the following data formats:

• Java serialization—enables you to convert a Java object to a blob of binarydata. For this data format, unmarshalling converts a binary blob to a Javaobject and marshalling converts a Java object to a binary blob. For example,to read a serialized Java object from an endpoint, SourceURL, and convert

it to a Java object, you could use the following rule:

from("SourceURL").unmarshal().serialization().<FurtherProcessing>.to("TargetURL");

• JAXB—provides a mapping between XML schema types and Java types(see https://jaxb.dev.java.net/). For JAXB, unmarshalling converts an XMLdata type to a Java object and marshalling converts a Java object to anXML data type. Before you can use JAXB data formats, you must compileyour XML schema using a JAXB compiler in order to generate the Javaclasses that represent the XML data types in the schema. This is calledbinding the schema. After you have bound the schema, you can define arule to unmarshal XML data to a Java object, using code like the following:

org.apache.camel.spi.DataFormat jaxb = neworg.apache.camel.model.dataformat.JaxbDataFormat("GeneratedPackageName");

from("SourceURL").unmarshal(jaxb).<FurtherProcessing>.to("TargetURL");

60

Defining Routes in Java DSL

Page 61: Enterprise Integration Patterns (OSGi Container)

Where GeneratedPackagename is the name of the Java package generated

by the JAXB compiler, which contains the Java classes representing yourXML schema.

• XMLBeans—provides an alternative mapping between XML schema typesand Java types (see http://xmlbeans.apache.org/). For XMLBeans,unmarshalling converts an XML data type to a Java object and marshallingconverts a Java object to an XML data type. For example, to unmarshalXML data to a Java object using XMLBeans, you can use code like thefollowing:

from("SourceURL").unmarshal().xmlBeans().<FurtherProcessing>.to("TargetURL");

• XStream—provides another mapping between XML types and Java types(see http://xstream.codehaus.org/). XStream is a serialization library (likeJava serialization), enabling you to convert any Java object to XML. ForXStream, unmarshalling converts an XML data type to a Java object andmarshalling converts a Java object to an XML data type. For example, tounmarshal XML data to a Java object using XStream, you can use codelike the following:

from("SourceURL").unmarshal().xstream().<FurtherProcessing>.to("TargetURL");

• Artix Data Services— also integrates with Artix Data Services, enablingyou to integrate stub code generated by Artix Data Services. See Artix DataServices on page 61 for details.

Artix Data ServicesArtix Data Services is a powerful tool for converting documents and messagesbetween different data formats. In Artix Data Services, you can use a graphcialtool to define complex mapping rules (including processing of data content)and then generate stub code to implement the mapping rules (see ProgressArtix Data Services[http://www.iona.com/products/artix/data_services.htm?WT.mc_id=125795]home page and the Artix Data Services documentation[http://www.iona.com/support/docs/artix/data_services/3.6/index.xml] formore details). The marshal() and unmarshal() DSL commands are capable

of consuming Artix Data Services stub code in order to perform transformationson message formats. For example, Example 10 on page 62 shows a rulethat unmarshals XML documents into a canonical format (Java objects) andthen marshals the canonical format into the tag/value pair format.

61

Transforming Message Content

Page 62: Enterprise Integration Patterns (OSGi Container)

Example 10. Using Artix Data Services to Marshal and Unmarshal

from("SourceURL").unmarshal().artixDS(DocumentElement.class, ArtixDSContent

Type.Xml).marshal().artixDS(ArtixDSContentType.TagValuePair).

to("TargetURL");

NoteArtix Data Services is licensed separately from .

62

Defining Routes in Java DSL

Page 63: Enterprise Integration Patterns (OSGi Container)

Defining Routes in XMLYou can define routing rules in XML. This approach is not as flexible as Java DSL, but has the advantage that itis easy to reconfigure the routing rules at runtime.

Using the Router Schema in an XML File ..................................................................................... 64Defining a Basic Route in XML .................................................................................................. 66Processors ........................................................................................................................... 67Languages for Expressions and Predicates .................................................................................... 74Transforming Message Content .................................................................................................. 76

63

Page 64: Enterprise Integration Patterns (OSGi Container)

Using the Router Schema in an XML FileOverview

The root element of the router schema is camelContext, which is defined

in the XML namespace,http://activemq.apache.org/camel/schema/spring. Router

configurations are typically embedded in other XML configuration files (forexample, in a Spring configuration file). In general, whenever a routerconfiguration is embedded in another configuration file, you need to specifythe location of the router schema (so that the router configuration can beparsed). For example, Example 11 on page 64 shows how to embed therouter configuration, camelContext, in an arbitrary document,

DocRootElement.

Example 11. Specifying the Router Schema Location

<DocRootElement ...xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://activemq.apache.org/camel/schema/spring ht

tp://activemq.apache.org/camel/schema/spring/camel-spring.xsd">

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

<!-- Define your routing rules here --></camelContext>

</DocRootElement>

Where the schema location is specified to behttp://activemq.apache.org/camel/schema/spring/camel-spring.xsd,

which gives the location of the schema on the Apache Web site. This locationalways contains the latest, most up-to-date version of the XML schema. Ifyou prefer to tie your configuration to a specific version of the schema, changethe schema file name to camel-spring-Version.xsd, where Version can

be one of: 1.0.0, 1.1.0, 1.2.0, 1.3.0, or 1.4.0. For example, the location

of schema version 1.4.0 would be specified ashttp://activemq.apache.org/camel/schema/spring/camel-spring-1.4.0.xsd.

Example 12 on page 65 shows an example of embedding a routerconfiguration, camelContext, in a Spring configuration file.

64

Defining Routes in XML

Page 65: Enterprise Integration Patterns (OSGi Container)

Example 12. Router Schema in a Spring Configuration File

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans ht

tp://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.xsd">

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

<!-- Define your routing rules in here --></camelContext><!-- Other Spring configuration --><!-- ... -->

</beans>

65

Using the Router Schema in an XML File

Page 66: Enterprise Integration Patterns (OSGi Container)

Defining a Basic Route in XMLBasic concepts

In order to understand how to build a route using XML, you need to understandsome of the basic concepts of the routing language—for example, sourcesand targets, processors, expressions and predicates, and message exchanges.For definitions and explanations of these concepts see Basic Java DSLSyntax on page 42.

Example of a basic routeExample 13 on page 66 shows an example of a basic route in XML, whichconnects a source endpoint, SourceURL, directly to a destination endpoint,

TargetURL.

Example 13. Basic Route in XML

<camelContext id="CamelContextID" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><to uri="TargetURL"/>

</route></camelContext>

Where CamelContextID is an arbitrary, unique identifier for the Camel

context. The route is defined by a route element and there can be multiple

route elements under the camelContext element.

66

Defining Routes in XML

Page 67: Enterprise Integration Patterns (OSGi Container)

ProcessorsOverview

To enable the router to something more interesting than simply connecting asource endpoint to a target endpoint, you can add processors to your route.A processor is a command you can insert into a routing rule in order to performarbitrary processing of the messages that flow through the rule. provides awide variety of different processors, as follows:

• Filter on page 67.

• Choice on page 68.

• Recipient list on page 68.

• Splitter on page 69.

• Aggregator on page 70.

• Resequencer on page 70.

• Throttler on page 72.

• Delayer on page 72.

FilterThe filter processor can be used to prevent uninteresting messages from

reaching the target endpoint. It takes a single predicate argument: if thepredicate is true, the message exchange is allowed through to the target; ifthe predicate is false, the message exchange is blocked. For example, thefollowing filter blocks a message exchange, unless the incoming messagecontains a header, foo, with value equal to bar:

<camelContext id="filterRoute" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><filter><simple>header.foo = 'bar'</simple><to uri="TargetURL"/>

</filter>

67

Processors

Page 68: Enterprise Integration Patterns (OSGi Container)

</route></camelContext>

ChoiceThe choice processor is a conditional statement that is used to route incoming

messages to alternative targets. The alternative targets are each enclosed ina when element, which takes a predicate argument. If the predicate is true,

the current target is selected, otherwise processing proceeds to the next when

element in the rule. For example, the following choice() processor directs

incoming messages to either Target1, Target2, or Target3, depending on

the values of the predicates:

<camelContext id="buildSimpleRouteWithChoice" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><choice><when><!-- First predicate --><simple>header.foo = 'bar'</simple><to uri="Target1"/>

</when><when><!-- Second predicate --><simple>header.foo = 'manchu'</simple><to uri="Target2"/>

</when><otherwise><to uri="Target3"/>

</otherwise></choice>

</route></camelContext>

Recipient listIf you want the messages from a source endpoint, SourceURL, to be sent to

more than one target, there are two alternative approaches you can use. Oneapproach is to include multiple to elements in the route, for example:

<camelContext id="staticRecipientList" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><to uri="Target1"/><to uri="Target2"/>

68

Defining Routes in XML

Page 69: Enterprise Integration Patterns (OSGi Container)

<to uri="Target3"/></route>

</camelContext>

The alternative approach is to add arecipientList element, which takes

a list of recipients as its argument (dynamic recipient list). The advantage ofusing the recipientList element is that the list of recipients can be

calculated at runtime. For example, the following rule generates a recipientlist by reading the contents of the recipientListHeader from the incoming

message:

<camelContext id="dynamicRecipientList" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><recipientList><!-- Requires XPath 2.0 --><xpath>tokenize(/headers/recipientListHead

er,"\s+")</xpath></recipientList>

</route></camelContext>

SplitterThe splitter processor is used to split a message into parts, which are then

processed as separate messages. The splitter element must contain an

expression that returns a list, where each item in the list represents a messagepart that is to be re-sent as a separate message. For example, the followingrule splits the body of an incoming message into separate sections (representedby a top-level section element) and then sends each section to the target

in a separate message:

<camelContext id="splitterRoute" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="seda:a"/><splitter><xpath>/section</xpath><to uri="seda:b"/>

</splitter>

69

Processors

Page 70: Enterprise Integration Patterns (OSGi Container)

</route></camelContext>

AggregatorThe aggregator processor is used to aggregate related incoming messages

into a single message. In order to distinguish which messages are eligible tobe aggregated together, you need to define a correlation key for the aggregator.The correlation key is normally derived from a field in the message (forexample, a header field). Messages that have the same correlation key valueare eligible to be aggregated together. You can also optionally specify anaggregation algorithm to the aggregator processor (the default algorithm is

to pck the latest message with a given value of the correlation key and todiscard the older messages with that correlation key value).

For example, if you are monitoring a data stream that reports stock prices inreal time, you might only be interested in the latest price of each stock symbol.In this case, you could configure an aggregator to transmit only the latestprice for a given stock and discard the older (out-of-date) price notifications.The following rule implements this functionality, where the correlation key isread from the stockSymbol header and the default aggregator algorithm is

used:

<camelContext id="aggregatorRoute" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><aggregator><simple>header.stockSymbol</simple><to uri="TargetURL"/>

</aggregator></route>

</camelContext>

ResequencerA resequencer processor is used to re-arrange the order in which incoming

messages are transmitted. The resequencer element needs to be provided

with a sequence number (where the sequence number is calculated from thecontents of a field in the incoming message). Naturally, before you can startre-ordering messages, you need to wait until a certain number of messageshave been received from the source. There are a couple of different ways tospecify how long the resequencer processor should wait before attempting

to re-order the accumulated messages and forward them to the target, asfollows:

70

Defining Routes in XML

Page 71: Enterprise Integration Patterns (OSGi Container)

• Batch resequencing—(the default) wait until a specified number ofmessages have accumulated before starting to re-order and forwardmessages. For example, the following resequencing rule would re-ordermessages based on the timeOfDay header, waiting until at least 300

messages have accumulated or 4000 ms have elapsed since the lastmessage received.

<camelContext id="batchResequencer" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL" /><resequencer><!-- Sequence ordering based on timeOfDay header --><simple>header.timeOfDay</simple><to uri="TargetURL" /><!--batch-config can be ommitted for default (batch)

resequencer settings--><batch-config batchSize="300" batchTimeout="4000" />

</resequencer></route>

</camelContext>

• Stream resequencing—transmit messages as soon as they ariive unlessthe resequencer detects a gap in the incoming message stream (missingsequence numbers), in which case the resequencer waits until the missingmessages arrive and then forwards the messages in the correct order. Toavoid the resequencer blocking forever, you can specify a timeout (defaultis 1000 ms), after which time the message sequence is transmitted withunresolved gaps. For example, the following resequencing rule detects gapsin the message stream by monitoring the value of the sequenceNumber

header, where the maximum buffer size is limited to 5000 and the timeoutis specified to be 4000 ms:

<camelContext id="streamResequencer" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><resequencer><simple>header.sequenceNumber</simple><to uri="TargetURL" /><stream-config capacity="5000" timeout="4000"/>

</resequencer>

71

Processors

Page 72: Enterprise Integration Patterns (OSGi Container)

</route></camelContext>

ThrottlerThe throttler processor is used to ensure that a target endpoint does not

get overloaded. The throttler works by limiting the number of messages thatcan pass through per second. If the incoming messages exceed the specifiedrate, the throttler accumulates excess messages in a buffer and transmitsthem more slowly to the target endpoint. For example, to limit the rate ofthroughput to 100 messages per second, you can define the following rule:

<camelContext id="throttlerRoute" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><throttler maximumRequestsPerPeriod="100" timePeriodMil

lis="1000"><to uri="TargetURL"/>

</throttler></route>

</camelContext>

DelayerThe delayer processor is used to hold up messages for a specified length of

time. The delay can either be relative (wait a specified length of time afterreceipt of the incoming message) or absolute (wait until a specific time). Forexample, to add a delay of 2 seconds before transmitting received messages,you can use the following rule:

<camelContext id="delayerRelative" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><delayer><delay>2000</delay><to uri="TargetURL"/>

</delayer></route>

</camelContext>

To wait until the absolute time specified in the processAfter header, you

can use the following rule:

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

72

Defining Routes in XML

Page 73: Enterprise Integration Patterns (OSGi Container)

<route><from uri="SourceURL"/><delayer><simple>header.processAfter</simple><to uri="TargetURL"/>

</delayer></route>

</camelContext>

73

Processors

Page 74: Enterprise Integration Patterns (OSGi Container)

Languages for Expressions and PredicatesOverview

In the definition of a route, it is frequently necessary to evaluate expressionsand predicates. For example, if a route includes a filter processor, you needto evaluate a predicate to determine whether or not a message is to be allowedthrough the filter. To facilitate the evaluation of expressions and predicates,supports multiple language plug-ins, which can be accessed through XMLelements.

Elements for expressions andpredicates Table 5 on page 74 lists the elements that you can insert whenever the

context demands an expression or a predicate. The content of the elementmust be a script written in the relevant language. At runtime, the return valueof the script is read by the parent element.

Table 5. Elements for Expression and Predicate Languages

DescriptionLanguageElement

A simple expression language, nativeto (see Simple on page 51).

N/Asimple

The XPath language, which is usedto select element, attribute, and text

XPathxpath

nodes from XML documents (seehttp://www.w3schools.com/xpath/default.asp).The XPath expression is applied tothe current message.

The XQuery language, which is anextension of XPath (see

XQueryxquery

http://www.w3schools.com/xquery/default.asp).The XQuery expression is applied tothe current message.

The JoSQL language, which is alanguage for extracting and

JoSQLsql

manipulating data from collections ofJava objects, using a SQL-like syntax(see http://josql.sourceforge.net/).

The OGNL (Object Graph NavigationLanguage) language (seehttp://www.ognl.org/).

OGNLognl

The Unified Expression Language(EL), originally developed as part of

ELel

74

Defining Routes in XML

Page 75: Enterprise Integration Patterns (OSGi Container)

DescriptionLanguageElement

the JSP standard (seehttp://juel.sourceforge.net/).

The Groovy scripting language (seehttp://groovy.codehaus.org/).

Groovygroovy

The JavaScript scripting language (seehttp://developer.mozilla.org/en/docs/JavaScript),

JavaScriptjavaScript

also known as ECMAScript (seehttp://www.ecmascript.org/).

The PHP scripting language (seehttp://www.php.net/).

PHPphp

The Python scripting language (seehttp://www.python.org/).

Pythonpython

The Ruby scripting language (seehttp://www.ruby-lang.org/).

Rubyruby

Not really a language. The bean

element is actually a mechanism for

Beanbean

integrating with Java beans. You usethe bean element to obtain an

expression or predicate by invoking amethod on a Java bean.

75

Languages for Expressions and Predicates

Page 76: Enterprise Integration Patterns (OSGi Container)

Transforming Message ContentOverview

This section describes how you can transform messages using the featuresprovided in XML configuration.

Marshalling and unmarshallingYou can convert between low-level and high-level message formats using thefollowing elements:

• marshal—convert a high-level data format to a low-level data format.

• unmarshal—convert a low-level data format to a high-level data format.

supports marshalling and unmarshalling of the following data formats:

• Java serialization—enables you to convert a Java object to a blob of binarydata. For this data format, unmarshalling converts a binary blob to a Javaobject and marshalling converts a Java object to a binary blob. For example,to read a serialized Java object from an endpoint, SourceURL, and convert

it to a Java object, you could use the following rule:

<camelContext id="serialization" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><unmarshal><serialization/>

</unmarshal><to uri="TargetURL"/>

</route></camelContext>

• JAXB—provides a mapping between XML schema types and Java types(see https://jaxb.dev.java.net/). For JAXB, unmarshalling converts an XMLdata type to a Java object and marshalling converts a Java object to anXML data type. Before you can use JAXB data formats, you must compileyour XML schema using a JAXB compiler in order to generate the Javaclasses that represent the XML data types in the schema. This is calledbinding the schema. After you have bound the schema, you can define arule to unmarshal XML data to a Java object, as follows:

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

76

Defining Routes in XML

Page 77: Enterprise Integration Patterns (OSGi Container)

<from uri="SourceURL"/><unmarshal><jaxb prettyPrint="true" contextPath="GeneratedPackage

Name"/></unmarshal><to uri="TargetURL"/>

</route></camelContext>

Where GeneratedPackagename is the name of the Java package generated

by the JAXB compiler, which contains the Java classes representing yourXML schema.

• XMLBeans—provides an alternative mapping between XML schema typesand Java types (see http://xmlbeans.apache.org/). For XMLBeans,unmarshalling converts an XML data type to a Java object and marshallingconverts a Java object to an XML data type. For example, to unmarshalXML data to a Java object using XMLBeans, define a rule like the following:

<camelContext id="xmlBeans" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><unmarshal><xmlBeans prettyPrint="true"/>

</unmarshal><to uri="TargetURL"/>

</route></camelContext>

• XStream—is currently not supported in XML configuration.

• Artix Data Services— also integrates with Artix Data Services, enablingyou to integrate stub code generated by Artix Data Services. See Artix DataServices on page 77 for details.

Artix Data ServicesArtix Data Services is a powerful tool for converting documents and messagesbetween different data formats. In Artix Data Services, you can use a graphcialtool to define complex mapping rules (including processing of data content)and then generate stub code to implement the mapping rules (see ProgressArtix Data Services[http://www.iona.com/products/artix/data_services.htm?WT.mc_id=125795]home page and the Artix Data Services documentation[http://www.iona.com/support/docs/artix/data_services/3.6/index.xml] for

77

Transforming Message Content

Page 78: Enterprise Integration Patterns (OSGi Container)

more details). The marshal and unmarshal elements are capable of

consuming Artix Data Services stub code in order to perform transformationson message formats. For example, Example 14 on page 78 shows a rulethat unmarshals XML documents into a canonical format (Java objects) andthen marshals the canonical format into the tag/value pair format.

Example 14. Using Artix Data Services to Marshal and Unmarshal

<camelContext id="artixDS" xmlns="http://activemq.apache.org/camel/schema/spring"><route><from uri="SourceURL"/><unmarshal><artixDS contentType="Xml" elementType

Name="iso.std.iso.x20022.tech.xsd.pacs.x008.x001.x01.DocumentElement"/>

</unmarshal><marshal><artixDS contentType="TagValuePair"/>

</marshal><to uri="TargetURL"/>

</route></camelContext>

Where the contentType attribute can be set to one of the following values:

TagValuePair, Sax, Xml, Java, Text, Binary, Auto, Default.

NoteArtix Data Services is licensed separately from .

78

Defining Routes in XML