Upload
ibrahim-candir
View
398
Download
3
Embed Size (px)
Citation preview
FUSE™ ESBEnterprise Integration Patterns (OSGi Container)
Version 4.0October 2008
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.
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
4
List of Figures1. FUSE Mediation Router Deployed into the OSGi Container ............. 142. Local Routing Rules .............................................................. 43
5
6
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
8
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
10
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
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
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?
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
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
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
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
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&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
❶ 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
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
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
❶ 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
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
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
...<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
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
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
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
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
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
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
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&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
❶ 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
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
• org.apache.servicemix.camel.nmr.api—this package contains
the NMR API.
35
Using the NMR Component
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
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
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
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
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
}}
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
</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
<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
</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
• 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
</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
<route><from uri="SourceURL"/><delayer><simple>header.processAfter</simple><to uri="TargetURL"/>
</delayer></route>
</camelContext>
73
Processors
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
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
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
<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
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