Fuse 6 is no longer supported
As of February 2025, Red Hat Fuse 6 is no longer supported. If you are using Fuse 6, please upgrade to Red Hat build of Apache Camel.Apache Camel Development Guide
Develop applications with Apache Camel
Copyright © 2011-2015 Red Hat, Inc. and/or its affiliates.
Abstract
Part I. Implementing Enterprise Integration Patterns Copy linkLink copied to clipboard!
Abstract
Chapter 1. Building Blocks for Route Definitions Copy linkLink copied to clipboard!
Abstract
1.1. Implementing a RouteBuilder Class Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
RouteBuilder class and override its configure() method (where you define your routing rules).
RouteBuilder classes as necessary. Each class is instantiated once and is registered with the CamelContext object. Normally, the lifecycle of each RouteBuilder object is managed automatically by the container in which you deploy the router.
RouteBuilder classes Copy linkLink copied to clipboard!
RouteBuilder classes. There are two alternative RouteBuilder classes that you can inherit from:
org.apache.camel.builder.RouteBuilder—this is the genericRouteBuilderbase class that is suitable for deploying into any container type. It is provided in thecamel-coreartifact.org.apache.camel.spring.SpringRouteBuilder—this base class is specially adapted to the Spring container. In particular, it provides extra support for the following Spring specific features: looking up beans in the Spring registry (using thebeanRef()Java DSL command) and transactions (see the Transactions Guide for details). It is provided in thecamel-springartifact.
RouteBuilder class defines methods used to initiate your routing rules (for example, from(), intercept(), and exception()).
Implementing a RouteBuilder Copy linkLink copied to clipboard!
RouteBuilder implementation. The configure() method body contains a routing rule; each rule is a single Java statement.
Example 1.1. Implementation of a RouteBuilder Class
from(URL1).to(URL2) instructs the router to read files from the directory src/data and send them to the directory target/messages. The option ?noop=true instructs the router to retain (not delete) the source files in the src/data directory.
contextScan with Spring or Blueprint to filter RouteBuilder classes, by default Apache Camel will look for singleton beans. However, you can turn on the old behavior to include prototype scoped with the new option includeNonSingletons.
1.2. Basic Java DSL Syntax Copy linkLink copied to clipboard!
What is a DSL? Copy linkLink copied to clipboard!
command01; command02; command03;
command01;
command02;
command03;
command01().command02().command03()
command01().command02().command03()
command01().startBlock().command02().command03().endBlock()
command01().startBlock().command02().command03().endBlock()
Router rule syntax Copy linkLink copied to clipboard!
RouteBuilder.configure() implementation. Figure 1.1, “Local Routing Rules” shows an overview of the basic syntax for defining local routing rules.
Figure 1.1. Local Routing Rules
from("EndpointURL") method, which specifies the source of messages (consumer endpoint) for the routing rule. You can then add an arbitrarily long chain of processors to the rule (for example, filter()). You typically finish off the rule with a to("EndpointURL") method, which specifies the target (producer endpoint) for the messages that pass through the rule. However, it is not always necessary to end a rule with to(). There are alternative ways of specifying the message target in a rule.
intercept(), exception(), or errorHandler()). Global rules are outside the scope of this guide.
Consumers and producers Copy linkLink copied to clipboard!
from("EndpointURL"), and typically (but not always) ends by defining a producer 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, an Apache CXF endpoint, cxf:MyServiceName, or an Apache ActiveMQ endpoint, activemq:queue:MyQName. For a complete list of component types, see "Apache Camel Component Reference".
Exchanges Copy linkLink copied to clipboard!
- In message—is the current message encapsulated by the exchange. As the exchange progresses through a route, this message may be modified. So the In message at the start of a route is typically not the same as the In message at the end of the route. The
org.apache.camel.Messagetype provides a generic model of a message, with the following parts:- Body.
- Headers.
- Attachments.
It is important to realize that this is a generic model of a message. Apache Camel supports a large variety of protocols and endpoint types. Hence, it is not possible to standardize the format of the message body or the message headers. For example, the body of a JMS message would have a completely different format to the body of a HTTP message or a Web services message. For this reason, the body and the headers are declared to be ofObjecttype. The original content of the body and the headers is then determined by the endpoint that created the exchange instance (that is, the endpoint appearing in thefrom()command). - Out message—is a temporary holding area for a reply message or for a transformed message. Certain processing nodes (in particular, the
to()command) can modify the current message by treating the In message as a request, sending it to a producer endpoint, and then receiving a reply from that endpoint. The reply message is then inserted into the Out message slot in the exchange.Normally, if an Out message has been set by the current node, Apache Camel modifies the exchange as follows before passing it to the next node in the route: the old In message is discarded and the Out message is moved to the In message slot. Thus, the reply becomes the new current message. For a more detailed discussion of how Apache Camel connects nodes together in a route, see Section 2.1, “Pipeline Processing”.There is one special case where an Out message is treated differently, however. If the consumer endpoint at the start of a route is expecting a reply message, the Out message at the very end of the route is taken to be the consumer endpoint's reply message (and, what is more, in this case the final node must create an Out message or the consumer endpoint would hang) . - Message exchange pattern (MEP)—affects the interaction between the exchange and endpoints in the route, as follows:
- Consumer endpoint—the consumer endpoint that creates the original exchange sets the initial value of the MEP. The initial value indicates whether the consumer endpoint expects to receive a reply (for example, the InOut MEP) or not (for example, the InOnly MEP).
- Producer endpoints—the MEP affects the producer endpoints that the exchange encounters along the route (for example, when an exchange passes through a
to()node). For example, if the current MEP is InOnly, ato()node would not expect to receive a reply from the endpoint. Sometimes you need to change the current MEP in order to customize the exchange's interaction with a producer endpoint. For more details, see Section 1.4, “Endpoints”.
- Exchange properties—a list of named properties containing metadata for the current message.
Message exchange patterns Copy linkLink copied to clipboard!
Exchange object makes it easy to generalize message processing to different message exchange patterns. For example, an asynchronous protocol might define an MEP that consists of a single message that flows from the consumer endpoint to the producer endpoint (an InOnly MEP). An RPC protocol, on the other hand, might define an MEP that consists of a request message and a reply message (an InOut MEP). Currently, Apache Camel supports the following MEPs:
InOnlyRobustInOnlyInOutInOptionalOutOutOnlyRobustOutOnlyOutInOutOptionalIn
org.apache.camel.ExchangePattern.
Grouped exchanges Copy linkLink copied to clipboard!
java.util.List of Exchange objects stored in the Exchange.GROUPED_EXCHANGE exchange property. For an example of how to use grouped exchanges, see Section 8.5, “Aggregator”.
Processors Copy linkLink copied to clipboard!
filter() processor that takes an xpath() predicate as its argument.
Expressions and predicates Copy linkLink copied to clipboard!
foo header is equal to the value bar:
from("seda:a").filter(header("foo").isEqualTo("bar")).to("seda:b");
from("seda:a").filter(header("foo").isEqualTo("bar")).to("seda:b");
header("foo").isEqualTo("bar"). To construct more sophisticated predicates and expressions, based on the message content, you can use one of the expression and predicate languages (see Expression and Predicate Languages).
1.3. Router Schema in a Spring XML File Copy linkLink copied to clipboard!
Namespace Copy linkLink copied to clipboard!
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring
Specifying the schema location Copy linkLink copied to clipboard!
http://camel.apache.org/schema/spring/camel-spring.xsd, which references the latest version of the schema on the Apache Web site. For example, the root beans element of an Apache Camel Spring file is normally configured as shown in Example 1.2, “ Specifying the Router Schema Location”.
Example 1.2. Specifying the Router Schema Location
Runtime schema location Copy linkLink copied to clipboard!
camel-spring JAR file. This ensures that the version of the schema used to parse the Spring file always matches the current runtime version. This is important, because the latest version of the schema posted up on the Apache Web site might not match the version of the runtime you are currently using.
Using an XML editor Copy linkLink copied to clipboard!
xsi:schemaLocation attribute. In order to be sure you are using the correct schema version whilst editing, it is usually a good idea to select a specific version of the camel-spring.xsd file. For example, to edit a Spring file for the 2.3 version of Apache Camel, you could modify the beans element as follows:
camel-spring.xsd, when you are finished editing. To see which schema versions are currently available for download, navigate to the Web page, http://camel.apache.org/schema/spring.
1.4. Endpoints Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Endpoint URIs Copy linkLink copied to clipboard!
scheme:contextPath[?queryOptions]
scheme:contextPath[?queryOptions]
http, and the contextPath provides URI details that are interpreted by the protocol. In addition, most schemes allow you to define query options, queryOptions, which are specified in the following format:
?option01=value01&option02=value02&...
?option01=value01&option02=value02&...
http://www.google.com
http://www.google.com
C:\temp\src\data directory:
file://C:/temp/src/data
file://C:/temp/src/data
timer://tickTock?period=1000
timer://tickTock?period=1000
Working with Long Endpoint URIs Copy linkLink copied to clipboard!
- Configure Endpoints Separately
- You can configure the endpoint separately, and from the routes refer to the endpoints using their shorthand IDs.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow You can also configure some options in the URI and then use thepropertyattribute to specify additional options (or to override options from the URI).<endpoint id="foo" uri="ftp://foo@myserver?recursive=true"> <property name="password" value="secret"/> <property name="ftpClient.dataTimeout" value="30000"/> <property name="ftpClient.serverLanguageCode" value="fr"/> </endpoint>
<endpoint id="foo" uri="ftp://foo@myserver?recursive=true"> <property name="password" value="secret"/> <property name="ftpClient.dataTimeout" value="30000"/> <property name="ftpClient.serverLanguageCode" value="fr"/> </endpoint>Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Split Endpoint Configuration Across New Lines
- You can split URI attributes using new lines.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteYou can specify one or more options on each line, each separated by&.
Specifying time periods in a URI Copy linkLink copied to clipboard!
[NHour(h|hour)][NMin(m|minute)][NSec(s|second)]
[NHour(h|hour)][NMin(m|minute)][NSec(s|second)]
[], is optional and the notation, (A|B), indicates that A and B are alternatives.
timer endpoint with a 45 minute period as follows:
from("timer:foo?period=45m")
.to("log:foo");
from("timer:foo?period=45m")
.to("log:foo");
Specifying raw values in URI options Copy linkLink copied to clipboard!
RAW(RawValue). For example,
from("SourceURI")
.to("ftp:joe@myftpserver.com?password=RAW(se+re?t&23)&binary=true")
from("SourceURI")
.to("ftp:joe@myftpserver.com?password=RAW(se+re?t&23)&binary=true")
se+re?t&23.
Case-insensitive enum options Copy linkLink copied to clipboard!
enum constants. For example, the level option of the Log component, which can take the enum values, INFO, WARN, ERROR, and so on. This type conversion is case-insensitive, so any of the following alternatives could be used to set the logging level of a Log producer endpoint:
<to uri="log:foo?level=info"/> <to uri="log:foo?level=INfo"/> <to uri="log:foo?level=InFo"/>
<to uri="log:foo?level=info"/>
<to uri="log:foo?level=INfo"/>
<to uri="log:foo?level=InFo"/>
Apache Camel components Copy linkLink copied to clipboard!
camel-core artifact), so they are always available:
- Bean
- Browse
- Dataset
- Direct
- File
- Log
- Mock
- Properties
- Ref
- SEDA
- Timer
- VM
Consumer endpoints Copy linkLink copied to clipboard!
from() DSL command). In other words, the consumer endpoint is responsible for initiating processing in a route: it creates a new exchange instance (typically, based on some message that it has received or obtained), and provides a thread to process the exchange in the rest of the route.
payments queue and processes them in the route:
from("jms:queue:payments")
.process(SomeProcessor)
.to("TargetURI");
from("jms:queue:payments")
.process(SomeProcessor)
.to("TargetURI");
from("quartz://secondTimer?trigger.repeatInterval=1000")
.process(SomeProcessor)
.to("TargetURI");
from("quartz://secondTimer?trigger.repeatInterval=1000")
.process(SomeProcessor)
.to("TargetURI");
fromF() Java DSL command. For example, to substitute the username and password into the URI for an FTP endpoint, you could write the route in Java, as follows:
fromF("ftp:%s@fusesource.com?password=%s", username, password)
.process(SomeProcessor)
.to("TargetURI");
fromF("ftp:%s@fusesource.com?password=%s", username, password)
.process(SomeProcessor)
.to("TargetURI");
%s is replaced by the value of the username string and the second occurrence of %s is replaced by the password string. This string formatting mechanism is implemented by String.format() and is similar to the formatting provided by the C printf() function. For details, see java.util.Formatter.
Producer endpoints Copy linkLink copied to clipboard!
to() DSL command). In other words, the producer endpoint receives an existing exchange object and sends the contents of the exchange to the specified endpoint.
from("SourceURI")
.process(SomeProcessor)
.to("jms:queue:orderForms");
from("SourceURI")
.process(SomeProcessor)
.to("jms:queue:orderForms");
from("SourceURI")
.process(SomeProcessor)
.to("http://www.google.com/search?hl=en&q=camel+router");
from("SourceURI")
.process(SomeProcessor)
.to("http://www.google.com/search?hl=en&q=camel+router");
toF() Java DSL command. For example, to substitute a custom Google query into the HTTP URI, you could write the route in Java, as follows:
from("SourceURI")
.process(SomeProcessor)
.toF("http://www.google.com/search?hl=en&q=%s", myGoogleQuery);
from("SourceURI")
.process(SomeProcessor)
.toF("http://www.google.com/search?hl=en&q=%s", myGoogleQuery);
%s is replaced by your custom query string, myGoogleQuery. For details, see java.util.Formatter.
1.5. Processors Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
| Java DSL | XML DSL | Description |
|---|---|---|
aggregate() | aggregate |
Aggregator EIP: Creates an aggregator, which combines multiple incoming exchanges into a single exchange.
|
aop() | aop |
Use Aspect Oriented Programming (AOP) to do work before and after a specified sub-route. See ???.
|
bean(), beanRef() | bean |
Process the current exchange by invoking a method on a Java object (or bean). See Section 2.4, “Bean Integration”.
|
choice() | choice |
Content Based Router EIP: Selects a particular sub-route based on the exchange content, using
when and otherwise clauses.
|
convertBodyTo() | convertBodyTo |
Converts the In message body to the specified type.
|
delay() | delay |
Delayer EIP: Delays the propagation of the exchange to the latter part of the route.
|
doTry() | doTry |
Creates a try/catch block for handling exceptions, using
doCatch, doFinally, and end clauses.
|
end() | N/A | Ends the current command block. |
enrich(),enrichRef() | enrich |
Content Enricher EIP: Combines the current exchange with data requested from a specified producer endpoint URI.
|
filter() | filter |
Message Filter EIP: Uses a predicate expression to filter incoming exchanges.
|
idempotentConsumer() | idempotentConsumer |
Idempotent Consumer EIP: Implements a strategy to suppress duplicate messages.
|
inheritErrorHandler() | @inheritErrorHandler | Boolean option that can be used to disable the inherited error handler on a particular route node (defined as a sub-clause in the Java DSL and as an attribute in the XML DSL). |
inOnly() | inOnly |
Either sets the current exchange's MEP to InOnly (if no arguments) or sends the exchange as an InOnly to the specified endpoint(s).
|
inOut() | inOut |
Either sets the current exchange's MEP to InOut (if no arguments) or sends the exchange as an InOut to the specified endpoint(s).
|
loadBalance() | loadBalance |
Load Balancer EIP: Implements load balancing over a collection of endpoints.
|
log() | log | Logs a message to the console. |
loop() | loop |
Loop EIP: Repeatedly resends each exchange to the latter part of the route.
|
markRollbackOnly() | @markRollbackOnly | (Transactions) Marks the current transaction for rollback only (no exception is raised). In the XML DSL, this option is set as a boolean attribute on the rollback element. See "Transaction Guide". |
markRollbackOnlyLast() | @markRollbackOnlyLast | (Transactions) If one or more transactions have previously been associated with this thread and then suspended, this command marks the latest transaction for rollback only (no exception is raised). In the XML DSL, this option is set as a boolean attribute on the rollback element. See "Transaction Guide". |
marshal() | marshal |
Transforms into a low-level or binary format using the specified data format, in preparation for sending over a particular transport protocol.
|
multicast() | multicast |
Multicast EIP: Multicasts the current exchange to multiple destinations, where each destination gets its own copy of the exchange.
|
onCompletion() | onCompletion |
Defines a sub-route (terminated by
end() in the Java DSL) that gets executed after the main route has completed. For conditional execution, use the onWhen sub-clause. Can also be defined on its own line (not in a route).
|
onException() | onException |
Defines a sub-route (terminated by
end() in the Java DSL) that gets executed whenever the specified exception occurs. Usually defined on its own line (not in a route).
|
pipeline() | pipeline |
Pipes and Filters EIP: Sends the exchange to a series of endpoints, where the output of one endpoint becomes the input of the next endpoint. See also Section 2.1, “Pipeline Processing”.
|
policy() | policy |
Apply a policy to the current route (currently only used for transactional policies—see "Transaction Guide").
|
pollEnrich(),pollEnrichRef() | pollEnrich |
Content Enricher EIP: Combines the current exchange with data polled from a specified consumer endpoint URI.
|
process(),processRef | process |
Execute a custom processor on the current exchange. See the section called “Custom processor” and Part IV, “Programming EIP Components”.
|
recipientList() | recipientList |
Recipient List EIP: Sends the exchange to a list of recipients that is calculated at runtime (for example, based on the contents of a header).
|
removeHeader() | removeHeader |
Removes the specified header from the exchange's In message.
|
removeHeaders() | removeHeaders | Removes the headers matching the specified pattern from the exchange's In message. The pattern can have the form, prefix*—in which case it matches every name starting with prefix—otherwise, it is interpreted as a regular expression. |
removeProperty() | removeProperty |
Removes the specified exchange property from the exchange.
|
removeProperties() | removeProperties |
Removes the properties matching the specified pattern from the exchange. Takes a comma separated list of 1 or more strings as arguments. The first string is the pattern (see
removeHeaders() above). Subsequent strings specify exceptions - these properties remain.
|
resequence() | resequence |
Resequencer EIP: Re-orders incoming exchanges on the basis of a specified comparotor operation. Supports a batch mode and a stream mode.
|
rollback() | rollback |
(Transactions) Marks the current transaction for rollback only (also raising an exception, by default). See "Transaction Guide".
|
routingSlip() | routingSlip |
Routing Slip EIP: Routes the exchange through a pipeline that is constructed dynamically, based on the list of endpoint URIs extracted from a slip header.
|
sample() | sample | Creates a sampling throttler, allowing you to extract a sample of exchanges from the traffic on a route. |
setBody() | setBody |
Sets the message body of the exchange's In message.
|
setExchangePattern() | setExchangePattern |
Sets the current exchange's MEP to the specified value. See the section called “Message exchange patterns”.
|
setHeader() | setHeader |
Sets the specified header in the exchange's In message.
|
setOutHeader() | setOutHeader |
Sets the specified header in the exchange's Out message.
|
setProperty() | setProperty() |
Sets the specified exchange property.
|
sort() | sort |
Sorts the contents of the In message body (where a custom comparator can optionally be specified).
|
split() | split |
Splitter EIP: Splits the current exchange into a sequence of exchanges, where each split exchange contains a fragment of the original message body.
|
stop() | stop |
Stops routing the current exchange and marks it as completed.
|
threads() | threads |
Creates a thread pool for concurrent processing of the latter part of the route.
|
throttle() | throttle |
Throttler EIP: Limit the flow rate to the specified level (exchanges per second).
|
throwException() | throwException |
Throw the specified Java exception.
|
to() | to |
Send the exchange to one or more endpoints. See Section 2.1, “Pipeline Processing”.
|
toF() | N/A | Send the exchange to an endpoint, using string formatting. That is, the endpoint URI string can embed substitutions in the style of the C printf() function. |
transacted() | transacted |
Create a Spring transaction scope that encloses the latter part of the route. See "Transaction Guide".
|
transform() | transform |
Message Translator EIP: Copy the In message headers to the Out message headers and set the Out message body to the specified value.
|
unmarshal() | unmarshal |
Transforms the In message body from a low-level or binary format to a high-level format, using the specified data format.
|
validate() | validate | Takes a predicate expression to test whether the current message is valid. If the predicate returns false, throws a PredicateValidationException exception. |
wireTap() | wireTap |
Wire Tap EIP: Sends a copy of the current exchange to the specified wire tap URI, using the
ExchangePattern.InOnly MEP.
|
Some sample processors Copy linkLink copied to clipboard!
Choice Copy linkLink copied to clipboard!
choice() processor is a conditional statement that is used to route incoming messages to alternative producer endpoints. Each alternative producer endpoint is preceded by a when() method, which takes a predicate argument. If the predicate is true, the following target is selected, otherwise processing proceeds to 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");
from("SourceURL")
.choice()
.when(Predicate1).to("Target1")
.when(Predicate2).to("Target2")
.otherwise().to("Target3");
endChoice() command. Some of the standard Apache Camel processors enable you to specify extra parameters using special sub-clauses, effectively opening an extra level of nesting which is usually terminated by the end() command. For example, you could specify a load balancer clause as loadBalance().roundRobin().to("mock:foo").to("mock:bar").end(), which load balances messages between the mock:foo and mock:bar endpoints. If the load balancer clause is embedded in a choice condition, however, it is necessary to terminate the clause using the endChoice() command, as follows:
Filter Copy linkLink copied to clipboard!
filter() processor can be used to prevent uninteresting messages from reaching the producer endpoint. It takes a single predicate argument: if the predicate is true, the message exchange is allowed through to the producer; if the predicate is false, the message exchange is blocked. For example, the following filter blocks a message exchange, unless the incoming message contains a header, foo, with value equal to bar:
from("SourceURL").filter(header("foo").isEqualTo("bar")).to("TargetURL");
from("SourceURL").filter(header("foo").isEqualTo("bar")).to("TargetURL");
Throttler Copy linkLink copied to clipboard!
throttle() processor ensures that a producer endpoint does not get overloaded. The throttler works by limiting the number of messages that can pass through per second. If the incoming messages exceed the specified rate, the throttler accumulates excess messages in a buffer and transmits them more slowly to the producer endpoint. For example, to limit the rate of throughput to 100 messages per second, you can define the following rule:
from("SourceURL").throttle(100).to("TargetURL");
from("SourceURL").throttle(100).to("TargetURL");
Custom processor Copy linkLink copied to clipboard!
org.apache.camel.Processor interface and overrides the process() method. The following custom processor, MyProcessor, removes the header named foo from incoming messages:
Example 1.3. Implementing a Custom Processor Class
process() method, which provides a generic mechanism for inserting processors into rules. For example, the following rule invokes the processor defined in Example 1.3, “Implementing a Custom Processor Class”:
org.apache.camel.Processor myProc = new MyProcessor();
from("SourceURL").process(myProc).to("TargetURL");
org.apache.camel.Processor myProc = new MyProcessor();
from("SourceURL").process(myProc).to("TargetURL");
Chapter 2. Basic Principles of Route Building Copy linkLink copied to clipboard!
Abstract
2.1. Pipeline Processing Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
ls | more is an example of a command that pipes a directory listing, ls, to the page-scrolling utility, more. The basic idea of a pipeline is that the output of one command is fed into the input of the next. The natural analogy in the case of a route is for the Out message from one processor to be copied to the In message of the next processor.
Processor nodes Copy linkLink copied to clipboard!
org.apache.camel.Processor interface. In other words, processors make up the basic building blocks of a DSL route. For example, DSL commands such as filter(), delayer(), setBody(), setHeader(), and to() all represent processors. When considering how processors connect together to build up a route, it is important to distinguish two different processing approaches.
null in this case.
Figure 2.1. Processor Modifying an In Message
setHeader() command that modifies the current In message by adding (or modifying) the BillingSystem heading:
from("activemq:orderQueue")
.setHeader("BillingSystem", xpath("/order/billingSystem"))
.to("activemq:billingQueue");
from("activemq:orderQueue")
.setHeader("BillingSystem", xpath("/order/billingSystem"))
.to("activemq:billingQueue");
Figure 2.2. Processor Creating an Out Message
transform() command that creates an Out message with a message body containing the string, DummyBody:
from("activemq:orderQueue")
.transform(constant("DummyBody"))
.to("activemq:billingQueue");
from("activemq:orderQueue")
.transform(constant("DummyBody"))
.to("activemq:billingQueue");
constant("DummyBody") represents a constant expression. You cannot pass the string, DummyBody, directly, because the argument to transform() must be an expression type.
Pipeline for InOnly exchanges Copy linkLink copied to clipboard!
Figure 2.3. Sample Pipeline for InOnly Exchanges
userdataQueue queue, pipes the message through a Velocity template (to produce a customer address in text format), and then sends the resulting text address to the queue, envelopeAddressQueue:
from("activemq:userdataQueue")
.to(ExchangePattern.InOut, "velocity:file:AdressTemplate.vm")
.to("activemq:envelopeAddresses");
from("activemq:userdataQueue")
.to(ExchangePattern.InOut, "velocity:file:AdressTemplate.vm")
.to("activemq:envelopeAddresses");
velocity:file:AdressTemplate.vm, specifies the location of a Velocity template file, file:AdressTemplate.vm, in the file system. The to() command changes the exchange pattern to InOut before sending the exchange to the Velocity endpoint and then changes it back to InOnly afterwards. For more details of the Velocity endpoint, see Velocity in the Apache Camel Component Reference Guide.
Pipeline for InOut exchanges Copy linkLink copied to clipboard!
Figure 2.4. Sample Pipeline for InOut Exchanges
from("jetty:http://localhost:8080/foo")
.to("cxf:bean:addAccountDetails")
.to("cxf:bean:getCreditRating")
.to("cxf:bean:processTransaction");
from("jetty:http://localhost:8080/foo")
.to("cxf:bean:addAccountDetails")
.to("cxf:bean:getCreditRating")
.to("cxf:bean:processTransaction");
cxf:bean:addAccountDetails, cxf:bean:getCreditRating, and cxf:bean:processTransaction. The final Web service, processTransaction, generates a response (Out message) that is sent back through the JETTY endpoint.
from("jetty:http://localhost:8080/foo")
.pipeline("cxf:bean:addAccountDetails", "cxf:bean:getCreditRating", "cxf:bean:processTransaction");
from("jetty:http://localhost:8080/foo")
.pipeline("cxf:bean:addAccountDetails", "cxf:bean:getCreditRating", "cxf:bean:processTransaction");
Pipeline for InOptionalOut exchanges Copy linkLink copied to clipboard!
null Out message is copied to the In message of the next node in the pipeline. By contrast, in the case of an InOut exchange, a null Out message is discarded and the original In message from the current node would be copied to the In message of the next node instead.
2.2. Multiple Inputs Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
from(EndpointURL) syntax in the Java DSL. But what if you need to define multiple inputs for your route? Apache Camel provides several alternatives for specifying multiple inputs to a route. The approach to take depends on whether you want the exchanges to be processed independently of each other or whether you want the exchanges from different inputs to be combined in some way (in which case, you should use the the section called “Content enricher pattern”).
Multiple independent inputs Copy linkLink copied to clipboard!
from() DSL command, for example:
from("URI1", "URI2", "URI3").to("DestinationUri");
from("URI1", "URI2", "URI3").to("DestinationUri");
from("URI1").from("URI2").from("URI3").to("DestinationUri");
from("URI1").from("URI2").from("URI3").to("DestinationUri");
from("URI1").to("DestinationUri");
from("URI2").to("DestinationUri");
from("URI3").to("DestinationUri");
from("URI1").to("DestinationUri");
from("URI2").to("DestinationUri");
from("URI3").to("DestinationUri");
Segmented routes Copy linkLink copied to clipboard!
Figure 2.5. Processing Multiple Inputs with Segmented Routes
activemq:Nyse and activemq:Nasdaq—and send the incoming exchanges to an internal endpoint, InternalUrl. The second route segment merges the incoming exchanges, taking them from the internal endpoint and sending them to the destination queue, activemq:USTxn. The InternalUrl is the URL for an endpoint that is intended only for use within a router application. The following types of endpoints are suitable for internal use:
Direct endpoints Copy linkLink copied to clipboard!
direct:EndpointID, where the endpoint ID, EndpointID, is simply a unique alphanumeric string that identifies the endpoint instance.
activemq:Nyse and activemq:Nasdaq, and merge them into a single message queue, activemq:USTxn, you can do this by defining the following set of routes:
from("activemq:Nyse").to("direct:mergeTxns");
from("activemq:Nasdaq").to("direct:mergeTxns");
from("direct:mergeTxns").to("activemq:USTxn");
from("activemq:Nyse").to("direct:mergeTxns");
from("activemq:Nasdaq").to("direct:mergeTxns");
from("direct:mergeTxns").to("activemq:USTxn");
Nyse and Nasdaq, and send them to the endpoint, direct:mergeTxns. The last queue combines the inputs from the previous two queues and sends the combined message stream to the activemq:USTxn queue.
to("direct:mergeTxns")), the direct endpoint passes the exchange directly to all of the consumers endpoints that have the same endpoint ID (for example, from("direct:mergeTxns")). Direct endpoints can only be used to communicate between routes that belong to the same CamelContext in the same Java virtual machine (JVM) instance.
SEDA endpoints Copy linkLink copied to clipboard!
- Processing of a SEDA endpoint is not synchronous. That is, when you send an exchange to a SEDA producer endpoint, control immediately returns to the preceding processor in the route.
- SEDA endpoints contain a queue buffer (of
java.util.concurrent.BlockingQueuetype), which stores all of the incoming exchanges prior to processing by the next route segment. - Each SEDA consumer endpoint creates a thread pool (the default size is 5) to process exchange objects from the blocking queue.
- The SEDA component supports the competing consumers pattern, which guarantees that each incoming exchange is processed only once, even if there are multiple consumers attached to a specific endpoint.
from("activemq:Nyse").to("seda:mergeTxns");
from("activemq:Nasdaq").to("seda:mergeTxns");
from("seda:mergeTxns").to("activemq:USTxn");
from("activemq:Nyse").to("seda:mergeTxns");
from("activemq:Nasdaq").to("seda:mergeTxns");
from("seda:mergeTxns").to("activemq:USTxn");
seda:mergeTxns to activemq:USTxn) is processed by a pool of five threads.
VM endpoints Copy linkLink copied to clipboard!
CamelContext, the VM component enables you to link together routes from distinct Apache Camel applications, as long as they are running within the same Java virtual machine.
from("activemq:Nyse").to("vm:mergeTxns");
from("activemq:Nasdaq").to("vm:mergeTxns");
from("activemq:Nyse").to("vm:mergeTxns");
from("activemq:Nasdaq").to("vm:mergeTxns");
from("vm:mergeTxns").to("activemq:USTxn");
from("vm:mergeTxns").to("activemq:USTxn");
Content enricher pattern Copy linkLink copied to clipboard!
src/data/ratings. You can combine the incoming credit request with data from the ratings file using the pollEnrich() pattern and a GroupedExchangeAggregationStrategy aggregation strategy, as follows:
from("jms:queue:creditRequests")
.pollEnrich("file:src/data/ratings?noop=true", new GroupedExchangeAggregationStrategy())
.bean(new MergeCreditRequestAndRatings(), "merge")
.to("jms:queue:reformattedRequests");
from("jms:queue:creditRequests")
.pollEnrich("file:src/data/ratings?noop=true", new GroupedExchangeAggregationStrategy())
.bean(new MergeCreditRequestAndRatings(), "merge")
.to("jms:queue:reformattedRequests");
GroupedExchangeAggregationStrategy class is a standard aggregation strategy from the org.apache.camel.processor.aggregate package that adds each new exchange to a java.util.List instance and stores the resulting list in the Exchange.GROUPED_EXCHANGE exchange property. In this case, the list contains two elements: the original exchange (from the creditRequests JMS queue); and the enricher exchange (from the file endpoint).
2.3. Exception Handling Copy linkLink copied to clipboard!
Abstract
doTry, doCatch, and doFinally; or you can specify what action to take for each exception type and apply this rule to all routes in a RouteBuilder using onException; or you can specify what action to take for all exception types and apply this rule to all routes in a RouteBuilder using errorHandler.
2.3.1. onException Clause Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
onException clause is a powerful mechanism for trapping exceptions that occur in one or more routes: it is type-specific, enabling you to define distinct actions to handle different exception types; it allows you to define actions using essentially the same (actually, slightly extended) syntax as a route, giving you considerable flexibility in the way you handle exceptions; and it is based on a trapping model, which enables a single onException clause to deal with exceptions occurring at any node in any route.
Trapping exceptions using onException Copy linkLink copied to clipboard!
onException clause is a mechanism for trapping, rather than catching exceptions. That is, once you define an onException clause, it traps exceptions that occur at any point in a route. This contrasts with the Java try/catch mechanism, where an exception is caught, only if a particular code fragment is explicitly enclosed in a try block.
onException clause is that the Apache Camel runtime implicitly encloses each route node in a try block. This is why the onException clause is able to trap exceptions at any point in the route. But this wrapping is done for you automatically; it is not visible in the route definitions.
Java DSL example Copy linkLink copied to clipboard!
onException clause applies to all of the routes defined in the RouteBuilder class. If a ValidationException exception occurs while processing either of the routes (from("seda:inputA") or from("seda:inputB")), the onException clause traps the exception and redirects the current exchange to the validationFailed JMS queue (which serves as a deadletter queue).
XML DSL example Copy linkLink copied to clipboard!
onException element to define the exception clause, as follows:
Trapping multiple exceptions Copy linkLink copied to clipboard!
onException clauses to trap exceptions in a RouteBuilder scope. This enables you to take different actions in response to different exceptions. For example, the following series of onException clauses defined in the Java DSL define different deadletter destinations for ValidationException, ValidationException, and Exception:
onException(ValidationException.class).to("activemq:validationFailed");
onException(java.io.IOException.class).to("activemq:ioExceptions");
onException(Exception.class).to("activemq:exceptions");
onException(ValidationException.class).to("activemq:validationFailed");
onException(java.io.IOException.class).to("activemq:ioExceptions");
onException(Exception.class).to("activemq:exceptions");
onException clauses in the XML DSL as follows:
onException clause. In the Java DSL, you can group multiple exceptions as follows:
onException(ValidationException.class, BuesinessException.class)
.to("activemq:validationFailed");
onException(ValidationException.class, BuesinessException.class)
.to("activemq:validationFailed");
exception element inside the onException element, as follows:
<onException>
<exception>com.mycompany.ValidationException</exception>
<exception>com.mycompany.BuesinessException</exception>
<to uri="activemq:validationFailed"/>
</onException>
<onException>
<exception>com.mycompany.ValidationException</exception>
<exception>com.mycompany.BuesinessException</exception>
<to uri="activemq:validationFailed"/>
</onException>
onException clauses is significant. Apache Camel initially attempts to match the thrown exception against the first clause. If the first clause fails to match, the next onException clause is tried, and so on until a match is found. Each matching attempt is governed by the following algorithm:
- If the thrown exception is a chained exception (that is, where an exception has been caught and rethrown as a different exception), the most nested exception type serves initially as the basis for matching. This exception is tested as follows:
- If the exception-to-test has exactly the type specified in the
onExceptionclause (tested usinginstanceof), a match is triggered. - If the exception-to-test is a sub-type of the type specified in the
onExceptionclause, a match is triggered.
- If the most nested exception fails to yield a match, the next exception in the chain (the wrapping exception) is tested instead. The testing continues up the chain until either a match is triggered or the chain is exhausted.
throwException EIP enables you to create a new exception instance from a simple language expression. You can make it dynamic, based on the available information from the current exchange. for example,
<throwException exceptionType="java.lang.IllegalArgumentException" message="${body}"/>
<throwException exceptionType="java.lang.IllegalArgumentException" message="${body}"/>
Deadletter channel Copy linkLink copied to clipboard!
onException usage have so far all exploited the deadletter channel pattern. That is, when an onException clause traps an exception, the current exchange is routed to a special destination (the deadletter channel). The deadletter channel serves as a holding area for failed messages that have not been processed. An administrator can inspect the messages at a later time and decide what action needs to be taken.
Use original message Copy linkLink copied to clipboard!
useOriginalMessage() DSL command, as follows:
onException(ValidationException.class)
.useOriginalMessage()
.to("activemq:validationFailed");
onException(ValidationException.class)
.useOriginalMessage()
.to("activemq:validationFailed");
useOriginalMessage attribute on the onException element, as follows:
<onException useOriginalMessage="true">
<exception>com.mycompany.ValidationException</exception>
<to uri="activemq:validationFailed"/>
</onException>
<onException useOriginalMessage="true">
<exception>com.mycompany.ValidationException</exception>
<to uri="activemq:validationFailed"/>
</onException>
useOriginalMessage(). But if the setAllowUseOriginalMessage() option is set to false on the Camel context, the original message will not be accessible and you cannot call useOriginalMessage() (for example, you might want to choose this behaviour to optimize performance when processing large messages).
Redelivery policy Copy linkLink copied to clipboard!
-
maximumRedeliveries() - Specifies the maximum number of times redelivery can be attempted (default is
0). A negative value means redelivery is always attempted (equivalent to an infinite value). -
retryWhile() - Specifies a predicate (of
Predicatetype), which determines whether Apache Camel ought to continue redelivering. If the predicate evaluates totrueon the current exchange, redelivery is attempted; otherwise, redelivery is stopped and no further redelivery attempts are made.This option takes precedence over themaximumRedeliveries()option.
onException clause. For example, you can specify a maximum of six redeliveries, after which the exchange is sent to the validationFailed deadletter queue, as follows:
onException(ValidationException.class)
.maximumRedeliveries(6)
.retryAttemptedLogLevel(org.apache.camel.LogginLevel.WARN)
.to("activemq:validationFailed");
onException(ValidationException.class)
.maximumRedeliveries(6)
.retryAttemptedLogLevel(org.apache.camel.LogginLevel.WARN)
.to("activemq:validationFailed");
redeliveryPolicy element. For example, the preceding route can be expressed in XML DSL as follows:
<onException useOriginalMessage="true">
<exception>com.mycompany.ValidationException</exception>
<redeliveryPolicy maximumRedeliveries="6"/>
<to uri="activemq:validationFailed"/>
</onException>
<onException useOriginalMessage="true">
<exception>com.mycompany.ValidationException</exception>
<redeliveryPolicy maximumRedeliveries="6"/>
<to uri="activemq:validationFailed"/>
</onException>
redeliveryPolicyProfile instance. You can then reference the redeliveryPolicyProfile instance using the onException element's redeliverPolicyRef attribute. For example, the preceding route can be expressed as follows:
redeliveryPolicyProfile is useful, if you want to re-use the same redelivery policy in multiple onException clauses.
Conditional trapping Copy linkLink copied to clipboard!
onException can be made conditional by specifying the onWhen option. If you specify the onWhen option in an onException clause, a match is triggered only when the thrown exception matches the clause and the onWhen predicate evaluates to true on the current exchange.
onException clause triggers, only if the thrown exception matches MyUserException and the user header is non-null in the current exchange:
onException clauses can be expressed in the XML DSL as follows:
Handling exceptions Copy linkLink copied to clipboard!
onException clause is triggered, the behavior is essentially the same, except that the onException clause performs some processing before the thrown exception is propagated back.
onException provides various options to modify the exception handling behavior, as follows:
- the section called “Suppressing exception rethrow”—you have the option of suppressing the rethrown exception after the
onExceptionclause has completed. In other words, in this case the exception does not propagate back to the consumer endpoint at the start of the route. - the section called “Continuing processing”—you have the option of resuming normal processing of the exchange from the point where the exception originally occurred. Implicitly, this approach also suppresses the rethrown exception.
- the section called “Sending a response”—in the special case where the consumer endpoint at the start of the route expects a reply (that is, having an InOut MEP), you might prefer to construct a custom fault reply message, rather than propagating the exception back to the consumer endpoint.
Suppressing exception rethrow Copy linkLink copied to clipboard!
handled() option to true in the Java DSL, as follows:
onException(ValidationException.class)
.handled(true)
.to("activemq:validationFailed");
onException(ValidationException.class)
.handled(true)
.to("activemq:validationFailed");
handled() option can be of boolean type, of Predicate type, or of Expression type (where any non-boolean expression is interpreted as true, if it evaluates to a non-null value).
handled element, as follows:
Continuing processing Copy linkLink copied to clipboard!
continued option to true in the Java DSL, as follows:
onException(ValidationException.class) .continued(true);
onException(ValidationException.class)
.continued(true);
continued() option can be of boolean type, of Predicate type, or of Expression type (where any non-boolean expression is interpreted as true, if it evaluates to a non-null value).
continued element, as follows:
Sending a response Copy linkLink copied to clipboard!
handled option; and populate the exchange's Out message slot with a custom fault message.
Sorry, whenever the MyFunctionalException exception occurs:
// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body as Sorry.
onException(MyFunctionalException.class)
.handled(true)
.transform().constant("Sorry");
// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body as Sorry.
onException(MyFunctionalException.class)
.handled(true)
.transform().constant("Sorry");
exceptionMessage() builder method. For example, you can send a reply containing just the text of the exception message whenever the MyFunctionalException exception occurs, as follows:
// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body and return the exception message
onException(MyFunctionalException.class)
.handled(true)
.transform(exceptionMessage());
// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body and return the exception message
onException(MyFunctionalException.class)
.handled(true)
.transform(exceptionMessage());
exception.message variable. For example, you could embed the current exception text in a reply message, as follows:
onException clause can be expressed in XML DSL as follows:
Exception thrown while handling an exception Copy linkLink copied to clipboard!
onException clause) is handled in a special way. Such an exception is handled by the special fallback exception handler, which handles the exception as follows:
- All existing exception handlers are ignored and processing fails immediately.
- The new exception is logged.
- The new exception is set on the exchange object.
onException clause getting locked into an infinite loop.
Scopes Copy linkLink copied to clipboard!
onException clauses can be effective in either of the following scopes:
- RouteBuilder scope—
onExceptionclauses defined as standalone statements inside aRouteBuilder.configure()method affect all of the routes defined in thatRouteBuilderinstance. On the other hand, theseonExceptionclauses have no effect whatsoever on routes defined inside any otherRouteBuilderinstance. TheonExceptionclauses must appear before the route definitions.All of the examples up to this point are defined using theRouteBuilderscope. - Route scope—
onExceptionclauses can also be embedded directly within a route. These onException clauses affect only the route in which they are defined.
Route scope Copy linkLink copied to clipboard!
onException clause anywhere inside a route definition, but you must terminate the embedded onException clause using the end() DSL command.
onException clause in the Java DSL, as follows:
onException clause in the XML DSL, as follows:
2.3.2. Error Handler Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
errorHandler() clause provides similar features to the onException clause, except that this mechanism is not able to discriminate between different exception types. The errorHandler() clause is the original exception handling mechanism provided by Apache Camel and was available before the onException clause was implemented.
Java DSL example Copy linkLink copied to clipboard!
errorHandler() clause is defined in a RouteBuilder class and applies to all of the routes in that RouteBuilder class. It is triggered whenever an exception of any kind occurs in one of the applicable routes. For example, to define an error handler that routes all failed exchanges to the ActiveMQ deadLetter queue, you can define a RouteBuilder as follows:
XML DSL example Copy linkLink copied to clipboard!
camelContext scope using the errorHandler element. For example, to define an error handler that routes all failed exchanges to the ActiveMQ deadLetter queue, you can define an errorHandler element as follows:
Types of error handler Copy linkLink copied to clipboard!
| Java DSL Builder | XML DSL Type Attribute | Description |
|---|---|---|
defaultErrorHandler() | DefaultErrorHandler | Propagates exceptions back to the caller and supports the redelivery policy, but it does not support a dead letter queue. |
deadLetterChannel() | DeadLetterChannel | Supports the same features as the default error handler and, in addition, supports a dead letter queue. |
loggingErrorChannel() | LoggingErrorChannel | Logs the exception text whenever an exception occurs. |
noErrorHandler() | NoErrorHandler | Dummy handler implementation that can be used to disable the error handler. |
TransactionErrorHandler | An error handler for transacted routes. A default transaction error handler instance is automatically used for a route that is marked as transacted. |
2.3.3. doTry, doCatch, and doFinally Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
doTry, doCatch, and doFinally clauses, which handle exceptions in a similar way to Java's try, catch, and finally blocks.
Similarities between doCatch and Java catch Copy linkLink copied to clipboard!
doCatch() clause in a route definition behaves in an analogous way to the catch() statement in Java code. In particular, the following features are supported by the doCatch() clause:
- Multiple doCatch clauses—you can have multiple
doCatchclauses within a singledoTryblock. ThedoCatchclauses are tested in the order they appear, just like Javacatch()statements. Apache Camel executes the firstdoCatchclause that matches the thrown exception.NoteThis algorithm is different from the exception matching algorithm used by theonExceptionclause—see Section 2.3.1, “onException Clause” for details. - Rethrowing exceptions—you can rethrow the current exception from within a
doCatchclause using thehandledsub-clause (see the section called “Rethrowing exceptions in doCatch”).
Special features of doCatch Copy linkLink copied to clipboard!
doCatch() clause, however, that have no analogue in the Java catch() statement. The following features are specific to doCatch():
- Catching multiple exceptions—the
doCatchclause allows you to specify a list of exceptions to catch, in contrast to the Javacatch()statement, which catches only one exception (see the section called “Example”). - Conditional catching—you can catch an exception conditionally, by appending an
onWhensub-clause to thedoCatchclause (see the section called “Conditional exception catching using onWhen”).
Example Copy linkLink copied to clipboard!
doTry block in the Java DSL, where the doCatch() clause will be executed, if either the IOException exception or the IllegalStateException exception are raised, and the doFinally() clause is always executed, irrespective of whether an exception is raised or not.
Rethrowing exceptions in doCatch Copy linkLink copied to clipboard!
doCatch() clause by calling the handled() sub-clause with its argument set to false, as follows:
IOException is caught by doCatch(), the current exchange is sent to the mock:io endpoint, and then the IOException is rethrown. This gives the consumer endpoint at the start of the route (in the from() command) an opportunity to handle the exception as well.
Conditional exception catching using onWhen Copy linkLink copied to clipboard!
doCatch() clause is that you can conditionalize the catching of exceptions based on an expression that is evaluated at run time. In other words, if you catch an exception using a clause of the form, doCatch(ExceptionList).doWhen(Expression), an exception will only be caught, if the predicate expression, Expression, evaluates to true at run time.
doTry block will catch the exceptions, IOException and IllegalStateException, only if the exception message contains the word, Severe:
Nested Conditions in doTry Copy linkLink copied to clipboard!
dotry() creates a try or catch block for handling exceptions and is useful for route specific error handling.
ChoiceDefinition, you can use the following doTry blocks:
2.3.4. Propagating SOAP Exceptions Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
How to propagate stack trace information Copy linkLink copied to clipboard!
dataFormat to PAYLOAD and set the faultStackTraceEnabled property to true in the cxfEndpoint element, as follows:
Caused by). If you want to include the causing exception in the stack trace, set the exceptionMessageCauseEnabled property to true in the cxfEndpoint element, as follows:
exceptionMessageCauseEnabled flag for testing and diagnostic purposes. It is normal practice for servers to conceal the original cause of an exception to make it harder for hostile users to probe the server.
2.4. Bean Integration Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Conventional method signatures — If the method signature conforms to certain conventions, the parameter binding can use Java reflection to determine what parameters to pass.
- Annotations and dependency injection — For a more flexible binding mechanism, employ Java annotations to specify what to inject into the method's arguments. This dependency injection mechanism relies on Spring 2.5 component scanning. Normally, if you are deploying your Apache Camel application into a Spring container, the dependency injection mechanism will work automatically.
- Explicitly specified parameters — You can specify parameters explicitly (either as constants or using the Simple language), at the point where the bean is invoked.
Bean registry Copy linkLink copied to clipboard!
Registry plug-in strategy Copy linkLink copied to clipboard!
| Registry Implementation | Camel Component with Registry Plug-In |
|---|---|
| Spring bean registry | camel-spring |
| Guice bean registry | camel-guice |
| Blueprint bean registry | camel-blueprint |
| OSGi service registry | deployed in OSGi container |
| JNDI registry |
ApplicationContextRegistry plug-in is automatically installed in the current CamelContext instance.
CamelContext automatically sets up a registry chain for resolving bean instances: the registry chain consists of the OSGi registry, followed by the Blueprint (or Spring) registry.
Accessing a bean created in Java Copy linkLink copied to clipboard!
bean() processor, which binds the inbound exchange to a method on the Java object. For example, to process inbound exchanges using the class, MyBeanProcessor, define a route like the following:
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBody")
.to("file:data/outbound");
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBody")
.to("file:data/outbound");
bean() processor creates an instance of MyBeanProcessor type and invokes the processBody() method to process inbound exchanges. This approach is adequate if you only want to access the MyBeanProcessor instance from a single route. However, if you want to access the same MyBeanProcessor instance from multiple routes, use the variant of bean() that takes the Object type as its first argument. For example:
Accessing overloaded bean methods Copy linkLink copied to clipboard!
MyBeanBrocessor class has two overloaded methods, processBody(String) and processBody(String,String), you can invoke the latter overloaded method as follows:
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBody(String,String)")
.to("file:data/outbound");
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBody(String,String)")
.to("file:data/outbound");
*. For example, to invoke a method named processBody that takes two parameters, irrespective of the exact type of the parameters, invoke the bean() processor as follows:
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBody(*,*)")
.to("file:data/outbound");
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBody(*,*)")
.to("file:data/outbound");
processBody(Exchange)—or a fully qualified type name—for example, processBody(org.apache.camel.Exchange).
Specify parameters explicitly Copy linkLink copied to clipboard!
- Boolean:
trueorfalse. - Numeric:
123,7, and so on. - String:
'In single quotes'or"In double quotes". - Null object:
null.
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBody(String, 'Sample string value', true, 7)")
.to("file:data/outbound");
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBody(String, 'Sample string value', true, 7)")
.to("file:data/outbound");
title header to a bean method:
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBodyAndHeader(${body},${header.title})")
.to("file:data/outbound");
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBodyAndHeader(${body},${header.title})")
.to("file:data/outbound");
java.util.Map:
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBodyAndAllHeaders(${body},${header})")
.to("file:data/outbound");
from("file:data/inbound")
.bean(MyBeanProcessor.class, "processBodyAndAllHeaders(${body},${header})")
.to("file:data/outbound");
Basic method signatures Copy linkLink copied to clipboard!
Method signature for processing message bodies Copy linkLink copied to clipboard!
String argument and returns a String value. For example:
Method signature for processing exchanges Copy linkLink copied to clipboard!
org.apache.camel.Exchange parameter and returns void. For example:
Accessing a Spring bean from Spring XML Copy linkLink copied to clipboard!
bean element. The following example shows how to create an instance of MyBeanProcessor:
<beans ...>
...
<bean id="myBeanId" class="com.acme.MyBeanProcessor"/>
</beans>
<beans ...>
...
<bean id="myBeanId" class="com.acme.MyBeanProcessor"/>
</beans>
bean element, see The IoC Container from the Spring reference guide.
beanRef() processor invokes the MyBeanProcessor.processBody() method on the specified bean instance. You can also invoke the bean from within a Spring XML route, using the Camel schema's bean element. For example:
cache option to true, which avoids looking up the registry every time a bean is used. For example, to enable caching, you can set the cache attribute on the bean element as follows:
<bean ref="myBeanId" method="processBody" cache="true"/>
<bean ref="myBeanId" method="processBody" cache="true"/>
Accessing a Spring bean from Java Copy linkLink copied to clipboard!
bean element, you can reference it from Java using the bean's ID (the value of the bean element's id attribute). For example, given the bean element with ID equal to myBeanId, you can reference the bean in a Java DSL route using the beanRef() processor, as follows:
from("file:data/inbound").beanRef("myBeanId", "processBody").to("file:data/outbound");
from("file:data/inbound").beanRef("myBeanId", "processBody").to("file:data/outbound");
@BeanInject annotation as follows:
@BeanInject annotation, Camel looks up the registry by type, but this only works if there is just a single bean of the given type. For example, to look up and inject the bean of com.acme.MyBeanProcessor type:
@BeanInject com.acme.MyBeanProcessor bean;
@BeanInject
com.acme.MyBeanProcessor bean;
Bean shutdown order in Spring XML Copy linkLink copied to clipboard!
- Shut down the
camelContextinstance, followed by; - Shut down the used beans.
camelContext appear in the Spring XML file. In order to avoid random errors due to incorrect shutdown order, therefore, the camelContext is configured to shut down before any of the other beans in the Spring XML file. This is the default behaviour since Apache Camel 2.13.0.
shutdownEager attribute on the camelContext element to false. In this case, you could potentially exercise more fine-grained control over shutdown order using the Spring depends-on attribute.
Parameter binding annotations Copy linkLink copied to clipboard!
Basic annotations Copy linkLink copied to clipboard!
org.apache.camel Java package that you can use to inject message data into the arguments of a bean method.
| Annotation | Meaning | Parameter? |
|---|---|---|
@Attachments | Binds to a list of attachments. | |
@Body | Binds to an inbound message body. | |
@Header | Binds to an inbound message header. | String name of the header. |
@Headers | Binds to a java.util.Map of the inbound message headers. | |
@OutHeaders | Binds to a java.util.Map of the outbound message headers. | |
@Property | Binds to a named exchange property. | String name of the property. |
@Properties | Binds to a java.util.Map of the exchange properties. |
processExchange() method arguments.
org.apache.camel.Exchange argument.
Expression language annotations Copy linkLink copied to clipboard!
org.apache.camel.language package (and sub-packages, for the non-core annotations) that you can use to inject message data into the arguments of a bean method.
| Annotation | Description |
|---|---|
@Bean | Injects a Bean expression. |
@Constant | Injects a Constant expression |
@EL | Injects an EL expression. |
@Groovy | Injects a Groovy expression. |
@Header | Injects a Header expression. |
@JavaScript | Injects a JavaScript expression. |
@OGNL | Injects an OGNL expression. |
@PHP | Injects a PHP expression. |
@Python | Injects a Python expression. |
@Ruby | Injects a Ruby expression. |
@Simple | Injects a Simple expression. |
@XPath | Injects an XPath expression. |
@XQuery | Injects an XQuery expression. |
@XPath annotation to extract a username and a password from the body of an incoming message in XML format:
@Bean annotation is a special case, because it enables you to inject the result of invoking a registered bean. For example, to inject a correlation ID into a method argument, you can use the @Bean annotation to invoke an ID generator class, as follows:
myCorrIdGenerator, is the bean ID of the ID generator instance. The ID generator class can be instantiated using the spring bean element, as follows:
<beans ...>
...
<bean id="myCorrIdGenerator" class="com.acme.MyIdGenerator"/>
</beans>
<beans ...>
...
<bean id="myCorrIdGenerator" class="com.acme.MyIdGenerator"/>
</beans>
MySimpleIdGenerator class could be defined as follows:
MyIdGenerator. The only restriction on the generate() method signature is that it must return the correct type to inject into the argument annotated by @Bean. Because the @Bean annotation does not let you specify a method name, the injection mechanism simply invokes the first method in the referenced bean that has the matching return type.
@Bean, @Constant, @Simple, and @XPath). For non-core components, however, you will have to make sure that you load the relevant component. For example, to use the OGNL script, you must load the camel-ognl component.
Inherited annotations Copy linkLink copied to clipboard!
Header annotation and a Body annotation, as follows:
MyBeanProcessor, now inherit the annotations defined in the base interface, as follows:
Interface implementations Copy linkLink copied to clipboard!
protected, private or in package-only scope. If you try to invoke a method on an implementation class that is restricted in this way, the bean binding falls back to invoking the corresponding interface method, which is publicly accessible.
BeanIntf interface:
// Java
public interface BeanIntf {
void processBodyAndHeader(String body, String title);
}
// Java
public interface BeanIntf {
void processBodyAndHeader(String body, String title);
}
BeanIntf interface is implemented by the following protected BeanIntfImpl class:
BeanIntf.processBodyAndHeader method:
from("file:data/inbound")
.bean(BeanIntfImpl.class, "processBodyAndHeader(${body}, ${header.title})")
.to("file:data/outbound");
from("file:data/inbound")
.bean(BeanIntfImpl.class, "processBodyAndHeader(${body}, ${header.title})")
.to("file:data/outbound");
Invoking static methods Copy linkLink copied to clipboard!
changeSomething():
changeSomething method, as follows:
from("direct:a")
.bean(MyStaticClass.class, "changeSomething")
.to("mock:a");
from("direct:a")
.bean(MyStaticClass.class, "changeSomething")
.to("mock:a");
MyStaticClass.
Invoking an OSGi service Copy linkLink copied to clipboard!
org.fusesource.example.HelloWorldOsgiService, you could invoke the sayHello method using the following bean integration code:
from("file:data/inbound")
.bean(org.fusesource.example.HelloWorldOsgiService.class, "sayHello")
.to("file:data/outbound");
from("file:data/inbound")
.bean(org.fusesource.example.HelloWorldOsgiService.class, "sayHello")
.to("file:data/outbound");
<to uri="bean:org.fusesource.example.HelloWorldOsgiService?method=sayHello"/>
<to uri="bean:org.fusesource.example.HelloWorldOsgiService?method=sayHello"/>
2.5. Creating Exchange Instances Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Exchange object, the easiest approach is to invoke the methods of the ExchangeBuilder class, as described here.
ExchangeBuilder class Copy linkLink copied to clipboard!
ExchangeBuilder class is as follows:
org.apache.camel.builder.ExchangeBuilder
org.apache.camel.builder.ExchangeBuilder
ExchangeBuilder exposes the static method, anExchange, which you can use to start building an exchange object.
Example Copy linkLink copied to clipboard!
Hello World!, and with headers containing username and password credentials:
ExchangeBuilder methods Copy linkLink copied to clipboard!
ExchangeBuilder class supports the following methods:
ExchangeBuilder anExchange(CamelContext context)- (static method) Initiate building an exchange object.
Exchange build()- Build the exchange.
ExchangeBuilder withBody(Object body)- Set the message body on the exchange (that is, sets the exchange's In message body).
ExchangeBuilder withHeader(String key, Object value)- Set a header on the exchange (that is, sets a header on the exchange's In message).
ExchangeBuilder withPattern(ExchangePattern pattern)- Sets the exchange pattern on the exchange.
ExchangeBuilder withProperty(String key, Object value)- Sets a property on the exchange.
2.6. Transforming Message Content Copy linkLink copied to clipboard!
Abstract
2.6.1. Simple Message Transformations Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
World!, to the end of the incoming message body.
Example 2.1. Simple Transformation of Incoming Messages
from("SourceURL").setBody(body().append(" World!")).to("TargetURL");
from("SourceURL").setBody(body().append(" World!")).to("TargetURL");
setBody() command replaces the content of the incoming message's body.
API for simple transformations Copy linkLink copied to clipboard!
org.apache.camel.model.ProcessorDefinitionorg.apache.camel.builder.Builderorg.apache.camel.builder.ValueBuilder
ProcessorDefinition class Copy linkLink copied to clipboard!
org.apache.camel.model.ProcessorDefinition class defines the DSL commands you can insert directly into a router rule—for example, the setBody() command in Example 2.1, “Simple Transformation of Incoming Messages”. Table 2.5, “Transformation Methods from the ProcessorDefinition Class” shows the ProcessorDefinition methods that are relevant to transforming message content:
| Method | Description |
|---|---|
Type convertBodyTo(Class type) | Converts the IN message body to the specified type. |
Type removeFaultHeader(String name) | Adds a processor which removes the header on the FAULT message. |
Type removeHeader(String name) | Adds a processor which removes the header on the IN message. |
Type removeProperty(String name) | Adds a processor which removes the exchange property. |
ExpressionClause<ProcessorDefinition<Type>> setBody() | Adds a processor which sets the body on the IN message. |
Type setFaultBody(Expression expression) | Adds a processor which sets the body on the FAULT message. |
Type setFaultHeader(String name, Expression expression) | Adds a processor which sets the header on the FAULT message. |
ExpressionClause<ProcessorDefinition<Type>> setHeader(String name) | Adds a processor which sets the header on the IN message. |
Type setHeader(String name, Expression expression) | Adds a processor which sets the header on the IN message. |
ExpressionClause<ProcessorDefinition<Type>> setOutHeader(String name) | Adds a processor which sets the header on the OUT message. |
Type setOutHeader(String name, Expression expression) | Adds a processor which sets the header on the OUT message. |
ExpressionClause<ProcessorDefinition<Type>> setProperty(String name) | Adds a processor which sets the exchange property. |
Type setProperty(String name, Expression expression) | Adds a processor which sets the exchange property. |
ExpressionClause<ProcessorDefinition<Type>> transform() | Adds a processor which sets the body on the OUT message. |
Type transform(Expression expression) | Adds a processor which sets the body on the OUT message. |
Builder class Copy linkLink copied to clipboard!
org.apache.camel.builder.Builder class provides access to message content in contexts where expressions or predicates are expected. In other words, Builder methods are typically invoked in the arguments of DSL commands—for example, the body() command in Example 2.1, “Simple Transformation of Incoming Messages”. Table 2.6, “Methods from the Builder Class” summarizes the static methods available in the Builder class.
| Method | Description |
|---|---|
static <E extends Exchange> ValueBuilder<E> body() | Returns a predicate and value builder for the inbound body on an exchange. |
static <E extends Exchange,T> ValueBuilder<E> bodyAs(Class<T> type) | Returns a predicate and value builder for the inbound message body as a specific type. |
static <E extends Exchange> ValueBuilder<E> constant(Object value) | Returns a constant expression. |
static <E extends Exchange> ValueBuilder<E> faultBody() | Returns a predicate and value builder for the fault body on an exchange. |
static <E extends Exchange,T> ValueBuilder<E> faultBodyAs(Class<T> type) | Returns a predicate and value builder for the fault message body as a specific type. |
static <E extends Exchange> ValueBuilder<E> header(String name) | Returns a predicate and value builder for headers on an exchange. |
static <E extends Exchange> ValueBuilder<E> outBody() | Returns a predicate and value builder for the outbound body on an exchange. |
static <E extends Exchange> ValueBuilder<E> outBodyAs(Class<T> type) | Returns a predicate and value builder for the outbound message body as a specific type. |
static ValueBuilder property(String name) | Returns a predicate and value builder for properties on an exchange. |
static ValueBuilder regexReplaceAll(Expression content, String regex, Expression replacement) | Returns an expression that replaces all occurrences of the regular expression with the given replacement. |
static ValueBuilder regexReplaceAll(Expression content, String regex, String replacement) | Returns an expression that replaces all occurrences of the regular expression with the given replacement. |
static ValueBuilder sendTo(String uri) | Returns an expression processing the exchange to the given endpoint uri. |
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) | Returns an expression for the given system property. |
ValueBuilder class Copy linkLink copied to clipboard!
org.apache.camel.builder.ValueBuilder class enables you to modify values returned by the Builder methods. In other words, the methods in ValueBuilder provide a simple way of modifying message content. Table 2.7, “Modifier Methods from the ValueBuilder Class” summarizes the methods available in the ValueBuilder class. That is, the table shows only the methods that are used to modify the value they are invoked on (for full details, see the API Reference documentation).
| Method | Description |
|---|---|
ValueBuilder<E> append(Object value) | Appends the string evaluation of this expression with the given value. |
Predicate contains(Object value) | Create a predicate that the left hand expression contains the value of the right hand expression. |
ValueBuilder<E> convertTo(Class type) | Converts the current value to the given type using the registered type converters. |
ValueBuilder<E> convertToString() | Converts the current value a String using the registered type converters. |
Predicate endsWith(Object value) | |
<T> T evaluate(Exchange exchange, Class<T> type) | |
Predicate in(Object... values) | |
Predicate in(Predicate... predicates) | |
Predicate isEqualTo(Object value) | Returns true, if the current value is equal to the given value argument. |
Predicate isGreaterThan(Object value) | Returns true, if the current value is greater than the given value argument. |
Predicate isGreaterThanOrEqualTo(Object value) | Returns true, if the current value is greater than or equal to the given value argument. |
Predicate isInstanceOf(Class type) | Returns true, if the current value is an instance of the given type. |
Predicate isLessThan(Object value) | Returns true, if the current value is less than the given value argument. |
Predicate isLessThanOrEqualTo(Object value) | Returns true, if the current value is less than or equal to the given value argument. |
Predicate isNotEqualTo(Object value) | Returns true, if the current value is not equal to the given value argument. |
Predicate isNotNull() | Returns true, if the current value is not null. |
Predicate isNull() | Returns true, if the current value is null. |
Predicate matches(Expression expression) | |
Predicate not(Predicate predicate) | Negates the predicate argument. |
ValueBuilder prepend(Object value) | Prepends the string evaluation of this expression to the given value. |
Predicate regex(String regex) | |
ValueBuilder<E> regexReplaceAll(String regex, Expression<E> replacement) | Replaces all occurrencies of the regular expression with the given replacement. |
ValueBuilder<E> regexReplaceAll(String regex, String replacement) | Replaces all occurrencies of the regular expression with the given replacement. |
ValueBuilder<E> regexTokenize(String regex) | Tokenizes the string conversion of this expression using the given regular expression. |
ValueBuilder sort(Comparator comparator) | Sorts the current value using the given comparator. |
Predicate startsWith(Object value) | Returns true, if the current value matches the string value of the value argument. |
ValueBuilder<E> tokenize() | Tokenizes the string conversion of this expression using the comma token separator. |
ValueBuilder<E> tokenize(String token) | Tokenizes the string conversion of this expression using the given token separator. |
2.6.2. Marshalling and Unmarshalling Copy linkLink copied to clipboard!
Java DSL commands Copy linkLink copied to clipboard!
marshal()— Converts a high-level data format to a low-level data format.unmarshal() — Converts a low-level data format to a high-level data format.
Data formats Copy linkLink copied to clipboard!
- Java serialization
- JAXB
- XMLBeans
- XStream
Java serialization Copy linkLink copied to clipboard!
from("SourceURL").unmarshal().serialization()
.<FurtherProcessing>.to("TargetURL");
from("SourceURL").unmarshal().serialization()
.<FurtherProcessing>.to("TargetURL");
JAXB Copy linkLink copied to clipboard!
org.apache.camel.spi.DataFormat jaxb = new org.apache.camel.model.dataformat.JaxbDataFormat("GeneratedPackageName");
from("SourceURL").unmarshal(jaxb)
.<FurtherProcessing>.to("TargetURL");
org.apache.camel.spi.DataFormat jaxb = new org.apache.camel.model.dataformat.JaxbDataFormat("GeneratedPackageName");
from("SourceURL").unmarshal(jaxb)
.<FurtherProcessing>.to("TargetURL");
XMLBeans Copy linkLink copied to clipboard!
from("SourceURL").unmarshal().xmlBeans()
.<FurtherProcessing>.to("TargetURL");
from("SourceURL").unmarshal().xmlBeans()
.<FurtherProcessing>.to("TargetURL");
XStream Copy linkLink copied to clipboard!
from("SourceURL").unmarshal().xstream()
.<FurtherProcessing>.to("TargetURL");
from("SourceURL").unmarshal().xstream()
.<FurtherProcessing>.to("TargetURL");
2.6.3. Endpoint Bindings Copy linkLink copied to clipboard!
What is a binding? Copy linkLink copied to clipboard!
DataFormatBinding Copy linkLink copied to clipboard!
DataFormatBinding class is useful for the specific case where you want to define a binding that marshals and unmarshals a particular data format (see Section 2.6.2, “Marshalling and Unmarshalling”). In this case, all that you need to do to create a binding is to create a DataFormatBinding instance, passing a reference to the relevant data format in the constructor.
jaxb) that is capable of marshalling and unmarshalling the JAXB data format when it is associated with an Apache Camel endpoint:
Example 2.2. JAXB Binding
Associating a binding with an endpoint Copy linkLink copied to clipboard!
Binding URI Copy linkLink copied to clipboard!
binding:NameOfBinding, where NameOfBinding is the bean ID of the binding (for example, the ID of a binding bean created in Spring XML).
BindingComponent Copy linkLink copied to clipboard!
BindingComponent class.
jaxb binding with activemq endpoints, you could define a new BindingComponent instance as follows:
jaxbmq defines a URI prefix. You can now use the jaxbmq ID as the scheme for an endpoint URI. For example, you can define the following route using this binding component:
org.apache.camel.spi.HasBinding interface.
BindingComponent constructors Copy linkLink copied to clipboard!
BindingComponent class supports the following constructors:
public BindingComponent()- No arguments form. Use property injection to configure the binding component instance.
public BindingComponent(Binding binding)- Associate this binding component with the specified
Bindingobject,binding. public BindingComponent(Binding binding, String uriPrefix)- Associate this binding component with the specified
Bindingobject,binding, and URI prefix,uriPrefix. This is the most commonly used constructor. public BindingComponent(Binding binding, String uriPrefix, String uriPostfix)- This constructor supports the additional URI post-fix,
uriPostfix, argument, which is automatically appended to any URIs defined using this binding component.
Implementing a custom binding Copy linkLink copied to clipboard!
DataFormatBinding, which is used for marshalling and unmarshalling data formats, you can implement your own custom bindings. Define a custom binding as follows:
- Implement an
org.apache.camel.Processorclass to perform a transformation on messages incoming to a consumer endpoint (appearing in afromelement). - Implement a complementary
org.apache.camel.Processorclass to perform the reverse transformation on messages outgoing from a producer endpoint (appearing in atoelement). - Implement the
org.apache.camel.spi.Bindinginterface, which acts as a factory for the processor instances.
Binding interface Copy linkLink copied to clipboard!
org.apache.camel.spi.Binding interface, which you must implement to define a custom binding.
Example 2.3. The org.apache.camel.spi.Binding Interface
When to use bindings Copy linkLink copied to clipboard!
2.7. Property Placeholders Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
{{remote.host}} and {{remote.port}}:
from("direct:start").to("http://{{remote.host}}:{{remote.port}}");
from("direct:start").to("http://{{remote.host}}:{{remote.port}}");
# Java properties file remote.host=myserver.com remote.port=8080
# Java properties file
remote.host=myserver.com
remote.port=8080
.properties file, using a specific character set such as UTF-8. However, by default, it implements the ISO-8859-1 character set.
PropertyPlaceholders support the following:
- Specify the default value together with the key to lookup.
- No need to define the
PropertiesComponent, if all the placeholder keys consist of default values, which are to be used. - Use third-party functions to lookup the property values. It enables you to implement your own logic.NoteProvide three out of the box functions to lookup values from OS environmental variable, JVM system properties, or the service name idiom.
Property files Copy linkLink copied to clipboard!
Key=Value. Lines with # or ! as the first non-blank character are treated as comments.
Example 2.4. Sample Property File
Resolving properties Copy linkLink copied to clipboard!
-
classpath:PathName,PathName,... - (Default) Specifies locations on the classpath, where PathName is a file pathname delimited using forward slashes.
-
file:PathName,PathName,... - Specifies locations on the file system, where PathName is a file pathname delimited using forward slashes.
-
ref:BeanID - Specifies the ID of a
java.util.Propertiesobject in the registry. -
blueprint:BeanID - Specifies the ID of a
cm:property-placeholderbean, which is used in the context of an OSGi blueprint file to access properties defined in the OSGi Configuration Admin service. For details, see the section called “Integration with OSGi blueprint property placeholders”.
com/fusesource/cheese.properties property file and the com/fusesource/bar.properties property file, both located on the classpath, you would use the following location string:
com/fusesource/cheese.properties,com/fusesource/bar.properties
com/fusesource/cheese.properties,com/fusesource/bar.properties
classpath: prefix in this example, because the classpath resolver is used by default.
Specifying locations using system properties and environment variables Copy linkLink copied to clipboard!
${PropertyName}. For example, if the root directory of Red Hat JBoss Fuse is stored in the Java system property, karaf.home, you could embed that directory value in a file location, as follows:
file:${karaf.home}/etc/foo.properties
file:${karaf.home}/etc/foo.properties
${env:VarName}. For example, if the root directory of JBoss Fuse is stored in the environment variable, SMX_HOME, you could embed that directory value in a file location, as follows:
file:${env:SMX_HOME}/etc/foo.properties
file:${env:SMX_HOME}/etc/foo.properties
Configuring the properties component Copy linkLink copied to clipboard!
addComponent() call, the name of the properties component must be set to properties.
propertyPlacholder element, as follows:
.properties files when it is being initialized, you can set the ignoreMissingLocation option to true (normally, a missing .properties file would result in an error being raised).
ignoreMissingLocation option to true.
Placeholder syntax Copy linkLink copied to clipboard!
- In endpoint URIs and in Spring XML files—the placeholder is specified as
{{Key}}. - When setting XML DSL attributes—
xs:stringattributes are set using the following syntax:AttributeName="{{Key}}"AttributeName="{{Key}}"Copy to Clipboard Copied! Toggle word wrap Toggle overflow Other attribute types (for example,xs:intorxs:boolean) must be set using the following syntax:prop:AttributeName="Key"
prop:AttributeName="Key"Copy to Clipboard Copied! Toggle word wrap Toggle overflow Wherepropis associated with thehttp://camel.apache.org/schema/placeholdernamespace. - When setting Java DSL EIP options—to set an option on an Enterprise Integration Pattern (EIP) command in the Java DSL, add a
placeholder()clause like the following to the fluent DSL:.placeholder("OptionName", "Key").placeholder("OptionName", "Key")Copy to Clipboard Copied! Toggle word wrap Toggle overflow - In Simple language expressions—the placeholder is specified as
${properties:Key}.
Substitution in endpoint URIs Copy linkLink copied to clipboard!
{{Key}}. For example, given the property settings shown in Example 2.4, “Sample Property File”, you could define a route as follows:
from("{{cool.start}}")
.to("log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}")
.to("mock:{{cool.result}}");
from("{{cool.start}}")
.to("log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}")
.to("mock:{{cool.result}}");
properties bean ID in the registry to find the property component. If you prefer, you can explicitly specify the scheme in the endpoint URIs. For example, by prefixing properties: to each of the endpoint URIs, you can define the following equivalent route:
from("properties:{{cool.start}}")
.to("properties:log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}")
.to("properties:mock:{{cool.result}}");
from("properties:{{cool.start}}")
.to("properties:log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}")
.to("properties:mock:{{cool.result}}");
location option as follows:
from("direct:start").to("properties:{{bar.end}}?location=com/mycompany/bar.properties");
from("direct:start").to("properties:{{bar.end}}?location=com/mycompany/bar.properties");
Substitution in Spring XML files Copy linkLink copied to clipboard!
{{Key}}. For example, you could define a jmxAgent element using property placeholders, as follows:
Substitution of XML DSL attribute values Copy linkLink copied to clipboard!
xs:string type—for example, <jmxAgent registryPort="{{myjmx.port}}" ...>. But for attributes of any other type (for example, xs:int or xs:boolean), you must use the special syntax, prop:AttributeName="Key".
stop.flag property to have the value, true, you can use this property to set the stopOnException boolean attribute, as follows:
prop prefix must be explicitly assigned to the http://camel.apache.org/schema/placeholder namespace in your Spring file, as shown in the beans element of the preceding example.
Substitution of Java DSL EIP options Copy linkLink copied to clipboard!
placeholder("OptionName", "Key").
stop.flag property to have the value, true, you can use this property to set the stopOnException option of the multicast EIP, as follows:
from("direct:start")
.multicast().placeholder("stopOnException", "stop.flag")
.to("mock:a").throwException(new IllegalAccessException("Damn")).to("mock:b");
from("direct:start")
.multicast().placeholder("stopOnException", "stop.flag")
.to("mock:a").throwException(new IllegalAccessException("Damn")).to("mock:b");
Substitution in Simple language expressions Copy linkLink copied to clipboard!
${properties:Key}. For example, you can substitute the cheese.quote placeholder inside a Simple expression, as follows:
from("direct:start")
.transform().simple("Hi ${body} do you think ${properties:cheese.quote}?");
from("direct:start")
.transform().simple("Hi ${body} do you think ${properties:cheese.quote}?");
${properties:Key:DefaultVal}. For example:
from("direct:start")
.transform().simple("Hi ${body} do you think ${properties:cheese.quote:cheese is good}?");
from("direct:start")
.transform().simple("Hi ${body} do you think ${properties:cheese.quote:cheese is good}?");
${properties-location:Location:Key}. For example, to substitute the bar.quote placeholder using the settings from the com/mycompany/bar.properties property file, you can define a Simple expression as follows:
from("direct:start")
.transform().simple("Hi ${body}. ${properties-location:com/mycompany/bar.properties:bar.quote}.");
from("direct:start")
.transform().simple("Hi ${body}. ${properties-location:com/mycompany/bar.properties:bar.quote}.");
Using Property Placeholders in the XML DSL Copy linkLink copied to clipboard!
xs:string type attributes were used to support placeholders in the XML DSL. For example, the timeout attribute would be a xs:int type. Therefore, you cannot set a string value as the placeholder key.
stopOnException as the value of the placeholder with the key stop. Also, in the properties file, define the value as
stop=true
stop=true
Integration with OSGi blueprint property placeholders Copy linkLink copied to clipboard!
Implicit blueprint integration Copy linkLink copied to clipboard!
camelContext element inside an OSGi blueprint file, the Apache Camel property placeholder mechanism automatically integrates with the blueprint property placeholder mechanism. That is, placeholders obeying the Apache Camel syntax (for example, {{cool.end}}) that appear within the scope of camelContext are implicitly resolved by looking up the blueprint property placeholder mechanism.
{{result}}:
cm:property-placeholder bean. In the preceding example, the cm:property-placeholder bean is associated with the camel.blueprint persistent ID, where a persistent ID is the standard way of referencing a group of related properties from the OSGi Configuration Admin service. In other words, the cm:property-placeholder bean provides access to all of the properties defined under the camel.blueprint persistent ID. It is also possible to specify default values for some of the properties (using the nested cm:property elements).
cm:property-placeholder in the bean registry. If it finds such an instance, it automatically integrates the Apache Camel placeholder mechanism, so that placeholders like, {{result}}, are resolved by looking up the key in the blueprint property placeholder mechanism (in this example, through the myblueprint.placeholder bean).
${Key}. Hence, outside the scope of a camelContext element, the placeholder syntax you must use is ${Key}. Whereas, inside the scope of a camelContext element, the placeholder syntax you must use is {{Key}}.
Explicit blueprint integration Copy linkLink copied to clipboard!
propertyPlaceholder element and specify the resolver locations explicitly.
propertyPlaceholder instance:
propertyPlaceholder element specifies explicitly which cm:property-placeholder bean to use by setting the location to blueprint:myblueprint.placeholder. That is, the blueprint: resolver explicitly references the ID, myblueprint.placeholder, of the cm:property-placeholder bean.
cm:property-placeholder bean defined in the blueprint file and you need to specify which one to use. It also makes it possible to source properties from multiple locations, by specifying a comma-separated list of locations. For example, if you wanted to look up properties both from the cm:property-placeholder bean and from the properties file, myproperties.properties, on the classpath, you could define the propertyPlaceholder element as follows:
<propertyPlaceholder id="properties" location="blueprint:myblueprint.placeholder,classpath:myproperties.properties"/>
<propertyPlaceholder id="properties"
location="blueprint:myblueprint.placeholder,classpath:myproperties.properties"/>
Integration with Spring property placeholders Copy linkLink copied to clipboard!
org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer.
BridgePropertyPlaceholderConfigurer, which replaces both Apache Camel's propertyPlaceholder element and Spring's ctx:property-placeholder element in the Spring XML file. You can then refer to the configured properties using either the Spring ${PropName} syntax or the Apache Camel {{PropName}} syntax.
cheese.properties file:
location attribute of the BridgePropertyPlaceholderConfigurer to point at a Spring properties file. The Spring properties file syntax is fully supported.
2.8. Threading Model Copy linkLink copied to clipboard!
Java thread pool API Copy linkLink copied to clipboard!
ExecutorService interface, which represents a thread pool. Using the concurrency API, you can create many different kinds of thread pool, covering a wide range of scenarios.
Apache Camel thread pool API Copy linkLink copied to clipboard!
org.apache.camel.spi.ExecutorServiceManager type) for all of the thread pools in your Apache Camel application. Centralising the creation of thread pools in this way provides several advantages, including:
- Simplified creation of thread pools, using utility classes.
- Integrating thread pools with graceful shutdown.
- Threads automatically given informative names, which is beneficial for logging and management.
Component threading model Copy linkLink copied to clipboard!
ExecutorServiceManager object.
Processor threading model Copy linkLink copied to clipboard!
| Processor | Java DSL | XML DSL |
|---|---|---|
aggregate |
parallelProcessing() executorService() executorServiceRef()
|
@parallelProcessing @executorServiceRef
|
multicast |
parallelProcessing() executorService() executorServiceRef()
|
@parallelProcessing @executorServiceRef
|
recipientList |
parallelProcessing() executorService() executorServiceRef()
|
@parallelProcessing @executorServiceRef
|
split |
parallelProcessing() executorService() executorServiceRef()
|
@parallelProcessing @executorServiceRef
|
threads |
|
|
wireTap |
wireTap(String uri, ExecutorService executorService) wireTap(String uri, String executorServiceRef)
|
@executorServiceRef
|
threads DSL options Copy linkLink copied to clipboard!
threads processor is a general-purpose DSL command, which you can use to introduce a thread pool into a route. It supports the following options to customize the thread pool:
poolSize()- Minimum number of threads in the pool (and initial pool size).
maxPoolSize()- Maximum number of threads in the pool.
keepAliveTime()- If any threads are idle for longer than this period of time (specified in seconds), they are terminated.
timeUnit()- Time unit for keep alive, specified using the
java.util.concurrent.TimeUnittype. maxQueueSize()- Maximum number of pending tasks that this thread pool can store in its incoming task queue.
rejectedPolicy()- Specifies what course of action to take, if the incoming task queue is full. See Table 2.10, “Thread Pool Builder Options”
executorServiceRef option (for example, you cannot use these options to override the settings in the thread pool referenced by an executorServiceRef option). Apache Camel validates the DSL to enforce this.
Creating a default thread pool Copy linkLink copied to clipboard!
parallelProcessing option, using the parallelProcessing() sub-clause, in the Java DSL, or the parallelProcessing attribute, in the XML DSL.
from("direct:start")
.multicast().parallelProcessing()
.to("mock:first")
.to("mock:second")
.to("mock:third");
from("direct:start")
.multicast().parallelProcessing()
.to("mock:first")
.to("mock:second")
.to("mock:third");
Default thread pool profile settings Copy linkLink copied to clipboard!
| Thread Option | Default Value |
|---|---|
maxQueueSize | 1000 |
poolSize | 10 |
maxPoolSize | 20 |
keepAliveTime | 60 (seconds) |
rejectedPolicy | CallerRuns |
Changing the default thread pool profile Copy linkLink copied to clipboard!
poolSize option and the maxQueueSize option in the default thread pool profile, as follows:
defaultProfile attribute to true in the preceding XML DSL example, otherwise the thread pool profile would be treated like a custom thread pool profile (see the section called “Creating a custom thread pool profile”), instead of replacing the default thread pool profile.
Customizing a processor's thread pool Copy linkLink copied to clipboard!
executorService or executorServiceRef options (where these options are used instead of the parallelProcessing option). There are two approaches you can use to customize a processor's thread pool, as follows:
- Specify a custom thread pool—explicitly create an
ExecutorService(thread pool) instance and pass it to theexecutorServiceoption. - Specify a custom thread pool profile—create and register a custom thread pool factory. When you reference this factory using the
executorServiceRefoption, the processor automatically uses the factory to create a custom thread pool instance.
executorServiceRef option, the threading-aware processor first tries to find a custom thread pool with that ID in the registry. If no thread pool is registered with that ID, the processor then attempts to look up a custom thread pool profile in the registry and uses the custom thread pool profile to instantiate a custom thread pool.
Creating a custom thread pool Copy linkLink copied to clipboard!
- Use the
org.apache.camel.builder.ThreadPoolBuilderutility to build the thread pool class. - Use the
org.apache.camel.spi.ExecutorServiceManagerinstance from the currentCamelContextto create the thread pool class.
ThreadPoolBuilder is actually defined using the ExecutorServiceManager instance. Normally, the ThreadPoolBuilder is preferred, because it offers a simpler approach. But there is at least one kind of thread (the ScheduledExecutorService) that can only be created by accessing the ExecutorServiceManager instance directory.
ThreadPoolBuilder class, which you can set when defining a new custom thread pool.
| Builder Option | Description |
|---|---|
maxQueueSize() | Sets the maximum number of pending tasks that this thread pool can store in its incoming task queue. A value of -1 specifies an unbounded queue. Default value is taken from default thread pool profile. |
poolSize() | Sets the minimum number of threads in the pool (this is also the initial pool size). Default value is taken from default thread pool profile. |
maxPoolSize() | Sets the maximum number of threads that can be in the pool. Default value is taken from default thread pool profile. |
keepAliveTime() | If any threads are idle for longer than this period of time (specified in seconds), they are terminated. This allows the thread pool to shrink when the load is light. Default value is taken from default thread pool profile. |
rejectedPolicy() |
Specifies what course of action to take, if the incoming task queue is full. You can specify four possible values:
|
build() | Finishes building the custom thread pool and registers the new thread pool under the ID specified as the argument to build(). |
ThreadPoolBuilder, as follows:
customPool, directly to the executorService() option, you can look up the thread pool in the registry, by passing its bean ID to the executorServiceRef() option, as follows:
ThreadPoolBuilder using the threadPool element. You can then reference the custom thread pool using the executorServiceRef attribute to look up the thread pool by ID in the Spring registry, as follows:
Creating a custom thread pool profile Copy linkLink copied to clipboard!
customProfile, and reference it from within a route, as follows:
threadPoolProfile element to create a custom pool profile (where you let the defaultProfile option default to false, because this is not a default thread pool profile). You can create a custom thread pool profile with the bean ID, customProfile, and reference it from within a route, as follows:
Sharing a thread pool between components Copy linkLink copied to clipboard!
Customizing thread names Copy linkLink copied to clipboard!
setThreadNamePattern method on the ExecutorServiceStrategy class or the ExecutorServiceManager class. Alternatively, an easier way to set the thread name pattern is to set the threadNamePattern property on the CamelContext object.
#camelId#- The name of the current
CamelContext. #counter#- A unique thread identifier, implemented as an incrementing counter.
#name#- The regular Camel thread name.
#longName#- The long thread name—which can include endpoint parameters and so on.
Camel (#camelId#) thread #counter# - #name#
Camel (#camelId#) thread #counter# - #name#
threadNamePattern attribute on a Camel context using XML DSL:
2.9. Controlling Start-Up and Shutdown of Routes Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
CamelContext instance) starts up and routes are automatically shut down when your Apache Camel application shuts down. For non-critical deployments, the details of the shutdown sequence are usually not very important. But in a production environment, it is often crucial that existing tasks should run to completion during shutdown, in order to avoid data loss. You typically also want to control the order in which routes shut down, so that dependencies are not violated (which would prevent existing tasks from running to completion).
Setting the route ID Copy linkLink copied to clipboard!
myCustomerRouteId, to a route by invoking the routeId() command as follows:
from("SourceURI").routeId("myCustomRouteId").process(...).to(TargetURI);
from("SourceURI").routeId("myCustomRouteId").process(...).to(TargetURI);
route element's id attribute, as follows:
Disabling automatic start-up of routes Copy linkLink copied to clipboard!
autoStartup command, either with a boolean argument (true or false) or a String argument (true or false). For example, you can disable automatic start-up of a route in the Java DSL, as follows:
from("SourceURI")
.routeId("nonAuto")
.autoStartup(false)
.to(TargetURI);
from("SourceURI")
.routeId("nonAuto")
.autoStartup(false)
.to(TargetURI);
autoStartup attribute to false on the route element, as follows:
Manually starting and stopping routes Copy linkLink copied to clipboard!
startRoute() and stopRoute() methods on the CamelContext instance. For example, to start the route having the route ID, nonAuto, invoke the startRoute() method on the CamelContext instance, context, as follows:
// Java
context.startRoute("nonAuto");
// Java
context.startRoute("nonAuto");
nonAuto, invoke the stopRoute() method on the CamelContext instance, context, as follows:
// Java
context.stopRoute("nonAuto");
// Java
context.stopRoute("nonAuto");
Startup order of routes Copy linkLink copied to clipboard!
startupOrder() command, which takes a positive integer value as its argument. The route with the lowest integer value starts first, followed by the routes with successively higher startup order values.
seda:buffer endpoint. You can ensure that the first route segment starts after the second route segment by assigning startup orders (2 and 1 respectively), as follows:
Example 2.5. Startup Order in Java DSL
route element's startupOrder attribute, as follows:
Example 2.6. Startup Order in XML DSL
Shutdown sequence Copy linkLink copied to clipboard!
CamelContext instance is shutting down, Apache Camel controls the shutdown sequence using a pluggable shutdown strategy. The default shutdown strategy implements the following shutdown sequence:
- Routes are shut down in the reverse of the start-up order.
- Normally, the shutdown strategy waits until the currently active exchanges have finshed processing. The treatment of running tasks is configurable, however.
- Overall, the shutdown sequence is bound by a timeout (default, 300 seconds). If the shutdown sequence exceeds this timeout, the shutdown strategy will force shutdown to occur, even if some tasks are still running.
Shutdown order of routes Copy linkLink copied to clipboard!
startupOrder() command (in Java DSL) or startupOrder attribute (in XML DSL), the first route to shut down is the route with the highest integer value assigned by the start-up order and the last route to shut down is the route with the lowest integer value assigned by the start-up order.
first, and the second route segment to be shut down is the route with the ID, second. This example illustrates a general rule, which you should observe when shutting down routes: the routes that expose externally-accessible consumer endpoints should be shut down first, because this helps to throttle the flow of messages through the rest of the route graph.
shutdownRoute(Defer), which enables you to specify that a route must be amongst the last routes to shut down (overriding the start-up order value). But you should rarely ever need this option. This option was mainly needed as a workaround for earlier versions of Apache Camel (prior to 2.3), for which routes would shut down in the same order as the start-up order.
Shutting down running tasks in a route Copy linkLink copied to clipboard!
shutdownRunningTask option, which can take either of the following values:
-
ShutdownRunningTask.CompleteCurrentTaskOnly - (Default) Usually, a route operates on just a single message at a time, so you can safely shut down the route after the current task has completed.
-
ShutdownRunningTask.CompleteAllTasks - Specify this option in order to shut down batch consumers gracefully. Some consumer endpoints (for example, File, FTP, Mail, iBATIS, and JPA) operate on a batch of messages at a time. For these endpoints, it is more appropriate to wait until all of the messages in the current batch have completed.
CompleteAllTasks option, as shown in the following Java DSL fragment:
Shutdown timeout Copy linkLink copied to clipboard!
setTimeout() method on the shutdown strategy. For example, you can change the timeout value to 600 seconds, as follows:
// Java // context = CamelContext instance context.getShutdownStrategy().setTimeout(600);
// Java
// context = CamelContext instance
context.getShutdownStrategy().setTimeout(600);
Integration with custom components Copy linkLink copied to clipboard!
org.apache.camel.Service interface), you can ensure that your custom code receives a shutdown notification by implementing the org.apache.camel.spi.ShutdownPrepared interface. This gives the component an opportunity execute custom code in preparation for shutdown.
2.10. Scheduled Route Policy Copy linkLink copied to clipboard!
2.10.1. Overview of Scheduled Route Policies Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Scheduling tasks Copy linkLink copied to clipboard!
- Start a route—start the route at the time (or times) specified. This event only has an effect, if the route is currently in a stopped state, awaiting activation.
- Stop a route—stop the route at the time (or times) specified. This event only has an effect, if the route is currently active.
- Suspend a route—temporarily de-activate the consumer endpoint at the start of the route (as specified in
from()). The rest of the route is still active, but clients will not be able to send new messages into the route. - Resume a route—re-activate the consumer endpoint at the start of the route, returning the route to a fully active state.
Quartz component Copy linkLink copied to clipboard!
2.10.2. Simple Scheduled Route Policy Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.routepolicy.quartz.SimpleScheduledRoutePolicy
org.apache.camel.routepolicy.quartz.SimpleScheduledRoutePolicy
Dependency Copy linkLink copied to clipboard!
camel-quartz. For example, if you are using Maven as your build system, you would need to add a dependency on the camel-quartz artifact.
Java DSL example Copy linkLink copied to clipboard!
startTime, is defined to be 3 seconds after the current time. The policy is also configured to start the route a second time, 3 seconds after the initial start time, which is configured by setting routeStartRepeatCount to 1 and routeStartRepeatInterval to 3000 milliseconds.
routePolicy() DSL command in the route.
Example 2.7. Java DSL Example of Simple Scheduled Route
routePolicy() with multiple arguments.
XML DSL example Copy linkLink copied to clipboard!
routePolicyRef attribute on the route element.
Example 2.8. XML DSL Example of Simple Scheduled Route
routePolicyRef as a comma-separated list of bean IDs.
Defining dates and times Copy linkLink copied to clipboard!
java.util.Date type.The most flexible way to define a Date instance is through the java.util.GregorianCalendar class. Use the convenient constructors and methods of the GregorianCalendar class to define a date and then obtain a Date instance by calling GregorianCalendar.getTime().
GregorianCalendar constructor as follows:
GregorianCalendar class also supports the definition of times in different time zones. By default, it uses the local time zone on your computer.
Graceful shutdown Copy linkLink copied to clipboard!
Logging Inflight Exchanges on Timeout Copy linkLink copied to clipboard!
org.apache.camel.impl.DefaultShutdownStrategy, then it logs the same inflight exchange information.
2015-01-12 13:23:23,656 [- ShutdownTask] INFO DefaultShutdownStrategy - There are 1 inflight exchanges: InflightExchange: [exchangeId=ID-davsclaus-air-62213-1421065401253-0-3, fromRouteId=route1, routeId=route1, nodeId=delay1, elapsed=2007, duration=2017]
2015-01-12 13:23:23,656 [- ShutdownTask] INFO DefaultShutdownStrategy - There are 1 inflight exchanges:
InflightExchange: [exchangeId=ID-davsclaus-air-62213-1421065401253-0-3, fromRouteId=route1, routeId=route1, nodeId=delay1, elapsed=2007, duration=2017]
context.getShutdownStrategegy().setLogInflightExchangesOnTimeout(false);
context.getShutdownStrategegy().setLogInflightExchangesOnTimeout(false);
Scheduling tasks Copy linkLink copied to clipboard!
Starting a route Copy linkLink copied to clipboard!
| Parameter | Type | Default | Description |
|---|---|---|---|
routeStartDate | java.util.Date | None | Specifies the date and time when the route is started for the first time. |
routeStartRepeatCount | int | 0 | When set to a non-zero value, specifies how many times the route should be started. |
routeStartRepeatInterval | long | 0 | Specifies the time interval between starts, in units of milliseconds. |
Stopping a route Copy linkLink copied to clipboard!
| Parameter | Type | Default | Description |
|---|---|---|---|
routeStopDate | java.util.Date | None | Specifies the date and time when the route is stopped for the first time. |
routeStopRepeatCount | int | 0 | When set to a non-zero value, specifies how many times the route should be stopped. |
routeStopRepeatInterval | long | 0 | Specifies the time interval between stops, in units of milliseconds. |
routeStopGracePeriod | int | 10000 | Specifies how long to wait for the current exchange to finish processing (grace period) before forcibly stopping the route. Set to 0 for an infinite grace period. |
routeStopTimeUnit | long | TimeUnit.MILLISECONDS | Specifies the time unit of the grace period. |
Suspending a route Copy linkLink copied to clipboard!
| Parameter | Type | Default | Description |
|---|---|---|---|
routeSuspendDate | java.util.Date | None | Specifies the date and time when the route is suspended for the first time. |
routeSuspendRepeatCount | int | 0 | When set to a non-zero value, specifies how many times the route should be suspended. |
routeSuspendRepeatInterval | long | 0 | Specifies the time interval between suspends, in units of milliseconds. |
Resuming a route Copy linkLink copied to clipboard!
| Parameter | Type | Default | Description |
|---|---|---|---|
routeResumeDate | java.util.Date | None | Specifies the date and time when the route is resumed for the first time. |
routeResumeRepeatCount | int | 0 | When set to a non-zero value, specifies how many times the route should be resumed. |
routeResumeRepeatInterval | long | 0 | Specifies the time interval between resumes, in units of milliseconds. |
2.10.3. Cron Scheduled Route Policy Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.routepolicy.quartz.CronScheduledRoutePolicy
org.apache.camel.routepolicy.quartz.CronScheduledRoutePolicy
Dependency Copy linkLink copied to clipboard!
camel-quartz. For example, if you are using Maven as your build system, you would need to add a dependency on the camel-quartz artifact.
Java DSL example Copy linkLink copied to clipboard!
*/3 * * * * ?, which triggers a start event every 3 seconds.
routePolicy() DSL command in the route.
Example 2.9. Java DSL Example of a Cron Scheduled Route
routePolicy() with multiple arguments.
XML DSL example Copy linkLink copied to clipboard!
routePolicyRef attribute on the route element.
Example 2.10. XML DSL Example of a Cron Scheduled Route
routePolicyRef as a comma-separated list of bean IDs.
Defining cron expressions Copy linkLink copied to clipboard!
cron utility, which schedules jobs to run in the background on a UNIX system. A cron expression is effectively a syntax for wildcarding dates and times that enables you to specify either a single event or multiple events that recur periodically.
Seconds Minutes Hours DayOfMonth Month DayOfWeek [Year]
Seconds Minutes Hours DayOfMonth Month DayOfWeek [Year]
Year field is optional and usually omitted, unless you want to define an event that occurs once and once only. Each field consists of a mixture of literals and special characters. For example, the following cron expression specifies an event that fires once every day at midnight:
0 0 24 * * ?
0 0 24 * * ?
* character is a wildcard that matches every value of a field. Hence, the preceding expression matches every day of every month. The ? character is a dummy placeholder that means ignore this field. It always appears either in the DayOfMonth field or in the DayOfWeek field, because it is not logically consistent to specify both of these fields at the same time. For example, if you want to schedule an event that fires once a day, but only from Monday to Friday, use the following cron expression:
0 0 24 ? * MON-FRI
0 0 24 ? * MON-FRI
MON-FRI. You can also use the forward slash character, /, to specify increments. For example, to specify that an event fires every 5 minutes, use the following cron expression:
0 0/5 * * * ?
0 0/5 * * * ?
Scheduling tasks Copy linkLink copied to clipboard!
Starting a route Copy linkLink copied to clipboard!
| Parameter | Type | Default | Description |
|---|---|---|---|
routeStartString | String | None | Specifies a cron expression that triggers one or more route start events. |
Stopping a route Copy linkLink copied to clipboard!
| Parameter | Type | Default | Description |
|---|---|---|---|
routeStopTime | String | None | Specifies a cron expression that triggers one or more route stop events. |
routeStopGracePeriod | int | 10000 | Specifies how long to wait for the current exchange to finish processing (grace period) before forcibly stopping the route. Set to 0 for an infinite grace period. |
routeStopTimeUnit | long | TimeUnit.MILLISECONDS | Specifies the time unit of the grace period. |
Suspending a route Copy linkLink copied to clipboard!
| Parameter | Type | Default | Description |
|---|---|---|---|
routeSuspendTime | String | None | Specifies a cron expression that triggers one or more route suspend events. |
Resuming a route Copy linkLink copied to clipboard!
| Parameter | Type | Default | Description |
|---|---|---|---|
routeResumeTime | String | None | Specifies a cron expression that triggers one or more route resume events. |
2.10.4. Route Policy Factory Copy linkLink copied to clipboard!
Using Route Policy Factory Copy linkLink copied to clipboard!
org.apache.camel.spi.RoutePolicyFactory as a factory for creating a RoutePolicy instance for each route. This can be used when you want to use the same kind of route policy for every route. Then you need to only configure the factory once, and every route created will have the policy assigned.
context.addRoutePolicyFactory(new MyRoutePolicyFactory());
context.addRoutePolicyFactory(new MyRoutePolicyFactory());
<bean> with the factory
<bean id="myRoutePolicyFactory" class="com.foo.MyRoutePolicyFactory"/>
<bean id="myRoutePolicyFactory" class="com.foo.MyRoutePolicyFactory"/>
addRoutePolicyFactory again, or declare the other factories as <bean> in XML.
2.11. Metrics Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Add camel-metrics component
- Enable route metrics in XML or Java code
Metrics Route Policy Copy linkLink copied to clipboard!
MetricsRoutePolicy on a per route basis.
MetricsRoutePolicy to be assigned as the route's policy. This is shown below:
from("file:src/data?noop=true").routePolicy(new MetricsRoutePolicy()).to("jms:incomingOrders");
from("file:src/data?noop=true").routePolicy(new MetricsRoutePolicy()).to("jms:incomingOrders");
<bean> which is specified as the route's policy; for example:
Metrics Route Policy Factory Copy linkLink copied to clipboard!
RoutePolicy for each route which exposes route utilization statistics using Codahale metrics. This factory can be used in Java and XML as the examples below demonstrate.
CamelContext as shown below:
context.addRoutePolicyFactory(new MetricsRoutePolicyFactory());
context.addRoutePolicyFactory(new MetricsRoutePolicyFactory());
<bean> as follows:
<!-- use camel-metrics route policy to gather metrics for all routes --> <bean id="metricsRoutePolicyFactory" class="org.apache.camel.component.metrics.routepolicy.MetricsRoutePolicyFactory"/>
<!-- use camel-metrics route policy to gather metrics for all routes -->
<bean id="metricsRoutePolicyFactory" class="org.apache.camel.component.metrics.routepolicy.MetricsRoutePolicyFactory"/>
com.codahale.metrics.MetricRegistry from the org.apache.camel.component.metrics.routepolicy.MetricsRegistryService as shown below:
MetricRegistryService registryService = context.hasService(MetricsRegistryService.class);
if (registryService != null) {
MetricsRegistry registry = registryService.getMetricsRegistry();
...
}
MetricRegistryService registryService = context.hasService(MetricsRegistryService.class);
if (registryService != null) {
MetricsRegistry registry = registryService.getMetricsRegistry();
...
}
Options Copy linkLink copied to clipboard!
MetricsRoutePolicyFactory and MetricsRoutePolicy supports the following options:
| Name | Default | Description |
|---|---|---|
durationUnit
|
TimeUnit.MILLISECONDS
|
The unit to use for duration in the metrics reporter or when dumping the statistics as json. |
jmxDomain
|
org.apache.camel.metrics
|
The JXM domain name. |
metricsRegistry
|
Allow to use a shared com.codahale.metrics.MetricRegistry. If none is provided then Camel will create a shared instance used by the this CamelContext.
|
|
prettyPrint
|
false
|
Whether to use pretty print when outputting statistics in json format. |
rateUnit
|
TimeUnit.SECONDS
|
The unit to use for rate in the metrics reporter or when dumping the statistics as json. |
useJmx
|
false
|
Whether to report fine grained statistics to JMX by using the
com.codahale.metrics.JmxReporter.
Notice that if JMX is enabled on CamelContext then a
MetricsRegistryService mbean is enlisted under the services type in the JMX tree. That mbean has a single operation to output the statistics using json. Setting useJmx to true is only needed if you want fine grained mbeans per statistics type.
|
2.12. JMX Naming Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
CamelContext bean as it appears in JMX, by defining a management name pattern for it. For example, you can customise the name pattern of an XML CamelContext instance, as follows:
<camelContext id="myCamel" managementNamePattern="#name#">
...
</camelContext>
<camelContext id="myCamel" managementNamePattern="#name#">
...
</camelContext>
CamelContext bean, Apache Camel reverts to a default naming strategy.
Default naming strategy Copy linkLink copied to clipboard!
CamelContext bean deployed in an OSGi bundle is equal to the OSGi symbolic name of the bundle. For example, if the OSGi symbolic name is MyCamelBundle, the JMX name would be MyCamelBundle. In cases where there is more than one CamelContext in the bundle, the JMX name is disambiguated by adding a counter value as a suffix. For example, if there are multiple Camel contexts in the MyCamelBundle bundle, the corresponding JMX MBeans are named as follows:
MyCamelBundle-1 MyCamelBundle-2 MyCamelBundle-3 ...
MyCamelBundle-1
MyCamelBundle-2
MyCamelBundle-3
...
Customising the JMX naming strategy Copy linkLink copied to clipboard!
CamelContext bean will have the same JMX name between runs. If you want to have greater consistency between runs, you can control the JMX name more precisely by defining a JMX name pattern for the CamelContext instances.
Specifying a name pattern in Java Copy linkLink copied to clipboard!
CamelContext in Java, call the setNamePattern method, as follows:
// Java
context.getManagementNameStrategy().setNamePattern("#name#");
// Java
context.getManagementNameStrategy().setNamePattern("#name#");
Specifying a name pattern in XML Copy linkLink copied to clipboard!
CamelContext in XML, set the managementNamePattern attribute on the camelContext element, as follows:
<camelContext id="myCamel" managementNamePattern="#name#">
<camelContext id="myCamel" managementNamePattern="#name#">
Name pattern tokens Copy linkLink copied to clipboard!
| Token | Description |
|---|---|
#camelId# | Value of the id attribute on the CamelContext bean. |
#name# | Same as #camelId#. |
#counter# | An incrementing counter (starting at 1). |
#bundleId# | The OSGi bundle ID of the deployed bundle (OSGi only). |
#symbolicName# | The OSGi symbolic name (OSGi only). |
#version# | The OSGi bundle version (OSGi only). |
Examples Copy linkLink copied to clipboard!
Ambiguous names Copy linkLink copied to clipboard!
<camelContext id="foo" managementNamePattern="SameOldSameOld"> ... </camelContext> ... <camelContext id="bar" managementNamePattern="SameOldSameOld"> ... </camelContext>
<camelContext id="foo" managementNamePattern="SameOldSameOld"> ... </camelContext>
...
<camelContext id="bar" managementNamePattern="SameOldSameOld"> ... </camelContext>
2.13. Performance and Optimization Copy linkLink copied to clipboard!
Avoid unnecessary message copying Copy linkLink copied to clipboard!
allowUseOriginalMessage option to false on the CamelContext object. For example, in Blueprint XML you can set this option as follows:
<camelContext xmlns="http://camel.apache.org/schema/blueprint"
allowUseOriginalMessage="false">
...
</camelContext>
<camelContext xmlns="http://camel.apache.org/schema/blueprint"
allowUseOriginalMessage="false">
...
</camelContext>
allowUseOriginalMessage to false, if the following conditions are satisfied:
- You do not set
useOriginalMessage=trueon any of the error handlers or on theonExceptionelement. - You do not use the
getOriginalMessagemethod anywhere in your Java application code.
Chapter 3. Introducing Enterprise Integration Patterns Copy linkLink copied to clipboard!
Abstract
3.1. Overview of the Patterns Copy linkLink copied to clipboard!
Enterprise Integration Patterns book Copy linkLink copied to clipboard!
Messaging systems Copy linkLink copied to clipboard!
| Icon | Name | Use Case |
|---|---|---|
| | Message | How can two applications connected by a message channel exchange a piece of information? |
| | Message Channel | How does one application communicate with another application using messaging? |
| | Message Endpoint | How does an application connect to a messaging channel to send and receive messages? |
| | Pipes and Filters | How can we perform complex processing on a message while still maintaining independence and flexibility? |
| | Message Router | How can you decouple individual processing steps so that messages can be passed to different filters depending on a set of defined conditions? |
| | Message Translator | How do systems using different data formats communicate with each other using messaging? |
Messaging channels Copy linkLink copied to clipboard!
| Icon | Name | Use Case |
|---|---|---|
| | Point to Point Channel | How can the caller be sure that exactly one receiver will receive the document or will perform the call? |
| | Publish Subscribe Channel | How can the sender broadcast an event to all interested receivers? |
| | Dead Letter Channel | What will the messaging system do with a message it cannot deliver? |
| | Guaranteed Delivery | How does the sender make sure that a message will be delivered, even if the messaging system fails? |
| | Message Bus | What is an architecture that enables separate, decoupled applications to work together, such that one or more of the applications can be added or removed without affecting the others? |
Message construction Copy linkLink copied to clipboard!
| Icon | Name | Use Case |
|---|---|---|
| | Correlation Identifier | How does a requestor identify the request that generated the received reply? |
| | Return Address | How does a replier know where to send the reply? |
Message routing Copy linkLink copied to clipboard!
| Icon | Name | Use Case |
|---|---|---|
| | Content Based Router | How do we handle a situation where the implementation of a single logical function (e.g., inventory check) is spread across multiple physical systems? |
| | Message Filter | How does a component avoid receiving uninteresting messages? |
| | Recipient List | How do we route a message to a list of dynamically specified recipients? |
| | Splitter | How can we process a message if it contains multiple elements, each of which might have to be processed in a different way? |
| | Aggregator | How do we combine the results of individual, but related messages so that they can be processed as a whole? |
| | Resequencer | How can we get a stream of related, but out-of-sequence, messages back into the correct order? |
| | Composed Message Processor | How can you maintain the overall message flow when processing a message consisting of multiple elements, each of which may require different processing? |
| Scatter-Gather | How do you maintain the overall message flow when a message needs to be sent to multiple recipients, each of which may send a reply? | |
| | Routing Slip | How do we route a message consecutively through a series of processing steps when the sequence of steps is not known at design-time, and might vary for each message? |
| Throttler | How can I throttle messages to ensure that a specific endpoint does not get overloaded, or that we don't exceed an agreed SLA with some external service? | |
| Delayer | How can I delay the sending of a message? | |
| Load Balancer | How can I balance load across a number of endpoints? | |
| Multicast | How can I route a message to a number of endpoints at the same time? | |
| Loop | How can I repeat processing a message in a loop? | |
| Sampling | How can I sample one message out of many in a given period to avoid downstream route does not get overloaded? |
Message transformation Copy linkLink copied to clipboard!
| Icon | Name | Use Case |
|---|---|---|
| | Content Enricher | How do we communicate with another system if the message originator does not have all the required data items available? |
| | Content Filter | How do you simplify dealing with a large message, when you are interested in only a few data items? |
| | Claim Check | How can we reduce the data volume of message sent across the system without sacrificing information content? |
| | Normalizer | How do you process messages that are semantically equivalent, but arrive in a different format? |
| Sort | How can I sort the body of a message? |
Messaging endpoints Copy linkLink copied to clipboard!
| Icon | Name | Use Case |
|---|---|---|
| Messaging Mapper | How do you move data between domain objects and the messaging infrastructure while keeping the two independent of each other? | |
| | Event Driven Consumer | How can an application automatically consume messages as they become available? |
| | Polling Consumer | How can an application consume a message when the application is ready? |
| | Competing Consumers | How can a messaging client process multiple messages concurrently? |
| | Message Dispatcher | How can multiple consumers on a single channel coordinate their message processing? |
| | Selective Consumer | How can a message consumer select which messages it wants to receive? |
| | Durable Subscriber | How can a subscriber avoid missing messages when it's not listening for them? |
| Idempotent Consumer | How can a message receiver deal with duplicate messages? | |
| | Transactional Client | How can a client control its transactions with the messaging system? |
| | Messaging Gateway | How do you encapsulate access to the messaging system from the rest of the application? |
| | Service Activator | How can an application design a service to be invoked both via various messaging technologies and via non-messaging techniques? |
System management Copy linkLink copied to clipboard!
| Icon | Name | Use Case |
|---|---|---|
| | Wire Tap | How do you inspect messages that travel on a point-to-point channel? |
Chapter 4. Defining REST Services Copy linkLink copied to clipboard!
Abstract
4.1. Overview of REST in Camel Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
What is REST? Copy linkLink copied to clipboard!
GET, POST, PUT, and DELETE.
A sample REST invocation Copy linkLink copied to clipboard!
localhost:9091, you could navigate to a URL like the following in your browser:
http://localhost:9091/say/hello/Garp
http://localhost:9091/say/hello/Garp
Hello Garp
Hello Garp
curl command-line utility), is one of the many reasons why the REST protocol has rapidly gained popularity.
REST wrapper layers Copy linkLink copied to clipboard!
- REST DSL
- The REST DSL (in
camel-core) is a facade or wrapper layer that provides a simplified builder API for defining REST services. The REST DSL does not itself provide a REST implementation: it must be combined with an underlying REST implementation. For example, the following Java code shows how to define a simple Hello World service using the REST DSL:rest("/say") .get("/hello/{name}").route().transform().simple("Hello ${header.name}");rest("/say") .get("/hello/{name}").route().transform().simple("Hello ${header.name}");Copy to Clipboard Copied! Toggle word wrap Toggle overflow For more details, see Section 4.2, “Defining Services with REST DSL”. - Rest component
- The Rest component (in
camel-core) is a wrapper layer that enables you to define REST services using a URI syntax. Like the REST DSL, the Rest component does not itself provide a REST implementation: it must be combined with an underlying REST implementation. For example, the following Java code shows how to define a simple Hello World service using the Rest component:from("rest:get:say:/hello/{name}").transform().simple("Hello ${header.name}");from("rest:get:say:/hello/{name}").transform().simple("Hello ${header.name}");Copy to Clipboard Copied! Toggle word wrap Toggle overflow
REST implementations Copy linkLink copied to clipboard!
- Spark-Rest component
- The Spark-Rest component (in
camel-spark-rest) is a REST implementation that enables you to define REST services using a URI syntax. The Spark framework itself is a Java API, which is loosely based on the Sinatra framework (a Python API). For example, the following Java code shows how to define a simple Hello World service using the Spark-Rest component:from("spark-rest:get:/say/hello/:name").transform().simple("Hello ${header.name}");from("spark-rest:get:/say/hello/:name").transform().simple("Hello ${header.name}");Copy to Clipboard Copied! Toggle word wrap Toggle overflow Notice that, in contrast to the Rest component, the syntax for a variable in the URI is:nameinstead of{name}.NoteThe Spark-Rest component requires Java 8. - Restlet component
- The Restlet component (in
camel-restlet) is a REST implementation that can, in principle, be layered above different transport protocols (although this component is only tested against the HTTP protocol). This component also provides an integration with the Restlet Framework, which is a commercial framework for developing REST services in Java. For example, the following Java code shows how to define a simple Hello World service using the Restlet component:from("restlet:http://0.0.0.0:9091/say/hello/{name}?restletMethod=get") .transform().simple("Hello ${header.name}");from("restlet:http://0.0.0.0:9091/say/hello/{name}?restletMethod=get") .transform().simple("Hello ${header.name}");Copy to Clipboard Copied! Toggle word wrap Toggle overflow For more details, see see Restlet in the Apache Camel Component Reference Guide. - Servlet component
- The Servlet component (in
camel-servlet) is a component that binds a Java servlet to a Camel route. In other words, the Servlet component enables you to package and deploy a Camel route as if it was a standard Java servlet. The Servlet component is therefore particularly useful, if you need to deploy a Camel route inside a servlet container (for example, into an Apache Tomcat HTTP server or into a JBoss Enterprise Application Platform container).The Servlet component on its own, however, does not provide any convenient REST API for defining REST services. The easiest way to use the Servlet component, therefore, is to combine it with the REST DSL, so that you can define REST services with a user-friendly API.For more details, see see Servlet in the Apache Camel Component Reference Guide. .
JAX-RS REST implementation Copy linkLink copied to clipboard!
- @Path
- Annotation that can map a context path to a Java class or map a sub-path to a particular Java method.
- @GET, @POST, @PUT, @DELETE
- Annotations that map a HTTP method to a Java method.
- @PathParam
- Annotation that either maps a URI parameter to a Java method argument, or injects a URI parameter into a field.
- @QueryParam
- Annotation that either maps a query parameter to a Java method argument, or injects a query parameter into a field.
4.2. Defining Services with REST DSL Copy linkLink copied to clipboard!
REST DSL is a facade Copy linkLink copied to clipboard!
Advantages of the REST DSL Copy linkLink copied to clipboard!
- A modern easy-to-use syntax for defining REST services.
- Compatible with multiple different Apache Camel components.
- Swagger integration (through the
camel-swaggercomponent).
Components that integrate with REST DSL Copy linkLink copied to clipboard!
- Servlet component (
camel-servlet). - Spark-Rest component (
camel-spark-rest). - Netty HTTP component (
camel-netty-http). - Netty4 HTTP component (
camel-netty4-http). - Jetty component (
camel-jetty). - Restlet component (
camel-restlet).
camel-core) is not a REST implementation. Like the REST DSL, the Rest component is a facade, providing a simplified syntax to define REST services using a URI syntax. The Rest component also requires an underlying REST implementation.
Configuring REST DSL to use a REST implementation Copy linkLink copied to clipboard!
restConfiguration() builder (in Java DSL) or the restConfiguration element (in XML DSL). For example, to configure REST DSL to use the Spark-Rest component, you would use a builder expression like the following in the Java DSL:
restConfiguration().component("spark-rest").port(9091);
restConfiguration().component("spark-rest").port(9091);
camelContext) in the XML DSL:
<restConfiguration component="spark-rest" port="9091"/>
<restConfiguration component="spark-rest" port="9091"/>
Syntax Copy linkLink copied to clipboard!
rest("BasePath").Option()+.
.Verb("Path").Option()+.[to() | route().CamelRoute.endRest()]
.Verb("Path").Option()+.[to() | route().CamelRoute.endRest()]
...
.Verb("Path").Option()+.[to() | route().CamelRoute];
rest("BasePath").Option()+.
.Verb("Path").Option()+.[to() | route().CamelRoute.endRest()]
.Verb("Path").Option()+.[to() | route().CamelRoute.endRest()]
...
.Verb("Path").Option()+.[to() | route().CamelRoute];
CamelRoute is an optional embedded Camel route (defined using the standard Java DSL syntax for routes).
rest() keyword, followed by one or more verb clauses that handle specific URL path segments. The HTTP verb can be one of get(), head(), put(), post(), delete(), or verb(). Each verb clause can use either of the following syntaxes:
- Verb clause ending in
to()keyword. For example:get("...").Option()+.to("...")get("...").Option()+.to("...")Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Verb clause ending in
route()keyword (for embedding a Camel route). For example:get("...").Option()+.route("...").CamelRoute.endRest()get("...").Option()+.route("...").CamelRoute.endRest()Copy to Clipboard Copied! Toggle word wrap Toggle overflow
REST DSL with Java Copy linkLink copied to clipboard!
RouteBuilder.configure() method, just like you do for regular Apache Camel routes. For example, to define a simple Hello World service using the REST DSL with the Spark-Rest component, define the following Java code:
-
restConfiguration() - Configures the REST DSL to use a specific REST implementation (Spark-Rest).
-
rest() - Defines a service using the REST DSL. Each of the verb clauses are terminated by a
to()keyword, which forwards the incoming message to adirectendpoint (thedirectcomponent splices routes together within the same application). -
from() - Defines a regular Camel route.
REST DSL with XML Copy linkLink copied to clipboard!
rest element as a child of the camelContext element. For example, to define a simple Hello World service using the REST DSL with the Spark-Rest component, define the following XML code (in Blueprint):
Specifying a base path Copy linkLink copied to clipboard!
rest() keyword (Java DSL) or the path attribute of the rest element (XML DSL) allows you to define a base path, which is then prefixed to the paths in all of the verb clauses. For example, given the following snippet of Java DSL:
rest("/say")
.get("/hello").to("direct:hello")
.get("/bye").to("direct:bye");
rest("/say")
.get("/hello").to("direct:hello")
.get("/bye").to("direct:bye");
/say/hello /say/bye
/say/hello
/say/bye
rest()
.get("/say/hello").to("direct:hello")
.get("/say/bye").to("direct:bye");
rest()
.get("/say/hello").to("direct:hello")
.get("/say/bye").to("direct:bye");
URI templates Copy linkLink copied to clipboard!
{name} path segment and copies this captured text into the name message header. If you invoke the service by sending a GET HTTP Request with the URL ending in /say/hello/Joe, the HTTP Response is Hello Joe.
Embedded route syntax Copy linkLink copied to clipboard!
to() keyword (Java DSL) or the to element (XML DSL), you have the option of embedding an Apache Camel route directly into the REST DSL, using the route() keyword (Java DSL) or the route element (XML DSL). The route() keyword enables you to embed a route into a verb clause, with the following syntax:
RESTVerbClause.route("...").CamelRoute.endRest()
RESTVerbClause.route("...").CamelRoute.endRest()
endRest() keyword (Java DSL only) is a necessary punctuation mark that enables you to separate the verb clauses (when there is more than one verb clause in the rest() builder).
rest("/say")
.get("/hello").route().transform().constant("Hello World").endRest()
.get("/bye").route().transform().constant("Bye World");
rest("/say")
.get("/hello").route().transform().constant("Hello World").endRest()
.get("/bye").route().transform().constant("Bye World");
onException()) or interceptors (using intercept()) in the current CamelContext, these exception clauses and interceptors are also active in the embedded routes.
Specifying the content type of requests and responses Copy linkLink copied to clipboard!
consumes() and produces() options in Java, or the consumes and produces attributes in XML. For example, some common content types (officially known as Internet media types) are the following:
text/plaintext/htmltext/xmlapplication/jsonapplication/xml
text/plain HTTP requests, and to send only text/html HTTP responses, you would use Java code like the following:
rest("/email")
.post("/to/{recipient}").consumes("text/plain").produces("text/html").to("direct:foo");
rest("/email")
.post("/to/{recipient}").consumes("text/plain").produces("text/html").to("direct:foo");
consumes and produces attributes, as follows:
consumes() or produces() as a comma-separated list. For example, consumes("text/plain, application/json").
Additional HTTP methods Copy linkLink copied to clipboard!
get(), head(), put(), post(), delete(). To access additional HTTP methods, you can use the generic keyword, verb(), in Java DSL and the generic element, verb, in XML DSL.
rest("/say")
.verb("TRACE", "/hello").route().transform();
rest("/say")
.verb("TRACE", "/hello").route().transform();
transform() copies the body of the IN message to the body of the OUT message, thus echoing the HTTP request.
Defining custom HTTP error messages Copy linkLink copied to clipboard!
- Specify the HTTP error code by setting the
Exchange.HTTP_RESPONSE_CODEheader key to the error code value (for example,400,404, and so on). This setting indicates to the REST DSL that you want to send an error message reply, instead of a regular response. - Populate the message body with your custom error message.
- Set the
Content-Typeheader, if required. - If your REST service is configured to marshal to and from Java objects (that is,
bindingModeis enabled), you should ensure that theskipBindingOnErrorCodeoption is enabled (which it is, by default). This is to ensure that the REST DSL does not attempt to unmarshal the message body when sending the response.For more details about object binding, see Section 4.3, “Marshalling to and from Java Objects”.
UserErrorService bean, which is implemented as follows:
UserErrorService bean we define the custom error message and set the HTTP error code to 400.
Wrapping a JsonParserException in a custom HTTP error message Copy linkLink copied to clipboard!
JsonParserException exception. For example, you can conveniently exploit the Camel exception handling mechanism to create a custom HTTP error message, with HTTP error code 400, as follows:
REST DSL options Copy linkLink copied to clipboard!
rest()), as follows:
rest("/email").consumes("text/plain").produces("text/html")
.post("/to/{recipient}").to("direct:foo")
.get("/for/{username}").to("direct:bar");
rest("/email").consumes("text/plain").produces("text/html")
.post("/to/{recipient}").to("direct:foo")
.get("/for/{username}").to("direct:bar");
rest("/email")
.post("/to/{recipient}").consumes("text/plain").produces("text/html").to("direct:foo")
.get("/for/{username}").consumes("text/plain").produces("text/html").to("direct:bar");
rest("/email")
.post("/to/{recipient}").consumes("text/plain").produces("text/html").to("direct:foo")
.get("/for/{username}").consumes("text/plain").produces("text/html").to("direct:bar");
| Java DSL | XML DSL | Description |
|---|---|---|
bindingMode() | @bindingMode | Specifies the binding mode, which can be used to marshal incoming messages to Java objects (and, optionally, unmarshal Java objects to outgoing messages). Can have the following values: off (default), auto, json, xml, json_xml. |
consumes() | @consumes | Restricts the verb clause to accept only the specified Internet media type (MIME type) in a HTTP Request. Typical values are: text/plain, text/http, text/xml, application/json, application/xml. |
customId() | @customId | Defines a custom ID for JMX management. |
description() | description | Document the REST service or verb clause. Useful for JMX management and tooling. |
enableCORS() | @enableCORS | If true, enables CORS (cross-origin resource sharing) headers in the HTTP response. Default is false. |
id() | @id | Defines a unique ID for the REST service, which is useful to define for JMX management and other tooling. |
method() | @method | Specifies the HTTP method processed by this verb clause. Usually used in conjunction with the generic verb() keyword. |
outType() | @outType | When object binding is enabled (that is, when bindingMode option is enabled), this option specifies the Java type that represents a HTTP Response message. |
produces() | produces | Restricts the verb clause to produce only the specified Internet media type (MIME type) in a HTTP Response. Typical values are: text/plain, text/http, text/xml, application/json, application/xml. |
type() | @type | When object binding is enabled (that is, when bindingMode option is enabled), this option specifies the Java type that represents a HTTP Request message. |
VerbURIArgument | @uri | Specifies a path segment or URI template as an argument to a verb. For example, get(VerbURIArgument). |
BasePathArgument | @path | Specifies the base path in the rest() keyword (Java DSL) or in the rest element (XML DSL). |
4.3. Marshalling to and from Java Objects Copy linkLink copied to clipboard!
Marshalling Java objects for transmission over HTTP Copy linkLink copied to clipboard!
- JSON
- JSON (JavaScript object notation) is a lightweight data format that can easily be mapped to and from Java objects. The JSON syntax is compact, lightly typed, and easy for humans to read and write. For all of these reasons, JSON has become popular as a message format for REST services.For example, the following JSON code could represent a
Userbean with two property fields,idandname:{ "id" : 1234, "name" : "Jane Doe" }{ "id" : 1234, "name" : "Jane Doe" }Copy to Clipboard Copied! Toggle word wrap Toggle overflow - JAXB
- JAXB (Java Architecture for XML Binding) is an XML-based data format that can easily be mapped to and from Java objects. In order to marshal the XML to a Java object, you must also annotate the Java class that you want to use.For example, the following JAXB code could represent a
Userbean with two property fields,idandname:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <User> <Id>1234</Id> <Name>Jane Doe</Name> </User>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <User> <Id>1234</Id> <Name>Jane Doe</Name> </User>Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Integration of JSON and JAXB with the REST DSL Copy linkLink copied to clipboard!
- Marshalling to and from Java objects is performed automatically (given the appropriate configuration).
- The REST DSL can automatically detect the data format (either JSON or JAXB) and perform the appropriate conversion.
- The REST DSL provides an abstraction layer, so that the code you write is not specific to a particular JSON or JAXB implementation. So you can switch the implementation later on, with minimum impact to your application code.
Supported data format components Copy linkLink copied to clipboard!
- JSON
- Jackson data format (
camel-jackson) (default) - GSon data format (
camel-gson) - XStream data format (
camel-xstream)
- JAXB
- JAXB data format (
camel-jaxb)
How to enable object marshalling Copy linkLink copied to clipboard!
- Enable binding mode, by setting the
bindingModeoption (there are several levels at which you can set the binding mode—for details, see the section called “Configuring the binding mode”). - Specify the Java type to convert to (or from), on the incoming message with the
typeoption (required), and on the outgoing message with theoutTypeoption (optional). - If you want to convert your Java object to and from the JAXB data format, you must remember to annotate the Java class with the appropriate JAXB annotations.
- Specify the underlying data format implementation (or implementations), using the
jsonDataFormatoption and/or thexmlDataFormatoption (which can be specified on therestConfigurationbuilder). - If your route provides a return value in JAXB format, you are normally expected to set the Out message of the exchange body to be an instance of a class with JAXB annotations (a JAXB element). If you prefer to provide the JAXB return value directly in XML format, however, set the
dataFormatPropertywith the key,xml.out.mustBeJAXBElement, tofalse(which can be specified on therestConfigurationbuilder). For example, in the XML DSL syntax:<restConfiguration ...> <dataFormatProperty key="xml.out.mustBeJAXBElement" value="false"/> ... </restConfiguration><restConfiguration ...> <dataFormatProperty key="xml.out.mustBeJAXBElement" value="false"/> ... </restConfiguration>Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Add the required dependencies to your project build file. For example, if you are using the Maven build system and you are using the Jackson data format, you would add the following dependency to your Maven POM file:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - When deploying your application to the OSGi container, remember to install the requisite feature for your chosen data format. For example, if you are using the Jackson data format (the default), you would install the
camel-jacksonfeature, by entering the following Karaf console command:JBossFuse:karaf@root> features:install camel-jackson
JBossFuse:karaf@root> features:install camel-jacksonCopy to Clipboard Copied! Toggle word wrap Toggle overflow Alternatively, if you are deploying into a Fabric environment, you would add the feature to a Fabric profile. For example, if you are using the profile,MyRestProfile, you could add the feature by entering the following console command:JBossFuse:karaf@root> fabric:profile-edit --features camel-jackson MyRestProfile
JBossFuse:karaf@root> fabric:profile-edit --features camel-jackson MyRestProfileCopy to Clipboard Copied! Toggle word wrap Toggle overflow
Configuring the binding mode Copy linkLink copied to clipboard!
bindingMode option is off by default, so you must configure it explicitly, in order to enable marshalling of Java objects. TABLE shows the list of supported binding modes.
| Binding Mode | Description |
|---|---|
off |
Binding is turned off (default).
|
auto |
Binding is enabled for JSON and/or XML. In this mode, Camel auto-selects either JSON or XML (JAXB), based on the format of the incoming message. You are not required to enable both kinds of data format, however: either a JSON implementation, an XML implementation, or both can be provided on the classpath.
|
json |
Binding is enabled for JSON only. A JSON implementation must be provided on the classpath (by default, Camel tries to enable the
camel-jackson implementation).
|
xml |
Binding is enabled for XML only. An XML implementation must be provided on the classpath (by default, Camel tries to enable the
camel-jaxb implementation).
|
json_xml |
Binding is enabled for both JSON and XML. In this mode, Camel auto-selects either JSON or XML (JAXB), based on the format of the incoming message. You are required to provide both kinds of data format on the classpath.
|
enum type:
org.apache.camel.model.rest.RestBindingMode
org.apache.camel.model.rest.RestBindingMode
bindingMode, as follows:
- REST DSL configuration
- You can set the
bindingModeoption from therestConfigurationbuilder, as follows:restConfiguration().component("servlet").port(8181).bindingMode(RestBindingMode.json);restConfiguration().component("servlet").port(8181).bindingMode(RestBindingMode.json);Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Service definition base part
- You can set the
bindingModeoption immediately following therest()keyword (before the verb clauses), as follows:rest("/user").bindingMode(RestBindingMode.json).get("/{id}").VerbClauserest("/user").bindingMode(RestBindingMode.json).get("/{id}").VerbClauseCopy to Clipboard Copied! Toggle word wrap Toggle overflow - Verb clause
- You can set the
bindingModeoption in a verb clause, as follows:rest("/user") .get("/{id}").bindingMode(RestBindingMode.json).to("...");rest("/user") .get("/{id}").bindingMode(RestBindingMode.json).to("...");Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Example Copy linkLink copied to clipboard!
camel-example-servlet-rest-blueprint example. You can find this example by installing the standalone Apache Camel distribution, apache-camel-2.15.1.redhat-621084.zip, which is provided in the extras/ subdirectory of your JBoss Fuse installation.
ApacheCamelInstallDir/examples/camel-example-servlet-rest-blueprint
ApacheCamelInstallDir/examples/camel-example-servlet-rest-blueprint
Configure the Servlet component as the REST implementation Copy linkLink copied to clipboard!
camel-example-servlet-rest-blueprint example, the underlying implementation of the REST DSL is provided by the Servlet component. The Servlet component is configured in the Blueprint XML file, as shown in Example 4.1, “Configure Servlet Component for REST DSL”.
Example 4.1. Configure Servlet Component for REST DSL
- REST DSL layer
- The REST DSL layer is configured by the
restConfigurationelement, which integrates with the Servlet component by setting thecomponentattribute to the value,servlet. - Servlet component layer
- The Servlet component layer is implemented as an instance of the class,
CamelHttpTransportServlet, where the example instance has the bean ID,camelServlet. - HTTP container layer
- The Servlet component must be deployed into a HTTP container. The Karaf container is normally configured with a default HTTP container (a Jetty HTTP container), which listens for HTTP requests on the port, 8181. To deploy the Servlet component to the default Jetty container, you need to do the following:
- Get an OSGi reference to the
org.osgi.service.http.HttpServiceOSGi service, where this service is a standardised OSGi interface that provides access to the default HTTP server in OSGi. - Create an instance of the utility class,
OsgiServletRegisterer, to register the Servlet component in the HTTP container. TheOsgiServletRegistererclass is a utility that simplifies managing the lifecycle of the Servlet component. When an instance of this class is created, it automatically calls theregisterServletmethod on theHttpServiceOSGi service; and when the instance is destroyed, it automatically calls theunregistermethod.
Required dependencies Copy linkLink copied to clipboard!
- Servlet component
- Provides the underlying implementation of the REST DSL. This is specified in the Maven POM file, as follows:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-servlet</artifactId> <version>${camel-version}</version> </dependency><dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-servlet</artifactId> <version>${camel-version}</version> </dependency>Copy to Clipboard Copied! Toggle word wrap Toggle overflow And before you deploy the application bundle to the OSGi container, you must install the Servlet component feature, as follows:JBossFuse:karaf@root> features:install camel-servlet
JBossFuse:karaf@root> features:install camel-servletCopy to Clipboard Copied! Toggle word wrap Toggle overflow - Jackson data format
- Provides the JSON data format implementation. This is specified in the Maven POM file, as follows:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jackson</artifactId> <version>${camel-version}</version> </dependency><dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jackson</artifactId> <version>${camel-version}</version> </dependency>Copy to Clipboard Copied! Toggle word wrap Toggle overflow And before you deploy the application bundle to the OSGi container, you must install the Jackson data format feature, as follows:JBossFuse:karaf@root> features:install camel-jackson
JBossFuse:karaf@root> features:install camel-jacksonCopy to Clipboard Copied! Toggle word wrap Toggle overflow
Java type for responses Copy linkLink copied to clipboard!
User type objects back and forth in HTTP Request and Response messages. The User Java class is defined as shown in Example 4.2, “User Class for JSON Response”.
Example 4.2. User Class for JSON Response
User class has a relatively simple representation in the JSON data format. For example, a typical instance of this class expressed in JSON format is:
{
"id" : 1234,
"name" : "Jane Doe"
}
{
"id" : 1234,
"name" : "Jane Doe"
}
Sample REST DSL route with JSON binding Copy linkLink copied to clipboard!
Example 4.3. REST DSL Route with JSON Binding
REST operations Copy linkLink copied to clipboard!
-
GET /camel-example-servlet-rest-blueprint/rest/user/{id} - Get the details for the user identified by
{id}, where the HTTP response is returned in JSON format. -
PUT /camel-example-servlet-rest-blueprint/rest/user - Create a new user, where the user details are contained in the body of the PUT message, encoded in JSON format (to match the
Userobject type). -
GET /camel-example-servlet-rest-blueprint/rest/user/findAll - Get the details for all users, where the HTTP response is returned as an array of users, in JSON format.
URLs to invoke the REST service Copy linkLink copied to clipboard!
-
http://localhost:8181 - In
restConfiguration, the protocol defaults tohttpand the port is set explicitly to8181. -
/camel-example-servlet-rest-blueprint/rest - Specified by the
contextPathattribute of therestConfigurationelement. -
/user - Specified by the
pathattribute of therestelement. -
/{id} - Specified by the
uriattribute of thegetverb element.
curl utility, by entering the following command at the command line:
curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/123
curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/123
curl, by entering the following sample commands:
curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/findAll
curl -X PUT -d "{ \"id\": 666, \"name\": \"The devil\"}" -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user
curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/findAll
curl -X PUT -d "{ \"id\": 666, \"name\": \"The devil\"}" -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user
4.4. Configuring the REST DSL Copy linkLink copied to clipboard!
Configuring with Java Copy linkLink copied to clipboard!
restConfiguration() builder API. For example, to configure the REST DSL to use the Servlet component as the underlying implementation:
restConfiguration().component("servlet").bindingMode("json").port("8181")
.contextPath("/camel-example-servlet-rest-blueprint/rest");
restConfiguration().component("servlet").bindingMode("json").port("8181")
.contextPath("/camel-example-servlet-rest-blueprint/rest");
Configuring with XML Copy linkLink copied to clipboard!
restConfiguration element. For example, to configure the REST DSL to use the Servlet component as the underlying implementation:
Configuration options Copy linkLink copied to clipboard!
restConfiguration() builder (Java DSL) or the restConfiguration element (XML DSL).
| Java DSL | XML DSL | Description |
|---|---|---|
component() | @component |
Specifies the Camel component to use as the REST transport (for example,
servlet, restlet, spark-rest, and so on). The value can either be the standard component name or the bean ID of a custom instance. If this option is not specified, Camel looks for an instance of RestConsumerFactory on the classpath or in the bean registry.
|
scheme() | @scheme |
The protocol to use for exposing the REST service. Depends on the underlying REST implementation, but
http and https are usually supported. Default is http.
|
host() | @host |
The hostname to use for exposing the REST service.
|
port() | @port |
The port number to use for exposing the REST service.
Note: This setting is ignored by the Servlet component, which uses the container's standard HTTP port instead. In the case of the Apache Karaf OSGi container, the standard HTTP port is normally 8181. It is good practice to set the port value nonetheless, for the sake of JMX and tooling.
|
contextPath() | @contextPath | Sets a leading context path for the REST services. This can be used with components such as Servlet, where the deployed Web application is deployed using a context-path setting. |
hostNameResolver() | @hostNameResolver |
If a hostname is not set explicitly, this resolver determines the host for the REST service. Possible values are
RestHostNameResolver.localHostName (Java DSL) or localHostName (XML DSL), which resolves to the host name format; and RestHostNameResolver.localIp (Java DSL) or localIp (XML DSL), which resolves to the dotted decimal IP address format. Default is localHostName.
|
bindingMode() | @bindingMode | Enables binding mode for JSON or XML format messages. Possible values are: off, auto, json, xml, or json_xml. Default is off. |
skipBindingOnErrorCode() | @skipBindingOnErrorCode |
Specifies whether to skip binding on output, if there is a custom HTTP error code header. This allows you to build custom error messages that do not bind to JSON or XML, as successful messages would otherwise do. Default is
true.
|
enableCORS() | @enableCORS | If true, enables CORS (cross-origin resource sharing) headers in the HTTP response. Default is false. |
jsonDataFormat() | @jsonDataFormat |
Specifies the component that Camel uses to implement the JSON data format. Possible values are:
json-jackson, json-gson, json-xstream. Default is json-jackson.
|
xmlDataFormat() | @xmlDataFormat |
Specifies the component that Camel uses to implement the XML data format. Possible value is:
jaxb. Default is jaxb.
|
componentProperty() | componentProperty | Enables you to set arbitrary component level properties on the underlying REST implementation. |
endpointProperty() | endpointProperty | Enables you to set arbitrary endpoint level properties on the underlying REST implementation. |
consumerProperty() | consumerProperty | Enables you to set arbitrary consumer endpoint properties on the underlying REST implementation. |
dataFormatProperty() | dataFormatProperty |
Enables you to set arbitrary properties on the underlying data format component (for example, Jackson or JAXB). From Camel 2.14.1 onwards, you can attach the following prefixes to the property keys:
To restrict the property setting to a specific format type (JSON or XML) and a particular message direction (IN or OUT).
|
corsHeaderProperty() | corsHeaders | Enables you to specify custom CORS headers, as key/value pairs. |
Default CORS headers Copy linkLink copied to clipboard!
corsHeaderProperty DSL command.
| Header Key | Header Value |
|---|---|
Access-Control-Allow-Origin | * |
Access-Control-Allow-Methods | GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH
|
Access-Control-Allow-Headers | Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers
|
Access-Control-Max-Age | 3600 |
Enabling or disabling Jackson JSON features Copy linkLink copied to clipboard!
dataFormatProperty option:
json.in.disableFeaturesjson.in.enableFeatures
FAIL_ON_UNKNOWN_PROPERTIES feature (which causes Jackson to fail if a JSON input has a property that cannot be mapped to a Java object):
restConfiguration().component("jetty")
.host("localhost").port(getPort())
.bindingMode(RestBindingMode.json)
.dataFormatProperty("json.in.disableFeatures", "FAIL_ON_UNKNOWN_PROPERTIES");
restConfiguration().component("jetty")
.host("localhost").port(getPort())
.bindingMode(RestBindingMode.json)
.dataFormatProperty("json.in.disableFeatures", "FAIL_ON_UNKNOWN_PROPERTIES");
.dataFormatProperty("json.in.disableFeatures", "FAIL_ON_UNKNOWN_PROPERTIES,ADJUST_DATES_TO_CONTEXT_TIME_ZONE");
.dataFormatProperty("json.in.disableFeatures", "FAIL_ON_UNKNOWN_PROPERTIES,ADJUST_DATES_TO_CONTEXT_TIME_ZONE");
restConfiguration().component("jetty")
.host("localhost").port(getPort())
.bindingMode(RestBindingMode.json)
.dataFormatProperty("json.in.disableFeatures", "FAIL_ON_UNKNOWN_PROPERTIES,ADJUST_DATES_TO_CONTEXT_TIME_ZONE")
.dataFormatProperty("json.in.enableFeatures", "FAIL_ON_NUMBERS_FOR_ENUMS,USE_BIG_DECIMAL_FOR_FLOATS");
restConfiguration().component("jetty")
.host("localhost").port(getPort())
.bindingMode(RestBindingMode.json)
.dataFormatProperty("json.in.disableFeatures", "FAIL_ON_UNKNOWN_PROPERTIES,ADJUST_DATES_TO_CONTEXT_TIME_ZONE")
.dataFormatProperty("json.in.enableFeatures", "FAIL_ON_NUMBERS_FOR_ENUMS,USE_BIG_DECIMAL_FOR_FLOATS");
<restConfiguration component="jetty" host="localhost" port="9090" bindingMode="json"> <dataFormatProperty key="json.in.disableFeatures" value="FAIL_ON_UNKNOWN_PROPERTIES,ADJUST_DATES_TO_CONTEXT_TIME_ZONE"/> <dataFormatProperty key="json.in.enableFeatures" value="FAIL_ON_NUMBERS_FOR_ENUMS,USE_BIG_DECIMAL_FOR_FLOATS"/> </restConfiguration>
<restConfiguration component="jetty" host="localhost" port="9090" bindingMode="json">
<dataFormatProperty key="json.in.disableFeatures" value="FAIL_ON_UNKNOWN_PROPERTIES,ADJUST_DATES_TO_CONTEXT_TIME_ZONE"/>
<dataFormatProperty key="json.in.enableFeatures" value="FAIL_ON_NUMBERS_FOR_ENUMS,USE_BIG_DECIMAL_FOR_FLOATS"/>
</restConfiguration>
enum IDs from the following Jackson classes
4.5. Swagger Integration Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-swagger component enables users to create API docs for any REST-defined routes and endpoints in a CamelContext file. The camel-swagger component creates a servlet integrated with the CamelContext that pulls the information from each REST endpoint to generate the API docs (JSON file).
camel-swagger component to your pom.xml file:
Configuring the camelContext Copy linkLink copied to clipboard!
- The
serviceelement, which exposes the camel-swagger servlet and initializes its parameters.In the service element, add the servlet (org.apache.camel.component.swagger.DefaultCamelSwaggerServlet) and theservice-propertiesthat configure the servlet's parameters.For details on servlet parameters, see Swagger in the Apache Camel Component Reference Guide. - Configure the REST implementationDefine the REST service within the
camelContextelement using therestConfigurationandrestelements.For details on configuring REST services in the CamelContext, see Section 4.2, “Defining Services with REST DSL”.
blueprint.xml file; for example:
-
service - The
serviceelement exposes the camel swagger servlet (<bean class="org.apache.camel.component.swagger.DefaultCamelSwaggerServlet"/>) and initializes several servlet properties. -
alias - The
aliasproperty binds the camel swagger servlet to/api-docs/*. -
init-prefix - The
init-prefixproperty sets the prefix for all camel swagger servlet properties toinit.. This is analogous to usinginit-paramelements in theweb.xmlconfiguration for WAR implementations (see chapter "Swagger" in "Apache Camel Component Reference"). -
restConfiguration - In the
camelContextelement, therestConfigurationelement specifies the REST implementation to use. In this case, it is Jetty web servlet on port 8080. -
rest - In the
camelContextelement, therestelement defines a REST service and provides the base path (/say) to it. In this case, the service consists of two REST endpoints,helloandbye, which are routed to their corresponding camel endpoints defined in therouteelements.
Chapter 5. Messaging Systems Copy linkLink copied to clipboard!
Abstract
5.1. Message Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 5.1. Message Pattern
Types of message Copy linkLink copied to clipboard!
- In message — A message that travels through a route from a consumer endpoint to a producer endpoint (typically, initiating a message exchange).
- Out message — A message that travels through a route from a producer endpoint back to a consumer endpoint (usually, in response to an In message).
org.apache.camel.Message interface.
Message structure Copy linkLink copied to clipboard!
- Headers — Contains metadata or header data extracted from the message.
- Body — Usually contains the entire message in its original form.
- Attachments — Message attachments (required for integrating with certain messaging systems, such as JBI).
Correlating messages Copy linkLink copied to clipboard!
Exchange objects Copy linkLink copied to clipboard!
Accessing messages Copy linkLink copied to clipboard!
header(String name),body()— Returns the named header and the body of the current In message.outBody()— Returns the body of the current Out message.
username header, you can use the following Java DSL route:
from(SourceURL).setHeader("username", "John.Doe").to(TargetURL);
from(SourceURL).setHeader("username", "John.Doe").to(TargetURL);
5.2. Message Channel Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 5.2. Message Channel Pattern
Message-oriented components Copy linkLink copied to clipboard!
ActiveMQ Copy linkLink copied to clipboard!
activemq:QueueName
activemq:QueueName
activemq:topic:TopicName
activemq:topic:TopicName
Foo.Bar, use the following endpoint URI:
activemq:Foo.Bar
activemq:Foo.Bar
JMS Copy linkLink copied to clipboard!
jms:QueueName
jms:QueueName
jms:topic:TopicName
jms:topic:TopicName
AMQP Copy linkLink copied to clipboard!
amqp:QueueName
amqp:QueueName
amqp:topic:TopicName
amqp:topic:TopicName
5.3. Message Endpoint Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 5.3. Message Endpoint Pattern
Types of endpoint Copy linkLink copied to clipboard!
- Consumer endpoint — Appears at the start of a Apache Camel route and reads In messages from an incoming channel (equivalent to a receiver endpoint).
- Producer endpoint — Appears at the end of a Apache Camel route and writes In messages to an outgoing channel (equivalent to a sender endpoint). It is possible to define a route with multiple producer endpoints.
Endpoint URIs Copy linkLink copied to clipboard!
- Endpoint URI for a consumer endpoint — Advertises a specific location (for example, to expose a service to which senders can connect). Alternatively, the URI can specify a message source, such as a message queue. The endpoint URI can include settings to configure the endpoint.
- Endpoint URI for a producer endpoint — Contains details of where to send messages and includes the settings to configure the endpoint. In some cases, the URI specifies the location of a remote receiver endpoint; in other cases, the destination can have an abstract form, such as a queue name.
ComponentPrefix:ComponentSpecificURI
ComponentPrefix:ComponentSpecificURI
Foo.Bar, you can define an endpoint URI like the following:
jms:Foo.Bar
jms:Foo.Bar
file://local/router/messages/foo, directly to the producer endpoint, jms:Foo.Bar, you can use the following Java DSL fragment:
from("file://local/router/messages/foo").to("jms:Foo.Bar");
from("file://local/router/messages/foo").to("jms:Foo.Bar");
5.4. Pipes and Filters Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
pipe command). The advantage of the pipeline approach is that it enables you to compose services (some of which can be external to the Apache Camel application) to create more complex forms of message processing.
Figure 5.4. Pipes and Filters Pattern
Pipeline for the InOut exchange pattern Copy linkLink copied to clipboard!
Figure 5.5. Pipeline for InOut Exchanges
from("jms:RawOrders").pipeline("cxf:bean:decrypt", "cxf:bean:authenticate", "cxf:bean:dedup", "jms:CleanOrders");
from("jms:RawOrders").pipeline("cxf:bean:decrypt", "cxf:bean:authenticate", "cxf:bean:dedup", "jms:CleanOrders");
from and to elements is semantically equivalent to a pipeline. See the section called “Comparison of pipeline() and to() DSL commands”.
Pipeline for the InOnly and RobustInOnly exchange patterns Copy linkLink copied to clipboard!
InOnly and RobustInOnly exchange patterns), a pipeline cannot be connected in the normal way. In this special case, the pipeline is constructed by passing a copy of the original In message to each of the endpoints in the pipeline, as shown in Figure 5.6, “Pipeline for InOnly Exchanges”. This type of pipeline is equivalent to a recipient list with fixed destinations(see Section 8.3, “Recipient List”).
Figure 5.6. Pipeline for InOnly Exchanges
Comparison of pipeline() and to() DSL commands Copy linkLink copied to clipboard!
- Using the pipeline() processor command — Use the pipeline processor to construct a pipeline route as follows:
from(SourceURI).pipeline(FilterA, FilterB, TargetURI);
from(SourceURI).pipeline(FilterA, FilterB, TargetURI);Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Using the to() command — Use the
to()command to construct a pipeline route as follows:from(SourceURI).to(FilterA, FilterB, TargetURI);
from(SourceURI).to(FilterA, FilterB, TargetURI);Copy to Clipboard Copied! Toggle word wrap Toggle overflow Alternatively, you can use the equivalent syntax:from(SourceURI).to(FilterA).to(FilterB).to(TargetURI);
from(SourceURI).to(FilterA).to(FilterB).to(TargetURI);Copy to Clipboard Copied! Toggle word wrap Toggle overflow
to() command syntax, because it is not always equivalent to a pipeline processor. In Java DSL, the meaning of to() can be modified by the preceding command in the route. For example, when the multicast() command precedes the to() command, it binds the listed endpoints into a multicast pattern, instead of a pipeline pattern(see Section 8.11, “Multicast”).
5.5. Message Router Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 5.7. Message Router Pattern
choice() processor, where each of the alternative target endpoints can be selected using a when() subclause (for details of the choice processor, see Section 1.5, “Processors”).
Java DSL example Copy linkLink copied to clipboard!
seda:a, seda:b, or seda:c) depending on the contents of the foo header:
from("seda:a").choice()
.when(header("foo").isEqualTo("bar")).to("seda:b")
.when(header("foo").isEqualTo("cheese")).to("seda:c")
.otherwise().to("seda:d");
from("seda:a").choice()
.when(header("foo").isEqualTo("bar")).to("seda:b")
.when(header("foo").isEqualTo("cheese")).to("seda:c")
.otherwise().to("seda:d");
XML configuration example Copy linkLink copied to clipboard!
Choice without otherwise Copy linkLink copied to clipboard!
choice() without an otherwise() clause, any unmatched exchanges are dropped by default.
5.6. Message Translator Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 5.8. Message Translator Pattern
Bean integration Copy linkLink copied to clipboard!
myMethodName(), on the bean with ID, myTransformerBean:
from("activemq:SomeQueue")
.beanRef("myTransformerBean", "myMethodName")
.to("mqseries:AnotherQueue");
from("activemq:SomeQueue")
.beanRef("myTransformerBean", "myMethodName")
.to("mqseries:AnotherQueue");
myTransformerBean bean is defined in either a Spring XML file or in JNDI. If, you omit the method name parameter from beanRef(), the bean integration will try to deduce the method name to invoke by examining the message exchange.
Processor instance to perform the transformation, as follows:
from("direct:start").setBody(body().append(" World!")).to("mock:result");
from("direct:start").setBody(body().append(" World!")).to("mock:result");
from("activemq:My.Queue").
to("velocity:com/acme/MyResponse.vm").
to("activemq:Another.Queue");
from("activemq:My.Queue").
to("velocity:com/acme/MyResponse.vm").
to("activemq:Another.Queue");
My.Queue queue on ActiveMQ with a template generated response, then you could use a route like the following to send responses back to the JMSReplyTo destination:
from("activemq:My.Queue").
to("velocity:com/acme/MyResponse.vm");
from("activemq:My.Queue").
to("velocity:com/acme/MyResponse.vm");
5.7. Message History Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Limiting Character Length in Logs Copy linkLink copied to clipboard!
[DEBUG ProducerCache - >>>> Endpoint[direct:start] Exchange[Message: 01234567890123456789... [Body clipped after 20 characters, total length is 1000]
[DEBUG ProducerCache - >>>> Endpoint[direct:start] Exchange[Message: 01234567890123456789... [Body clipped after 20 characters, total length is 1000]
- Customizing the Limit using Java DSL
- You can set the limit in Camel properties using Java DSL. For example,
context.getProperties().put(Exchange.LOG_DEBUG_BODY_MAX_CHARS, "500");
context.getProperties().put(Exchange.LOG_DEBUG_BODY_MAX_CHARS, "500");Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Customizing the Limit using Spring DSL
- You can set the limit in Camel properties using Spring DSL. For example,
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Chapter 6. Messaging Channels Copy linkLink copied to clipboard!
Abstract
6.1. Point-to-Point Channel Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 6.1. Point to Point Channel Pattern
Components that support point-to-point channel Copy linkLink copied to clipboard!
JMS Copy linkLink copied to clipboard!
Foo.Bar as follows:
jms:queue:Foo.Bar
jms:queue:Foo.Bar
queue:, is optional, because the JMS component creates a queue endpoint by default. Therefore, you can also specify the following equivalent endpoint URI:
jms:Foo.Bar
jms:Foo.Bar
ActiveMQ Copy linkLink copied to clipboard!
Foo.Bar as follows:
activemq:queue:Foo.Bar
activemq:queue:Foo.Bar
SEDA Copy linkLink copied to clipboard!
SedaQueue as follows:
seda:SedaQueue
seda:SedaQueue
JPA Copy linkLink copied to clipboard!
XMPP Copy linkLink copied to clipboard!
6.2. Publish-Subscribe Channel Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 6.2. Publish Subscribe Channel Pattern
Components that support publish-subscribe channel Copy linkLink copied to clipboard!
JMS Copy linkLink copied to clipboard!
StockQuotes as follows:
jms:topic:StockQuotes
jms:topic:StockQuotes
ActiveMQ Copy linkLink copied to clipboard!
StockQuotes, as follows:
activemq:topic:StockQuotes
activemq:topic:StockQuotes
XMPP Copy linkLink copied to clipboard!
Static subscription lists Copy linkLink copied to clipboard!
Java DSL example Copy linkLink copied to clipboard!
seda:a, and three subscribers, seda:b, seda:c, and seda:d:
from("seda:a").to("seda:b", "seda:c", "seda:d");
from("seda:a").to("seda:b", "seda:c", "seda:d");
XML configuration example Copy linkLink copied to clipboard!
6.3. Dead Letter Channel Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 6.3. Dead Letter Channel Pattern
Creating a dead letter channel in Java DSL Copy linkLink copied to clipboard!
errorHandler(deadLetterChannel("seda:errors"));
from("seda:a").to("seda:b");
errorHandler(deadLetterChannel("seda:errors"));
from("seda:a").to("seda:b");
errorHandler() method is a Java DSL interceptor, which implies that all of the routes defined in the current route builder are affected by this setting. The deadLetterChannel() method is a Java DSL command that creates a new dead letter channel with the specified destination endpoint, seda:errors.
errorHandler() interceptor provides a catch-all mechanism for handling all error types. If you want to apply a more fine-grained approach to exception handling, you can use the onException clauses instead(see the section called “onException clause”).
XML DSL example Copy linkLink copied to clipboard!
Redelivery policy Copy linkLink copied to clipboard!
errorHandler(deadLetterChannel("seda:errors").maximumRedeliveries(2).useExponentialBackOff());
from("seda:a").to("seda:b");
errorHandler(deadLetterChannel("seda:errors").maximumRedeliveries(2).useExponentialBackOff());
from("seda:a").to("seda:b");
RedeliveryPolicy object). Table 6.1, “Redelivery Policy Settings” summarizes the methods that you can use to set redelivery policies.
| Method Signature | Default | Description |
|---|---|---|
allowRedeliveryWhileStopping() | true | Controls whether redelivery is attempted during graceful shutdown or while a route is stopping. A delivery that is already in progress when stopping is initiated will not be interrupted. |
backOffMultiplier(double multiplier) | 2 |
If exponential backoff is enabled, let
m be the backoff multiplier and let d be the initial delay. The sequence of redelivery attempts are then timed as follows:
d, m*d, m*m*d, m*m*m*d, ...
|
collisionAvoidancePercent(double collisionAvoidancePercent) | 15 | If collision avoidance is enabled, let p be the collision avoidance percent. The collision avoidance policy then tweaks the next delay by a random amount, up to plus/minus p% of its current value. |
deadLetterHandleNewException | true | Camel 2.15: Specifies whether or not to handle an exception that occurs while processing a message in the dead letter channel. If true, the exception is handled and a logged at the WARN level (so that the dead letter channel is guaranteed to complete). If false, the exception is not handled, so the dead letter channel fails, and propagates the new exception. |
delayPattern(String delayPattern) | None | Apache Camel 2.0: |
disableRedelivery() | true | Apache Camel 2.0: Disables the redelivery feature. To enable redelivery, set maximumRedeliveries() to a positive integer value. |
handled(boolean handled) | true | Apache Camel 2.0: If true, the current exception is cleared when the message is moved to the dead letter channel; if false, the exception is propagated back to the client. |
initialRedeliveryDelay(long initialRedeliveryDelay) | 1000 | Specifies the delay (in milliseconds) before attempting the first redelivery. |
logNewException | true | Specifies whether to log at WARN level, when an exception is raised in the dead letter channel. |
logStackTrace(boolean logStackTrace) | false | Apache Camel 2.0: If true, the JVM stack trace is included in the error logs. |
maximumRedeliveries(int maximumRedeliveries) | 0 | Apache Camel 2.0: Maximum number of delivery attempts. |
maximumRedeliveryDelay(long maxDelay) | 60000 | Apache Camel 2.0: When using an exponential backoff strategy (see useExponentialBackOff()), it is theoretically possible for the redelivery delay to increase without limit. This property imposes an upper limit on the redelivery delay (in milliseconds) |
onRedelivery(Processor processor) | None | Apache Camel 2.0: Configures a processor that gets called before every redelivery attempt. |
redeliveryDelay(long int) | 0 | Apache Camel 2.0: Specifies the delay (in milliseconds) between redelivery attempts. |
retriesExhaustedLogLevel(LoggingLevel logLevel) | LoggingLevel.ERROR | Apache Camel 2.0: Specifies the logging level at which to log delivery failure (specified as an org.apache.camel.LoggingLevel constant). |
retryAttemptedLogLevel(LoggingLevel logLevel) | LoggingLevel.DEBUG | Apache Camel 2.0: Specifies the logging level at which to redelivery attempts (specified as an org.apache.camel.LoggingLevel constant). |
useCollisionAvoidance() | false | Enables collision avoidence, which adds some randomization to the backoff timings to reduce contention probability. |
useOriginalMessage() | false | Apache Camel 2.0: If this feature is enabled, the message sent to the dead letter channel is a copy of the original message exchange, as it existed at the beginning of the route (in the from() node). |
useExponentialBackOff() | false | Enables exponential backoff. |
Redelivery headers Copy linkLink copied to clipboard!
| Header Name | Type | Description |
|---|---|---|
CamelRedeliveryCounter | Integer | Apache Camel 2.0: Counts the number of unsuccessful delivery attempts. This value is also set in Exchange.REDELIVERY_COUNTER. |
CamelRedelivered | Boolean | Apache Camel 2.0: True, if one or more redelivery attempts have been made. This value is also set in Exchange.REDELIVERED. |
CamelRedeliveryMaxCounter | Integer | Apache Camel 2.6: Holds the maximum redelivery setting (also set in the Exchange.REDELIVERY_MAX_COUNTER exchange property). This header is absent if you use retryWhile or have unlimited maximum redelivery configured. |
Redelivery exchange properties Copy linkLink copied to clipboard!
| Exchange Property Name | Type | Description |
|---|---|---|
Exchange.FAILURE_ROUTE_ID | String | Provides the route ID of the route that failed. The literal name of this property is CamelFailureRouteId. |
Using the original message Copy linkLink copied to clipboard!
from("jms:queue:order:input")
.to("bean:validateOrder");
.to("bean:transformOrder")
.to("bean:handleOrder");
from("jms:queue:order:input")
.to("bean:validateOrder");
.to("bean:transformOrder")
.to("bean:handleOrder");
validateOrder, transformOrder, and handleOrder. But when an error occurs, we do not know in which state the message is in. Did the error happen before the transformOrder bean or after? We can ensure that the original message from jms:queue:order:input is logged to the dead letter channel by enabling the useOriginalMessage option as follows:
// will use original body
errorHandler(deadLetterChannel("jms:queue:dead")
.useOriginalMessage().maximumRedeliveries(5).redeliveryDelay(5000);
// will use original body
errorHandler(deadLetterChannel("jms:queue:dead")
.useOriginalMessage().maximumRedeliveries(5).redeliveryDelay(5000);
Redeliver delay pattern Copy linkLink copied to clipboard!
delayPattern option is used to specify delays for particular ranges of the redelivery count. The delay pattern has the following syntax: limit1:delay1;limit2:delay2;limit3:delay3;..., where each delayN is applied to redeliveries in the range limitN <= redeliveryCount < limitN+1
5:1000;10:5000;20:20000, which defines three groups and results in the following redelivery delays:
- Attempt number 1..4 = 0 milliseconds (as the first group starts with 5).
- Attempt number 5..9 = 1000 milliseconds (the first group).
- Attempt number 10..19 = 5000 milliseconds (the second group).
- Attempt number 20.. = 20000 milliseconds (the last group).
1:1000;5:5000 results in the following redelivery delays:
- Attempt number 1..4 = 1000 millis (the first group)
- Attempt number 5.. = 5000 millis (the last group)
1:5000;3:1000, starts with a 5 second delay and then reduces the delay to 1 second.
Which endpoint failed? Copy linkLink copied to clipboard!
// Java String lastEndpointUri = exchange.getProperty(Exchange.TO_ENDPOINT, String.class);
// Java
String lastEndpointUri = exchange.getProperty(Exchange.TO_ENDPOINT, String.class);
Exchange.TO_ENDPOINT is a string constant equal to CamelToEndpoint. This property is updated whenever Camel sends a message to any endpoint.
CamelFailureEndpoint, which identifies the last destination the exchange was sent to before the error occcured. Hence, you can access the failure endpoint from within a dead letter queue using the following code:
// Java String failedEndpointUri = exchange.getProperty(Exchange.FAILURE_ENDPOINT, String.class);
// Java
String failedEndpointUri = exchange.getProperty(Exchange.FAILURE_ENDPOINT, String.class);
Exchange.FAILURE_ENDPOINT is a string constant equal to CamelFailureEndpoint.
from("activemq:queue:foo")
.to("http://someserver/somepath")
.beanRef("foo");
from("activemq:queue:foo")
.to("http://someserver/somepath")
.beanRef("foo");
foo bean. In this case the Exchange.TO_ENDPOINT property and the Exchange.FAILURE_ENDPOINT property still contain the value.
onRedelivery processor Copy linkLink copied to clipboard!
Processor that is executed just before every redelivery attempt. This can be used for situations where you need to alter the message before it is redelivered.
MyRedeliverProcessor before redelivering exchanges:
MyRedeliveryProcessor process is implemented as follows:
Control redelivery during shutdown or stopping Copy linkLink copied to clipboard!
allowRedeliveryWhileStopping option to false, as shown in the following example:
errorHandler(deadLetterChannel("jms:queue:dead")
.allowRedeliveryWhileStopping(false)
.maximumRedeliveries(20)
.redeliveryDelay(1000)
.retryAttemptedLogLevel(LoggingLevel.INFO));
errorHandler(deadLetterChannel("jms:queue:dead")
.allowRedeliveryWhileStopping(false)
.maximumRedeliveries(20)
.redeliveryDelay(1000)
.retryAttemptedLogLevel(LoggingLevel.INFO));
allowRedeliveryWhileStopping option is true by default, for backwards compatibility reasons. During aggressive shutdown, however, redelivery is always suppressed, irrespective of this option setting (for example, after graceful shutdown has timed out).
onException clause Copy linkLink copied to clipboard!
errorHandler() interceptor in your route builder, you can define a series of onException() clauses that define different redelivery policies and different dead letter channels for various exception types. For example, to define distinct behavior for each of the NullPointerException, IOException, and Exception types, you can define the following rules in your route builder using Java DSL:
to() DSL command. You can also call other Java DSL commands in the onException() clauses. For example, the preceding example calls setHeader() to record some error details in a message header named, messageInfo.
NullPointerException and the IOException exception types are configured specially. All other exception types are handled by the generic Exception exception interceptor. By default, Apache Camel applies the exception interceptor that most closely matches the thrown exception. If it fails to find an exact match, it tries to match the closest base type, and so on. Finally, if no other interceptor matches, the interceptor for the Exception type matches all remaining exceptions.
OnPrepareFailure Copy linkLink copied to clipboard!
onPrepare option to allow a custom processor to prepare the exchange. It enables you to add information about the exchange, such as the cause of exchange failure. For example, the following processor adds a header with the exception message.
errorHandler(deadLetterChannel("jms:dead").onPrepareFailure(new MyPrepareProcessor()));
errorHandler(deadLetterChannel("jms:dead").onPrepareFailure(new MyPrepareProcessor()));
onPrepare option is also available using the default error handler.
<bean id="myPrepare" class="org.apache.camel.processor.DeadLetterChannelOnPrepareTest.MyPrepareProcessor"/> <errorHandler id="dlc" type="DeadLetterChannel" deadLetterUri="jms:dead" onPrepareFailureRef="myPrepare"/>
<bean id="myPrepare"
class="org.apache.camel.processor.DeadLetterChannelOnPrepareTest.MyPrepareProcessor"/>
<errorHandler id="dlc" type="DeadLetterChannel" deadLetterUri="jms:dead" onPrepareFailureRef="myPrepare"/>
6.4. Guaranteed Delivery Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 6.4. Guaranteed Delivery Pattern
Components that support guaranteed delivery Copy linkLink copied to clipboard!
- File Component in the Apache Camel Component Reference Guide
JMS Copy linkLink copied to clipboard!
deliveryPersistent query option indicates whether or not persistent storage of messages is enabled. Usually it is unnecessary to set this option, because the default behavior is to enable persistent delivery. To configure all the details of guaranteed delivery, it is necessary to set configuration options on the JMS provider. These details vary, depending on what JMS provider you are using. For example, MQSeries, TibCo, BEA, Sonic, and others, all provide various qualities of service to support guaranteed delivery.
ActiveMQ Copy linkLink copied to clipboard!
META-INF/spring/camel-context.xml, you can configure the ActiveMQ component to connect to the central broker using the OpenWire/TCP protocol as follows:
camel-context.xml configuration file, you can configure the ActiveMQ component to connect to all of the peers in group, GroupA, as follows:
broker1 is the broker name of the embedded broker (other peers in the group should use different broker names). One limiting feature of the Peer-to-Peer protocol is that it relies on IP multicast to locate the other peers in its group. This makes it unsuitable for use in wide area networks (and in some local area networks that do not have IP multicast enabled).
activemq.xml is an ActiveMQ file which configures the embedded broker instance. Within the ActiveMQ configuration file, you can choose to enable one of the following persistence mechanisms:
- AMQ persistence(the default) — A fast and reliable message store that is native to ActiveMQ. For details, see amqPersistenceAdapter and AMQ Message Store.
- JDBC persistence — Uses JDBC to store messages in any JDBC-compatible database. For details, see jdbcPersistenceAdapter and ActiveMQ Persistence.
- Journal persistence — A fast persistence mechanism that stores messages in a rolling log file. For details, see journalPersistenceAdapter and ActiveMQ Persistence.
- Kaha persistence — A persistence mechanism developed specifically for ActiveMQ. For details, see kahaPersistenceAdapter and ActiveMQ Persistence.
ActiveMQ Journal Copy linkLink copied to clipboard!
6.5. Message Bus Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 6.5. Message Bus Pattern
- Common communication infrastructure — The router itself provides the core of the common communication infrastructure in Apache Camel. However, in contrast to some message bus architectures, Apache Camel provides a heterogeneous infrastructure: messages can be sent into the bus using a wide variety of different transports and using a wide variety of different message formats.
- Adapters — Where necessary, Apache Camel can translate message formats and propagate messages using different transports. In effect, Apache Camel is capable of behaving like an adapter, so that external applications can hook into the message bus without refactoring their messaging protocols.In some cases, it is also possible to integrate an adapter directly into an external application. For example, if you develop an application using Apache CXF, where the service is implemented using JAX-WS and JAXB mappings, it is possible to bind a variety of different transports to the service. These transport bindings function as adapters.
Chapter 7. Message Construction Copy linkLink copied to clipboard!
Abstract
7.1. Correlation Identifier Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
JMSCorrelationID. You can add your own correlation identifier to any message exchange to help correlate messages together in a single conversation (or business process). A correlation identifier is usually stored in a Apache Camel message header.
Exchange.CORRELATION_ID, which links back to the source Exchanges. For example, the Splitter, Multicast, Recipient List, and Wire Tap EIPs do this.
Figure 7.1. Correlation Identifier Pattern
7.2. Event Message Copy linkLink copied to clipboard!
Event Message Copy linkLink copied to clipboard!
Explicitly specifying InOnly Copy linkLink copied to clipboard!
foo:bar?exchangePattern=InOnly
foo:bar?exchangePattern=InOnly
from("mq:someQueue").
inOnly().
bean(Foo.class);
from("mq:someQueue").
inOnly().
bean(Foo.class);
from("mq:someQueue").
inOnly("mq:anotherQueue");
from("mq:someQueue").
inOnly("mq:anotherQueue");
<route>
<from uri="mq:someQueue"/>
<inOnly uri="bean:foo"/>
</route>
<route>
<from uri="mq:someQueue"/>
<inOnly uri="bean:foo"/>
</route>
<route>
<from uri="mq:someQueue"/>
<inOnly uri="mq:anotherQueue"/>
</route>
<route>
<from uri="mq:someQueue"/>
<inOnly uri="mq:anotherQueue"/>
</route>
7.3. Return Address Copy linkLink copied to clipboard!
Return Address Copy linkLink copied to clipboard!
JMSReplyTo header.
JMSReplyTo.
Example Copy linkLink copied to clipboard!
getMockEndpoint("mock:bar").expectedBodiesReceived("Bye World");
template.sendBodyAndHeader("direct:start", "World", "JMSReplyTo", "queue:bar");
getMockEndpoint("mock:bar").expectedBodiesReceived("Bye World");
template.sendBodyAndHeader("direct:start", "World", "JMSReplyTo", "queue:bar");
from("direct:start").to("activemq:queue:foo?preserveMessageQos=true");
from("activemq:queue:foo").transform(body().prepend("Bye "));
from("activemq:queue:bar?disableReplyTo=true").to("mock:bar");
from("direct:start").to("activemq:queue:foo?preserveMessageQos=true");
from("activemq:queue:foo").transform(body().prepend("Bye "));
from("activemq:queue:bar?disableReplyTo=true").to("mock:bar");
Chapter 8. Message Routing Copy linkLink copied to clipboard!
Abstract
8.1. Content-Based Router Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 8.1. Content-Based Router Pattern
Java DSL example Copy linkLink copied to clipboard!
seda:a, endpoint to either seda:b, queue:c, or seda:d depending on the evaluation of various predicate expressions:
XML configuration example Copy linkLink copied to clipboard!
8.2. Message Filter Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
filter() Java DSL command. The filter() command takes a single predicate argument, which controls the filter. When the predicate is true, the incoming message is allowed to proceed, and when the predicate is false, the incoming message is blocked.
Figure 8.2. Message Filter Pattern
Java DSL example Copy linkLink copied to clipboard!
seda:a, to endpoint, seda:b, that blocks all messages except for those messages whose foo header have the value, bar:
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("seda:a").filter(header("foo").isEqualTo("bar")).to("seda:b");
}
};
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("seda:a").filter(header("foo").isEqualTo("bar")).to("seda:b");
}
};
person element whose name attribute is equal to James:
from("direct:start").
filter().xpath("/person[@name='James']").
to("mock:result");
from("direct:start").
filter().xpath("/person[@name='James']").
to("mock:result");
XML configuration example Copy linkLink copied to clipboard!
<to uri="seda:b"/>) before the closing </filter> tag or the filter will not be applied (in 2.8+, omitting this will result in an error).
Filtering with beans Copy linkLink copied to clipboard!
Using stop() Copy linkLink copied to clipboard!
Bye in the message body to propagate any further in the route. We prevent this in the when() predicate using .stop().
Knowing if Exchange was filtered or not Copy linkLink copied to clipboard!
Exchannge.FILTER_MATCHED which has the String value of CamelFilterMatched. Its value is a boolean indicating true or false. If the value is true then the Exchange was routed in the filter block.
8.3. Recipient List Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 8.3. Recipient List Pattern
Recipient list with fixed destinations Copy linkLink copied to clipboard!
to() Java DSL command.
Java DSL example Copy linkLink copied to clipboard!
queue:a, to a fixed list of destinations:
from("seda:a").to("seda:b", "seda:c", "seda:d");
from("seda:a").to("seda:b", "seda:c", "seda:d");
XML configuration example Copy linkLink copied to clipboard!
Recipient list calculated at run time Copy linkLink copied to clipboard!
recipientList() processor, which takes a list of destinations as its sole argument. Because Apache Camel applies a type converter to the list argument, it should be possible to use most standard Java list types (for example, a collection, a list, or an array). For more details about type converters, see Section 43.3, “Built-In Type Converters”.
Java DSL example Copy linkLink copied to clipboard!
recipientListHeader, where the header value is a comma-separated list of endpoint URIs:
from("direct:a").recipientList(header("recipientListHeader").tokenize(","));
from("direct:a").recipientList(header("recipientListHeader").tokenize(","));
recipientList(). For example:
from("seda:a").recipientList(header("recipientListHeader"));
from("seda:a").recipientList(header("recipientListHeader"));
XML configuration example Copy linkLink copied to clipboard!
Sending to multiple recipients in parallel Copy linkLink copied to clipboard!
parallelProcessing, which is similar to the corresponding feature in Splitter. Use the parallel processing feature to send the exchange to multiple recipients concurrently—for example:
from("direct:a").recipientList(header("myHeader")).parallelProcessing();
from("direct:a").recipientList(header("myHeader")).parallelProcessing();
recipientList tag—for example:
Stop on exception Copy linkLink copied to clipboard!
stopOnException feature, which you can use to stop sending to any further recipients, if any recipient fails.
from("direct:a").recipientList(header("myHeader")).stopOnException();
from("direct:a").recipientList(header("myHeader")).stopOnException();
recipientList tag—for example:
parallelProcessing and stopOnException in the same route.
Ignore invalid endpoints Copy linkLink copied to clipboard!
ignoreInvalidEndpoints option, which enables the recipient list to skip invalid endpoints (Routing Slip also supports this option). For example:
from("direct:a").recipientList(header("myHeader")).ignoreInvalidEndpoints();
from("direct:a").recipientList(header("myHeader")).ignoreInvalidEndpoints();
ignoreInvalidEndpoints attribute on the recipientList tag, as follows
myHeader contains the two endpoints, direct:foo,xxx:bar. The first endpoint is valid and works. The second is invalid and, therefore, ignored. Apache Camel logs at INFO level whenever an invalid endpoint is encountered.
Using custom AggregationStrategy Copy linkLink copied to clipboard!
AggregationStrategy with the Recipient List, which is useful for aggregating replies from the recipients in the list. By default, Apache Camel uses the UseLatestAggregationStrategy aggregation strategy, which keeps just the last received reply. For a more sophisticated aggregation strategy, you can define your own implementation of the AggregationStrategy interface—see Aggregator EIP for details. For example, to apply the custom aggregation strategy, MyOwnAggregationStrategy, to the reply messages, you can define a Java DSL route as follows:
from("direct:a")
.recipientList(header("myHeader")).aggregationStrategy(new MyOwnAggregationStrategy())
.to("direct:b");
from("direct:a")
.recipientList(header("myHeader")).aggregationStrategy(new MyOwnAggregationStrategy())
.to("direct:b");
recipientList tag, as follows:
Using custom thread pool Copy linkLink copied to clipboard!
parallelProcessing. By default Camel uses a thread pool with 10 threads. Notice this is subject to change when we overhaul thread pool management and configuration later (hopefully in Camel 2.2).
Using method call as recipient list Copy linkLink copied to clipboard!
from("activemq:queue:test").recipientList().method(MessageRouter.class, "routeTo");
from("activemq:queue:test").recipientList().method(MessageRouter.class, "routeTo");
MessageRouter bean is defined as follows:
Bean as recipient list Copy linkLink copied to clipboard!
@RecipientList annotation to a methods that returns a list of recipients. For example:
recipientList DSL command in the route. Define the route as follows:
from("activemq:queue:test").bean(MessageRouter.class, "routeTo");
from("activemq:queue:test").bean(MessageRouter.class, "routeTo");
Using timeout Copy linkLink copied to clipboard!
parallelProcessing, you can configure a total timeout value in milliseconds. Camel will then process the messages in parallel until the timeout is hit. This allows you to continue processing if one message is slow.
recipientlist header has the value, direct:a,direct:b,direct:c, so that the message is sent to three recipients. We have a timeout of 250 milliseconds, which means only the last two messages can be completed within the timeframe. The aggregation therefore yields the string result, BC.
timeout feature is also supported by splitter and both multicast and recipientList.
AggregationStrategy is not invoked. However you can implement a specialized version
AggregationStrategy if you really need to.
timeout method in the TimeoutAwareAggregationStrategy once, for the first index which caused the timeout.
Apply custom processing to the outgoing messages Copy linkLink copied to clipboard!
recipientList sends a message to one of the recipient endpoints, it creates a message replica, which is a shallow copy of the original message. If you want to perform some custom processing on each message replica before the replica is sent to its endpoint, you can invoke the onPrepare DSL command in the recipientList clause. The onPrepare command inserts a custom processor just after the message has been shallow-copied and just before the message is dispatched to its endpoint. For example, in the following route, the CustomProc processor is invoked on the message replica for each recipient endpoint:
from("direct:start")
.recipientList().onPrepare(new CustomProc());
from("direct:start")
.recipientList().onPrepare(new CustomProc());
onPrepare DSL command is to perform a deep copy of some or all elements of a message. This allows each message replica to be modified independently of the others. For example, the following CustomProc processor class performs a deep copy of the message body, where the message body is presumed to be of type, BodyType, and the deep copy is performed by the method, BodyType.deepCopy().
Options Copy linkLink copied to clipboard!
recipientList DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
delimiter
|
,
|
Delimiter used if the Expression returned multiple endpoints. |
strategyRef
|
Refers to an AggregationStrategy to be used to assemble the replies from the recipients, into a single outgoing message from the Recipient List. By default Camel will use the last reply as the outgoing message. | |
strategyMethodName
|
This option can be used to explicitly specify the method name to use, when using POJOs as the AggregationStrategy.
|
|
strategyMethodAllowNull
|
false
|
This option can be used, when using POJOs as the AggregationStrategy. If false, the aggregate method is not used, when there is no data to enrich. If true, null values are used for the oldExchange, when there is no data to enrich.
|
parallelProcessing
|
false
|
Camel 2.2: If enables then sending messages to the recipients occurs concurrently. Note the caller thread will still wait until all messages has been fully processed, before it continues. Its only the sending and processing the replies from the recipients which happens concurrently. |
parallelAggregate
|
false
|
If enabled, the aggregate method on AggregationStrategy can be called concurrently. Note that this requires the implementation of AggregationStrategy to be thread-safe. By default, this option is false, which means that Camel automatically synchronizes calls to the aggregate method. In some use-cases, however, you can improve performance by implementing AggregationStrategy as thread-safe and setting this option to true.
|
executorServiceRef
|
Camel 2.2: Refers to a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatic implied, and you do not have to enable that option as well. | |
stopOnException
|
false
|
Camel 2.2: Whether or not to stop continue processing immediately when an exception occurred. If disable, then Camel will send the message to all recipients regardless if one of them failed. You can deal with exceptions in the AggregationStrategy class where you have full control how to handle that. |
ignoreInvalidEndpoints
|
false
|
Camel 2.3: If an endpoint uri could not be resolved, should it be ignored. Otherwise Camel will thrown an exception stating the endpoint uri is not valid. |
streaming
|
false
|
Camel 2.5: If enabled then Camel will process replies out-of-order, eg in the order they come back. If disabled, Camel will process replies in the same order as the Expression specified. |
timeout
|
Camel 2.5: Sets a total timeout specified in millis. If the Recipient List hasn't been able to send and process all replies within the given timeframe, then the timeout triggers and the Recipient List breaks out and continues. Notice if you provide a TimeoutAwareAggregationStrategy then the timeout method is invoked before breaking out.
|
|
onPrepareRef
|
Camel 2.8: Refers to a custom Processor to prepare the copy of the Exchange each recipient will receive. This allows you to do any custom logic, such as deep-cloning the message payload if that's needed etc. | |
shareUnitOfWork
|
false
|
Camel 2.8: Whether the unit of work should be shared. See the same option on Splitter for more details. |
cacheSize
|
0
|
Camel 2.13.1/2.12.4: Allows to configure the cache size for the ProducerCache which caches producers for reuse in the routing slip. Will by default use the default cache size which is 0. Setting the value to -1 allows to turn off the cache all together. |
Using Exchange Pattern in Recipient List Copy linkLink copied to clipboard!
InOut exchange pattern must get a response during the timeout. However, it fails if the response is not recieved.
8.4. Splitter Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
split() Java DSL command.
Figure 8.4. Splitter Pattern
- Simple splitter—implements the splitter pattern on its own.
- Splitter/aggregator—combines the splitter pattern with the aggregator pattern, such that the pieces of the message are recombined after they have been processed.
Java DSL example Copy linkLink copied to clipboard!
seda:a to seda:b that splits messages by converting each line of an incoming message into a separate outgoing message:
bar elements from an incoming message and insert them into separate outgoing messages:
from("activemq:my.queue")
.split(xpath("//foo/bar"))
.to("file://some/directory")
from("activemq:my.queue")
.split(xpath("//foo/bar"))
.to("file://some/directory")
XML configuration example Copy linkLink copied to clipboard!
tokenize element. In the following example, the message body is tokenized using the \n separator character. To use a regular expression pattern, set regex=true in the tokenize element.
Splitting into groups of lines Copy linkLink copied to clipboard!
from("file:inbox")
.split().tokenize("\n", 1000).streaming()
.to("activemq:queue:order");
from("file:inbox")
.split().tokenize("\n", 1000).streaming()
.to("activemq:queue:order");
tokenize specifies the number of lines that should be grouped into a single chunk. The streaming() clause directs the splitter not to read the whole file at once (resulting in much better performance if the file is large).
group option is always of java.lang.String type.
< tokenize token="\n" group="1000"/> (XML DSL) or .tokenize("\n", 1000)") (Java DSL) does not exist if group option is used after a body expression. For example, as shown in the code snippet below, the group option does not work.
from("file:inbox")
.split(body(String.class).tokenize("\n", 1000)).streaming()
from("file:inbox")
.split(body(String.class).tokenize("\n", 1000)).streaming()
TokenizerExpression, as shown below:
TokenizerExpression token = new TokenizerExpression();
token.setGroup(1000);
token.setToken("\n");
TokenizerExpression token = new TokenizerExpression();
token.setGroup(1000);
token.setToken("\n");
Skip first item Copy linkLink copied to clipboard!
skipFirst option.
tokenize parameter true:
from("direct:start")
// split by new line and group by 3, and skip the very first element
.split().tokenize("\n", 3, true).streaming()
.to("mock:group");
from("direct:start")
// split by new line and group by 3, and skip the very first element
.split().tokenize("\n", 3, true).streaming()
.to("mock:group");
Splitter reply Copy linkLink copied to clipboard!
Parallel execution Copy linkLink copied to clipboard!
XPathBuilder xPathBuilder = new XPathBuilder("//foo/bar");
from("activemq:my.queue").split(xPathBuilder).parallelProcessing().to("activemq:my.parts");
XPathBuilder xPathBuilder = new XPathBuilder("//foo/bar");
from("activemq:my.queue").split(xPathBuilder).parallelProcessing().to("activemq:my.parts");
ThreadPoolExecutor used in the parallel splitter. For example, you can specify a custom executor in the Java DSL as follows:
Using a bean to perform splitting Copy linkLink copied to clipboard!
method() expression. The bean should return an iterable value such as: java.util.Collection, java.util.Iterator, or an array.
method() expression that calls a method on the mySplitterBean bean instance:
mySplitterBean is an instance of the MySplitterBean class, which is defined as follows:
Exchange properties Copy linkLink copied to clipboard!
| header | type | description |
|---|---|---|
CamelSplitIndex
|
int
|
Apache Camel 2.0: A split counter that increases for each Exchange being split. The counter starts from 0. |
CamelSplitSize
|
int
|
Apache Camel 2.0: The total number of Exchanges that was split. This header is not applied for stream based splitting. |
CamelSplitComplete
|
boolean
|
Apache Camel 2.4: Whether or not this Exchange is the last. |
Splitter/aggregator pattern Copy linkLink copied to clipboard!
split() DSL command lets you provide an AggregationStrategy object as the second argument.
Java DSL example Copy linkLink copied to clipboard!
AggregationStrategy implementation Copy linkLink copied to clipboard!
MyOrderStrategy, used in the preceding route is implemented as follows:
Stream based processing Copy linkLink copied to clipboard!
Stream based processing with XML Copy linkLink copied to clipboard!
tokenizeXML sub-command in streaming mode.
order elements, you can split the file into order elements using a route like the following:
from("file:inbox")
.split().tokenizeXML("order").streaming()
.to("activemq:queue:order");
from("file:inbox")
.split().tokenizeXML("order").streaming()
.to("activemq:queue:order");
tokenizeXML. For example, to inherit namespace definitions from the enclosing orders element:
from("file:inbox")
.split().tokenizeXML("order", "orders").streaming()
.to("activemq:queue:order");
from("file:inbox")
.split().tokenizeXML("order", "orders").streaming()
.to("activemq:queue:order");
inheritNamespaceTagName attribute. For example:
Options Copy linkLink copied to clipboard!
split DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
strategyRef
|
Refers to an AggregationStrategy to be used to assemble the replies from the sub-messages, into a single outgoing message from the Splitter. See the section titled What does the splitter return below for whats used by default. | |
strategyMethodName
|
This option can be used to explicitly specify the method name to use, when using POJOs as the AggregationStrategy.
|
|
strategyMethodAllowNull
|
false
|
This option can be used, when using POJOs as the AggregationStrategy. If false, the aggregate method is not used, when there is no data to enrich. If true, null values are used for the oldExchange, when there is no data to enrich.
|
parallelProcessing
|
false
|
If enables then processing the sub-messages occurs concurrently. Note the caller thread will still wait until all sub-messages has been fully processed, before it continues. |
parallelAggregate
|
false
|
If enabled, the aggregate method on AggregationStrategy can be called concurrently. Note that this requires the implementation of AggregationStrategy to be thread-safe. By default, this option is false, which means that Camel automatically synchronizes calls to the aggregate method. In some use-cases, however, you can improve performance by implementing AggregationStrategy as thread-safe and setting this option to true.
|
executorServiceRef
|
Refers to a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatic implied, and you do not have to enable that option as well. | |
stopOnException
|
false
|
Camel 2.2: Whether or not to stop continue processing immediately when an exception occurred. If disable, then Camel continue splitting and process the sub-messages regardless if one of them failed. You can deal with exceptions in the AggregationStrategy class where you have full control how to handle that. |
streaming
|
false
|
If enabled then Camel will split in a streaming fashion, which means it will split the input message in chunks. This reduces the memory overhead. For example if you split big messages its recommended to enable streaming. If streaming is enabled then the sub-message replies will be aggregated out-of-order, eg in the order they come back. If disabled, Camel will process sub-message replies in the same order as they where splitted. |
timeout
|
Camel 2.5: Sets a total timeout specified in millis. If the Recipient List hasn't been able to split and process all replies within the given timeframe, then the timeout triggers and the Splitter breaks out and continues. Notice if you provide a TimeoutAwareAggregationStrategy then the timeout method is invoked before breaking out.
|
|
onPrepareRef
|
Camel 2.8: Refers to a custom Processor to prepare the sub-message of the Exchange, before its processed. This allows you to do any custom logic, such as deep-cloning the message payload if that's needed etc. | |
shareUnitOfWork
|
false
|
Camel 2.8: Whether the unit of work should be shared. See further below for more details. |
8.5. Aggregator Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 8.5. Aggregator Pattern
- Correlation expression — Determines which messages should be aggregated together. The correlation expression is evaluated on each incoming message to produce a correlation key. Incoming messages with the same correlation key are then grouped into the same batch. For example, if you want to aggregate all incoming messages into a single message, you can use a constant expression.
- Completeness condition — Determines when a batch of messages is complete. You can specify this either as a simple size limit or, more generally, you can specify a predicate condition that flags when the batch is complete.
- Aggregation algorithm — Combines the message exchanges for a single correlation key into a single message exchange.
How the aggregator works Copy linkLink copied to clipboard!
Figure 8.6. Aggregator Implementation
- The correlator is responsible for sorting exchanges based on the correlation key. For each incoming exchange, the correlation expression is evaluated, yielding the correlation key. For example, for the exchange shown in Figure 8.6, “Aggregator Implementation”, the correlation key evaluates to A.
- The aggregation strategy is responsible for merging exchanges with the same correlation key. When a new exchange, A, comes in, the aggregator looks up the corresponding aggregate exchange, A', in the aggregation repository and combines it with the new exchange.Until a particular aggregation cycle is completed, incoming exchanges are continuously aggregated with the corresponding aggregate exchange. An aggregation cycle lasts until terminated by one of the completion mechanisms.NoteFrom Camel 2.16, the new XSLT Aggregation Strategy allows you to merge two messages with an XSLT file. You can access the
AggregationStrategies.xslt()file from the toolbox. - If a completion predicate is specified on the aggregator, the aggregate exchange is tested to determine whether it is ready to be sent to the next processor in the route. Processing continues as follows:
- If complete, the aggregate exchange is processed by the latter part of the route. There are two alternative models for this: synchronous (the default), which causes the calling thread to block, or asynchronous (if parallel processing is enabled), where the aggregate exchange is submitted to an executor thread pool (as shown in Figure 8.6, “Aggregator Implementation”).
- If not complete, the aggregate exchange is saved back to the aggregation repository.
- In parallel with the synchronous completion tests, it is possible to enable an asynchronous completion test by enabling either the
completionTimeoutoption or thecompletionIntervaloption. These completion tests run in a separate thread and, whenever the completion test is satisfied, the corresponding exchange is marked as complete and starts to be processed by the latter part of the route (either synchronously or asynchronously, depending on whether parallel processing is enabled or not). - If parallel processing is enabled, a thread pool is responsible for processing exchanges in the latter part of the route. By default, this thread pool contains ten threads, but you have the option of customizing the pool (the section called “Threading options”).
Java DSL example Copy linkLink copied to clipboard!
StockSymbol header value, using the UseLatestAggregationStrategy aggregation strategy. For a given StockSymbol value, if more than three seconds elapse since the last exchange with that correlation key was received, the aggregated exchange is deemed to be complete and is sent to the mock endpoint.
from("direct:start")
.aggregate(header("id"), new UseLatestAggregationStrategy())
.completionTimeout(3000)
.to("mock:aggregated");
from("direct:start")
.aggregate(header("id"), new UseLatestAggregationStrategy())
.completionTimeout(3000)
.to("mock:aggregated");
XML DSL example Copy linkLink copied to clipboard!
Specifying the correlation expression Copy linkLink copied to clipboard!
aggregate() DSL command. You are not limited to using the Simple expression language here. You can specify a correlation expression using any of the expression languages or scripting languages, such as XPath, XQuery, SQL, and so on.
from("direct:start")
.aggregate(xpath("/stockQuote/@symbol"), new UseLatestAggregationStrategy())
.completionTimeout(3000)
.to("mock:aggregated");
from("direct:start")
.aggregate(xpath("/stockQuote/@symbol"), new UseLatestAggregationStrategy())
.completionTimeout(3000)
.to("mock:aggregated");
CamelExchangeException by default. You can suppress this exception by setting the ignoreInvalidCorrelationKeys option. For example, in the Java DSL:
from(...).aggregate(...).ignoreInvalidCorrelationKeys()
from(...).aggregate(...).ignoreInvalidCorrelationKeys()
ignoreInvalidCorrelationKeys option is set as an attribute, as follows:
<aggregate strategyRef="aggregatorStrategy"
ignoreInvalidCorrelationKeys="true"
...>
...
</aggregate>
<aggregate strategyRef="aggregatorStrategy"
ignoreInvalidCorrelationKeys="true"
...>
...
</aggregate>
Specifying the aggregation strategy Copy linkLink copied to clipboard!
aggregate() DSL command or specify it using the aggregationStrategy() clause. For example, you can use the aggregationStrategy() clause as follows:
from("direct:start")
.aggregate(header("id"))
.aggregationStrategy(new UseLatestAggregationStrategy())
.completionTimeout(3000)
.to("mock:aggregated");
from("direct:start")
.aggregate(header("id"))
.aggregationStrategy(new UseLatestAggregationStrategy())
.completionTimeout(3000)
.to("mock:aggregated");
org.apache.camel.processor.aggregate Java package):
UseLatestAggregationStrategy- Return the last exchange for a given correlation key, discarding all earlier exchanges with this key. For example, this strategy could be useful for throttling the feed from a stock exchange, where you just want to know the latest price of a particular stock symbol.
UseOriginalAggregationStrategy- Return the first exchange for a given correlation key, discarding all later exchanges with this key. You must set the first exchange by calling
UseOriginalAggregationStrategy.setOriginal()before you can use this strategy. GroupedExchangeAggregationStrategy- Concatenates all of the exchanges for a given correlation key into a list, which is stored in the
Exchange.GROUPED_EXCHANGEexchange property. See the section called “Grouped exchanges”.
Implementing a custom aggregation strategy Copy linkLink copied to clipboard!
org.apache.camel.processor.aggregate.AggregationStrategy- The basic aggregation strategy interface.
org.apache.camel.processor.aggregate.TimeoutAwareAggregationStrategy- Implement this interface, if you want your implementation to receive a notification when an aggregation cycle times out. The
timeoutnotification method has the following signature:void timeout(Exchange oldExchange, int index, int total, long timeout)
void timeout(Exchange oldExchange, int index, int total, long timeout)Copy to Clipboard Copied! Toggle word wrap Toggle overflow org.apache.camel.processor.aggregate.CompletionAwareAggregationStrategy- Implement this interface, if you want your implementation to receive a notification when an aggregation cycle completes normally. The notification method has the following signature:
void onCompletion(Exchange exchange)
void onCompletion(Exchange exchange)Copy to Clipboard Copied! Toggle word wrap Toggle overflow
StringAggregationStrategy and ArrayListAggregationStrategy::
AggregationStrategy.aggregate() callback method is also invoked for the very first exchange. On the first invocation of the aggregate method, the oldExchange parameter is null and the newExchange parameter contains the first incoming exchange.
ArrayListAggregationStrategy, define a route like the following:
from("direct:start")
.aggregate(header("StockSymbol"), new ArrayListAggregationStrategy())
.completionTimeout(3000)
.to("mock:result");
from("direct:start")
.aggregate(header("StockSymbol"), new ArrayListAggregationStrategy())
.completionTimeout(3000)
.to("mock:result");
Controlling the lifecycle of a custom aggregation strategy Copy linkLink copied to clipboard!
org.apache.camel.Service interface (in addition to the AggregationStrategy interface) and provide implementations of the start() and stop() lifecycle methods. For example, the following code example shows an outline of an aggregation strategy with lifecycle support:
Exchange properties Copy linkLink copied to clipboard!
| Header | Type | Description |
|---|---|---|
Exchange.AGGREGATED_SIZE
|
int
|
The total number of exchanges aggregated into this exchange. |
Exchange.AGGREGATED_COMPLETED_BY
|
String
|
Indicates the mechanism responsible for completing the aggregate exchange. Possible values are: predicate, size, timeout, interval, or consumer.
|
| Header | Type | Description |
|---|---|---|
Exchange.REDELIVERY_COUNTER
|
int
|
Sequence number of the current redelivery attempt (starting at 1).
|
Specifying a completion condition Copy linkLink copied to clipboard!
completionPredicate- Evaluates a predicate after each exchange is aggregated in order to determine completeness. A value of
trueindicates that the aggregate exchange is complete. Alternatively, instead of setting this option, you can define a customAggregationStrategythat implements thePredicateinterface, in which case theAggregationStrategywill be used as the completion predicate. completionSize- Completes the aggregate exchange after the specified number of incoming exchanges are aggregated.
completionTimeout- (Incompatible with
completionInterval) Completes the aggregate exchange, if no incoming exchanges are aggregated within the specified timeout.In other words, the timeout mechanism keeps track of a timeout for each correlation key value. The clock starts ticking after the latest exchange with a particular key value is received. If another exchange with the same key value is not received within the specified timeout, the corresponding aggregate exchange is marked complete and sent to the next node on the route. completionInterval- (Incompatible with
completionTimeout) Completes all outstanding aggregate exchanges, after each time interval (of specified length) has elapsed.The time interval is not tailored to each aggregate exchange. This mechanism forces simultaneous completion of all outstanding aggregate exchanges. Hence, in some cases, this mechanism could complete an aggregate exchange immediately after it started aggregating. completionFromBatchConsumer- When used in combination with a consumer endpoint that supports the batch consumer mechanism, this completion option automatically figures out when the current batch of exchanges is complete, based on information it receives from the consumer endpoint. See the section called “Batch consumer”.
forceCompletionOnStop- When this option is enabled, it forces completion of all outstanding aggregate exchanges when the current route context is stopped.
completionTimeout and completionInterval conditions, which cannot be simultaneously enabled. When conditions are used in combination, the general rule is that the first completion condition to trigger is the effective completion condition.
Specifying the completion predicate Copy linkLink copied to clipboard!
- On the latest aggregate exchange—this is the default behavior.
- On the latest incoming exchange—this behavior is selected when you enable the
eagerCheckCompletionoption.
ALERT message (as indicated by the value of a MsgType header in the latest incoming exchange), you can define a route like the following:
Specifying a dynamic completion timeout Copy linkLink copied to clipboard!
timeout header in each incoming exchange, you could define a route as follows:
from("direct:start")
.aggregate(header("StockSymbol"), new UseLatestAggregationStrategy())
.completionTimeout(header("timeout"))
.to("mock:aggregated");
from("direct:start")
.aggregate(header("StockSymbol"), new UseLatestAggregationStrategy())
.completionTimeout(header("timeout"))
.to("mock:aggregated");
null or 0.
Specifying a dynamic completion size Copy linkLink copied to clipboard!
mySize header in each incoming exchange, you could define a route as follows:
from("direct:start")
.aggregate(header("StockSymbol"), new UseLatestAggregationStrategy())
.completionSize(header("mySize"))
.to("mock:aggregated");
from("direct:start")
.aggregate(header("StockSymbol"), new UseLatestAggregationStrategy())
.completionSize(header("mySize"))
.to("mock:aggregated");
null or 0.
Forcing completion of a single group from within an AggregationStrategy Copy linkLink copied to clipboard!
AggregationStrategy class, there is a mechanism available to force the completion of the current message group, by setting the Exchange.AGGREGATION_COMPLETE_CURRENT_GROUP exchange property to true on the exchange returned from the AggregationStrategy.aggregate() method. This mechanism only affects the current group: other message groups (with different correlation IDs) are not forced to complete. This mechanism overrides any other completion mechanisms, such as predicate, size, timeout, and so on.
AggregationStrategy class completes the current group, if the message body size is larger than 5:
Forcing completion of all groups with a special message Copy linkLink copied to clipboard!
Exchange.AGGREGATION_COMPLETE_ALL_GROUPS- Set to
true, to force completion of the current aggregation cycle. This message acts purely as a signal and is not included in any aggregation cycle. After processing this signal message, the content of the message is discarded. Exchange.AGGREGATION_COMPLETE_ALL_GROUPS_INCLUSIVE- Set to
true, to force completion of the current aggregation cycle. This message is included in the current aggregation cycle.
Using AggregateController Copy linkLink copied to clipboard!
getAggregateController() method. However, it is easy to configure a controller in the route using aggregateController.
AggregateControllerto force completion. For example, to complete a group with key foo
int groups = controller.forceCompletionOfGroup("foo");
int groups = controller.forceCompletionOfGroup("foo");
int groups = controller.forceCompletionOfAllGroups();
int groups = controller.forceCompletionOfAllGroups();
Enforcing unique correlation keys Copy linkLink copied to clipboard!
closeCorrelationKeyOnCompletion option. In order to suppress duplicate correlation key values, it is necessary for the aggregator to record previous correlation key values in a cache. The size of this cache (the number of cached correlation keys) is specified as an argument to the closeCorrelationKeyOnCompletion() DSL command. To specify a cache of unlimited size, you can pass a value of zero or a negative integer. For example, to specify a cache size of 10000 key values:
from("direct:start")
.aggregate(header("UniqueBatchID"), new MyConcatenateStrategy())
.completionSize(header("mySize"))
.closeCorrelationKeyOnCompletion(10000)
.to("mock:aggregated");
from("direct:start")
.aggregate(header("UniqueBatchID"), new MyConcatenateStrategy())
.completionSize(header("mySize"))
.closeCorrelationKeyOnCompletion(10000)
.to("mock:aggregated");
ClosedCorrelationKeyException exception.
Grouped exchanges Copy linkLink copied to clipboard!
org.apache.camel.impl.GroupedExchange holder class. To enable grouped exchanges, specify the groupExchanges() option, as shown in the following Java DSL route:
from("direct:start")
.aggregate(header("StockSymbol"))
.completionTimeout(3000)
.groupExchanges()
.to("mock:result");
from("direct:start")
.aggregate(header("StockSymbol"))
.completionTimeout(3000)
.groupExchanges()
.to("mock:result");
mock:result contains the list of aggregated exchanges in the message body. The following line of code shows how a subsequent processor can access the contents of the grouped exchange in the form of a list:
// Java List<Exchange> grouped = ex.getIn().getBody(List.class);
// Java
List<Exchange> grouped = ex.getIn().getBody(List.class);
Batch consumer Copy linkLink copied to clipboard!
CamelBatchSize, CamelBatchIndex , and CamelBatchComplete properties on the incoming exchange). For example, to aggregate all of the files found by a File consumer endpoint, you could use a route like the following:
from("file://inbox")
.aggregate(xpath("//order/@customerId"), new AggregateCustomerOrderStrategy())
.completionFromBatchConsumer()
.to("bean:processOrder");
from("file://inbox")
.aggregate(xpath("//order/@customerId"), new AggregateCustomerOrderStrategy())
.completionFromBatchConsumer()
.to("bean:processOrder");
Persistent aggregation repository Copy linkLink copied to clipboard!
camel-hawtdb component in your Maven POM. You can then configure a route to use the HawtDB aggregation repository as follows:
Figure 8.7. Recoverable Aggregation Repository
- The aggregator creates a dedicated recovery thread, which runs in the background, scanning the aggregation repository to find any failed exchanges.
- Each failed exchange is checked to see whether its current redelivery count exceeds the maximum redelivery limit. If it is under the limit, the recovery task resubmits the exchange for processing in the latter part of the route.
- If the current redelivery count is over the limit, the failed exchange is passed to the dead letter queue.
Threading options Copy linkLink copied to clipboard!
parallelProcessing option, as follows:
from("direct:start")
.aggregate(header("id"), new UseLatestAggregationStrategy())
.completionTimeout(3000)
.parallelProcessing()
.to("mock:aggregated");
from("direct:start")
.aggregate(header("id"), new UseLatestAggregationStrategy())
.completionTimeout(3000)
.parallelProcessing()
.to("mock:aggregated");
java.util.concurrent.ExecutorService instance using the executorService option (in which case it is unnecessary to enable the parallelProcessing option).
Aggregating into a List Copy linkLink copied to clipboard!
List object. To facilitate this scenario, Apache Camel provides the AbstractListAggregationStrategy abstract class, which you can quickly extend to create an aggregation strategy for this case. Incoming message bodies of type, T, are aggregated into a completed exchange, with a message body of type List<T>.
Integer message bodies into a List<Integer> object, you could use an aggregation strategy defined as follows:
Aggregator options Copy linkLink copied to clipboard!
| Option | Default | Description |
|---|---|---|
correlationExpression | Mandatory Expression which evaluates the correlation key to use for aggregation. The Exchange which has the same correlation key is aggregated together. If the correlation key could not be evaluated an Exception is thrown. You can disable this by using the ignoreBadCorrelationKeys option. | |
aggregationStrategy | Mandatory AggregationStrategy which is used to merge the incoming Exchange with the existing already merged exchanges. At first call the oldExchange parameter is null. On subsequent invocations the oldExchange contains the merged exchanges and newExchange is of course the new incoming Exchange. From Camel 2.9.2 onwards, the strategy can optionally be a TimeoutAwareAggregationStrategy implementation, which supports a timeout callback. From Camel 2.16 onwards, the strategy can also be a PreCompletionAwareAggregationStrategy implementation. It runs the completion check in a pre-completion mode. | |
strategyRef | A reference to lookup the AggregationStrategy in the Registry. | |
completionSize | Number of messages aggregated before the aggregation is complete. This option can be set as either a fixed value or using an Expression which allows you to evaluate a size dynamically - will use Integer as result. If both are set Camel will fallback to use the fixed value if the Expression result was null or 0. | |
completionTimeout | Time in millis that an aggregated exchange should be inactive before its complete. This option can be set as either a fixed value or using an Expression which allows you to evaluate a timeout dynamically - will use Long as result. If both are set Camel will fallback to use the fixed value if the Expression result was null or 0. You cannot use this option together with completionInterval, only one of the two can be used. | |
completionInterval | A repeating period in millis by which the aggregator will complete all current aggregated exchanges. Camel has a background task which is triggered every period. You cannot use this option together with completionTimeout, only one of them can be used. | |
completionPredicate | Specifies a predicate (of org.apache.camel.Predicate type), which signals when an aggregated exchange is complete. Alternatively, instead of setting this option, you can define a custom AggregationStrategy that implements the Predicate interface, in which case the AggregationStrategy will be used as the completion predicate. | |
completionFromBatchConsumer | false | This option is if the exchanges are coming from a Batch Consumer. Then when enabled the Aggregator will use the batch size determined by the Batch Consumer in the message header CamelBatchSize. See more details at Batch Consumer. This can be used to aggregate all files consumed from a see File endpoint in that given poll. |
eagerCheckCompletion | false | Whether or not to eager check for completion when a new incoming Exchange has been received. This option influences the behavior of the completionPredicate option as the Exchange being passed in changes accordingly. When false the Exchange passed in the Predicate is the aggregated Exchange which means any information you may store on the aggregated Exchange from the AggregationStrategy is available for the Predicate. When true the Exchange passed in the Predicate is the incoming Exchange, which means you can access data from the incoming Exchange. |
forceCompletionOnStop | false | If true, complete all aggregated exchanges when the current route context is stopped. |
groupExchanges | false | If enabled then Camel will group all aggregated Exchanges into a single combined org.apache.camel.impl.GroupedExchange holder class that holds all the aggregated Exchanges. And as a result only one Exchange is being sent out from the aggregator. Can be used to combine many incoming Exchanges into a single output Exchange without coding a custom AggregationStrategy yourself. |
ignoreInvalidCorrelationKeys | false | Whether or not to ignore correlation keys which could not be evaluated to a value. By default Camel will throw an Exception, but you can enable this option and ignore the situation instead. |
closeCorrelationKeyOnCompletion | Whether or not late Exchanges should be accepted or not. You can enable this to indicate that if a correlation key has already been completed, then any new exchanges with the same correlation key be denied. Camel will then throw a closedCorrelationKeyException exception. When using this option you pass in a integer which is a number for a LRUCache which keeps that last X number of closed correlation keys. You can pass in 0 or a negative value to indicate a unbounded cache. By passing in a number you are ensured that cache wont grown too big if you use a log of different correlation keys. | |
discardOnCompletionTimeout | false | Camel 2.5: Whether or not exchanges which complete due to a timeout should be discarded. If enabled, then when a timeout occurs the aggregated message will not be sent out but dropped (discarded). |
aggregationRepository | Allows you to plug in you own implementation of org.apache.camel.spi.AggregationRepository which keeps track of the current inflight aggregated exchanges. Camel uses by default a memory based implementation. | |
aggregationRepositoryRef | Reference to lookup a aggregationRepository in the Registry. | |
parallelProcessing | false | When aggregated are completed they are being send out of the aggregator. This option indicates whether or not Camel should use a thread pool with multiple threads for concurrency. If no custom thread pool has been specified then Camel creates a default pool with 10 concurrent threads. |
executorService | If using parallelProcessing you can specify a custom thread pool to be used. In fact also if you are not using parallelProcessing this custom thread pool is used to send out aggregated exchanges as well. | |
executorServiceRef | Reference to lookup a executorService in the Registry | |
timeoutCheckerExecutorService | If using one of the completionTimeout, completionTimeoutExpression, or completionInterval options, a background thread is created to check for the completion for every aggregator. Set this option to provide a custom thread pool to be used rather than creating a new thread for every aggregator. | |
timeoutCheckerExecutorServiceRef | Reference to look up a timeoutCheckerExecutorService in the registry. | |
completeAllOnStop | When you stop the Aggregator, this option allows it to complete all pending exchanges from the aggregation repository. | |
optimisticLocking | false | Turns on optimistic locking, which can be used in combination with an aggregation repository. |
optimisticLockRetryPolicy | Configures the retry policy for optimistic locking. | |
Using a AggregateController | Camel 2.16 allows you to use an external source to complete groups or all groups. This can be done using Java or JMX API. |
8.6. Resequencer Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 8.8. Resequencer Pattern
- Batch resequencing — Collects messages into a batch, sorts the messages and sends them to their output.
- Stream resequencing — Re-orders (continuous) message streams based on the detection of gaps between messages.
Batch resequencing Copy linkLink copied to clipboard!
TimeStamp header, you can define the following route in Java DSL:
from("direct:start").resequence(header("TimeStamp")).to("mock:result");
from("direct:start").resequence(header("TimeStamp")).to("mock:result");
batch() DSL command, which takes a BatchResequencerConfig instance as its sole argument. For example, to modify the preceding route so that the batch consists of messages collected in a 4000 millisecond time window, up to a maximum of 300 messages, you can define the Java DSL route as follows:
Batch options Copy linkLink copied to clipboard!
| Java DSL | XML DSL | Default | Description |
|---|---|---|---|
allowDuplicates() | batch-config/@allowDuplicates | false | If true, do not discard duplicate messages from the batch (where duplicate means that the message expression evaluates to the same value). |
reverse() | batch-config/@reverse | false | If true, put the messages in reverse order (where the default ordering applied to a message expression is based on Java's string lexical ordering, as defined by String.compareTo()). |
JMSPriority, you would need to combine the options, allowDuplicates and reverse, as follows:
Stream resequencing Copy linkLink copied to clipboard!
stream() to the resequence() DSL command. For example, to resequence incoming messages based on the value of a sequence number in the seqnum header, you define a DSL route as follows:
from("direct:start").resequence(header("seqnum")).stream().to("mock:result");
from("direct:start").resequence(header("seqnum")).stream().to("mock:result");
3 has a predecessor message with the sequence number 2 and a successor message with the sequence number 4. The message sequence 2,3,5 has a gap because the successor of 3 is missing. The resequencer therefore must retain message 5 until message 4 arrives (or a timeout occurs).
StreamResequencerConfig object as an argument to stream(). For example, to configure a stream resequencer with a message capacity of 5000 and a timeout of 4000 milliseconds, you define a route as follows:
long, you would must define a custom comparator, as follows:
// Java
ExpressionResultComparator<Exchange> comparator = new MyComparator();
StreamResequencerConfig config = new StreamResequencerConfig(5000, 4000L, comparator);
from("direct:start").resequence(header("seqnum")).stream(config).to("mock:result");
// Java
ExpressionResultComparator<Exchange> comparator = new MyComparator();
StreamResequencerConfig config = new StreamResequencerConfig(5000, 4000L, comparator);
from("direct:start").resequence(header("seqnum")).stream(config).to("mock:result");
Ignore invalid exchanges Copy linkLink copied to clipboard!
CamelExchangeException exception, if the incoming exchange is not valid—that is, if the sequencing expression cannot be evaluated for some reason (for example, due to a missing header). You can use the ignoreInvalidExchanges option to ignore these exceptions, which means the resequencer will skip any invalid exchanges.
from("direct:start")
.resequence(header("seqno")).batch().timeout(1000)
// ignore invalid exchanges (they are discarded)
.ignoreInvalidExchanges()
.to("mock:result");
from("direct:start")
.resequence(header("seqno")).batch().timeout(1000)
// ignore invalid exchanges (they are discarded)
.ignoreInvalidExchanges()
.to("mock:result");
Reject old messages Copy linkLink copied to clipboard!
rejectOld option can be used to prevent messages being sent out of order, regardless of the mechanism used to resequence messages. When the rejectOld option is enabled, the resequencer rejects an incoming message (by throwing a MessageRejectedException exception), if the incoming messages is older (as defined by the current comparator) than the last delivered message.
from("direct:start")
.onException(MessageRejectedException.class).handled(true).to("mock:error").end()
.resequence(header("seqno")).stream().timeout(1000).rejectOld()
.to("mock:result");
from("direct:start")
.onException(MessageRejectedException.class).handled(true).to("mock:error").end()
.resequence(header("seqno")).stream().timeout(1000).rejectOld()
.to("mock:result");
8.7. Routing Slip Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 8.9. Routing Slip Pattern
The slip header Copy linkLink copied to clipboard!
cxf:bean:decrypt,cxf:bean:authenticate,cxf:bean:dedup
cxf:bean:decrypt,cxf:bean:authenticate,cxf:bean:dedup
The current endpoint property Copy linkLink copied to clipboard!
Exchange.SLIP_ENDPOINT) on the exchange which contains the current endpoint as it advanced though the slip. This enables you to find out how far the exchange has progressed through the slip.
Java DSL example Copy linkLink copied to clipboard!
direct:a endpoint and reads a routing slip from the aRoutingSlipHeader header:
from("direct:b").routingSlip("aRoutingSlipHeader");
from("direct:b").routingSlip("aRoutingSlipHeader");
routingSlip(). The following example defines a route that uses the aRoutingSlipHeader header key for the routing slip and uses the # character as the URI delimiter:
from("direct:c").routingSlip("aRoutingSlipHeader", "#");
from("direct:c").routingSlip("aRoutingSlipHeader", "#");
XML configuration example Copy linkLink copied to clipboard!
Ignore invalid endpoints Copy linkLink copied to clipboard!
ignoreInvalidEndpoints, which the Recipient List pattern also supports. You can use it to skip endpoints that are invalid. For example:
from("direct:a").routingSlip("myHeader").ignoreInvalidEndpoints();
from("direct:a").routingSlip("myHeader").ignoreInvalidEndpoints();
ignoreInvalidEndpoints attribute on the <routingSlip> tag:
myHeader contains the two endpoints, direct:foo,xxx:bar. The first endpoint is valid and works. The second is invalid and, therefore, ignored. Apache Camel logs at INFO level whenever an invalid endpoint is encountered.
Options Copy linkLink copied to clipboard!
routingSlip DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
uriDelimiter
|
,
|
Delimiter used if the Expression returned multiple endpoints. |
ignoreInvalidEndpoints
|
false
|
If an endpoint uri could not be resolved, should it be ignored. Otherwise Camel will thrown an exception stating the endpoint uri is not valid. |
cacheSize
|
0
|
Camel 2.13.1/2.12.4: Allows to configure the cache size for the ProducerCache which caches producers for reuse in the routing slip. Will by default use the default cache size which is 0. Setting the value to -1 allows to turn off the cache all together. |
8.8. Throttler Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
throttle() Java DSL command.
Java DSL example Copy linkLink copied to clipboard!
from("seda:a").throttle(100).to("seda:b");
from("seda:a").throttle(100).to("seda:b");
timePeriodMillis() DSL command. For example, to limit the flow rate to 3 messages per 30000 milliseconds, define a route as follows:
from("seda:a").throttle(3).timePeriodMillis(30000).to("mock:result");
from("seda:a").throttle(3).timePeriodMillis(30000).to("mock:result");
XML configuration example Copy linkLink copied to clipboard!
Dynamically changing maximum requests per period Copy linkLink copied to clipboard!
java.lang.Long type. In the example below we use a header from the message to determine the maximum requests per period. If the header is absent, then the Throttler uses the old value. So that allows you to only provide a header if the value is to be changed:
Asynchronous delaying Copy linkLink copied to clipboard!
from("seda:a").throttle(100).asyncDelayed().to("seda:b");
from("seda:a").throttle(100).asyncDelayed().to("seda:b");
Options Copy linkLink copied to clipboard!
throttle DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
maximumRequestsPerPeriod
|
Maximum number of requests per period to throttle. This option must be provided and a positive number. Notice, in the XML DSL, from Camel 2.8 onwards this option is configured using an Expression instead of an attribute. | |
timePeriodMillis
|
1000
|
The time period in millis, in which the throttler will allow at most maximumRequestsPerPeriod number of messages.
|
asyncDelayed
|
false
|
Camel 2.4: If enabled then any messages which is delayed happens asynchronously using a scheduled thread pool. |
executorServiceRef
|
Camel 2.4: Refers to a custom Thread Pool to be used if asyncDelay has been enabled.
|
|
callerRunsWhenRejected
|
true
|
Camel 2.4: Is used if asyncDelayed was enabled. This controls if the caller thread should execute the task if the thread pool rejected the task.
|
8.9. Delayer Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Java DSL example Copy linkLink copied to clipboard!
delay() command to add a relative time delay, in units of milliseconds, to incoming messages. For example, the following route delays all incoming messages by 2 seconds:
from("seda:a").delay(2000).to("mock:result");
from("seda:a").delay(2000).to("mock:result");
from("seda:a").delay(header("MyDelay")).to("mock:result");
from("seda:a").delay(header("MyDelay")).to("mock:result");
delay() are interpreted as sub-clauses of delay(). Hence, in some contexts it is necessary to terminate the sub-clauses of delay() by inserting the end() command. For example, when delay() appears inside an onException() clause, you would terminate it as follows:
XML configuration example Copy linkLink copied to clipboard!
Creating a custom delay Copy linkLink copied to clipboard!
from("activemq:foo").
delay().expression().method("someBean", "computeDelay").
to("activemq:bar");
from("activemq:foo").
delay().expression().method("someBean", "computeDelay").
to("activemq:bar");
Asynchronous delaying Copy linkLink copied to clipboard!
from("activemq:queue:foo")
.delay(1000)
.asyncDelayed()
.to("activemq:aDelayedQueue");
from("activemq:queue:foo")
.delay(1000)
.asyncDelayed()
.to("activemq:aDelayedQueue");
Options Copy linkLink copied to clipboard!
| Name | Default Value | Description |
|---|---|---|
asyncDelayed
|
false
|
Camel 2.4: If enabled then delayed messages happens asynchronously using a scheduled thread pool. |
executorServiceRef
|
Camel 2.4: Refers to a custom Thread Pool to be used if asyncDelay has been enabled.
|
|
callerRunsWhenRejected
|
true
|
Camel 2.4: Is used if asyncDelayed was enabled. This controls if the caller thread should execute the task if the thread pool rejected the task.
|
8.10. Load Balancer Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Java DSL example Copy linkLink copied to clipboard!
mock:x, mock:y, mock:z, using a round robin load-balancing policy:
from("direct:start").loadBalance().roundRobin().to("mock:x", "mock:y", "mock:z");
from("direct:start").loadBalance().roundRobin().to("mock:x", "mock:y", "mock:z");
XML configuration example Copy linkLink copied to clipboard!
Load-balancing policies Copy linkLink copied to clipboard!
Round robin Copy linkLink copied to clipboard!
mock:x, mock:y, mock:z, then the incoming messages are sent to the following sequence of endpoints: mock:x, mock:y, mock:z, mock:x, mock:y, mock:z, and so on.
from("direct:start").loadBalance().roundRobin().to("mock:x", "mock:y", "mock:z");
from("direct:start").loadBalance().roundRobin().to("mock:x", "mock:y", "mock:z");
Random Copy linkLink copied to clipboard!
from("direct:start").loadBalance().random().to("mock:x", "mock:y", "mock:z");
from("direct:start").loadBalance().random().to("mock:x", "mock:y", "mock:z");
Sticky Copy linkLink copied to clipboard!
from("direct:start").loadBalance().sticky(header("username")).to("mock:x", "mock:y", "mock:z");
from("direct:start").loadBalance().sticky(header("username")).to("mock:x", "mock:y", "mock:z");
Topic Copy linkLink copied to clipboard!
from("direct:start").loadBalance().topic().to("mock:x", "mock:y", "mock:z");
from("direct:start").loadBalance().topic().to("mock:x", "mock:y", "mock:z");
Failover Copy linkLink copied to clipboard!
failover load balancer is capable of trying the next processor in case an Exchange failed with an exception during processing. You can configure the failover with a list of specific exceptions that trigger failover. If you do not specify any exceptions, failover is triggered by any exception. The failover load balancer uses the same strategy for matching exceptions as the onException exception clause.
failover load balancer supports the following options:
| Option | Type | Default | Description |
|---|---|---|---|
inheritErrorHandler
|
boolean
|
true
|
Camel 2.3: Specifies whether to use the
errorHandler configured on the route. If you want to fail over immediately to the next endpoint, you should disable this option (value of false). If you enable this option, Apache Camel will first attempt to process the message using the errorHandler.
For example, the
errorHandler might be configured to redeliver messages and use delays between attempts. Apache Camel will initially try to redeliver to the original endpoint, and only fail over to the next endpoint when the errorHandler is exhausted.
|
maximumFailoverAttempts
|
int
|
-1
|
Camel 2.3: Specifies the maximum number of attempts to fail over to a new endpoint. The value,
0, implies that no failover attempts are made and the value, -1, implies an infinite number of failover attempts.
|
roundRobin
|
boolean
|
false
|
Camel 2.3: Specifies whether the
failover load balancer should operate in round robin mode or not. If not, it will always start from the first endpoint when a new message is to be processed. In other words it restarts from the top for every message. If round robin is enabled, it keeps state and continues with the next endpoint in a round robin fashion. When using round robin it will not stick to last known good endpoint, it will always pick the next endpoint to use.
|
IOException exception is thrown:
Weighted round robin and weighted random Copy linkLink copied to clipboard!
| Option | Type | Default | Description |
|---|---|---|---|
roundRobin
|
boolean
|
false
|
The default value for round-robin is false. In the absence of this setting or parameter, the load-balancing algorithm used is random.
|
distributionRatioDelimiter
|
String
|
, |
The distributionRatioDelimiter is the delimiter used to specify the distributionRatio. If this attribute is not specified, comma , is the default delimiter.
|
Custom Load Balancer Copy linkLink copied to clipboard!
from("direct:start")
// using our custom load balancer
.loadBalance(new MyLoadBalancer())
.to("mock:x", "mock:y", "mock:z");
from("direct:start")
// using our custom load balancer
.loadBalance(new MyLoadBalancer())
.to("mock:x", "mock:y", "mock:z");
LoadBalancerSupport and SimpleLoadBalancerSupport. The former supports the asynchronous routing engine, and the latter does not. Here is an example:
Circuit Breaker Copy linkLink copied to clipboard!
halfOpenAfter timeout is reached. After the timeout, if there is a new call, the Circuit Breaker passes all the messages. If the result is success, the Circuit Breaker moves to a closed state, if not, it moves back to open state.
from("direct:start").loadBalance()
.circuitBreaker(2, 1000L, MyCustomException.class)
.to("mock:result");
from("direct:start").loadBalance()
.circuitBreaker(2, 1000L, MyCustomException.class)
.to("mock:result");
8.11. Multicast Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 8.10. Multicast Pattern
Multicast with a custom aggregation strategy Copy linkLink copied to clipboard!
multicast() DSL command, as follows:
from("cxf:bean:offer").multicast(new HighestBidAggregationStrategy()).
to("cxf:bean:Buyer1", "cxf:bean:Buyer2", "cxf:bean:Buyer3");
from("cxf:bean:offer").multicast(new HighestBidAggregationStrategy()).
to("cxf:bean:Buyer1", "cxf:bean:Buyer2", "cxf:bean:Buyer3");
cxf:bean:offer, and the buyers are represented by the endpoints, cxf:bean:Buyer1, cxf:bean:Buyer2, cxf:bean:Buyer3. To consolidate the bids received from the various buyers, the multicast processor uses the aggregation strategy, HighestBidAggregationStrategy. You can implement the HighestBidAggregationStrategy in Java, as follows:
Bid. For more details about custom aggregation strategies, see Section 8.5, “Aggregator”.
Parallel processing Copy linkLink copied to clipboard!
to() command). In some cases, this might cause unacceptably long latency. To avoid these long latency times, you have the option of enabling parallel processing by adding the parallelProcessing() clause. For example, to enable parallel processing in the electronic auction example, define the route as follows:
from("cxf:bean:offer")
.multicast(new HighestBidAggregationStrategy())
.parallelProcessing()
.to("cxf:bean:Buyer1", "cxf:bean:Buyer2", "cxf:bean:Buyer3");
from("cxf:bean:offer")
.multicast(new HighestBidAggregationStrategy())
.parallelProcessing()
.to("cxf:bean:Buyer1", "cxf:bean:Buyer2", "cxf:bean:Buyer3");
executorService() method to specify your own custom executor service. For example:
from("cxf:bean:offer")
.multicast(new HighestBidAggregationStrategy())
.executorService(MyExecutor)
.to("cxf:bean:Buyer1", "cxf:bean:Buyer2", "cxf:bean:Buyer3");
from("cxf:bean:offer")
.multicast(new HighestBidAggregationStrategy())
.executorService(MyExecutor)
.to("cxf:bean:Buyer1", "cxf:bean:Buyer2", "cxf:bean:Buyer3");
MyAggregationStrategy, is used to aggregate the replies from the endpoints, direct:a, direct:b, and direct:c:
XML configuration example Copy linkLink copied to clipboard!
parallelProcessing attribute and the threadPoolRef attribute are optional. It is only necessary to set them if you want to customize the threading behavior of the multicast processor.
Apply custom processing to the outgoing messages Copy linkLink copied to clipboard!
onPrepare DSL command in the multicast clause. The onPrepare command inserts a custom processor just after the message has been shallow-copied and just before the message is dispatched to its endpoint. For example, in the following route, the CustomProc processor is invoked on the message sent to direct:a and the CustomProc processor is also invoked on the message sent to direct:b.
from("direct:start")
.multicast().onPrepare(new CustomProc())
.to("direct:a").to("direct:b");
from("direct:start")
.multicast().onPrepare(new CustomProc())
.to("direct:a").to("direct:b");
onPrepare DSL command is to perform a deep copy of some or all elements of a message. For example, the following CustomProc processor class performs a deep copy of the message body, where the message body is presumed to be of type, BodyType, and the deep copy is performed by the method, BodyType.deepCopy().
multicast syntax allows you to invoke the process DSL command in the multicast clause, this does not make sense semantically and it does not have the same effect as onPrepare (in fact, in this context, the process DSL command has no effect).
Using onPrepare to execute custom logic when preparing messages Copy linkLink copied to clipboard!
onPrepare which allows you to do this using the Processor interface.
onPrepare can be used for any kind of custom logic which you would like to execute before the Exchange is being multicasted.
onPrepare option as shown:
from("direct:start")
.multicast().onPrepare(new AnimalDeepClonePrepare()).to("direct:a").to("direct:b");
from("direct:start")
.multicast().onPrepare(new AnimalDeepClonePrepare()).to("direct:a").to("direct:b");
Options Copy linkLink copied to clipboard!
multicast DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
strategyRef
|
Refers to an AggregationStrategy to be used to assemble the replies from the multicasts, into a single outgoing message from the Multicast. By default Camel will use the last reply as the outgoing message. | |
strategyMethodName
|
This option can be used to explicitly specify the method name to use, when using POJOs as the AggregationStrategy.
|
|
strategyMethodAllowNull
|
false
|
This option can be used, when using POJOs as the AggregationStrategy. If false, the aggregate method is not used, when there is no data to enrich. If true, null values are used for the oldExchange, when there is no data to enrich.
|
parallelProcessing
|
false
|
If enabled, sending messages to the multicasts occurs concurrently. Note the caller thread will still wait until all messages has been fully processed, before it continues. Its only the sending and processing the replies from the multicasts which happens concurrently. |
parallelAggregate
|
false
|
If enabled, the aggregate method on AggregationStrategy can be called concurrently. Note that this requires the implementation of AggregationStrategy to be thread-safe. By default, this option is false, which means that Camel automatically synchronizes calls to the aggregate method. In some use-cases, however, you can improve performance by implementing AggregationStrategy as thread-safe and setting this option to true.
|
executorServiceRef
|
Refers to a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatic implied, and you do not have to enable that option as well. | |
stopOnException
|
false
|
Camel 2.2: Whether or not to stop continue processing immediately when an exception occurred. If disable, then Camel will send the message to all multicasts regardless if one of them failed. You can deal with exceptions in the AggregationStrategy class where you have full control how to handle that. |
streaming
|
false
|
If enabled then Camel will process replies out-of-order, eg in the order they come back. If disabled, Camel will process replies in the same order as multicasted. |
timeout
|
Camel 2.5: Sets a total timeout specified in millis. If the Multicast hasn't been able to send and process all replies within the given timeframe, then the timeout triggers and the Multicast breaks out and continues. Notice if you provide a TimeoutAwareAggregationStrategy then the timeout method is invoked before breaking out.
|
|
onPrepareRef
|
Camel 2.8: Refers to a custom Processor to prepare the copy of the Exchange each multicast will receive. This allows you to do any custom logic, such as deep-cloning the message payload if that's needed etc. | |
shareUnitOfWork
|
false
|
Camel 2.8: Whether the unit of work should be shared. See the same option on Splitter for more details. |
8.12. Composed Message Processor Copy linkLink copied to clipboard!
Composed Message Processor Copy linkLink copied to clipboard!
Figure 8.11. Composed Message Processor Pattern
Java DSL example Copy linkLink copied to clipboard!
XML DSL example Copy linkLink copied to clipboard!
Processing steps Copy linkLink copied to clipboard!
OrderItems to a Content Based Router, which routes messages based on the item type. Widget items get sent for checking in the widgetInventory bean and gadget items get sent to the gadgetInventory bean. Once these OrderItems have been validated by the appropriate bean, they are sent on to the Aggregator which collects and re-assembles the validated OrderItems into an order again.
.header("orderId") qualifier on the aggregate() DSL command instructs the aggregator to use the header with the key, orderId, as the correlation expression.
8.13. Scatter-Gather Copy linkLink copied to clipboard!
Scatter-Gather Copy linkLink copied to clipboard!
Figure 8.12. Scatter-Gather Pattern
Dynamic scatter-gather example Copy linkLink copied to clipboard!
listOfVendors header to obtain the list of recipients. Hence, the client that sends messages to this application needs to add a listOfVendors header to the message. Example 8.1, “Messaging Client Sample” shows some sample code from a messaging client that adds the relevant header data to outgoing messages.
Example 8.1. Messaging Client Sample
Map<String, Object> headers = new HashMap<String, Object>();
headers.put("listOfVendors", "bean:vendor1, bean:vendor2, bean:vendor3");
headers.put("quoteRequestId", "quoteRequest-1");
template.sendBodyAndHeaders("direct:start", "<quote_request item=\"beer\"/>", headers);
Map<String, Object> headers = new HashMap<String, Object>();
headers.put("listOfVendors", "bean:vendor1, bean:vendor2, bean:vendor3");
headers.put("quoteRequestId", "quoteRequest-1");
template.sendBodyAndHeaders("direct:start", "<quote_request item=\"beer\"/>", headers);
bean:vendor1, bean:vendor2, and bean:vendor3. These beans are all implemented by the following class:
vendor1, vendor2, and vendor3, are instantiated using Spring XML syntax, as follows:
MyVendor.getQuote method. This method does a simple check to see whether this quote request is for beer and then sets the price of beer on the exchange for retrieval at a later step. The message is forwarded to the next step using POJO Producing (see the @Produce annotation).
quoteRequestId header (passed to the correlationExpression). As shown in Example 8.1, “Messaging Client Sample”, the correlation ID is set to quoteRequest-1 (the correlation ID should be unique). To pick the lowest quote out of the set, you can use a custom aggregation strategy like the following:
Static scatter-gather example Copy linkLink copied to clipboard!
8.14. Loop Copy linkLink copied to clipboard!
Loop Copy linkLink copied to clipboard!
Exchange properties Copy linkLink copied to clipboard!
| Property | Description |
|---|---|
CamelLoopSize
|
Apache Camel 2.0: Total number of loops |
CamelLoopIndex
|
Apache Camel 2.0: Index of the current iteration (0 based) |
Java DSL examples Copy linkLink copied to clipboard!
direct:x endpoint and then send the message repeatedly to mock:result. The number of loop iterations is specified either as an argument to loop() or by evaluating an expression at run time, where the expression must evaluate to an int (or else a RuntimeCamelException is thrown).
from("direct:a").loop(8).to("mock:result");
from("direct:a").loop(8).to("mock:result");
from("direct:b").loop(header("loop")).to("mock:result");
from("direct:b").loop(header("loop")).to("mock:result");
from("direct:c").loop().xpath("/hello/@times").to("mock:result");
from("direct:c").loop().xpath("/hello/@times").to("mock:result");
XML configuration example Copy linkLink copied to clipboard!
Using copy mode Copy linkLink copied to clipboard!
direct:start endpoint containing the letter A. The output of processing this route will be that, each mock:loop endpoint will receive AB as message.
mock:loop will receive AB, ABB, ABBB messages.
Options Copy linkLink copied to clipboard!
loop DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
copy
|
false
|
Camel 2.8: Whether or not copy mode is used. If false then the same Exchange is being used throughout the looping. So the result from the previous iteration will be visible for the next iteration. Instead you can enable copy mode, and then each iteration is restarting with a fresh copy of the input Exchange.
|
8.15. Sampling Copy linkLink copied to clipboard!
Sampling Throttler Copy linkLink copied to clipboard!
Java DSL example Copy linkLink copied to clipboard!
sample() DSL command to invoke the sampler as follows:
Spring XML example Copy linkLink copied to clipboard!
samplePeriod and units attributes:
Options Copy linkLink copied to clipboard!
sample DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
messageFrequency
|
Samples the message every N'th message. You can only use either frequency or period. | |
samplePeriod
|
1
|
Samples the message every N'th period. You can only use either frequency or period. |
units
|
SECOND
|
Time unit as an enum of java.util.concurrent.TimeUnit from the JDK.
|
8.16. Dynamic Router Copy linkLink copied to clipboard!
Dynamic Router Copy linkLink copied to clipboard!
Figure 8.13. Dynamic Router Pattern
dynamicRouter in the DSL, which is like a dynamic Routing Slip that evaluates the slip on-the-fly.
dynamicRouter (such as a bean), returns null to indicate the end. Otherwise, the dynamicRouter will continue in an endless loop.
Dynamic Router in Camel 2.5 onwards Copy linkLink copied to clipboard!
Exchange.SLIP_ENDPOINT, with the current endpoint as it advances through the slip. This enables you to find out how far the exchange has progressed through the slip. (It's a slip because the Dynamic Router implementation is based on Routing Slip).
Java DSL Copy linkLink copied to clipboard!
dynamicRouter as follows:
from("direct:start")
// use a bean as the dynamic router
.dynamicRouter(bean(DynamicRouterTest.class, "slip"));
from("direct:start")
// use a bean as the dynamic router
.dynamicRouter(bean(DynamicRouterTest.class, "slip"));
Exchange to ensure thread safety.
Spring XML Copy linkLink copied to clipboard!
Options Copy linkLink copied to clipboard!
dynamicRouter DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
uriDelimiter
|
,
|
Delimiter used if the Expression returned multiple endpoints. |
ignoreInvalidEndpoints
|
false
|
If an endpoint uri could not be resolved, should it be ignored. Otherwise Camel will thrown an exception stating the endpoint uri is not valid. |
@DynamicRouter annotation Copy linkLink copied to clipboard!
@DynamicRouter annotation. For example:
route method is invoked repeatedly as the message progresses through the slip. The idea is to return the endpoint URI of the next destination. Return null to indicate the end. You can return multiple endpoints if you like, just as the Routing Slip, where each endpoint is separated by a delimiter.
Chapter 9. Message Transformation Copy linkLink copied to clipboard!
Abstract
9.1. Content Enricher Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 9.1. Content Enricher Pattern
Models of content enrichment Copy linkLink copied to clipboard!
enrich()—obtains additional data from the resource by sending a copy of the current exchange to a producer endpoint and then using the data from the resulting reply (the exchange created by the enricher is always an InOut exchange).pollEnrich()—obtains the additional data by polling a consumer endpoint for data. Effectively, the consumer endpoint from the main route and the consumer endpoint inpollEnrich()are coupled, such that exchanges incoming on the main route trigger a poll of thepollEnrich()endpoint.
uris. You can compute uris using an expression that enables you to use values from the current exchange. For example, you can poll a file with a name that is computed from the data exchange. This change breaks the XML DSL and enables you to migrate easily. The Java DSL stays backwards compatible.
Content enrichment using enrich() Copy linkLink copied to clipboard!
enrich) retrieves additional data from a resource endpoint in order to enrich an incoming message (contained in the orginal exchange). An aggregation strategy combines the original exchange and the resource exchange. The first parameter of the AggregationStrategy.aggregate(Exchange, Exchange) method corresponds to the the original exchange, and the second parameter corresponds to the resource exchange. The results from the resource endpoint are stored in the resource exchange's Out message. Here is a sample template for implementing your own aggregation strategy class:
Spring XML Enrich Example Copy linkLink copied to clipboard!
Default aggregation strategy Copy linkLink copied to clipboard!
from("direct:start")
.enrich("direct:resource")
.to("direct:result");
from("direct:start")
.enrich("direct:resource")
.to("direct:result");
direct:result endpoint contains the output from the direct:resource, because this example does not use any custom aggregation.
strategyRef attribute, as follows:
<route>
<from uri="direct:start"/>
<enrich uri="direct:resource"/>
<to uri="direct:result"/>
</route>
<route>
<from uri="direct:start"/>
<enrich uri="direct:resource"/>
<to uri="direct:result"/>
</route>
Enrich Options Copy linkLink copied to clipboard!
enrich DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
uri
|
The endpoint uri for the external servie to enrich from. You must use either uri or ref.
|
|
ref
|
Refers to the endpoint for the external servie to enrich from. You must use either uri or ref.
|
|
strategyRef
|
Refers to an AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message. By default Camel will use the reply from the external service as outgoing message. | |
aggregateOnException
|
Refers to the Aggregate method. The aggregateOnException enables you to deal with exceptions. For example, you can suppress the exception or set a custom message. | |
shareUnitOfWork
|
false | Camel 2.16: Shares the unit of work with the parent and the resource exchange. However, by default, Enrich does not share the unit of work between the parent exchange and the resource exchange. Also, the resource exchange has its own individual unit of work. |
Content enrich using pollEnrich Copy linkLink copied to clipboard!
pollEnrich command treats the resource endpoint as a consumer. Instead of sending an exchange to the resource endpoint, it polls the endpoint. By default, the poll returns immediately, if there is no exchange available from the resource endpoint. For example, the following route reads a file whose name is extracted from the header of an incoming JMS message:
from("activemq:queue:order")
.pollEnrich("file://order/data/additional?fileName=orderId")
.to("bean:processOrder");
from("activemq:queue:order")
.pollEnrich("file://order/data/additional?fileName=orderId")
.to("bean:processOrder");
from("activemq:queue:order")
.pollEnrich("file://order/data/additional?fileName=orderId", 20000) // timeout is in milliseconds
.to("bean:processOrder");
from("activemq:queue:order")
.pollEnrich("file://order/data/additional?fileName=orderId", 20000) // timeout is in milliseconds
.to("bean:processOrder");
pollEnrich, as follows:
.pollEnrich("file://order/data/additional?fileName=orderId", 20000, aggregationStrategy)
.pollEnrich("file://order/data/additional?fileName=orderId", 20000, aggregationStrategy)
aggregate() method might be null, if the poll times out before an exchange is received.
pollEnrich does not access any data from the current Exchange, so that, when polling, it cannot use any of the existing headers you may have set on the Exchange. For example, you cannot set a filename in the Exchange.FILE_NAME header and use pollEnrich to consume only that file. For that, you must set the filename in the endpoint URI.
Polling methods used by pollEnrich() Copy linkLink copied to clipboard!
pollEnrich() enricher polls the consumer endpoint using one of the following polling methods:
receiveNoWait()(used by default)receive()receive(long timeout)
pollEnrich() command's timeout argument (specified in milliseconds) determines which method gets called, as follows:
- Timeout is
0or not specified,receiveNoWaitis called. - Timeout is negative,
receiveis called. - Otherwise,
receive(timeout)is called.
pollEnrich example Copy linkLink copied to clipboard!
from("direct:start")
.pollEnrich("file:inbox?fileName=data.txt")
.to("direct:result");
from("direct:start")
.pollEnrich("file:inbox?fileName=data.txt")
.to("direct:result");
<route>
<from uri="direct:start"/>
<pollEnrich uri="file:inbox?fileName=data.txt"/>
<to uri="direct:result"/>
</route>
<route>
<from uri="direct:start"/>
<pollEnrich uri="file:inbox?fileName=data.txt"/>
<to uri="direct:result"/>
</route>
<route>
<from uri="direct:start"/>
<pollEnrich uri="file:inbox?fileName=data.txt" timeout="5000"/>
<to uri="direct:result"/>
</route>
<route>
<from uri="direct:start"/>
<pollEnrich uri="file:inbox?fileName=data.txt" timeout="5000"/>
<to uri="direct:result"/>
</route>
PollEnrich Options Copy linkLink copied to clipboard!
pollEnrich DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
uri
|
The endpoint uri for the external servie to enrich from. You must use either uri or ref.
|
|
ref
|
Refers to the endpoint for the external servie to enrich from. You must use either uri or ref.
|
|
strategyRef
|
Refers to an AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message. By default Camel will use the reply from the external service as outgoing message. | |
timeout
|
0
|
Timeout in millis to use when polling from the external service. See below for important details about the timeout. |
9.2. Content Filter Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 9.2. Content Filter Pattern
Implementing a content filter Copy linkLink copied to clipboard!
- Message translator—see message translators.
- Processors—see Chapter 44, Implementing a Processor.
XML configuration example Copy linkLink copied to clipboard!
Using an XPath filter Copy linkLink copied to clipboard!
<route> <from uri="activemq:Input"/> <setBody><xpath resultType="org.w3c.dom.Document">//foo:bar</xpath></setBody> <to uri="activemq:Output"/> </route>
<route>
<from uri="activemq:Input"/>
<setBody><xpath resultType="org.w3c.dom.Document">//foo:bar</xpath></setBody>
<to uri="activemq:Output"/>
</route>
9.3. Normalizer Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 9.3. Normalizer Pattern
Java DSL example Copy linkLink copied to clipboard!
XML configuration example Copy linkLink copied to clipboard!
9.4. Claim Check Copy linkLink copied to clipboard!
Claim Check Copy linkLink copied to clipboard!
Figure 9.4. Claim Check Pattern
Java DSL example Copy linkLink copied to clipboard!
from("direct:start").to("bean:checkLuggage", "mock:testCheckpoint", "bean:dataEnricher", "mock:result");
from("direct:start").to("bean:checkLuggage", "mock:testCheckpoint", "bean:dataEnricher", "mock:result");
mock:testCheckpoint endpoint, which checks that the message body has been removed, the claim check added, and so on.
XML DSL example Copy linkLink copied to clipboard!
checkLuggage bean Copy linkLink copied to clipboard!
checkLuggage bean which is implemented as follows:
custId as the claim check. In this example, we are using a HashMap to store the message body; in a real application you would use a database or the file system. The claim check is added as a message header for later use and, finally, we remove the body from the message and pass it down the pipeline.
testCheckpoint endpoint Copy linkLink copied to clipboard!
mock:testCheckpoint endpoint.
dataEnricher bean Copy linkLink copied to clipboard!
dataEnricher bean, which is implemented as follows:
claimCheck header from the message.
9.5. Sort Copy linkLink copied to clipboard!
Sort Copy linkLink copied to clipboard!
java.util.List).
Java DSL example Copy linkLink copied to clipboard!
from("file://inbox").sort(body().tokenize("\n")).to("bean:MyServiceBean.processLine");
from("file://inbox").sort(body().tokenize("\n")).to("bean:MyServiceBean.processLine");
sort():
from("file://inbox").sort(body().tokenize("\n"), new MyReverseComparator()).to("bean:MyServiceBean.processLine");
from("file://inbox").sort(body().tokenize("\n"), new MyReverseComparator()).to("bean:MyServiceBean.processLine");
XML configuration example Copy linkLink copied to clipboard!
<simple>, you can supply an expression using any language you like, so long as it returns a list.
Options Copy linkLink copied to clipboard!
sort DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
comparatorRef
|
Refers to a custom java.util.Comparator to use for sorting the message body. Camel will by default use a comparator which does a A..Z sorting.
|
9.6. Validate Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
true, the route continues processing normally; if the predicate evaluates to false, a PredicateValidationException is thrown.
Java DSL example Copy linkLink copied to clipboard!
from("jms:queue:incoming")
.validate(body(String.class).regex("^\\w{10}\\,\\d{2}\\,\\w{24}$"))
.to("bean:MyServiceBean.processLine");
from("jms:queue:incoming")
.validate(body(String.class).regex("^\\w{10}\\,\\d{2}\\,\\w{24}$"))
.to("bean:MyServiceBean.processLine");
from("jms:queue:incoming")
.validate(header("bar").isGreaterThan(100))
.to("bean:MyServiceBean.processLine");
from("jms:queue:incoming")
.validate(header("bar").isGreaterThan(100))
.to("bean:MyServiceBean.processLine");
from("jms:queue:incoming")
.validate(simple("${in.header.bar} == 100"))
.to("bean:MyServiceBean.processLine");
from("jms:queue:incoming")
.validate(simple("${in.header.bar} == 100"))
.to("bean:MyServiceBean.processLine");
XML DSL example Copy linkLink copied to clipboard!
Chapter 10. Messaging Endpoints Copy linkLink copied to clipboard!
Abstract
10.1. Messaging Mapper Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- The canonical message format used to transmit domain objects should be suitable for consumption by non-object oriented applications.
- The mapper code should be implemented separately from both the domain object code and the messaging infrastructure. Apache Camel helps fulfill this requirement by providing hooks that can be used to insert mapper code into a route.
- The mapper might need to find an effective way of dealing with certain object-oriented concepts such as inheritance, object references, and object trees. The complexity of these issues varies from application to application, but the aim of the mapper implementation must always be to create messages that can be processed effectively by non-object-oriented applications.
Finding objects to map Copy linkLink copied to clipboard!
- Find a registered bean. — For singleton objects and small numbers of objects, you could use the
CamelContextregistry to store references to beans. For example, if a bean instance is instantiated using Spring XML, it is automatically entered into the registry, where the bean is identified by the value of itsidattribute. - Select objects using the JoSQL language. — If all of the objects you want to access are already instantiated at runtime, you could use the JoSQL language to locate a specific object (or objects). For example, if you have a class,
org.apache.camel.builder.sql.Person, with anamebean property and the incoming message has aUserNameheader, you could select the object whosenameproperty equals the value of theUserNameheader using the following code:import static org.apache.camel.builder.sql.SqlBuilder.sql; import org.apache.camel.Expression; ... Expression expression = sql("SELECT * FROM org.apache.camel.builder.sql.Person where name = :UserName"); Object value = expression.evaluate(exchange);import static org.apache.camel.builder.sql.SqlBuilder.sql; import org.apache.camel.Expression; ... Expression expression = sql("SELECT * FROM org.apache.camel.builder.sql.Person where name = :UserName"); Object value = expression.evaluate(exchange);Copy to Clipboard Copied! Toggle word wrap Toggle overflow Where the syntax,:HeaderName, is used to substitute the value of a header in a JoSQL expression. - Dynamic — For a more scalable solution, it might be necessary to read object data from a database. In some cases, the existing object-oriented application might already provide a finder object that can load objects from the database. In other cases, you might have to write some custom code to extract objects from a database, and in these cases the JDBC component and the SQL component might be useful.
10.2. Event Driven Consumer Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 10.1. Event Driven Consumer Pattern
10.3. Polling Consumer Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
receive(), receive(long timeout), and receiveNoWait() that return a new exchange object, if one is available from the monitored resource. A polling consumer implementation must provide its own thread pool to perform the polling.
Figure 10.2. Polling Consumer Pattern
Scheduled poll consumer Copy linkLink copied to clipboard!
Quartz component Copy linkLink copied to clipboard!
10.4. Competing Consumers Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 10.3. Competing Consumers Pattern
JMS based competing consumers Copy linkLink copied to clipboard!
HighVolumeQ, as follows:
from("jms:HighVolumeQ").to("cxf:bean:replica01");
from("jms:HighVolumeQ").to("cxf:bean:replica02");
from("jms:HighVolumeQ").to("cxf:bean:replica03");
from("jms:HighVolumeQ").to("cxf:bean:replica01");
from("jms:HighVolumeQ").to("cxf:bean:replica02");
from("jms:HighVolumeQ").to("cxf:bean:replica03");
replica01, replica02, and replica03, process messages from the HighVolumeQ queue in parallel.
concurrentConsumers, to create a thread pool of competing consumers. For example, the following route creates a pool of three competing threads that pick messages from the specified queue:
from("jms:HighVolumeQ?concurrentConsumers=3").to("cxf:bean:replica01");
from("jms:HighVolumeQ?concurrentConsumers=3").to("cxf:bean:replica01");
concurrentConsumers option can also be specified in XML DSL, as follows:
<route> <from uri="jms:HighVolumeQ?concurrentConsumers=3"/> <to uri="cxf:bean:replica01"/> </route>
<route>
<from uri="jms:HighVolumeQ?concurrentConsumers=3"/>
<to uri="cxf:bean:replica01"/>
</route>
SEDA based competing consumers Copy linkLink copied to clipboard!
java.util.concurrent.BlockingQueue). Therefore, you can use a SEDA endpoint to break a route into stages, where each stage might use multiple threads. For example, you can define a SEDA route consisting of two stages, as follows:
file://var/messages, and routes them to a SEDA endpoint, seda:fanout. The second stage contains three threads: a thread that routes exchanges to cxf:bean:replica01, a thread that routes exchanges to cxf:bean:replica02, and a thread that routes exchanges to cxf:bean:replica03. These three threads compete to take exchange instances from the SEDA endpoint, which is implemented using a blocking queue. Because the blocking queue uses locking to prevent more than one thread from accessing the queue at a time, you are guaranteed that each exchange instance can only be consumed once.
thread(), see chapter "SEDA" in "Apache Camel Component Reference".
10.5. Message Dispatcher Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 10.4. Message Dispatcher Pattern
JMS selectors Copy linkLink copied to clipboard!
true, the JMS message is allowed to reach the consumer, and if the selector evaluates to false, the JMS message is blocked. In many respects, a JMS selector is like a filter processor, but it has the additional advantage that the filtering is implemented inside the JMS provider. This means that a JMS selector can block messages before they are transmitted to the Apache Camel application. This provides a significant efficiency advantage.
selector query option on a JMS endpoint URI. For example:
from("jms:dispatcher?selector=CountryCode='US'").to("cxf:bean:replica01");
from("jms:dispatcher?selector=CountryCode='IE'").to("cxf:bean:replica02");
from("jms:dispatcher?selector=CountryCode='DE'").to("cxf:bean:replica03");
from("jms:dispatcher?selector=CountryCode='US'").to("cxf:bean:replica01");
from("jms:dispatcher?selector=CountryCode='IE'").to("cxf:bean:replica02");
from("jms:dispatcher?selector=CountryCode='DE'").to("cxf:bean:replica03");
CountryCode.
application/x-www-form-urlencoded MIME format (see the HTML specification). In practice, the &(ampersand) character might cause difficulties because it is used to delimit each query option in the URI. For more complex selector strings that might need to embed the & character, you can encode the strings using the java.net.URLEncoder utility class. For example:
from("jms:dispatcher?selector=" + java.net.URLEncoder.encode("CountryCode='US'","UTF-8")).
to("cxf:bean:replica01");
from("jms:dispatcher?selector=" + java.net.URLEncoder.encode("CountryCode='US'","UTF-8")).
to("cxf:bean:replica01");
JMS selectors in ActiveMQ Copy linkLink copied to clipboard!
from("activemq:dispatcher?selector=CountryCode='US'").to("cxf:bean:replica01");
from("activemq:dispatcher?selector=CountryCode='IE'").to("cxf:bean:replica02");
from("activemq:dispatcher?selector=CountryCode='DE'").to("cxf:bean:replica03");
from("activemq:dispatcher?selector=CountryCode='US'").to("cxf:bean:replica01");
from("activemq:dispatcher?selector=CountryCode='IE'").to("cxf:bean:replica02");
from("activemq:dispatcher?selector=CountryCode='DE'").to("cxf:bean:replica03");
Content-based router Copy linkLink copied to clipboard!
10.6. Selective Consumer Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 10.5. Selective Consumer Pattern
JMS selector Copy linkLink copied to clipboard!
true, the JMS message is allowed to reach the consumer, and if the selector evaluates to false, the JMS message is blocked. For example, to consume messages from the queue, selective, and select only those messages whose country code property is equal to US, you can use the following Java DSL route:
from("jms:selective?selector=" + java.net.URLEncoder.encode("CountryCode='US'","UTF-8")).
to("cxf:bean:replica01");
from("jms:selective?selector=" + java.net.URLEncoder.encode("CountryCode='US'","UTF-8")).
to("cxf:bean:replica01");
CountryCode='US', must be URL encoded (using UTF-8 characters) to avoid trouble with parsing the query options. This example presumes that the JMS property, CountryCode, is set by the sender. For more details about JMS selectors, see the section called “JMS selectors”.
JMS selector in ActiveMQ Copy linkLink copied to clipboard!
from("acivemq:selective?selector=" + java.net.URLEncoder.encode("CountryCode='US'","UTF-8")).
to("cxf:bean:replica01");
from("acivemq:selective?selector=" + java.net.URLEncoder.encode("CountryCode='US'","UTF-8")).
to("cxf:bean:replica01");
Message filter Copy linkLink copied to clipboard!
from("seda:a").filter(header("CountryCode").isEqualTo("US")).process(myProcessor);
from("seda:a").filter(header("CountryCode").isEqualTo("US")).process(myProcessor);
10.7. Durable Subscriber Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- non-durable subscriber—Can have two states: connected and disconnected. While a non-durable subscriber is connected to a topic, it receives all of the topic's messages in real time. However, a non-durable subscriber never receives messages sent to the topic while the subscriber is disconnected.
- durable subscriber—Can have two states: connected and inactive. The inactive state means that the durable subscriber is disconnected from the topic, but wants to receive the messages that arrive in the interim. When the durable subscriber reconnects to the topic, it receives a replay of all the messages sent while it was inactive.
Figure 10.6. Durable Subscriber Pattern
JMS durable subscriber Copy linkLink copied to clipboard!
news, with a client ID of conn01 and a durable subscription name of John.Doe:
from("jms:topic:news?clientId=conn01&durableSubscriptionName=John.Doe").
to("cxf:bean:newsprocessor");
from("jms:topic:news?clientId=conn01&durableSubscriptionName=John.Doe").
to("cxf:bean:newsprocessor");
from("activemq:topic:news?clientId=conn01&durableSubscriptionName=John.Doe").
to("cxf:bean:newsprocessor");
from("activemq:topic:news?clientId=conn01&durableSubscriptionName=John.Doe").
to("cxf:bean:newsprocessor");
Alternative example Copy linkLink copied to clipboard!
from("direct:start").to("activemq:topic:foo");
from("activemq:topic:foo?clientId=1&durableSubscriptionName=bar1").to("mock:result1");
from("activemq:topic:foo?clientId=2&durableSubscriptionName=bar2").to("mock:result2");
from("direct:start").to("activemq:topic:foo");
from("activemq:topic:foo?clientId=1&durableSubscriptionName=bar1").to("mock:result1");
from("activemq:topic:foo?clientId=2&durableSubscriptionName=bar2").to("mock:result2");
from("direct:start").to("activemq:topic:VirtualTopic.foo");
from("activemq:queue:Consumer.1.VirtualTopic.foo").to("mock:result1");
from("activemq:queue:Consumer.2.VirtualTopic.foo").to("mock:result2");
from("direct:start").to("activemq:topic:VirtualTopic.foo");
from("activemq:queue:Consumer.1.VirtualTopic.foo").to("mock:result1");
from("activemq:queue:Consumer.2.VirtualTopic.foo").to("mock:result2");
10.8. Idempotent Consumer Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
MemoryIdempotentRepository
Idempotent consumer with in-memory cache Copy linkLink copied to clipboard!
idempotentConsumer() processor, which takes two arguments:
messageIdExpression— An expression that returns a message ID string for the current message.messageIdRepository— A reference to a message ID repository, which stores the IDs of all the messages received.
TransactionID header to filter out duplicates.
Example 10.1. Filtering Duplicate Messages with an In-memory Cache
memoryMessageIdRepository(200) creates an in-memory cache that can hold up to 200 message IDs.
Idempotent consumer with JPA repository Copy linkLink copied to clipboard!
JpaTemplateinstance—Provides the handle for the JPA database.- processor name—Identifies the current idempotent consumer processor.
SpringRouteBuilder.bean() method is a shortcut that references a bean defined in the Spring XML file. The JpaTemplate bean provides a handle to the underlying JPA database. See the JPA documentation for details of how to configure this bean.
Spring XML example Copy linkLink copied to clipboard!
myMessageId header to filter out duplicates:
Idempotent consumer with JDBC repository Copy linkLink copied to clipboard!
camel-sql artifact.
SingleConnectionDataSource JDBC wrapper class from the Spring persistence API in order to instantiate the connection to a SQL database. For example, to instantiate a JDBC connection to a HyperSQL database instance, you could define the following JDBC data source:
mem protocol, which creates a memory-only database instance. This is a toy implementation of the HyperSQL database which is not actually persistent.
How to handle duplicate messages in the route Copy linkLink copied to clipboard!
skipDuplicate option to false which instructs the idempotent consumer to route duplicate messages as well. However the duplicate message has been marked as duplicate by having a property on the Exchange set to true. We can leverage this fact by using a Content-Based Router or Message Filter to detect this and handle duplicate messages.
How to handle duplicate message in a clustered environment with a data grid Copy linkLink copied to clipboard!
HazelcastIdempotentRepository idempotentRepo = new HazelcastIdempotentRepository("myrepo");
from("direct:in").idempotentConsumer(header("messageId"), idempotentRepo).to("mock:out");
HazelcastIdempotentRepository idempotentRepo = new HazelcastIdempotentRepository("myrepo");
from("direct:in").idempotentConsumer(header("messageId"), idempotentRepo).to("mock:out");
Options Copy linkLink copied to clipboard!
| Option | Default | Description |
|---|---|---|
eager
|
true
|
Camel 2.0: Eager controls whether Camel adds the message to the repository before or after the exchange has been processed. If enabled before then Camel will be able to detect duplicate messages even when messages are currently in progress. By disabling Camel will only detect duplicates when a message has successfully been processed. |
messageIdRepositoryRef
|
null
|
A reference to a IdempotentRepository to lookup in the registry. This option is mandatory when using XML DSL.
|
skipDuplicate
|
true
|
Camel 2.8: Sets whether to skip duplicate messages. If set to false then the message will be continued. However the Exchange has been marked as a duplicate by having the Exchange.DUPLICATE_MESSAG exchange property set to a Boolean.TRUE value.
|
completionEager
|
false
|
Camel 2.16: Sets whether to complete the Idempotent consumer eager, when the exchange is done. If you set the completeEager option true, then the Idempotent Consumer triggers its completion when the exchange reaches till the end of the idempotent consumer pattern block. However, if the exchange continues to route even after the end block, then it does not affect the state of the idempotent consumer. If you set the completeEager option false, then the Idempotent Consumer triggers its completion after the exchange is done and is being routed. However, if the exchange continues to route even after the block ends, then it also affects the state of the idempotent consumer. For example, due to an exception if the exchange fails, then the state of the idempotent consumer will be a rollback.
|
10.9. Transactional Client Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 10.7. Transactional Client Pattern
Transaction oriented endpoints Copy linkLink copied to clipboard!
CamelContext. This entails writing code to initialize your transactional components explicitly.
References Copy linkLink copied to clipboard!
10.10. Messaging Gateway Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 10.8. Messaging Gateway Pattern
10.11. Service Activator Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 10.9. Service Activator Pattern
Bean integration Copy linkLink copied to clipboard!
bean() and beanRef() that you can insert into a route to invoke methods on a registered Java bean. The detailed mapping of message data to Java method parameters is determined by the bean binding, which can be implemented by adding annotations to the bean class.
BankBean.getUserAccBalance(), to service requests incoming on a JMS/ActiveMQ queue:
from("activemq:BalanceQueries")
.setProperty("userid", xpath("/Account/BalanceQuery/UserID").stringResult())
.beanRef("bankBean", "getUserAccBalance")
.to("velocity:file:src/scripts/acc_balance.vm")
.to("activemq:BalanceResults");
from("activemq:BalanceQueries")
.setProperty("userid", xpath("/Account/BalanceQuery/UserID").stringResult())
.beanRef("bankBean", "getUserAccBalance")
.to("velocity:file:src/scripts/acc_balance.vm")
.to("activemq:BalanceResults");
activemq:BalanceQueries, have a simple XML format that provides the user ID of a bank account. For example:
setProperty(), extracts the user ID from the In message and stores it in the userid exchange property. This is preferable to storing it in a header, because the In headers are not available after invoking the bean.
beanRef() processor, which binds the incoming message to the getUserAccBalance() method on the Java object identified by the bankBean bean ID. The following code shows a sample implementation of the BankBean class:
@XPath annotation, which injects the content of the UserID XML element into the user method parameter. On completion of the call, the return value is inserted into the body of the Out message which is then copied into the In message for the next step in the route. In order for the bean to be accessible to the beanRef() processor, you must instantiate an instance in Spring XML. For example, you can add the following lines to the META-INF/spring/camel-context.xml configuration file to instantiate the bean:
<?xml version="1.0" encoding="UTF-8"?> <beans ... > ... <bean id="bankBean" class="tutorial.BankBean"/> </beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans ... >
...
<bean id="bankBean" class="tutorial.BankBean"/>
</beans>
bankBean, identifes this bean instance in the registry.
velocity:file:src/scripts/acc_balance.vm, specifies the location of a velocity script with the following contents:
exchange, which enables you to retrieve the userid exchange property, using ${exchange.getProperty("userid")}. The body of the current In message, ${body}, contains the result of the getUserAccBalance() method invocation.
Chapter 11. System Management Copy linkLink copied to clipboard!
Abstract
11.1. Detour Copy linkLink copied to clipboard!
Detour Copy linkLink copied to clipboard!
Example Copy linkLink copied to clipboard!
from("direct:start").to("mock:result") with a conditional detour to the mock:detour endpoint in the middle of the route..
from("direct:start").choice()
.when().method("controlBean", "isDetour").to("mock:detour").end()
.to("mock:result");
from("direct:start").choice()
.when().method("controlBean", "isDetour").to("mock:detour").end()
.to("mock:result");
ControlBean. So, when the detour is on the message is routed to mock:detour and then mock:result. When the detour is off, the message is routed to mock:result.
11.2. LogEIP Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
log DSL is much lighter and meant for logging human logs such as Starting to do .... It can only log a message based on the Simple language. In contrast, the Log component is a fully featured logging component. The Log component is capable of logging the message itself and you have many URI options to control the logging.
Java DSL example Copy linkLink copied to clipboard!
log DSL command to construct a log message at run time using the Simple expression language. For example, you can create a log message within a route, as follows:
from("direct:start").log("Processing ${id}").to("bean:foo");
from("direct:start").log("Processing ${id}").to("bean:foo");
String format message at run time. The log message will by logged at INFO level, using the route ID as the log name. By default, routes are named consecutively, route-1, route-2 and so on. But you can use the DSL command, routeId("myCoolRoute"), to specify a custom route ID.
LoggingLevel.DEBUG, you can invoke the log DSL as follows:
from("direct:start").log(LoggingLevel.DEBUG, "Processing ${id}").to("bean:foo");
from("direct:start").log(LoggingLevel.DEBUG, "Processing ${id}").to("bean:foo");
fileRoute, you can invoke the log DSL as follows:
from("file://target/files").log(LoggingLevel.DEBUG, "fileRoute", "Processing file ${file:name}").to("bean:foo");
from("file://target/files").log(LoggingLevel.DEBUG, "fileRoute", "Processing file ${file:name}").to("bean:foo");
XML DSL example Copy linkLink copied to clipboard!
log element and the log message is specified by setting the message attribute to a Simple expression, as follows:
<route id="foo">
<from uri="direct:foo"/>
<log message="Got ${body}"/>
<to uri="mock:foo"/>
</route>
<route id="foo">
<from uri="direct:foo"/>
<log message="Got ${body}"/>
<to uri="mock:foo"/>
</route>
log element supports the message, loggingLevel and logName attributes. For example:
<route id="baz">
<from uri="direct:baz"/>
<log message="Me Got ${body}" loggingLevel="FATAL" logName="cool"/>
<to uri="mock:baz"/>
</route>
<route id="baz">
<from uri="direct:baz"/>
<log message="Me Got ${body}" loggingLevel="FATAL" logName="cool"/>
<to uri="mock:baz"/>
</route>
11.3. Wire Tap Copy linkLink copied to clipboard!
Wire Tap Copy linkLink copied to clipboard!
Figure 11.1. Wire Tap Pattern
WireTap node Copy linkLink copied to clipboard!
wireTap node for doing wire taps. The wireTap node copies the original exchange to a tapped exchange, whose exchange pattern is set to InOnly, because the tapped exchange should be propagated in a oneway style. The tapped exchange is processed in a separate thread, so that it can run concurrently with the main route.
wireTap supports two different approaches to tapping an exchange:
- Tap a copy of the original exchange.
- Tap a new exchange instance, enabling you to customize the tapped exchange.
Tap a copy of the original exchange Copy linkLink copied to clipboard!
from("direct:start")
.to("log:foo")
.wireTap("direct:tap")
.to("mock:result");
from("direct:start")
.to("log:foo")
.wireTap("direct:tap")
.to("mock:result");
Tap and modify a copy of the original exchange Copy linkLink copied to clipboard!
from("direct:start")
.wireTap("direct:foo", constant("Bye World"))
.to("mock:result");
from("direct:foo").to("mock:foo");
from("direct:start")
.wireTap("direct:foo", constant("Bye World"))
.to("mock:result");
from("direct:foo").to("mock:foo");
processorRef attribute references a spring bean with the myProcessor ID:
<route>
<from uri="direct:start2"/>
<wireTap uri="direct:foo" processorRef="myProcessor"/>
<to uri="mock:result"/>
</route>
<route>
<from uri="direct:start2"/>
<wireTap uri="direct:foo" processorRef="myProcessor"/>
<to uri="mock:result"/>
</route>
Tap a new exchange instance Copy linkLink copied to clipboard!
false (the default is true). In this case, an initially empty exchange is created for the wiretap.
wireTap argument sets the copy flag to false, indicating that the original exchange is not copied and an empty exchange is created instead.
from("direct:start")
.wireTap("direct:foo", false, constant("Bye World"))
.to("mock:result");
from("direct:foo").to("mock:foo");
from("direct:start")
.wireTap("direct:foo", false, constant("Bye World"))
.to("mock:result");
from("direct:foo").to("mock:foo");
wireTap element's copy attribute to false.
processorRef attribute references a spring bean with the myProcessor ID, as follows:
<route>
<from uri="direct:start2"/>
<wireTap uri="direct:foo" processorRef="myProcessor" copy="false"/>
<to uri="mock:result"/>
</route>
<route>
<from uri="direct:start2"/>
<wireTap uri="direct:foo" processorRef="myProcessor" copy="false"/>
<to uri="mock:result"/>
</route>
Sending a new Exchange and set headers in DSL Copy linkLink copied to clipboard!
- "Bye World" as message body
- a header with key "id" with the value 123
- a header with key "date" which has current date as value
Java DSL Copy linkLink copied to clipboard!
XML DSL Copy linkLink copied to clipboard!
Using onPrepare to execute custom logic when preparing messages Copy linkLink copied to clipboard!
Options Copy linkLink copied to clipboard!
wireTap DSL command supports the following options:
| Name | Default Value | Description |
|---|---|---|
uri
|
The endpoint uri where to send the wire tapped message. You should use either uri or ref.
|
|
ref
|
Refers to the endpoint where to send the wire tapped message. You should use either uri or ref.
|
|
executorServiceRef
|
Refers to a custom Thread Pool to be used when processing the wire tapped messages. If not set then Camel uses a default thread pool. | |
processorRef
|
Refers to a custom Processorsto be used for creating a new message (eg the send a new message mode). See below. | |
copy
|
true
|
Camel 2.3: Should a copy of the Exchange to used when wire tapping the message. |
onPrepareRef
|
Camel 2.8: Refers to a custom Processors to prepare the copy of the Exchange to be wire tapped. This allows you to do any custom logic, such as deep-cloning the message payload if that's needed etc. |
Chapter 12. Service Component Runtime Copy linkLink copied to clipboard!
Abstract Copy linkLink copied to clipboard!
Working with Camel and SCR Copy linkLink copied to clipboard!
org.apache.felix:maven-scr-plugin. Using SCR, the bundle remains completely in Java world. There is no need to edit XML or properties file. It offers you full control over the project.
Creating a Service Component Copy linkLink copied to clipboard!
- Add the required
org.apache.felix.scr.annotationsat class level. For example,Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Implement the
getRouteBuilders()method that returns the Camel route you want to run. For example,Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Finally, enter the default configuration in annotations.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Example of a Service Component class Copy linkLink copied to clipboard!
camel-archetype-scr to generate a complete service component class:
Example of a RouteBuilder class Copy linkLink copied to clipboard!
camel-archetype-scr to generate a RouteBuilder class:
Using Apache Camel SCR bundle as a template Copy linkLink copied to clipboard!
- Create a configuration PID for your service component and add a tail with a dash.
- Camel SCR will use the configuration to create a new instance of your component.
- Finally, you can start a new
CamelContextwith your overridden properties.Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteMake sure that your service component does not start with the default configuration. To prevent this, addpolicy = ConfigurationPolicy.REQUIREto the class level at component annotation.
Using Apache camel-archetype-scr Copy linkLink copied to clipboard!
camel-archetype-scr and maven, you can easily create Apache Camel SCR bundle project. It includes the following steps:
- Run the following command:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Run Apache Maven.NoteFor details on setting up Apache Maven to work with Red Hat JBoss Fuse, see Building with Maven in Red Hat JBoss Fuse Deploying into the Container on the Red Hat Customer Portal
- You can now deploy the bundle. To deploy the bundle on Apache Karaf, perform the following steps on Karaf command line:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - By default, the Service Component's configuration PID equals the fully qualified name of its class. You can change the properties of a bundle with Apache Karaf's config.* commands:You can also change the configuration by editing the property file in Apache Karaf's
# Override the messageOk property karaf@root> config:propset -p example.CamelScrExample messageOk "This is better logging".
# Override the messageOk property karaf@root> config:propset -p example.CamelScrExample messageOk "This is better logging".Copy to Clipboard Copied! Toggle word wrap Toggle overflow etcdirectory.
Part II. Routing Expression and Predicate Languages Copy linkLink copied to clipboard!
Abstract
Chapter 13. Introduction Copy linkLink copied to clipboard!
Abstract
13.1. Overview of the Languages Copy linkLink copied to clipboard!
Table of expression and predicate languages Copy linkLink copied to clipboard!
| Language | Static Method | Fluent DSL Method | XML Element | Annotation | Artifact |
|---|---|---|---|---|---|
| Section 2.4, “Bean Integration” | bean() | EIP().method() | method | @Bean | Camel core |
| Constant | constant() | EIP().constant() | constant | @Constant | Camel core |
| EL | el() | EIP().el() | el | @EL | camel-juel |
| Groovy | groovy() | EIP().groovy() | groovy | @Groovy | camel-groovy |
| Header | header() | EIP().header() | header | @Header | Camel core |
| JavaScript | javaScript() | EIP().javaScript() | javaScript | @JavaScript | camel-script |
| JoSQL | sql() | EIP().sql() | sql | @SQL | camel-josql |
| JSonPath | None | EIP().jsonpath() | jsonpath | @JSonPath | camel-jsonpath |
| JXPath | None | EIP().jxpath() | jxpath | @JXPath | camel-jxpath |
| MVEL | mvel() | EIP().mvel() | mvel | @MVEL | camel-mvel |
| OGNL | ognl() | EIP().ognl() | ognl | @OGNL | camel-ognl |
| PHP | php() | EIP().php() | php | @PHP | camel-script |
| Property | property() | EIP().property() | property | @Property | Camel core |
| Python | python() | EIP().python() | python | @Python | camel-script |
| Ref | ref() | EIP().ref() | ref | N/A | Camel core |
| Ruby | ruby() | EIP().ruby() | ruby | @Ruby | camel-script |
| Simple/File | simple() | EIP().simple() | simple | @Simple | Camel core |
| SpEL | spel() | EIP().spel() | spel | @SpEL | camel-spring |
| XPath | xpath() | EIP().xpath() | xpath | @XPath | Camel core |
| XQuery | xquery() | EIP().xquery() | xquery | @XQuery | camel-saxon |
13.2. How to Invoke an Expression Language Copy linkLink copied to clipboard!
Prerequisites Copy linkLink copied to clipboard!
camel-groovy feature by entering the following OSGi console command:
karaf@root> features:install camel-groovy
karaf@root> features:install camel-groovy
resource:classpath:path or resource:file:path. For example, resource:classpath:com/foo/myscript.groovy.
Camel on EAP deployment Copy linkLink copied to clipboard!
camel-script component and the camel-groovy component are both supported by the Camel on EAP (Wildfly Camel) framework, which offers a simplified deployment model on the Red Hat JBoss Enterprise Application Platform (JBoss EAP) container. For details of this model, see chapter "Apache Camel on Red Hat JBoss EAP" in "Deploying into a Web Server".
Approaches to invoking Copy linkLink copied to clipboard!
As a static method Copy linkLink copied to clipboard!
org.apache.camel.Expression type or an org.apache.camel.Predicate type is expected. The static method takes a string expression (or predicate) as its argument and returns an Expression object (which is usually also a Predicate object).
/order/address/countryCode element, as follows:
As a fluent DSL method Copy linkLink copied to clipboard!
filter(xpath("Expression")), you can invoke the expression as, filter().xpath("Expression").
As an XML element Copy linkLink copied to clipboard!
xpath (which belongs to the standard Apache Camel namespace). You can use XPath expressions in a XML DSL content-based router, as follows:
language element, where you specify the name of the language in the language attribute. For example, you can define an XPath expression using the language element as follows:
<language language="xpath">/order/address/countryCode = 'us'</language>
<language language="xpath">/order/address/countryCode = 'us'</language>
As an annotation Copy linkLink copied to clipboard!
myBeanProc, which is invoked as a predicate of the filter() EIP. If the bean's checkCredentials method returns true, the message is allowed to proceed; but if the method returns false, the message is blocked by the filter. The filter pattern is implemented as follows:
MyBeanProcessor class exploits the @XPath annotation to extract the username and password from the underlying XML message, as follows:
@XPath annotation is placed just before the parameter into which it gets injected. Notice how the XPath expression explicitly selects the text node, by appending /text() to the path, which ensures that just the content of the element is selected, not the enclosing tags.
As a Camel endpoint URI Copy linkLink copied to clipboard!
Scheme), use the following URI syntax:
language://LanguageName:resource:Scheme:Location[?Options]
language://LanguageName:resource:Scheme:Location[?Options]
file:, classpath:, or http:.
mysimplescript.txt from the classpath:
from("direct:start")
.to("language:simple:classpath:org/apache/camel/component/language/mysimplescript.txt")
.to("mock:result");
from("direct:start")
.to("language:simple:classpath:org/apache/camel/component/language/mysimplescript.txt")
.to("mock:result");
language://LanguageName[:Script][?Options]
language://LanguageName[:Script][?Options]
script string:
String script = URLEncoder.encode("Hello ${body}", "UTF-8");
from("direct:start")
.to("language:simple:" + script)
.to("mock:result");
String script = URLEncoder.encode("Hello ${body}", "UTF-8");
from("direct:start")
.to("language:simple:" + script)
.to("mock:result");
Chapter 14. Constant Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
XML example Copy linkLink copied to clipboard!
username header to the value, Jane Doe as follows:
Java example Copy linkLink copied to clipboard!
username header to the value, Jane Doe as follows:
from("SourceURL")
.setHeader("username", constant("Jane Doe"))
.to("TargetURL");
from("SourceURL")
.setHeader("username", constant("Jane Doe"))
.to("TargetURL");
Chapter 15. EL Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Adding JUEL package Copy linkLink copied to clipboard!
camel-juel to your project as shown in Example 15.1, “Adding the camel-juel dependency”.
Example 15.1. Adding the camel-juel dependency
Static import Copy linkLink copied to clipboard!
el() static method in your application code, include the following import statement in your Java source files:
import static org.apache.camel.language.juel.JuelExpression.el;
import static org.apache.camel.language.juel.JuelExpression.el;
Variables Copy linkLink copied to clipboard!
| Variable | Type | Value |
|---|---|---|
exchange | org.apache.camel.Exchange | The current Exchange |
in | org.apache.camel.Message | The IN message |
out | org.apache.camel.Message | The OUT message |
Example Copy linkLink copied to clipboard!
Example 15.2. Routes using EL
Chapter 16. The File Language Copy linkLink copied to clipboard!
Abstract
16.1. When to Use the File Language Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
\, is not available in the file language.
In a File or FTP consumer endpoint Copy linkLink copied to clipboard!
fileName, move, preMove, moveFailed, and sortBy options using a file expression.
fileName option acts as a filter, determining which file will actually be read from the starting directory. If a plain text string is specified (for example, fileName=report.txt), the File consumer reads the same file each time it is updated. You can make this option more dynamic, however, by specifying a simple expression. For example, you could use a counter bean to select a different file each time the File consumer polls the starting directory, as follows:
file://target/filelanguage/bean/?fileName=${bean:counter.next}.txt&delete=true
file://target/filelanguage/bean/?fileName=${bean:counter.next}.txt&delete=true
${bean:counter.next} expression invokes the next() method on the bean registered under the ID, counter.
move option is used to move files to a backup location after then have been read by a File consumer endpoint. For example, the following endpoint moves files to a backup directory, after they have been processed:
file://target/filelanguage/?move=backup/${date:now:yyyyMMdd}/${file:name.noext}.bak&recursive=false
file://target/filelanguage/?move=backup/${date:now:yyyyMMdd}/${file:name.noext}.bak&recursive=false
${file:name.noext}.bak expression modifies the original file name, replacing the file extension with .bak.
sortBy option to specify the order in which file should be processed. For example, to process files according to the alphabetical order of their file name, you could use the following File consumer endpoint:
file://target/filelanguage/?sortBy=file:name
file://target/filelanguage/?sortBy=file:name
file://target/filelanguage/?sortBy=file:modified
file://target/filelanguage/?sortBy=file:modified
reverse: prefix—for example:
file://target/filelanguage/?sortBy=reverse:file:modified
file://target/filelanguage/?sortBy=reverse:file:modified
On exchanges created by a File or FTP consumer Copy linkLink copied to clipboard!
16.2. File Variables Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
java.io.File type. The file variables enable you to access various parts of the file pathname, almost as if you were invoking the methods of the java.io.File class (in fact, the file language extracts the information it needs from message headers that have been set by the File or FTP endpoint).
Starting directory Copy linkLink copied to clipboard!
./filetransfer (a relative path):
file:filetransfer
file:filetransfer
./ftptransfer (a relative path):
ftp://myhost:2100/ftptransfer
ftp://myhost:2100/ftptransfer
Naming convention of file variables Copy linkLink copied to clipboard!
java.io.File class. For example, the file:absolute variable gives the value that would be returned by the java.io.File.getAbsolute() method.
java.io.File.getSize().
Table of variables Copy linkLink copied to clipboard!
| Variable | Type | Description |
|---|---|---|
file:name | String | The pathname relative to the starting directory. |
file:name.ext | String | The file extension (characters following the last . character in the pathname). |
file:name.noext | String | The pathname relative to the starting directory, omitting the file extension. |
file:onlyname | String | The final segment of the pathname. That is, the file name without the parent directory path. |
file:onlyname.noext | String | The final segment of the pathname, omitting the file extension. |
file:ext | String | The file extension (same as file:name.ext). |
file:parent | String | The pathname of the parent directory, including the starting directory in the path. |
file:path | String | The file pathname, including the starting directory in the path. |
file:absolute | Boolean | true, if the starting directory was specified as an absolute path; false, otherwise. |
file:absolute.path | String | The absolute pathname of the file. |
file:length | Long | The size of the referenced file. |
file:size | Long | Same as file:length. |
file:modified | java.util.Date | Date last modified. |
16.3. Examples Copy linkLink copied to clipboard!
Relative pathname Copy linkLink copied to clipboard!
./filelanguage:
file://filelanguage
file://filelanguage
filelanguage directory, suppose that the endpoint has just consumed the following file:
./filelanguage/test/hello.txt
./filelanguage/test/hello.txt
filelanguage directory itself has the following absolute location:
/workspace/camel/camel-core/target/filelanguage
/workspace/camel/camel-core/target/filelanguage
| Expression | Result |
|---|---|
file:name | test/hello.txt |
file:name.ext | txt |
file:name.noext | test/hello |
file:onlyname | hello.txt |
file:onlyname.noext | hello |
file:ext | txt |
file:parent | filelanguage/test |
file:path | filelanguage/test/hello.txt |
file:absolute | false |
file:absolute.path | /workspace/camel/camel-core/target/filelanguage/test/hello.txt |
Absolute pathname Copy linkLink copied to clipboard!
/workspace/camel/camel-core/target/filelanguage:
file:///workspace/camel/camel-core/target/filelanguage
file:///workspace/camel/camel-core/target/filelanguage
filelanguage directory, suppose that the endpoint has just consumed the following file:
./filelanguage/test/hello.txt
./filelanguage/test/hello.txt
| Expression | Result |
|---|---|
file:name | test/hello.txt |
file:name.ext | txt |
file:name.noext | test/hello |
file:onlyname | hello.txt |
file:onlyname.noext | hello |
file:ext | txt |
file:parent | /workspace/camel/camel-core/target/filelanguage/test |
file:path | /workspace/camel/camel-core/target/filelanguage/test/hello.txt |
file:absolute | true |
file:absolute.path | /workspace/camel/camel-core/target/filelanguage/test/hello.txt |
Chapter 17. Groovy Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-script module.
Adding the script module Copy linkLink copied to clipboard!
camel-script to your project as shown in Example 17.1, “Adding the camel-script dependency”.
Example 17.1. Adding the camel-script dependency
Static import Copy linkLink copied to clipboard!
groovy() static method in your application code, include the following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Built-in attributes Copy linkLink copied to clipboard!
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the properties component inside scripts. |
ENGINE_SCOPE.
Example Copy linkLink copied to clipboard!
Example 17.2. Routes using Groovy
Using the properties component Copy linkLink copied to clipboard!
resolve method on the built-in properties attribute, as follows:
.setHeader("myHeader").groovy("properties.resolve(PropKey)")
.setHeader("myHeader").groovy("properties.resolve(PropKey)")
String type.
Customizing Groovy Shell Copy linkLink copied to clipboard!
GroovyShell instance, in your Groovy expressions. To provide custom GroovyShell, add an implementation of the org.apache.camel.language.groovy.GroovyShellFactory SPI interface to your Camel registry.
GroovyShell instance that includes the custom static imports, instead of the default one.
Chapter 18. Header Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-core.
XML example Copy linkLink copied to clipboard!
SequenceNumber header (where the sequence number must be a positive integer), you can define a route as follows:
Java example Copy linkLink copied to clipboard!
from("SourceURL")
.resequence(header("SequenceNumber"))
.to("TargetURL");
from("SourceURL")
.resequence(header("SequenceNumber"))
.to("TargetURL");
Chapter 19. JavaScript Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-script module.
Adding the script module Copy linkLink copied to clipboard!
camel-script to your project as shown in Example 19.1, “Adding the camel-script dependency”.
Example 19.1. Adding the camel-script dependency
Static import Copy linkLink copied to clipboard!
javaScript() static method in your application code, include the following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Built-in attributes Copy linkLink copied to clipboard!
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the properties component inside scripts. |
ENGINE_SCOPE.
Example Copy linkLink copied to clipboard!
Example 19.2. Route using JavaScript
Using the properties component Copy linkLink copied to clipboard!
resolve method on the built-in properties attribute, as follows:
.setHeader("myHeader").javaScript("properties.resolve(PropKey)")
.setHeader("myHeader").javaScript("properties.resolve(PropKey)")
String type.
Chapter 20. JoSQL Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Adding the JoSQL module Copy linkLink copied to clipboard!
camel-josql to your project as shown in Example 20.1, “Adding the camel-josql dependency”.
Example 20.1. Adding the camel-josql dependency
Static import Copy linkLink copied to clipboard!
sql() static method in your application code, include the following import statement in your Java source files:
import static org.apache.camel.builder.sql.SqlBuilder.sql;
import static org.apache.camel.builder.sql.SqlBuilder.sql;
Variables Copy linkLink copied to clipboard!
| Name | Type | Description |
|---|---|---|
exchange | org.apache.camel.Exchange | The current Exchange |
in | org.apache.camel.Message | The IN message |
out | org.apache.camel.Message | The OUT message |
| property | Object | the Exchange property whose key is property |
| header | Object | the IN message header whose key is header |
| variable | Object | the variable whose key is variable |
Example Copy linkLink copied to clipboard!
Example 20.2. Route using JoSQL
Chapter 21. JSonPath Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
jsonpath DSL command can be used either as an expression or as a predicate (where an empty result gets interpreted as boolean false).
Adding the JSonPath package Copy linkLink copied to clipboard!
camel-jsonpath to your project, as follows:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jsonpath</artifactId>
<version>${camel-version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jsonpath</artifactId>
<version>${camel-version}</version>
</dependency>
Java example Copy linkLink copied to clipboard!
jsonpath() DSL command to select items in a certain price range:
false. In this way, you can use a JSonPath query as a predicate.
XML example Copy linkLink copied to clipboard!
jsonpath DSL element to define predicates in a route:
Suppress Exceptions Copy linkLink copied to clipboard!
jsonpath expression is not found. The exception can be ignored by setting the SuppressExceptions option to true. For example, in the code below, adding the true option as part of the jsonpath parameters:
JSonPath injection Copy linkLink copied to clipboard!
Reference Copy linkLink copied to clipboard!
Chapter 22. JXPath Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Adding JXPath package Copy linkLink copied to clipboard!
camel-jxpath to your project as shown in Example 22.1, “Adding the camel-jxpath dependency”.
Example 22.1. Adding the camel-jxpath dependency
Variables Copy linkLink copied to clipboard!
| Variable | Type | Value |
|---|---|---|
this | org.apache.camel.Exchange | The current Exchange |
in | org.apache.camel.Message | The IN message |
out | org.apache.camel.Message | The OUT message |
Example Copy linkLink copied to clipboard!
Example 22.2. Routes using JXPath
Chapter 23. MVEL Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-mvel module.
Syntax Copy linkLink copied to clipboard!
getRequest().getBody().getFamilyName()
getRequest().getBody().getFamilyName()
Object type) before invoking the getFamilyName() method. You can also use an abbreviated syntax for invoking bean attributes, for example:
request.body.familyName
request.body.familyName
Adding the MVEL module Copy linkLink copied to clipboard!
camel-mvel to your project as shown in Example 23.1, “Adding the camel-mvel dependency”.
Example 23.1. Adding the camel-mvel dependency
Built-in variables Copy linkLink copied to clipboard!
| Name | Type | Description |
|---|---|---|
this | org.apache.camel.Exchange | The current Exchange |
exchange | org.apache.camel.Exchange | The current Exchange |
exception | Throwable | the Exchange exception (if any) |
exchangeID | String | the Exchange ID |
fault | org.apache.camel.Message | The Fault message(if any) |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | Map | The Exchange properties |
property(name) | Object | The value of the named Exchange property |
property(name, type) | Type | The typed value of the named Exchange property |
Example Copy linkLink copied to clipboard!
Example 23.2. Route using MVEL
Chapter 24. The Object-Graph Navigation Language(OGNL) Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-ognl module.
Camel on EAP deployment Copy linkLink copied to clipboard!
Adding the OGNL module Copy linkLink copied to clipboard!
camel-ognl to your project as shown in Example 24.1, “Adding the camel-ognl dependency”.
Example 24.1. Adding the camel-ognl dependency
Static import Copy linkLink copied to clipboard!
ognl() static method in your application code, include the following import statement in your Java source files:
import static org.apache.camel.language.ognl.OgnlExpression.ognl;
import static org.apache.camel.language.ognl.OgnlExpression.ognl;
Built-in variables Copy linkLink copied to clipboard!
| Name | Type | Description |
|---|---|---|
this | org.apache.camel.Exchange | The current Exchange |
exchange | org.apache.camel.Exchange | The current Exchange |
exception | Throwable | the Exchange exception (if any) |
exchangeID | String | the Exchange ID |
fault | org.apache.camel.Message | The Fault message(if any) |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | Map | The Exchange properties |
property(name) | Object | The value of the named Exchange property |
property(name, type) | Type | The typed value of the named Exchange property |
Example Copy linkLink copied to clipboard!
Example 24.2. Route using OGNL
Chapter 25. PHP Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-script module.
Adding the script module Copy linkLink copied to clipboard!
camel-script to your project as shown in Example 25.1, “Adding the camel-script dependency”.
Example 25.1. Adding the camel-script dependency
Static import Copy linkLink copied to clipboard!
php() static method in your application code, include the following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Built-in attributes Copy linkLink copied to clipboard!
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the properties component inside scripts. |
ENGINE_SCOPE.
Example Copy linkLink copied to clipboard!
Example 25.2. Route using PHP
Using the properties component Copy linkLink copied to clipboard!
resolve method on the built-in properties attribute, as follows:
.setHeader("myHeader").php("properties.resolve(PropKey)")
.setHeader("myHeader").php("properties.resolve(PropKey)")
String type.
Chapter 26. Exchange Property Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-core.
XML example Copy linkLink copied to clipboard!
listOfEndpoints exchange property contains the recipient list, you could define a route as follows:
Java example Copy linkLink copied to clipboard!
from("direct:a").recipientList(exchangeProperty("listOfEndpoints"));
from("direct:a").recipientList(exchangeProperty("listOfEndpoints"));
Chapter 27. Python Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-script module.
Adding the script module Copy linkLink copied to clipboard!
camel-script to your project as shown in Example 27.1, “Adding the camel-script dependency”.
Example 27.1. Adding the camel-script dependency
Static import Copy linkLink copied to clipboard!
python() static method in your application code, include the following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Built-in attributes Copy linkLink copied to clipboard!
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the properties component inside scripts. |
ENGINE_SCOPE.
Example Copy linkLink copied to clipboard!
Example 27.2. Route using Python
Using the properties component Copy linkLink copied to clipboard!
resolve method on the built-in properties attribute, as follows:
.setHeader("myHeader").python("properties.resolve(PropKey)")
.setHeader("myHeader").python("properties.resolve(PropKey)")
String type.
Chapter 28. Ref Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-core.
Static import Copy linkLink copied to clipboard!
import static org.apache.camel.language.simple.RefLanguage.ref;
import static org.apache.camel.language.simple.RefLanguage.ref;
XML example Copy linkLink copied to clipboard!
Java example Copy linkLink copied to clipboard!
from("seda:a")
.split().ref("myExpression")
.to("seda:b");
from("seda:a")
.split().ref("myExpression")
.to("seda:b");
Chapter 29. Ruby Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-script module.
Adding the script module Copy linkLink copied to clipboard!
camel-script to your project as shown in Example 29.1, “Adding the camel-script dependency”.
Example 29.1. Adding the camel-script dependency
Static import Copy linkLink copied to clipboard!
ruby() static method in your application code, include the following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Built-in attributes Copy linkLink copied to clipboard!
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the properties component inside scripts. |
ENGINE_SCOPE.
Example Copy linkLink copied to clipboard!
Example 29.2. Route using Ruby
Using the properties component Copy linkLink copied to clipboard!
resolve method on the built-in properties attribute, as follows:
.setHeader("myHeader").ruby("properties.resolve(PropKey)")
.setHeader("myHeader").ruby("properties.resolve(PropKey)")
String type.
Chapter 30. The Simple Language Copy linkLink copied to clipboard!
Abstract
30.1. Java DSL Copy linkLink copied to clipboard!
Simple expressions in Java DSL Copy linkLink copied to clipboard!
simple() command in a route. You can either pass the simple() command as an argument to a processor, as follows:
from("seda:order")
.filter(simple("${in.header.foo}"))
.to("mock:fooOrders");
from("seda:order")
.filter(simple("${in.header.foo}"))
.to("mock:fooOrders");
simple() command as a sub-clause on the processor, for example:
from("seda:order")
.filter()
.simple("${in.header.foo}")
.to("mock:fooOrders");
from("seda:order")
.filter()
.simple("${in.header.foo}")
.to("mock:fooOrders");
Embedding in a string Copy linkLink copied to clipboard!
${Expression}. For example, to embed the in.header.name expression in a string:
simple("Hello ${in.header.name}, how are you?")
simple("Hello ${in.header.name}, how are you?")
Customizing the start and end tokens Copy linkLink copied to clipboard!
{ and }, by default) by calling the changeFunctionStartToken static method and the changeFunctionEndToken static method on the SimpleLanguage object.
[ and ] in Java, as follows:
// Java
import org.apache.camel.language.simple.SimpleLanguage;
...
SimpleLanguage.changeFunctionStartToken("[");
SimpleLanguage.changeFunctionEndToken("]");
// Java
import org.apache.camel.language.simple.SimpleLanguage;
...
SimpleLanguage.changeFunctionStartToken("[");
SimpleLanguage.changeFunctionEndToken("]");
camel-core library on their classpath. For example, in an OSGi server this might affect many applications; whereas in a Web application (WAR file) it would affect only the Web application itself.
30.2. XML DSL Copy linkLink copied to clipboard!
Simple expressions in XML DSL Copy linkLink copied to clipboard!
simple element. For example, to define a route that performs filtering based on the contents of the foo header:
Alternative placeholder syntax Copy linkLink copied to clipboard!
${Expression} syntax clashes with another property placeholder syntax. In this case, you can disambiguate the placeholder using the alternative syntax, $simple{Expression}, for the simple expression. For example:
<simple>Hello $simple{in.header.name}, how are you?</simple>
<simple>Hello $simple{in.header.name}, how are you?</simple>
Customizing the start and end tokens Copy linkLink copied to clipboard!
{ and }, by default) by overriding the SimpleLanguage instance. For example, to change the start and end tokens to [ and ], define a new SimpleLanguage bean in your XML configuration file, as follows:
<bean id="simple" class="org.apache.camel.language.simple.SimpleLanguage"> <constructor-arg name="functionStartToken" value="["/> <constructor-arg name="functionEndToken" value="]"/> </bean>
<bean id="simple" class="org.apache.camel.language.simple.SimpleLanguage">
<constructor-arg name="functionStartToken" value="["/>
<constructor-arg name="functionEndToken" value="]"/>
</bean>
camel-core library on their classpath. For example, in an OSGi server this might affect many applications; whereas in a Web application (WAR file) it would affect only the Web application itself.
Whitespace and auto-trim in XML DSL Copy linkLink copied to clipboard!
<transform>
<simple>
data=${body}
</simple>
</transform>
<transform>
<simple>
data=${body}
</simple>
</transform>
<transform>
<simple>data=${body}</simple>
</transform>
<transform>
<simple>data=${body}</simple>
</transform>
<transform>
<simple>data=${body}\n</simple>
</transform>
<transform>
<simple>data=${body}\n</simple>
</transform>
trim attribute to false, as follows:
<transform trim="false">
<simple>data=${body}
</simple>
</transform>
<transform trim="false">
<simple>data=${body}
</simple>
</transform>
30.3. Invoking an External Script Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Syntax for script resource Copy linkLink copied to clipboard!
resource:Scheme:Location
resource:Scheme:Location
Scheme: can be either classpath:, file:, or http:.
mysimple.txt script from the classpath,
simple("resource:classpath:mysimple.txt")
simple("resource:classpath:mysimple.txt")
30.4. Expressions Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
simple("${header.timeOfDay}"), would return the contents of a header called timeOfDay from the incoming message.
${Expression}, to return a variable value. It is never permissible to omit the enclosing tokens (${ and }).
Contents of a single variable Copy linkLink copied to clipboard!
in.header.HeaderName, to obtain the value of the HeaderName header, as follows:
simple("${in.header.foo}")
simple("${in.header.foo}")
Variables embedded in a string Copy linkLink copied to clipboard!
simple("Received a message from ${in.header.user} on ${date:in.header.date:yyyyMMdd}.")
simple("Received a message from ${in.header.user} on ${date:in.header.date:yyyyMMdd}.")
date and bean variables Copy linkLink copied to clipboard!
date:command:pattern, and for calling bean methods, bean:beanRef. For example, you can use the date and the bean variables as follows:
simple("Todays date is ${date:now:yyyyMMdd}")
simple("The order type is ${bean:orderService?method=getOrderType}")
simple("Todays date is ${date:now:yyyyMMdd}")
simple("The order type is ${bean:orderService?method=getOrderType}")
Specifying the result type Copy linkLink copied to clipboard!
simple(). For example, to return an integer result, you could evaluate a simple expression as follows:
...
.setHeader("five", simple("5", Integer.class))
...
.setHeader("five", simple("5", Integer.class))
resultType attribute. For example:
<setHeader headerName="five"> <!-- use resultType to indicate that the type should be a java.lang.Integer --> <simple resultType="java.lang.Integer">5</simple> </setHeader>
<setHeader headerName="five">
<!-- use resultType to indicate that the type should be a java.lang.Integer -->
<simple resultType="java.lang.Integer">5</simple>
</setHeader>
Nested expressions Copy linkLink copied to clipboard!
simple("${header.${bean:headerChooser?method=whichHeader}}")
simple("${header.${bean:headerChooser?method=whichHeader}}")
Accessing constants or enums Copy linkLink copied to clipboard!
type:ClassName.Field
type:ClassName.Field
enum type:
package org.apache.camel.processor;
...
public enum Customer {
GOLD, SILVER, BRONZE
}
package org.apache.camel.processor;
...
public enum Customer {
GOLD, SILVER, BRONZE
}
Customer enum fields, as follows:
OGNL expressions Copy linkLink copied to clipboard!
getAddress() accessor, you can access the Address object and the Address object's properties as follows:
simple("${body.address}")
simple("${body.address.street}")
simple("${body.address.zip}")
simple("${body.address.city}")
simple("${body.address}")
simple("${body.address.street}")
simple("${body.address.zip}")
simple("${body.address.city}")
${body.address.street}, is shorthand for ${body.getAddress.getStreet}.
OGNL null-safe operator Copy linkLink copied to clipboard!
?., to avoid encountering null-pointer exceptions, in case the body does not have an address. For example:
simple("${body?.address?.street}")
simple("${body?.address?.street}")
java.util.Map type, you can look up a value in the map with the key, foo, using the following notation:
simple("${body[foo]?.name}")
simple("${body[foo]?.name}")
OGNL list element access Copy linkLink copied to clipboard!
[k], to access the elements of a list. For example:
simple("${body.address.lines[0]}")
simple("${body.address.lines[1]}")
simple("${body.address.lines[2]}")
simple("${body.address.lines[0]}")
simple("${body.address.lines[1]}")
simple("${body.address.lines[2]}")
last keyword returns the index of the last element of a list. For example, you can access the second last element of a list, as follows:
simple("${body.address.lines[last-1]}")
simple("${body.address.lines[last-1]}")
size method to query the size of a list, as follows:
simple("${body.address.lines.size}")
simple("${body.address.lines.size}")
OGNL array length access Copy linkLink copied to clipboard!
length method, as follows:
String[] lines = new String[]{"foo", "bar", "cat"};
exchange.getIn().setBody(lines);
simple("There are ${body.length} lines")
String[] lines = new String[]{"foo", "bar", "cat"};
exchange.getIn().setBody(lines);
simple("There are ${body.length} lines")
30.5. Predicates Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
simple("${header.timeOfDay} == '14:30'"), tests whether the timeOfDay header in the incoming message is equal to 14:30.
resultType is specified as a Boolean the expression is evaluated as a predicate instead of an expression. This allows the predicate syntax to be used for these expressions.
Syntax Copy linkLink copied to clipboard!
${LHSVariable} Op RHSValue
${LHSVariable} Op RHSValue
- Another variable,
${RHSVariable}. - A string literal, enclosed in single quotes,
' '. - A numeric constant, enclosed in single quotes,
' '. - The null object,
null.
Examples Copy linkLink copied to clipboard!
simple("${in.header.user} == 'john'")
simple("${in.header.number} > '100'") // String literal can be converted to integer
simple("${in.header.user} == 'john'")
simple("${in.header.number} > '100'") // String literal can be converted to integer
simple("${in.header.type} in 'gold,silver'")
simple("${in.header.type} in 'gold,silver'")
simple("${in.header.number} regex '\d{4}'")
simple("${in.header.number} regex '\d{4}'")
is operator, as follows:
simple("${in.header.type} is 'java.lang.String'")
simple("${in.header.type} is 'String'") // You can abbreviate java.lang. types
simple("${in.header.type} is 'java.lang.String'")
simple("${in.header.type} is 'String'") // You can abbreviate java.lang. types
simple("${in.header.number} range '100..199'")
simple("${in.header.number} range '100..199'")
Conjunctions Copy linkLink copied to clipboard!
&& and ||.
&& conjunction (logical and):
simple("${in.header.title} contains 'Camel' && ${in.header.type} == 'gold'")
simple("${in.header.title} contains 'Camel' && ${in.header.type} == 'gold'")
|| conjunction (logical inclusive or):
simple("${in.header.title} contains 'Camel' || ${in.header.type} == 'gold'")
simple("${in.header.title} contains 'Camel' || ${in.header.type} == 'gold'")
30.6. Variable Reference Copy linkLink copied to clipboard!
Table of variables Copy linkLink copied to clipboard!
| Variable | Type | Description |
|---|---|---|
camelContext | Object | The Camel context. Supports OGNL expressions. |
camelId | String | The Camel context's ID value. |
exchangeId | String | The exchange's ID value. |
id | String | The In message ID value. |
body | Object |
The In message body. Supports OGNL expressions.
|
in.body | Object | The In message body. Supports OGNL expressions. |
out.body | Object |
The Out message body.
|
bodyAs(Type) | Type | The In message body, converted to the specified type. All types, Type, must be specified using their fully-qualified Java name, except for the types: byte[], String, Integer, and Long. The converted body can be null. |
mandatoryBodyAs(Type) | Type | The In message body, converted to the specified type. All types, Type, must be specified using their fully-qualified Java name, except for the types: byte[], String, Integer, and Long. The converted body is expected to be non-null. |
header.HeaderName | Object |
The In message's HeaderName header. Supports OGNL expressions.
|
header[HeaderName] | Object |
The In message's HeaderName header (alternative syntax).
|
headers.HeaderName | Object | The In message's HeaderName header. |
headers[HeaderName] | Object | The In message's HeaderName header (alternative syntax). |
in.header.HeaderName | Object | The In message's HeaderName header. Supports OGNL expressions. |
in.header[HeaderName] | Object | The In message's HeaderName header (alternative syntax). |
in.headers.HeaderName | Object | The In message's HeaderName header. Supports OGNL expressions. |
in.headers[HeaderName] | Object | The In message's HeaderName header (alternative syntax). |
out.header.HeaderName | Object |
The Out message's HeaderName header.
|
out.header[HeaderName] | Object |
The Out message's HeaderName header (alternative syntax).
|
out.headers.HeaderName | Object | The Out message's HeaderName header. |
out.headers[HeaderName] | Object | The Out message's HeaderName header (alternative syntax). |
headerAs(Key,Type) | Type | The Key header, converted to the specified type. All types, Type, must be specified using their fully-qualified Java name, except for the types: byte[], String, Integer, and Long. The converted value can be null. |
headers | Map | All of the In headers (as a java.util.Map type). |
in.headers | Map | All of the In headers (as a java.util.Map type). |
property.PropertyName | Object |
The PropertyName property on the exchange.
|
property[PropertyName] | Object |
The PropertyName property on the exchange (alternative syntax).
|
sys.SysPropertyName | String | The SysPropertyName Java system property. |
sysenv.SysEnvVar | String | The SysEnvVar system environment variable. |
exception | String | Either the exception object from Exchange.getException() or, if this value is null, the caught exception from the Exchange.EXCEPTION_CAUGHT property; otherwise null. Supports OGNL expressions. |
exception.message | String | If an exception is set on the exchange, returns the value of Exception.getMessage(); otherwise, returns null. |
exception.stacktrace | String | If an exception is set on the exchange, returns the value of Exception.getStackTrace(); otherwise, returns null. Note: The simple language first tries to retrieve an exception from Exchange.getException(). If that property is not set, it checks for a caught exception, by calling Exchange.getProperty(Exchange.CAUGHT_EXCEPTION). |
date:command:pattern | String | A date formatted using a java.text.SimpleDateFormat pattern. The following commands are supported: now, for the current date and time; header.HeaderName, or in.header.HeaderName to use a java.util.Date object in the HeaderName header from the In message; out.header.HeaderName to use a java.util.Date object in the HeaderName header from the Out message; |
bean:beanID.Method | Object | Invokes a method on the referenced bean and returns the result of the method invocation. To specify a method name, you can either use the beanID.Method syntax; or you can use the beanID?method=methodName syntax. |
ref:beanID | Object | Looks up the bean with the ID, beanID, in the registry and returns a reference to the bean itself. For example, if you are using the splitter EIP, you could use this variable to reference the bean that implements the splitting algorithm. |
properties:Key | String | The value of the Key property placeholder (see Section 2.7, “Property Placeholders”). |
properties:Location:Key | String | The value of the Key property placeholder, where the location of the properties file is given by Location (see Section 2.7, “Property Placeholders”). |
threadName | String | The name of the current thread. |
routeId | String | Returns the ID of the current route through which the Exchange is being routed. |
type:Name[.Field] | Object | References a type or field by its Fully-Qualified-Name (FQN). To refer to a field, append .Field. For example, you can refer to the FILE_NAME constant field from the Exchange class as type:org.apache.camel.Exchange.FILE_NAME |
30.7. Operator Reference Copy linkLink copied to clipboard!
Binary operators Copy linkLink copied to clipboard!
| Operator | Description |
|---|---|
== | Equals. |
> | Greater than. |
>= | Greater than or equals. |
< | Less than. |
<= | Less than or equals. |
!= | Not equal to. |
contains | Test if LHS string contains RHS string. |
not contains | Test if LHS string does not contain RHS string. |
regex | Test if LHS string matches RHS regular expression. |
not regex | Test if LHS string does not match RHS regular expression. |
in | Test if LHS string appears in the RHS comma-separated list. |
not in | Test if LHS string does not appear in the RHS comma-separated list. |
is | Test if LHS is an instance of RHS Java type (using Java instanceof operator). |
not is | Test if LHS is not an instance of RHS Java type (using Java instanceof operator). |
range | Test if LHS number lies in the RHS range (where range has the format, 'min...max'). |
not range | Test if LHS number does not lie in the RHS range (where range has the format, 'min...max'). |
Unary operators and character escapes Copy linkLink copied to clipboard!
| Operator | Description |
|---|---|
++ | Increment a number by 1. |
-- | Decrement a number by 1. |
\n | The newline character. |
\r | The carriage return character. |
\t | The tab character. |
\ | (Obsolete) Since Camel version 2.11, the backslash escape character is not supported. |
Combining predicates Copy linkLink copied to clipboard!
| Operator | Description |
|---|---|
&& | Combine two predicates with logical and. |
|| | Combine two predicates with logical inclusive or. |
and | Deprecated. Use && instead. |
or | Deprecated. Use || instead. |
Chapter 31. SpEL Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Syntax Copy linkLink copied to clipboard!
#{SpelExpression}, so that they can be embedded in a plain text string (in other words, SpEL has expression templating enabled).
@BeanID syntax. For example, given a bean with the ID, headerUtils, and the method, count() (which counts the number of headers on the current message), you could use the headerUtils bean in an SpEL predicate, as follows:
#{@headerUtils.count > 4}
#{@headerUtils.count > 4}
Adding SpEL package Copy linkLink copied to clipboard!
camel-spring to your project as shown in Example 31.1, “Adding the camel-spring dependency”.
Example 31.1. Adding the camel-spring dependency
Variables Copy linkLink copied to clipboard!
| Variable | Type | Description |
|---|---|---|
this | Exchange | The current exchange is the root object. |
exchange | Exchange | The current exchange. |
exchangeId | String | The current exchange's ID. |
exception | Throwable | The exchange exception (if any). |
fault | Message | The fault message (if any). |
request | Message | The exchange's In message. |
response | Message | The exchange's Out message (if any). |
properties | Map | The exchange properties. |
property(Name) | Object | The exchange property keyed by Name. |
property(Name, Type) | Type | The exchange property keyed by Name, converted to the type, Type. |
XML example Copy linkLink copied to clipboard!
Country header has the value USA, you can use the following SpEL expression:
Java example Copy linkLink copied to clipboard!
from("SourceURL")
.filter().spel("#{request.headers['Country'] == 'USA'}")
.to("TargetURL");
from("SourceURL")
.filter().spel("#{request.headers['Country'] == 'USA'}")
.to("TargetURL");
from("SourceURL")
.setBody(spel("Hello #{request.body}! What a beautiful #{request.headers['dayOrNight']}"))
.to("TargetURL");
from("SourceURL")
.setBody(spel("Hello #{request.body}! What a beautiful #{request.headers['dayOrNight']}"))
.to("TargetURL");
Chapter 32. The XPath Language Copy linkLink copied to clipboard!
Abstract
32.1. Java DSL Copy linkLink copied to clipboard!
Basic expressions Copy linkLink copied to clipboard!
xpath("Expression") to evaluate an XPath expression on the current exchange (where the XPath expression is applied to the body of the current In message). The result of the xpath() expression is an XML node (or node set, if more than one node matches).
/person/name element from the current In message body and use it to set a header named user, you could define a route like the following:
from("queue:foo")
.setHeader("user", xpath("/person/name/text()"))
.to("direct:tie");
from("queue:foo")
.setHeader("user", xpath("/person/name/text()"))
.to("direct:tie");
xpath() as an argument to setHeader(), you can use the fluent builder xpath() command—for example:
from("queue:foo")
.setHeader("user").xpath("/person/name/text()")
.to("direct:tie");
from("queue:foo")
.setHeader("user").xpath("/person/name/text()")
.to("direct:tie");
xpath(). For example, to specify explicitly that the result type is String:
xpath("/person/name/text()", String.class)
xpath("/person/name/text()", String.class)
Namespaces Copy linkLink copied to clipboard!
org.apache.camel.builder.xml.Namespaces, which enables you to define associations between namespaces and prefixes.
cust, with the namespace, http://acme.com/customer/record, and then extract the contents of the element, /cust:person/cust:name, you could define a route like the following:
xpath() expression builder by passing the Namespaces object, ns, as an additional argument. If you need to define multiple namespaces, use the Namespace.add() method, as follows:
import org.apache.camel.builder.xml.Namespaces;
...
Namespaces ns = new Namespaces("cust", "http://acme.com/customer/record");
ns.add("inv", "http://acme.com/invoice");
ns.add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
import org.apache.camel.builder.xml.Namespaces;
...
Namespaces ns = new Namespaces("cust", "http://acme.com/customer/record");
ns.add("inv", "http://acme.com/invoice");
ns.add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
xpath(), as follows:
xpath("/person/name/text()", String.class, ns)
xpath("/person/name/text()", String.class, ns)
Auditing namespaces Copy linkLink copied to clipboard!
INFO log level, enable the logNamespaces option in the Java DSL, as follows:
xpath("/foo:person/@id", String.class).logNamespaces()
xpath("/foo:person/@id", String.class).logNamespaces()
TRACE level logging on the org.apache.camel.builder.xml.XPathBuilder logger.
2012-01-16 13:23:45,878 [stSaxonWithFlag] INFO XPathBuilder -
Namespaces discovered in message: {xmlns:a=[http://apache.org/camel],
DEFAULT=[http://apache.org/default],
xmlns:b=[http://apache.org/camelA, http://apache.org/camelB]}
2012-01-16 13:23:45,878 [stSaxonWithFlag] INFO XPathBuilder -
Namespaces discovered in message: {xmlns:a=[http://apache.org/camel],
DEFAULT=[http://apache.org/default],
xmlns:b=[http://apache.org/camelA, http://apache.org/camelB]}
32.2. XML DSL Copy linkLink copied to clipboard!
Basic expressions Copy linkLink copied to clipboard!
xpath element. The XPath expression is applied to the body of the current In message and returns an XML node (or node set). Typically, the returned XML node is automatically converted to a string.
/person/name element from the current In message body and use it to set a header named user, you could define a route like the following:
resultType attribute to a Java type name (where you must specify the fully-qualified type name). For example, to specify explicitly that the result type is java.lang.String (you can omit the java.lang. prefix here):
<xpath resultType="String">/person/name/text()</xpath>
<xpath resultType="String">/person/name/text()</xpath>
Namespaces Copy linkLink copied to clipboard!
xmlns:Prefix="NamespaceURI".
cust, with the namespace, http://acme.com/customer/record, and then extract the contents of the element, /cust:person/cust:name, you could define a route like the following:
Auditing namespaces Copy linkLink copied to clipboard!
INFO log level, enable the logNamespaces option in the XML DSL, as follows:
<xpath logNamespaces="true" resultType="String">/foo:person/@id</xpath>
<xpath logNamespaces="true" resultType="String">/foo:person/@id</xpath>
TRACE level logging on the org.apache.camel.builder.xml.XPathBuilder logger.
2012-01-16 13:23:45,878 [stSaxonWithFlag] INFO XPathBuilder -
Namespaces discovered in message: {xmlns:a=[http://apache.org/camel],
DEFAULT=[http://apache.org/default],
xmlns:b=[http://apache.org/camelA, http://apache.org/camelB]}
2012-01-16 13:23:45,878 [stSaxonWithFlag] INFO XPathBuilder -
Namespaces discovered in message: {xmlns:a=[http://apache.org/camel],
DEFAULT=[http://apache.org/default],
xmlns:b=[http://apache.org/camelA, http://apache.org/camelB]}
32.3. XPath Injection Copy linkLink copied to clipboard!
Parameter binding annotation Copy linkLink copied to clipboard!
@XPath annotation to extract a value from the exchange and bind it to a method parameter.
credit method on an AccountService object:
from("queue:payments")
.beanRef("accountService","credit")
...
from("queue:payments")
.beanRef("accountService","credit")
...
credit method uses parameter binding annotations to extract relevant data from the message body and inject it into its parameters, as follows:
Namespaces Copy linkLink copied to clipboard!
XPath expression that appears in the @XPath annotation.
| Namespace URI | Prefix |
|---|---|
http://www.w3.org/2001/XMLSchema | xsd |
http://www.w3.org/2003/05/soap-envelope | soap |
Custom namespaces Copy linkLink copied to clipboard!
@NamespacePrefix annotation to define custom XML namespaces. Invoke the @NamespacePrefix annotation to initialize the namespaces argument of the @XPath annotation. The namespaces defined by @NamespacePrefix can then be used in the @XPath annotation's expression value.
ex, with the custom namespace, http://fusesource.com/examples, invoke the @XPath annotation as follows:
32.4. XPath Builder Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.builder.xml.XPathBuilder class enables you to evaluate XPath expressions independently of an exchange. That is, if you have an XML fragment from any source, you can use XPathBuilder to evaluate an XPath expression on the XML fragment.
Matching expressions Copy linkLink copied to clipboard!
matches() method to check whether one or more XML nodes can be found that match the given XPath expression. The basic syntax for matching an XPath expression using XPathBuilder is as follows:
boolean matches = XPathBuilder
.xpath("Expression")
.matches(CamelContext, "XMLString");
boolean matches = XPathBuilder
.xpath("Expression")
.matches(CamelContext, "XMLString");
true, because the XPath expression finds a match in the xyz attribute.
boolean matches = XPathBuilder
.xpath("/foo/bar/@xyz")
.matches(getContext(), "<foo><bar xyz='cheese'/></foo>"));
boolean matches = XPathBuilder
.xpath("/foo/bar/@xyz")
.matches(getContext(), "<foo><bar xyz='cheese'/></foo>"));
Evaluating expressions Copy linkLink copied to clipboard!
evaluate() method to return the contents of the first node that matches the given XPath expression. The basic syntax for evaluating an XPath expression using XPathBuilder is as follows:
String nodeValue = XPathBuilder
.xpath("Expression")
.evaluate(CamelContext, "XMLString");
String nodeValue = XPathBuilder
.xpath("Expression")
.evaluate(CamelContext, "XMLString");
evaluate()—for example:
32.5. Enabling Saxon Copy linkLink copied to clipboard!
Prerequisites Copy linkLink copied to clipboard!
camel-saxon artifact (either adding this dependency to your Maven POM, if you use Maven, or adding the camel-saxon-6.2.1.redhat-084.jar file to your classpath, otherwise).
Using the Saxon parser in Java DSL Copy linkLink copied to clipboard!
saxon() fluent builder method. For example, you could invoke the Saxon parser as shown in the following example:
Using the Saxon parser in XML DSL Copy linkLink copied to clipboard!
saxon attribute to true in the xpath element. For example, you could invoke the Saxon parser as shown in the following example:
<xpath saxon="true" resultType="java.lang.String">current-dateTime()</xpath>
<xpath saxon="true" resultType="java.lang.String">current-dateTime()</xpath>
Programming with Saxon Copy linkLink copied to clipboard!
// Java import javax.xml.transform.TransformerFactory; import net.sf.saxon.TransformerFactoryImpl; ... TransformerFactory saxonFactory = new net.sf.saxon.TransformerFactoryImpl();
// Java
import javax.xml.transform.TransformerFactory;
import net.sf.saxon.TransformerFactoryImpl;
...
TransformerFactory saxonFactory = new net.sf.saxon.TransformerFactoryImpl();
javax.xml.transform.TransformerFactory property in the ESBInstall/etc/system.properties file, as follows:
javax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl
javax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl
// Java import javax.xml.transform.TransformerFactory; ... TransformerFactory factory = TransformerFactory.newInstance();
// Java
import javax.xml.transform.TransformerFactory;
...
TransformerFactory factory = TransformerFactory.newInstance();
net.sf.saxon/saxon9he (normally installed by default). In versions of Fuse ESB prior to 7.1, it is not possible to load Saxon using the generic JAXP API.
32.6. Expressions Copy linkLink copied to clipboard!
Result type Copy linkLink copied to clipboard!
org.w3c.dom.NodeList type. You can use the type converter mechanism to convert the result to a different type, however. In the Java DSL, you can specify the result type in the second argument of the xpath() command. For example, to return the result of an XPath expression as a String:
xpath("/person/name/text()", String.class)
xpath("/person/name/text()", String.class)
resultType attribute, as follows:
<xpath resultType="java.lang.String">/person/name/text()</xpath>
<xpath resultType="java.lang.String">/person/name/text()</xpath>
Patterns in location paths Copy linkLink copied to clipboard!
/people/person- The basic location path specifies the nested location of a particular element. That is, the preceding location path would match the person element in the following XML fragment:
<people> <person>...</person> </people>
<people> <person>...</person> </people>Copy to Clipboard Copied! Toggle word wrap Toggle overflow Note that this basic pattern can match multiple nodes—for example, if there is more than onepersonelement inside thepeopleelement. /name/text()- If you just want to access the text inside by the element, append
/text()to the location path, otherwise the node includes the element's start and end tags (and these tags would be included when you convert the node to a string). /person/telephone/@isDayTime- To select the value of an attribute, AttributeName, use the syntax
@AttributeName. For example, the preceding location path returnstruewhen applied to the following XML fragment:<person> <telephone isDayTime="true">1234567890</telephone> </person>
<person> <telephone isDayTime="true">1234567890</telephone> </person>Copy to Clipboard Copied! Toggle word wrap Toggle overflow *- A wildcard that matches all elements in the specified scope. For example,
/people/person/*matches all the child elements ofperson. @*- A wildcard that matches all attributes of the matched elements. For example,
/person/name/@*matches all attributes of every matchednameelement. //- Match the location path at every nesting level. For example, the
//namepattern matches everynameelement highlighted in the following XML fragment:Copy to Clipboard Copied! Toggle word wrap Toggle overflow ..- Selects the parent of the current context node. Not normally useful in the Apache Camel XPath language, because the current context node is the document root, which has no parent.
node()- Match any kind of node.
text()- Match a text node.
comment()- Match a comment node.
processing-instruction()- Match a processing-instruction node.
Predicate filters Copy linkLink copied to clipboard!
[Predicate]. For example, you can select the Nth node from the list of matches by appending [N] to a location path. The following expression selects the first matching person element:
/people/person[1]
/people/person[1]
person element:
/people/person[last()-1]
/people/person[last()-1]
name elements, whose surname attribute is either Strachan or Davies:
/person/name[@surname="Strachan" or @surname="Davies"]
/person/name[@surname="Strachan" or @surname="Davies"]
and, or, not(), and you can compare expressions using the comparators, =, !=, >, >=, <, <= (in practice, the less-than symbol must be replaced by the < entity). You can also use XPath functions in the predicate filter.
Axes Copy linkLink copied to clipboard!
AxisType::MatchingNode. For example, you can use the child:: axis to search the children of the current context node, as follows:
/invoice/items/child::item
/invoice/items/child::item
child::item is the items element that is selected by the path, /invoice/items. The child:: axis restricts the search to the children of the context node, items, so that child::item matches the children of items that are named item. As a matter of fact, the child:: axis is the default axis, so the preceding example can be written equivalently as:
/invoice/items/item
/invoice/items/item
@ is an abbreviation of attribute::, and // is an abbreviation of descendant-or-self::. The full list of axes is as follows (for details consult the reference below):
ancestorancestor-or-selfattributechilddescendantdescendant-or-selffollowingfollowing-siblingnamespaceparentprecedingpreceding-siblingself
Functions Copy linkLink copied to clipboard!
/people/person[last()]
/people/person[last()]
person element in a sequence (in document order).
Reference Copy linkLink copied to clipboard!
32.7. Predicates Copy linkLink copied to clipboard!
Basic predicates Copy linkLink copied to clipboard!
xpath in the Java DSL or the XML DSL in a context where a predicate is expected—for example, as the argument to a filter() processor or as the argument to a when() clause.
/person/city element contains the value, London:
from("direct:tie")
.filter().xpath("/person/city = 'London'").to("file:target/messages/uk");
from("direct:tie")
.filter().xpath("/person/city = 'London'").to("file:target/messages/uk");
when() clause:
from("direct:tie")
.choice()
.when(xpath("/person/city = 'London'")).to("file:target/messages/uk")
.otherwise().to("file:target/messages/others");
from("direct:tie")
.choice()
.when(xpath("/person/city = 'London'")).to("file:target/messages/uk")
.otherwise().to("file:target/messages/others");
XPath predicate operators Copy linkLink copied to clipboard!
| Operator | Description |
|---|---|
= | Equals. |
!= | Not equal to. |
> | Greater than. |
>= | Greater than or equals. |
< | Less than. |
<= | Less than or equals. |
or | Combine two predicates with logical and. |
and | Combine two predicates with logical inclusive or. |
not() | Negate predicate argument. |
32.8. Using Variables and Functions Copy linkLink copied to clipboard!
Evaluating variables in a route Copy linkLink copied to clipboard!
$VarName or $Prefix:VarName, if the variable is accessed through an XML namespace.
$in:body and the In message's header value as $in:HeaderName. O/S environment variables can be accessed as $env:EnvVar and Java system properties can be accessed as $system:SysVar.
/person/city element and inserts it into the city header. The second route filters exchanges using the XPath expression, $in:city = 'London', where the $in:city variable is replaced by the value of the city header.
Evaluating functions in a route Copy linkLink copied to clipboard!
in:header() function and the in:body() function to access a head and the body from the underlying exchange:
from("direct:start").choice()
.when().xpath("in:header('foo') = 'bar'").to("mock:x")
.when().xpath("in:body() = '<two/>'").to("mock:y")
.otherwise().to("mock:z");
from("direct:start").choice()
.when().xpath("in:header('foo') = 'bar'").to("mock:x")
.when().xpath("in:body() = '<two/>'").to("mock:y")
.otherwise().to("mock:z");
in:HeaderName or in:body variables. The functions have a slightly different syntax however: in:header('HeaderName') instead of in:HeaderName; and in:body() instead of in:body.
Evaluating variables in XPathBuilder Copy linkLink copied to clipboard!
XPathBuilder class. In this case, you cannot use variables such as $in:body or $in:HeaderName, because there is no exchange object to evaluate against. But you can use variables that are defined inline using the variable(Name, Value) fluent builder method.
$test variable, which is defined to have the value, London:
String var = XPathBuilder.xpath("$test")
.variable("test", "London")
.evaluate(getContext(), "<name>foo</name>");
String var = XPathBuilder.xpath("$test")
.variable("test", "London")
.evaluate(getContext(), "<name>foo</name>");
$test, uses no prefix).
32.9. Variable Namespaces Copy linkLink copied to clipboard!
Table of namespaces Copy linkLink copied to clipboard!
| Namespace URI | Prefix | Description |
|---|---|---|
http://camel.apache.org/schema/spring | None | Default namespace (associated with variables that have no namespace prefix). |
http://camel.apache.org/xml/in/ | in | Used to reference header or body of the current exchange's In message. |
http://camel.apache.org/xml/out/ | out | Used to reference header or body of the current exchange's Out message. |
http://camel.apache.org/xml/functions/ | functions | Used to reference some custom functions. |
http://camel.apache.org/xml/variables/environment-variables | env | Used to reference O/S environment variables. |
http://camel.apache.org/xml/variables/system-properties | system | Used to reference Java system properties. |
http://camel.apache.org/xml/variables/exchange-property | Undefined | Used to reference exchange properties. You must define your own prefix for this namespace. |
32.10. Function Reference Copy linkLink copied to clipboard!
Table of custom functions Copy linkLink copied to clipboard!
| Function | Description |
|---|---|
in:body() | Returns the In message body. |
in:header(HeaderName) | Returns the In message header with name, HeaderName. |
out:body() | Returns the Out message body. |
out:header(HeaderName) | Returns the Out message header with name, HeaderName. |
function:properties(PropKey) | Looks up a property with the key, PropKey (see Section 2.7, “Property Placeholders”). |
function:simple(SimpleExp) | Evaluates the specified simple expression, SimpleExp. |
Chapter 33. XQuery Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Java syntax Copy linkLink copied to clipboard!
xquery() in several ways. For simple expressions, you can pass the XQuery expressions as a string (java.lang.String). For longer XQuery expressions, you might prefer to store the expression in a file, which you can then reference by 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 the result. Depending on the context, the return value is interpreted either as a predicate (where an empty node set is interpreted as false) or as an expression.
Adding the Saxon module Copy linkLink copied to clipboard!
camel-saxon to your project as shown in Example 33.1, “Adding the camel-saxon dependency”.
Example 33.1. Adding the camel-saxon dependency
Camel on EAP deployment Copy linkLink copied to clipboard!
camel-saxon component is supported by the Camel on EAP (Wildfly Camel) framework, which offers a simplified deployment model on the Red Hat JBoss Enterprise Application Platform (JBoss EAP) container. For details of this model, see chapter "Apache Camel on Red Hat JBoss EAP" in "Deploying into a Web Server".
Static import Copy linkLink copied to clipboard!
xquery() static method in your application code, include the following import statement in your Java source files:
import static org.apache.camel.builder.saxon.XQueryBuilder.xquery;
import static org.apache.camel.builder.saxon.XQueryBuilder.xquery;
Variables Copy linkLink copied to clipboard!
| Variable | Type | Description |
|---|---|---|
exchange | Exchange | The current Exchange |
in.body | Object | The body of the IN message |
out.body | Object | The body of the OUT message |
in.headers.key | Object | The IN message header whose key is key |
out.headers.key | Object | The OUT message header whose key is key |
| key | Object | The Exchange property whose key is key |
Example Copy linkLink copied to clipboard!
Example 33.2. Route using XQuery
Part III. Web Services and Routing with Camel CXF Copy linkLink copied to clipboard!
Abstract
Chapter 34. Demonstration Code for Camel/CXF Copy linkLink copied to clipboard!
Abstract
34.1. Downloading and Installing the Demonstrations Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Prerequisites Copy linkLink copied to clipboard!
- Java platform—the demonstrations can run on Java 6 or Java 7.
- Apache Maven build tool—to build the demonstration, you require Apache Maven 3.0.4.
- Internet connection—Maven requires an Internet connection in order to download required dependencies from remote repositories while performing a build.
- Red Hat JBoss Fuse—the demonstrations are deployed into the JBoss Fuse container.
Downloading the demonstration package Copy linkLink copied to clipboard!
cxf-webinars-jboss-fuse-6.2.1.zip, and is available from the following location:
34.2. Running the Demonstrations Copy linkLink copied to clipboard!
Building the demonstrations Copy linkLink copied to clipboard!
cxf-webinars-jboss-fuse-6.2.1, and enter the following commands:
mvn install
mvn install
cxf-webinars-jboss-fuse-6.2.1 directory (where the demonstrations are defined to be submodules of the cxf-webinars-jboss-fuse-6.2.1/pom.xml project). While Maven is building the demonstration code, it downloads whatever dependencies it needs from the Internet and installs them in the local Maven repository.
Starting and configuring the Red Hat JBoss Fuse container Copy linkLink copied to clipboard!
- (Optional) If your local Maven repository is in a non-standard location, you might need to edit the JBoss Fuse configuration to specify your custom location. Edit the
InstallDir/etc/org.ops4j.pax.url.mvn.cfgfile and set theorg.ops4j.pax.url.mvn.localRepositoryproperty to the location of your local Maven repository:Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Launch the JBoss Fuse container. Open a new command prompt, change directory to
InstallDir/bin, and enter the following command:./fuse
./fuseCopy to Clipboard Copied! Toggle word wrap Toggle overflow
Running the customer-ws-osgi-bundle demonstration Copy linkLink copied to clipboard!
JBossFuse:karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-osgi-bundle
JBossFuse:karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-osgi-bundle
JBossFuse:karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-client
JBossFuse:karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-client
JBossFuse:karaf@root> log:tail -n 4
JBossFuse:karaf@root> log:tail -n 4
2015-08-20 16:10:16,271 | INFO | #0 - timer://foo | timerToLog | ? ? | 198 - org.apache.camel.camel-core - 2.15.1.redhat-620133 | The message contains Hi from Camel at 2015-08-20 16:10:16 2015-08-20 16:10:16,367 | INFO | qtp432302853-183 | CustomerServiceImpl | ? ? | 283 - com.fusesource.byexample.cxf-webinars.customer-ws-osgi-bundle - 1.0.0.SNAPSHOT | Getting status for customer 1234 2015-08-20 16:10:16,370 | INFO | invoker thread. | ClientInvoker | ? ? | 284 - com.fusesource.byexample.cxf-webinars.customer-ws-client - 1.0.0.SNAPSHOT | Got back: status = Active, statusMessage = In the park, playing with my frisbee. 2015-08-20 16:10:18,373 | INFO | qtp432302853-182 | CustomerServiceImpl | ? ? | 283 - com.fusesource.byexample.cxf-webinars.customer-ws-osgi-bundle - 1.0.0.SNAPSHOT | Getting status for customer 1234 2015-08-20 16:10:18,376 | INFO | invoker thread. | ClientInvoker | ? ? | 284 - com.fusesource.byexample.cxf-webinars.customer-ws-client - 1.0.0.SNAPSHOT | Got back: status = Active, statusMessage = In the park, playing with my frisbee.
2015-08-20 16:10:16,271 | INFO | #0 - timer://foo | timerToLog | ? ? | 198 - org.apache.camel.camel-core - 2.15.1.redhat-620133 | The message contains Hi from Camel at 2015-08-20 16:10:16
2015-08-20 16:10:16,367 | INFO | qtp432302853-183 | CustomerServiceImpl | ? ? | 283 - com.fusesource.byexample.cxf-webinars.customer-ws-osgi-bundle - 1.0.0.SNAPSHOT | Getting status for customer 1234
2015-08-20 16:10:16,370 | INFO | invoker thread. | ClientInvoker | ? ? | 284 - com.fusesource.byexample.cxf-webinars.customer-ws-client - 1.0.0.SNAPSHOT | Got back: status = Active, statusMessage = In the park, playing with my frisbee.
2015-08-20 16:10:18,373 | INFO | qtp432302853-182 | CustomerServiceImpl | ? ? | 283 - com.fusesource.byexample.cxf-webinars.customer-ws-osgi-bundle - 1.0.0.SNAPSHOT | Getting status for customer 1234
2015-08-20 16:10:18,376 | INFO | invoker thread. | ClientInvoker | ? ? | 284 - com.fusesource.byexample.cxf-webinars.customer-ws-client - 1.0.0.SNAPSHOT | Got back: status = Active, statusMessage = In the park, playing with my frisbee.
osgi:list console command. For example:
JBossFuse:karaf@root> list | grep customer-ws-client [ 284] [Active ] [ ] [Started] [ 80] customer-ws-client (1.0.0.SNAPSHOT)
JBossFuse:karaf@root> list | grep customer-ws-client
[ 284] [Active ] [ ] [Started] [ 80] customer-ws-client (1.0.0.SNAPSHOT)
osgi:stop console command. For example:
JBossFuse:karaf@root> stop 284
JBossFuse:karaf@root> stop 284
JBossFuse:karaf@root> shutdown -f
JBossFuse:karaf@root> shutdown -f
Running the other demonstrations Copy linkLink copied to clipboard!
customer-ws-camel-cxf-pojocustomer-ws-camel-cxf-payloadcustomer-ws-camel-cxf-provider
JBossFuse:karaf@root> features:install camel-cxf JBossFuse:karaf@root> features:install camel-velocity
JBossFuse:karaf@root> features:install camel-cxf
JBossFuse:karaf@root> features:install camel-velocity
customer-ws-client client or using the third-party SoapUI utility.
Chapter 35. Java-First Service Implementation Copy linkLink copied to clipboard!
35.1. Java-First Overview Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Service Endpoint Interface (SEI) Copy linkLink copied to clipboard!
@WebService annotation.[1]
- Base type of the Web service implementation (server side)—you define the Web service by implementing the SEI.
- Proxy type (client side)—on the client side, you use the SEI to invoke operations on the client proxy object.
- Basis for generating the WSDL contract—in the Java-first approach, you generate the WSDL contract by converting the SEI to WSDL.
WSDL contract Copy linkLink copied to clipboard!
The CustomerService demonstration Copy linkLink copied to clipboard!
CustomerService Web service using the Java-first approach.
Figure 35.1. Building a Java-First Web Service
Implementing and building the service Copy linkLink copied to clipboard!
- Implement the SEI, which constitutes the basic definition of the Web service's interface.
- Annotate the SEI (you can use the annotations to influence the ultimate form of the generated WSDL contract).
- Implement any other requisite Java classes. In particular, implement the following:
- Any data types referenced by the SEI—for example, the
Customerclass. - The implementation of the SEI,
CustomerServiceImpl.
- Instantiate the Web service endpoint, by adding the appropriate code to a Spring XML file.
- Generate the WSDL contract using a Java-to-WSDL converter.
35.2. Define SEI and Related Classes Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
CustomerService interface, which enables you to access the details of a customer's account.
The CustomerService SEI Copy linkLink copied to clipboard!
CustomerService interface, which defines methods for accessing the Customer data type:
CustomerService interface, this interface provides the basis for defining the CustomerService Web service.
javax.xml.ws.Holder types Copy linkLink copied to clipboard!
getCustomerStatus method from the CustomerService interface has parameters declared to be of javax.xml.ws.Holder<String> type. These so-called holder types are needed in order to declare the OUT or INOUT parameters of a WSDL operation.
getStringValues(), which takes a holder type as its second parameter:
rightWay string as rightWay.value. For example:
Holder<> types in a Java-first example, because this is not a normal Java idiom. But it is interesting to include OUT parameters in the example, so that you can see how a Web service processes this kind of parameter.
Related classes Copy linkLink copied to clipboard!
Default constructor for related classes Copy linkLink copied to clipboard!
The Customer class Copy linkLink copied to clipboard!
Customer class appears as a related class in the definition of the CustomerService SEI (the section called “The CustomerService SEI”). The Customer class consists of a collection of String fields and the only special condition it needs to satisfy is that it includes a default constructor:
35.3. Annotate SEI for JAX-WS Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
serviceName and portName (there can be more than one implementation of a given SEI).
Minimal annotation Copy linkLink copied to clipboard!
@WebService. For example, the CustomerService SEI could be minimally annotated as follows:
@WebService annotation Copy linkLink copied to clipboard!
@WebService annotation without any attributes, it is usually better to specify some attributes to provide a more descriptive WSDL service name and WSDL port name. You will also usually want to specify the XML target namespace. For this, you can specify the following optional attributes of the @WebService annotation:
name- Specifies the name of the WSDL contract (appearing in the
wsdl:definitionselement). serviceName- Specifies the name of the WSDL service (a SOAP service is defined by default in the generated contract).
portName- Specifies the name of the WSDL port (a SOAP/HTTP port is defined by default in the generated contract).
targetNamespace- The XML schema namespace that is used, by default, to qualify the elements and types defined in the contract.
@WebParam annotation Copy linkLink copied to clipboard!
@WebParam annotation to method arguments in the SEI. The @WebParam annotation is optional, but there are a couple of good reasons for adding it:
- By default, JAX-WS maps Java arguments to parameters with names like
arg0, ...,argN. Messages are much easier to read, however, when the parameters have meaningful names. - It is a good idea to define parameter elements without a namespace. This makes the XML encoding of requests and responses more compact.
- To enable support for WSDL OUT and INOUT parameters.
@WebParam annotations with the following attributes:
name- Specifies the mapped name of the parameter.
targetNamespace- Specifies the namespace of the mapped parameter. Set this to a blank string for a more compact XML encoding.
mode- Can have one of the following values:
WebParam.Mode.IN—(default) parameter is passed from client to service (in request).WebParam.Mode.INOUT—parameter is passed from client to service (request) and from the service back to the client (in reply).WebParam.Mode.OUT—parameter is passed from service back to the client (in reply).
OUT and INOUT parameters Copy linkLink copied to clipboard!
- Declare the corresponding Java argument using a
javax.xml.ws.Holder<ParamType>type, whereParamTypeis the type of the parameter you want to send. - Annotate the Java argument with
@WebParam, setting eithermode = WebParam.Mode.OUTormode = WebParam.Mode.INOUT.
Annotated CustomerService SEI Copy linkLink copied to clipboard!
CustomerService SEI after it has been annotated. Many other annotations are possible, but this level of annotation is usually adequate for a WSDL-first project.
35.4. Instantiate the WS Endpoint Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
jaxws:endpoint element in XML. The WS endpoint is effectively the runtime representation of the Web service: it opens an IP port to listen for SOAP/HTTP requests, is responsible for marshalling and unmarshalling messages (making use of the generated Java stub code), and routes incoming requests to the relevant methods on the implementor class.
- Create an instance of the implementor class, using the Spring
beanelement. - Create a WS endpoint, using the
jaxws:endpointelement.
The jaxws:endpoint element Copy linkLink copied to clipboard!
jaxws:endpoint element in a Spring file, where the jaxws: prefix is associated with the http://cxf.apache.org/jaxws namespace.
jaxws:endpoint element with the cxf:cxfEndpoint element, which you meet later in this guide: the jaxws:endpoint element is used to integrate a WS endpoint with a Java implementation class; whereas the cxf:cxfEndpoint is used to integrate a WS endpoint with a Camel route.
Define JAX-WS endpoint in XML Copy linkLink copied to clipboard!
jaxws:endpoint element.
Address for the Jetty container Copy linkLink copied to clipboard!
address attribute of jaxws:endpoint is therefore used to configure the addressing information for the endpoint in the Jetty container.
- Address syntax for default servlet container—to use the default servlet container, specify only the servlet context for this endpoint. Do not specify the protocol, host, and IP port in the address. For example, to deploy the endpoint to the
/Customersservlet context in the default servlet container:address="/Customers"
address="/Customers"Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Address syntax for custom servlet container—to instantiate a custom Jetty container for the endpoint, specify a complete HTTP URL, including the host and IP port (the value of the IP port effectively identifies the target Jetty container). Typically, for a Jetty container, you specify the host as
0.0.0.0, which is interpreted as a wildcard that matches every IP network interface on the local machine (that is, if deployed on a multi-homed host, Jetty opens a listening port on every network card). For example, to deploy the endpoint to the custom Jetty container listening on IP port,8083:address="http://0.0.0.0:8083/Customers"
address="http://0.0.0.0:8083/Customers"Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteIf you want to configure a secure endpoint (secured by SSL), you would specify thehttps:scheme in the address.
Referencing the service implementation Copy linkLink copied to clipboard!
implementor attribute of the jaxws:endpoint element references the implementation of the WS service. The value of this attribute can either be the name of the implementation class or (as in this example) a bean reference in the format, #BeanID, where the # character indicates that the following identifier is the name of a bean in the bean registry.
35.5. Java-to-WSDL Maven Plug-In Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
java2ws command-line utility or the cxf-java2ws-plugin Maven plug-in. The plug-in approach is ideal for Maven-based projects: after you paste the requisite plug-in configuration into your POM file, the WSDL code generation step is integrated into your build.
Configure the Java-to-WSDL Maven plug-in Copy linkLink copied to clipboard!
plugin element into your project's POM file, there are just a few basic settings that need to be customized, as follows:
- CXF version—make sure that the plug-in's dependencies are using the latest version of Apache CXF.
- SEI class name—specify the fully-qualified class name of the SEI in the
configuration/classNameelement. - Location of output—specify the location of the generated WSDL file in the
configuration/outputFileelement.
cxf-java2ws-plugin plug-in to generate WSDL from the CustomerService SEI:
Generated WSDL Copy linkLink copied to clipboard!
outputFile configuration element.
outputFile configuration element, the generated WSDL is sent to the following location, by default:
BaseDir/target/generated/wsdl/SEIClassName.wsdl
BaseDir/target/generated/wsdl/SEIClassName.wsdl
Reference Copy linkLink copied to clipboard!
Chapter 36. WSDL-First Service Implementation Copy linkLink copied to clipboard!
36.1. WSDL-First Overview Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Demonstration location Copy linkLink copied to clipboard!
cxf-webinars-jboss-fuse-6.2.1/customer-ws-osgi-bundle
cxf-webinars-jboss-fuse-6.2.1/customer-ws-osgi-bundle
WSDL contract Copy linkLink copied to clipboard!
Service Endpoint Interface (SEI) Copy linkLink copied to clipboard!
- Base type of the Web service implementation (server side)—you define the Web service by implementing the SEI.
- Proxy type (client side)—on the client side, you use the SEI to invoke operations on the client proxy object.
The CustomerService demonstration Copy linkLink copied to clipboard!
CustomerService Web service using the WSDL-first approach.
Figure 36.1. Building a WSDL-First Web Service
Implementing and building the service Copy linkLink copied to clipboard!
- Create the WSDL contract.
- Generate the Java stub code from the WSDL contract using a WSDL-to-Java converter,
ws2java. This gives you the SEI,CustomerService, and its related classes, such asCustomer. - Write the implementation of the SEI,
CustomerServiceImpl. - Instantiate the Web service endpoint, by adding the appropriate code to a Spring XML file.
36.2. CustomerService WSDL Contract Copy linkLink copied to clipboard!
Sample WSDL contract Copy linkLink copied to clipboard!
CustomerService WSDL contract, which is available in the following location:
cxf-webinars-jboss-fuse-6.2.1/src/main/resources/wsdl
cxf-webinars-jboss-fuse-6.2.1/src/main/resources/wsdl
CustomerSerivice WSDL contract exposes the following operations:
lookupCustomer- Given a customer ID, the operation returns the corresponding
Customerdata object. updateCustomer- Stores the given
Customerdata object against the given customer ID. getCustomerStatus- Returns the status of the customer with the given customer ID.
Parts of the WSDL contract Copy linkLink copied to clipboard!
Port type Copy linkLink copied to clipboard!
wsdl:portType element. It is analogous to an interface and it defines the operations that can be invoked on the Web service.
wsdl:portType definition from the CustomerService WSDL contract:
WSDL binding Copy linkLink copied to clipboard!
WSDL port Copy linkLink copied to clipboard!
CustomerService WSDL contract defines the following WSDL port:
soap:address element's location attribute in the original WSDL contract is typically overridden at run time, however.
The getCustomerStatus operation Copy linkLink copied to clipboard!
getCustomerStatus operation has its request parameters (IN parameters) encoded by the getCustomerStatus element and its response parameters (OUT parameters) encoded by the getCustomerStatusResponse element, as follows:
References Copy linkLink copied to clipboard!
36.3. WSDL-to-Java Maven Plug-In Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
ws2java command-line utility or the cxf-codegen-plugin Maven plug-in. The plug-in approach is ideal for Maven-based projects: after you paste the requisite plug-in configuration into your POM file, the WSDL-to-Java code generation step is integrated into your build.
Configure the WSDL-to-Java Maven plug-in Copy linkLink copied to clipboard!
plugin element into your project's POM file, there are just a few basic settings that need to be customized, as follows:
- CXF version—make sure that the plug-in's dependencies are using the latest version of Apache CXF.
- WSDL file location—specify the WSDL file location in the
configuration/wsdlOptions/wsdlOption/wsdlelement. - Location of output—specify the root directory of the generated Java source files in the
configuration/sourceRootelement.
cxf-codegen-plugin plug-in to generate Java stub code from the CustomerService.wsdl WSDL file:
Generated Java source code Copy linkLink copied to clipboard!
target/generated-sources/jaxws directory. Note that the Web service implementation is dependent on this generated stub code—for example, the service implementation class must implement the generated CustomerService SEI.
Adding the generated source to an IDE Copy linkLink copied to clipboard!
target/generated-sources/jaxws directory to the project as a source code directory.
Compiling the generated code Copy linkLink copied to clipboard!
BaseDir/target/generated-sources/
BaseDir/target/generated-sources/
Reference Copy linkLink copied to clipboard!
36.4. Instantiate the WS Endpoint Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
jaxws:endpoint element in XML. The WS endpoint is effectively the runtime representation of the Web service: it opens an IP port to listen for SOAP/HTTP requests, is responsible for marshalling and unmarshalling messages (making use of the generated Java stub code), and routes incoming requests to the relevant methods on the implementor class.
- Create an instance of the implementor class, using the Spring
beanelement. - Create a WS endpoint, using the
jaxws:endpointelement.
Define JAX-WS endpoint in XML Copy linkLink copied to clipboard!
jaxws:endpoint element.
Address for the Jetty container Copy linkLink copied to clipboard!
address attribute of the jaxws:endpoint element specifies the servlet context for this endpoint, relative to the Jetty container in which it is deployed.
Referencing the service implementation Copy linkLink copied to clipboard!
implementor attribute of the jaxws:endpoint element is used to reference the implementation of the WS service. The value of this attribute can either be the name of the implementation class or (as in this example) a bean reference in the format, #BeanID, where the # character indicates that the following identifier is the name of a bean in the bean registry.
36.5. Deploy to an OSGi Container Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Bundles are a relatively lightweight deployment option (because dependencies can be shared between deployed bundles).
- OSGi provides sophisticated dependency management, ensuring that only version-consistent dependencies are added to the bundle's classpath.
Using the Maven bundle plug-in Copy linkLink copied to clipboard!
pom.xml file:
- Change the packaging type to
bundle(by editing the value of theproject/packagingelement in the POM). - Add the Maven bundle plug-in to your POM file and configure it as appropriate.
Sample bundle plug-in configuration Copy linkLink copied to clipboard!
Dynamic imports Copy linkLink copied to clipboard!
DynamicImport-Package element). This is a pragmatic way of dealing with the fact that Spring XML files are not terribly well integrated with the Maven bundle plug-in. At build time, the Maven bundle plug-in is not able to figure out which Java classes are required by the Spring XML code. By listing wildcarded package names in the DynamicImport-Package element, however, you allow the OSGi container to figure out which Java classes are needed by the Spring XML code at run time.
DynamicImport-Package headers is not recommended in OSGi, because it short-circuits OSGi version checking. Normally, what should happen is that the Maven bundle plug-in lists the Java packages used at build time, along with their versions, in the Import-Package header. At deploy time, the OSGi container then checks that the available Java packages are compatible with the build-time versions listed in the Import-Package header. With dynamic imports, this version checking cannot be performed.
Build and deploy the service bundle Copy linkLink copied to clipboard!
mvn install
mvn install
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-osgi-bundle
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-osgi-bundle
org.ops4j.pax.url.mvn.localRepository property in the EsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before you can use the mvn: scheme to access Maven artifacts.
Red Hat JBoss Fuse default servlet container Copy linkLink copied to clipboard!
cxf/. Hence, any WS endpoint whose address attribute is configured in the jaxws:endpoint element as /EndpointContext will have the following effective address:
http://Hostname:8181/cxf/EndpointContext
http://Hostname:8181/cxf/EndpointContext
InstallDir/etc/org.ops4j.pax.web.cfg
InstallDir/etc/org.ops4j.pax.web.cfg
Check that the service is running Copy linkLink copied to clipboard!
http://localhost:8181/cxf/Customer?wsdl
http://localhost:8181/cxf/Customer?wsdl
Chapter 37. Implementing a WS Client Copy linkLink copied to clipboard!
37.1. WS Client Overview Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
jaxws:client element in Spring XML.
Demonstration location Copy linkLink copied to clipboard!
cxf-webinars-jboss-fuse-6.2.1/customer-ws-client
cxf-webinars-jboss-fuse-6.2.1/customer-ws-client
WSDL contract Copy linkLink copied to clipboard!
Service Endpoint Interface (SEI) Copy linkLink copied to clipboard!
WS client proxy Copy linkLink copied to clipboard!
The CustomerService client Copy linkLink copied to clipboard!
customer-ws-client demonstration, which is available from the following location:
cxf-webinars-jboss-fuse-6.2.1/customer-ws-client
cxf-webinars-jboss-fuse-6.2.1/customer-ws-client
Figure 37.1. Building a WS Client
Implementing and building the WS client Copy linkLink copied to clipboard!
- Obtain a copy of the WSDL contract.
- Generate the Java stub code from the WSDL contract using a WSDL-to-Java converter,
ws2java. This gives you the SEI,CustomerService, and its related classes, such asCustomer. - Implement the main client class,
ClientInvoker, which invokes the Web service operations. In this class define a bean property of type,CustomerService, so that the client class can receive a reference to the WS client proxy by property injection. - In a Spring XML file, instantiate the WS client proxy and inject it into the main client class,
ClientInvoker.
37.2. WSDL-to-Java Maven Plug-In Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
ws2java command-line utility or the cxf-codegen-plugin Maven plug-in. When using Maven, the plug-in approach is ideal: after you paste the requisite plug-in configuration into your POM file, the WSDL-to-Java code generation step is integrated into your build.
Configure the WSDL-to-Java Maven plug-in Copy linkLink copied to clipboard!
plugin element into your project's POM file, there are just a few basic settings that need to be customized, as follows:
- CXF version—make sure that the plug-in's dependencies are using the latest version of Apache CXF.
- WSDL file location—specify the WSDL file location in the
configuration/wsdlOptions/wsdlOption/wsdlelement. - Location of output—specify the root directory of the generated Java source files in the
configuration/sourceRootelement.
cxf-codegen-plugin plug-in to generate Java stub code from the CustomerService.wsdl WSDL file:
Generated Java source code Copy linkLink copied to clipboard!
target/generated-sources/jaxws directory. Note that the client implementation is dependent on this generated stub code—for example, the client invokes the proxy using the generated CustomerService SEI.
Add generated source to IDE Copy linkLink copied to clipboard!
target/generated-sources/jaxws directory to the project as a source code directory.
Compiling the generated code Copy linkLink copied to clipboard!
BaseDir/target/generated-sources/
BaseDir/target/generated-sources/
Reference Copy linkLink copied to clipboard!
37.3. Instantiate the WS Client Proxy Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
jaxws:client element.
Define the WS client in XML Copy linkLink copied to clipboard!
jaxws:client element.
The jaxws:client element Copy linkLink copied to clipboard!
jaxws:client element creates a client proxy dynamically (that is, there is no dedicated class that represents a proxy implementation in the Java stub code). The following attributes are used to define the proxy:
-
id - The ID that you specify here is entered in the bean registry and can be used to reference the proxy instance from other beans.
-
address - The full address of the remote Web service that this proxy connects to.
-
serviceClass - The fully-qualified class name of the Web service's SEI (you invoke methods on the proxy through the SEI).
Injecting with the proxy reference Copy linkLink copied to clipboard!
customerServiceProxy, you can inject it into a bean property using the Spring property element, as follows:
<bean ...> <property name="customerService" ref="customerServiceProxy"/> </bean>
<bean ...>
<property name="customerService" ref="customerServiceProxy"/>
</bean>
setCustomerService setter method—for example:
37.4. Invoke WS Operations Copy linkLink copied to clipboard!
Proxy interface is SEI interface Copy linkLink copied to clipboard!
Invoking the lookupCustomer operation Copy linkLink copied to clipboard!
CustomerService SEI exposes the lookupCustomer method, which takes a customer ID as its argument and returns a Customer data object. Using the proxy instance, customerService, you can invoke the lookupCustomer operation as follows:
The ClientInvoker class Copy linkLink copied to clipboard!
cxf-webinars-jboss-fuse-6.2.1/customer-ws-client project, there is a ClientInvoker class (located in src/main/java/com/fusesource/customer/client), which defines a continuous loop that invokes the lookupCustomer operation.
ClientInvoker class, possibly adding operation invocations.
37.5. Deploy to an OSGi Container Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Bundles are a relatively lightweight deployment option (because dependencies can be shared between deployed bundles).
- OSGi provides sophisticated dependency management, ensuring that only version-consistent dependencies are added to the bundle's classpath.
Using the Maven bundle plug-in Copy linkLink copied to clipboard!
pom.xml file:
- Change the packaging type to
bundle(by editing the value of theproject/packagingelement in the POM). - Add the Maven bundle plug-in to your POM file and configure it as appropriate.
Sample bundle plug-in configuration Copy linkLink copied to clipboard!
Dynamic imports Copy linkLink copied to clipboard!
DynamicImport-Package element). This is a pragmatic way of dealing with the fact that Spring XML files are not terribly well integrated with the Maven bundle plug-in. At build time, the Maven bundle plug-in is not able to figure out which Java classes are required by the Spring XML code. By listing wildcarded package names in the DynamicImport-Package element, however, you allow the OSGi container to figure out which Java classes are needed by the Spring XML code at run time.
DynamicImport-Package headers is not recommended in OSGi, because it short-circuits OSGi version checking. Normally, what should happen is that the Maven bundle plug-in lists the Java packages used at build time, along with their versions, in the Import-Package header. At deploy time, the OSGi container then checks that the available Java packages are compatible with the build time versions listed in the Import-Package header. With dynamic imports, this version checking cannot be performed.
Build and deploy the client bundle Copy linkLink copied to clipboard!
mvn install
mvn install
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-client
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-client
org.ops4j.pax.url.mvn.localRepository property in the EsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before you can use the mvn: scheme to access Maven artifacts.
Check that the client is running Copy linkLink copied to clipboard!
karaf@root> log:display -n 10
karaf@root> log:display -n 10
Chapter 38. Pojo-Based Route Copy linkLink copied to clipboard!
38.1. Processing Messages in POJO Format Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- The big advantage of the POJO data format is that the operation parameters are encoded using the JAXB standard, which makes them easy to manipulate in Java.
- The downside of the POJO data format, on the other hand, is that it requires that the WSDL metadata is converted to Java in advance (as defined by the JAX-WS and JAXB mappings) and compiled into your application. This means that a POJO-based route is not very dynamic.
Demonstration location Copy linkLink copied to clipboard!
cxf-webinars-jboss-fuse-6.2.1/customer-ws-camel-cxf-pojo
cxf-webinars-jboss-fuse-6.2.1/customer-ws-camel-cxf-pojo
Camel CXF component Copy linkLink copied to clipboard!
cxf:cxfEndpoint XML element and are implemented by the Apache Camel project—are not to be confused with the Apache CXF JAX-WS endpoints—which are instantiated using the jaxws:endpoint XML element and are implemented by the Apache CXF project.
POJO data format Copy linkLink copied to clipboard!
- JAX-WS and JAXB stub code (as generated from the WSDL contract) must be provided.
- The SOAP body is marshalled into a list of Java objects.
- One Java object for each part or parameter of the corresponding WSDL operation.
- The type of the message body is
org.apache.cxf.message.MessageContentsList.
- The SOAP headers are converted into headers in the exchange's In message.
Implementing and building a POJO route Copy linkLink copied to clipboard!
- Obtain a copy of the WSDL contract that is to be integrated into the route.
- Generate the Java stub code from the WSDL contract using a WSDL-to-Java converter. This gives you the SEI,
CustomerService, and its related classes, such asCustomer. - Instantiate the Camel CXF endpoint in Spring, using the
cxf:cxfEndpointelement. - Implement the route in XML, where you can use the content-based router to sort requests by operation name.
- Implement the operation processor beans, which are responsible for processing each operation. When implementing these beans, the message contents must be accessed in POJO data format.
Sample POJO route Copy linkLink copied to clipboard!
CustomerService Web service using the POJO data format. After sorting the request messages by operation name, an operation-specific processor bean reads the incoming request parameters and then generates a response in the POJO data format.
Figure 38.1. Sample POJO Route
38.2. WSDL-to-Java Maven Plug-In Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
ws2java command-line utility or the cxf-codegen-plugin Maven plug-in. When using Maven, the plug-in approach is ideal: after you paste the requisite plug-in configuration into your POM file, the WSDL-to-Java code generation step is integrated into your build.
Configure the WSDL-to-Java Maven plug-in Copy linkLink copied to clipboard!
plugin element into your project's POM file, there are just a few basic settings that need to be customized, as follows:
- CXF version—make sure that the plug-in's dependencies are using the latest version of Apache CXF.
- WSDL file location—specify the WSDL file location in the
configuration/wsdlOptions/wsdlOption/wsdlelement. - Location of output—specify the root directory of the generated Java source files in the
configuration/sourceRootelement.
cxf-codegen-plugin plug-in to generate Java stub code from the CustomerService.wsdl WSDL file:
Generated Java source code Copy linkLink copied to clipboard!
target/generated-sources/jaxws directory. Note that the route is dependent on this generated stub code—for example, when processing the POJO parameters, the parameter processor uses the Customer data type from the stub code.
Add generated code to IDE Copy linkLink copied to clipboard!
target/generated-sources/jaxws directory to the project as a source code directory.
Compiling the generated code Copy linkLink copied to clipboard!
BaseDir/target/generated-sources/
BaseDir/target/generated-sources/
Reference Copy linkLink copied to clipboard!
38.3. Instantiate the WS Endpoint Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Consumer—(at the start of a route) represents a Web service instance, which integrates with the route. The type of payload injected into the route depends on the value of the endpoint's
dataFormatoption. - Producer—(at other points in the route) represents a WS client proxy, which converts the current exchange object into an operation invocation on a remote Web service. The format of the current exchange must match the endpoint's
dataFormatsetting.
dataFormat option set to POJO.
Maven dependency Copy linkLink copied to clipboard!
camel-cxf component in your Maven POM. For example, the pom.xml file from the customer-ws-camel-cxf-pojo demonstration project includes the following dependency:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>${camel-version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>${camel-version}</version>
</dependency>
The cxf:bean: URI syntax Copy linkLink copied to clipboard!
cxf:bean: URI is used to bind an Apache CXF endpoint to a route and has the following general syntax:
cxf:bean:CxfEndpointID[?Options]
cxf:bean:CxfEndpointID[?Options]
CxfEndpointID is the ID of a bean created using the cxf:cxfEndpoint element, which configures the details of the WS endpoint. You can append options to this URI (where the options are described in detail in chapter "CXF" in "Apache Camel Component Reference"). If you do not specify any additional options, the endpoint uses the POJO data format by default.
customer-ws, define the route as follows:
<route>
<from uri="cxf:bean:customer-ws"/>
...
</route>
<route>
<from uri="cxf:bean:customer-ws"/>
...
</route>
cxf://WsAddress[?Options], which enables you to specify all of the WS endpoint details in the URI (so there is no need to reference a bean instance). This typically results in a long and cumbersome URI, but is useful in some cases.
The cxf:cxfEndpoint element Copy linkLink copied to clipboard!
cxf:cxfEndpoint element is used to define a WS endpoint that binds either to the start (consumer endpoint) or the end (producer endpoint) of a route. For example, to define the customer-ws WS endpoint referenced in the preceding route, you would define a cxf:cxfEndpoint element as follows:
cxf:cxfEndpoint element and the jaxws:endpoint element use different XML schemas (although the syntax looks superficially similar). These elements bind a WS endpoint in different ways: the cxf:cxfEndpoint element instantiates and binds a WS endpoint to an Apache Camel route, whereas the jaxws:endpoint element instantiates and binds a WS endpoint to a Java class using the JAX-WS mapping.
Address for the Jetty container Copy linkLink copied to clipboard!
address attribute of cxf:cxfEndpoint is therefore used to configure the addressing information for the endpoint in the Jetty container.
- Address syntax for default servlet container—to use the default servlet container, specify only the servlet context for this endpoint. Do not specify the protocol, host, and IP port in the address. For example, to deploy the endpoint to the
/Customerservlet context in the default servlet container:address="/Customer"
address="/Customer"Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Address syntax for custom servlet container—to instantiate a custom Jetty container for this endpoint, specify a complete HTTP URL, including the host and IP port (the value of the IP port effectively identifies the target Jetty container). Typically, for a Jetty container, you specify the host as
0.0.0.0, which is interpreted as a wildcard that matches every IP network interface on the local machine (that is, if deployed on a multi-homed host, Jetty opens a listening port on every network card). For example, to deploy the endpoint to the custom Jetty container listening on IP port,8083:address="http://0.0.0.0:8083/Customer"
address="http://0.0.0.0:8083/Customer"Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteIf you want to configure a secure endpoint (secured by SSL), you would specify thehttps:scheme in the address.
Referencing the SEI Copy linkLink copied to clipboard!
serviceClass attribute of the cxf:cxfEndpoint element references the SEI of the Web service, which in this case is the CustomerService interface.
38.4. Sort Messages by Operation Name Copy linkLink copied to clipboard!
The operationName header Copy linkLink copied to clipboard!
operationName header to the name of the invoked operation. You can then use this header to sort messages by operation name.
Sorting by operation name Copy linkLink copied to clipboard!
customer-ws-camel-cxf-pojo demonstration defines the following route, which uses the content-based router pattern to sort incoming messages, based on the operation name. The when predicates check the value of the operationName header using simple language expressions, sorting messages into invocations on the updateCustomer operation, the lookupCustomer operation, or the getCustomerStatus operation.
Beans as endpoints Copy linkLink copied to clipboard!
choice DSL to a different processor bean. The DSL for sending exchanges to producer endpoints (for example, <to uri="Destination"/>) is integrated with the bean registry: if the Destination does not resolve to an endpoint or a component, the Destination is used as a bean ID to look up the bean registry. In this example, the exchange is routed to processor beans (which implement the org.apache.camel.Processor interface).
38.5. Process Operation Parameters Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Contents of request message body Copy linkLink copied to clipboard!
org.apache.cxf.message.MessageContentsList object. You can also obtain the message body as an Object[] array (where type conversion is automatic).
Object[] array, the array contains the list of all the operation's IN, INOUT, and OUT parameters in exactly the same order as defined in the WSDL contract (and in the same order as the corresponding operation signature of the SEI). The parameter mode affects the content as follows:
IN- Contains a parameter value from the client.
INOUT- Contains a
Holderobject containing a parameter value from the client. OUT- Contains an empty
Holderobject, which is a placeholder for the response.
Object[] array to represent a return value.
Contents of response message body Copy linkLink copied to clipboard!
org.apache.cxf.message.MessageContentsList object or an Object[] array.
Object[] array, the array should contain only the operation's INOUT and OUT parameters in the same order as defined in the WSDL contract, omitting the IN parameters. The parameter mode affects the content as follows:
INOUT- Contains a
Holderobject, which you must set to a response value. TheHolderobject used here must be exactly theHolderobject for the corresponding parameter that was extracted from the requestObject[]array. Creating and inserting a newHolderobject into theObject[]array does not work. OUT- Contains a
Holderobject, which you must initialize with a response value. TheHolderobject used here must be exactly theHolderobject for the corresponding parameter that was extracted from the requestObject[]array. Creating and inserting a newHolderobject into theObject[]array does not work.
Object[] array. The return type is set as a plain object: it does not use a Holder object.
Example: getCustomerStatus operation Copy linkLink copied to clipboard!
getCustomerStatus operation takes three parameters: IN, OUT, and OUT, respectively. The corresponding method signature in the SEI is, as follows:
Example: request and response bodies Copy linkLink copied to clipboard!
getCustomerStatus operation, the bodies of the request message and the response message have the following contents:
- Request message—as an
Object[]array type, the contents are:{ String customerId, Holder<String> status, Holder<String> statusMessage }. - Response message—as an
Object[]array type, the contents are:{Holder<String> status, Holder<String> statusMessage }
Example: processing getCustomerStatus Copy linkLink copied to clipboard!
GetCustomerStatusProcessor class is responsible for processing incoming getCustomerStatus invocations. The following sample implementation for POJO mode shows how to read the request parameters from the In message body and then set the response parameters in the Out message body.
38.6. Deploy to OSGi Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Bundles are a relatively lightweight deployment option (because dependencies can be shared between deployed bundles).
- OSGi provides sophisticated dependency management, ensuring that only version-consistent dependencies are added to the bundle's classpath.
Using the Maven bundle plug-in Copy linkLink copied to clipboard!
pom.xml file:
- Change the packaging type to
bundle(by editing the value of theproject/packagingelement in the POM). - Add the Maven bundle plug-in to your POM file and configure it as appropriate.
Sample bundle plug-in configuration Copy linkLink copied to clipboard!
Dynamic imports Copy linkLink copied to clipboard!
DynamicImport-Package element). This is a pragmatic way of dealing with the fact that Spring XML files are not terribly well integrated with the Maven bundle plug-in. At build time, the Maven bundle plug-in is not able to figure out which Java classes are required by the Spring XML code. By listing wildcarded package names in the DynamicImport-Package element, however, you allow the OSGi container to figure out which Java classes are needed by the Spring XML code at run time.
DynamicImport-Package headers is not recommended in OSGi, because it short-circuits OSGi version checking. Normally, what should happen is that the Maven bundle plug-in lists the Java packages used at build time, along with their versions, in the Import-Package header. At deploy time, the OSGi container then checks that the available Java packages are compatible with the build time versions listed in the Import-Package header. With dynamic imports, this version checking cannot be performed.
Build and deploy the POJO route bundle Copy linkLink copied to clipboard!
mvn install
mvn install
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-camel-cxf-pojo
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-camel-cxf-pojo
org.ops4j.pax.url.mvn.localRepository property in the EsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before you can use the mvn: scheme to access Maven artifacts.
Chapter 39. Payload-Based Route Copy linkLink copied to clipboard!
39.1. Processing Messages in PAYLOAD Format Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.w3c.dom.Node type). One of the advantages of the PAYLOAD format is that no JAX-WS and JAXB stub code is required, which allows your application to be dynamic, potentially handling many different WSDL interfaces.
Demonstration location Copy linkLink copied to clipboard!
cxf-webinars-jboss-fuse-6.2.1/customer-ws-camel-cxf-payload
cxf-webinars-jboss-fuse-6.2.1/customer-ws-camel-cxf-payload
Camel CXF component Copy linkLink copied to clipboard!
cxf:cxfEndpoint XML element and are implemented by the Apache Camel project—are not to be confused with the Apache CXF JAX-WS endpoints—which are instantiated using the jaxws:endpoint XML element and are implemented by the Apache CXF project.
PAYLOAD data format Copy linkLink copied to clipboard!
dataFormat=PAYLOAD option on a Camel CXF endpoint URI and it has the following characteristics:
- Enables you to access the message body as a DOM object (XML payload).
- No JAX-WS or JAXB stub code required.
- The SOAP body is marshalled as follows:
- The message body is effectively an XML payload of
org.w3c.dom.Nodetype (wrapped in aCxfPayloadobject). - The type of the message body is
org.apache.camel.component.cxf.CxfPayload.
- The SOAP headers are converted into headers in the exchange's In message, of
org.apache.cxf.binding.soap.SoapHeadertype.
Implementing and building a PAYLOAD route Copy linkLink copied to clipboard!
- Instantiate the Camel CXF endpoint in Spring, using the
cxf:cxfEndpointelement. - Implement the route in XML, where you can use the content-based router to sort requests by operation name.
- For each operation, define a processor bean to process the request.
- Define velocity templates for generating the reponse messages.
Sample PAYLOAD route Copy linkLink copied to clipboard!
CustomerService Web service using the PAYLOAD data format. After sorting the request messages by operation name, an operation-specific processor bean reads the incoming request parameters. Finally, the response messages are generated using Velocity templates.
Figure 39.1. Sample PAYLOAD Route
39.2. Instantiate the WS Endpoint Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Consumer endpoint—(at the start of a route) represents a Web service instance, which integrates with the route. The type of payload injected into the route depends on the value of the endpoint's
dataFormatoption. - Producer endpoint—represents a special kind of WS client proxy, which converts the current exchange object into an operation invocation on a remote Web service. The format of the current exchange must match the endpoint's
dataFormatsetting.
The cxf:bean: URI syntax Copy linkLink copied to clipboard!
cxf:bean: URI is used to bind an Apache CXF endpoint to a route and has the following general syntax:
cxf:bean:CxfEndpointID[?Options]
cxf:bean:CxfEndpointID[?Options]
CxfEndpointID is the ID of a bean created using the cxf:cxfEndpoint element, which configures the details of the WS endpoint. You can append options to this URI (where the options are described in detail in CXF in the Apache Camel Component Reference Guide ). To enable payload mode, you must set the URI option, dataFormat=PAYLOAD.
customer-ws bean, define the route as follows:
<route>
<from uri="cxf:bean:customer-ws?dataFormat=PAYLOAD"/>
...
</route>
<route>
<from uri="cxf:bean:customer-ws?dataFormat=PAYLOAD"/>
...
</route>
The cxf:cxfEndpoint element Copy linkLink copied to clipboard!
cxf:cxfEndpoint element is used to define a WS endpoint that binds either to the start (consumer endpoint) or the end (producer endpoint) of a route. For example, to define the customer-ws WS endpoint in PAYLOAD mode, you define a cxf:cxfEndpoint element as follows:
Address for the Jetty container Copy linkLink copied to clipboard!
address attribute of cxf:cxfEndpoint is therefore used to configure the addressing information for the endpoint in the Jetty container.
- Address syntax for default servlet container—to use the default servlet container, specify only the servlet context for this endpoint. Do not specify the protocol, host, and IP port in the address. For example, to deploy the endpoint to the
/Customerservlet context in the default servlet container:address="/Customer"
address="/Customer"Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Address syntax for custom servlet container—to instantiate a custom Jetty container for this endpoint, specify a complete HTTP URL, including the host and IP port (the value of the IP port effectively identifies the target Jetty container). Typically, for a Jetty container, you specify the host as
0.0.0.0, which is interpreted as a wildcard that matches every IP network interface on the local machine (that is, if deployed on a multi-homed host, Jetty opens a listening port on every network card). For example, to deploy the endpoint to the custom Jetty container listening on IP port,8083:address="http://0.0.0.0:8083/Customer"
address="http://0.0.0.0:8083/Customer"Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteIf you want to configure a secure endpoint (secured by SSL), you would specify thehttps:scheme in the address.
Specifying the WSDL location Copy linkLink copied to clipboard!
wsdlURL attribute of the cxf:cxfEndpoint element is used to specify the location of the WSDL contract for this endpoint. The WSDL contract is used exclusively as the source of metadata for this endpoint: there is need to specify an SEI in PAYLOAD mode.
39.3. Sort Messages by Operation Name Copy linkLink copied to clipboard!
The operationName header Copy linkLink copied to clipboard!
operationName header to the name of the invoked operation. You can then use this header to sort messages by operation name.
Sorting by operation name Copy linkLink copied to clipboard!
customer-ws-camel-cxf-payload demonstration defines the following route, which uses the content-based router pattern to sort incoming messages, based on the operation name. The when predicates check the value of the operationName header using simple language expressions, sorting messages into invocations on the updateCustomer operation, the lookupCustomer operation, or the getCustomerStatus operation.
39.4. SOAP/HTTP-to-JMS Bridge Use Case Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 39.2. SOAP/HTTP-to-JMS Bridge
Transforming RPC operations to One Way Copy linkLink copied to clipboard!
- The WS client invokes a synchronous operation on the Camel CXF endpoint at the start of the route. The Camel CXF endpoint then creates an initial InOut exchange at the start of the route, where the body of the exchange message contains a payload in XML format.
- The
inOnlyDSL command pushes a copy of the XML payload onto a JMS queue, so that it can be processed offline at some later time. - The
transformDSL command constructs an immediate response to send back to the client, where the response has the form of an XML string. - The Camel CXF component supports implicit type conversion of the XML string to payload format.
- The response is sent back to the WS client, thus completing the synchronous operation invocation.
Creating a broker instance Copy linkLink copied to clipboard!
amq:broker element in the Spring XML file, as follows:
persistent attribute set to false, so that the messages are stored only in memory.
Configuring the JMS component Copy linkLink copied to clipboard!
id value of activemq, you are implicitly overriding the component associated with the endpoint URI prefix, activemq:. In other words, your custom ActiveMQComponent instance is used instead of the default ActiveMQComponent instance from the camel-activemq JAR file.
Sample SOAP/HTTP-to-JMS route Copy linkLink copied to clipboard!
updateCustomer operation from the CustomerService SEI, as follows:
Sending to the JMS endpoint in inOnly mode Copy linkLink copied to clipboard!
inOnly DSL command instead of the to DSL command. When you send a message using the to DSL command, the default behavior is to use the same invocation mode as the current exchange. But the current exchange has an InOut MEP, which means that the to DSL command would wait forever for a response message from JMS.
inOnly DSL command into the route.
jmsMessageType=Text, Camel CXF implicitly converts the message payload to an XML string before pushing it onto the JMS queue.
Returning a literal response value Copy linkLink copied to clipboard!
transform DSL command uses an expression to set the body of the exchange's Out message and this message is then used as the response to the client. Your first impulse when defining a response in XML format might be to use a DOM API, but in this example, the response is specified as a string literal. This approach has the advantage of being both efficient and very easy to program.
39.5. Generating Responses Using Templates Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 39.3. Response Generated by Velocity
Sample template-based route Copy linkLink copied to clipboard!
getCustoemrStatus operation, as follows:
Route processing steps Copy linkLink copied to clipboard!
getCustomerStatus would be processed as follows:
- To facilitate processing the payload body, the first step uses
convertBodyToto convert the body type fromorg.apache.camel.component.cxf.CxfPayload(the default payload type) toorg.w3c.dom.Node. - The route then applies an XPath expression to the message in order to extract the customer ID value and then stashes it in the
customerIdheader. - The next step sends the message to the
getCustomerStatusbean, which does whatever processing is required to get the customer status for the specified customer ID. The results from this step are stashed in message headers. - Finally, a response is generated using a velocity template.
Converting XPath result to a string Copy linkLink copied to clipboard!
- Specify the result type explicitly using the
resultTypeattribute, as follows:<xpath resultType="java.lang.String">/cus:getCustomerStatus/customerId</xpath>
<xpath resultType="java.lang.String">/cus:getCustomerStatus/customerId</xpath>Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Modify the expression so that it returns a
text()node, which automatically converts to string:<xpath>/cus:getCustomerStatus/customerId/text()</xpath>
<xpath>/cus:getCustomerStatus/customerId/text()</xpath>Copy to Clipboard Copied! Toggle word wrap Toggle overflow
getCustomerStatus processor bean Copy linkLink copied to clipboard!
getCustomerStatus processor bean is an instance of the GetCustomerStatus processor class, which is defined as follows:
status and statusMessage are simply set to constant values and stashed in message headers.
null, the next processor in the route gets a copy of the current In message instead
null.
getCustomerStatusResponse.vm Velocity template Copy linkLink copied to clipboard!
${header.HeaderName} substitutes the value of a named header.
getCustomerStatus reponse is located in the customer-ws-camel-cxf-payload/src/main/resources directory and it contains the following template script:
<ns2:getCustomerStatusResponse xmlns:ns2="http://demo.fusesource.com/wsdl/CustomerService/">
<status>${headers.status}</status>
<statusMessage>${headers.statusMessage}</statusMessage>
</ns2:getCustomerStatusResponse>
<ns2:getCustomerStatusResponse xmlns:ns2="http://demo.fusesource.com/wsdl/CustomerService/">
<status>${headers.status}</status>
<statusMessage>${headers.statusMessage}</statusMessage>
</ns2:getCustomerStatusResponse>
39.6. TypeConverter for CXFPayload Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
String objects to CXFPayload objects. This type converter automatically gets invoked at the end of the Camel route, when the generated response message (which is a String type) gets converted into a CXFPayload object.
String to CXFPayload type converter Copy linkLink copied to clipboard!
String to CXFPayload type converter is implemented in the AdditionalCxfPayloadConverters class, as follows:
Reference Copy linkLink copied to clipboard!
39.7. Deploy to OSGi Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Bundles are a relatively lightweight deployment option (because dependencies can be shared between deployed bundles).
- OSGi provides sophisticated dependency management, ensuring that only version-consistent dependencies are added to the bundle's classpath.
Using the Maven bundle plug-in Copy linkLink copied to clipboard!
pom.xml file:
- Change the packaging type to
bundle(by editing the value of theproject/packagingelement in the POM). - Add the Maven bundle plug-in to your POM file and configure it as appropriate.
Sample bundle plug-in configuration Copy linkLink copied to clipboard!
Dynamic imports Copy linkLink copied to clipboard!
DynamicImport-Package element). This is a pragmatic way of dealing with the fact that Spring XML files are not terribly well integrated with the Maven bundle plug-in. At build time, the Maven bundle plug-in is not able to figure out which Java classes are required by the Spring XML code. By listing wildcarded package names in the DynamicImport-Package element, however, you allow the OSGi container to figure out which Java classes are needed by the Spring XML code at run time.
DynamicImport-Package headers is not recommended in OSGi, because it short-circuits OSGi version checking. Normally, what should happen is that the Maven bundle plug-in lists the Java packages used at build time, along with their versions, in the Import-Package header. At deploy time, the OSGi container then checks that the available Java packages are compatible with the build time versions listed in the Import-Package header. With dynamic imports, this version checking cannot be performed.
Build and deploy the client bundle Copy linkLink copied to clipboard!
mvn install
mvn install
camel-velocity feature, which is needed for this example:
karaf@root> features:install camel-velocity
karaf@root> features:install camel-velocity
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-camel-cxf-payload
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-camel-cxf-payload
org.ops4j.pax.url.mvn.localRepository property in the InstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before you can use the mvn: scheme to access Maven artifacts.
Chapter 40. Provider-Based Route Copy linkLink copied to clipboard!
40.1. Provider-Based JAX-WS Endpoint Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
SAXSource. Since the XMLstreaming types are more efficient than DOM objects, the provider-based approach is ideal for large XML messages.
Demonstration location Copy linkLink copied to clipboard!
cxf-webinars-jboss-fuse-6.2.1/customer-ws-camel-cxf-provider
cxf-webinars-jboss-fuse-6.2.1/customer-ws-camel-cxf-provider
Camel CXF component Copy linkLink copied to clipboard!
cxf:cxfEndpoint XML element and are implemented by the Apache Camel project—are not to be confused with the Apache CXF JAX-WS endpoints—which are instantiated using the jaxws:endpoint XML element and are implemented by the Apache CXF project.
Provider-based approach and the PAYLOAD data format Copy linkLink copied to clipboard!
- Define a custom
javax.xml.ws.Provider<StreamType>class, where the StreamType type is an XML streaming type, such asSAXSource. - The PAYLOAD data format is selected by an annotation on the custom
Provider<?>class (see the section called “The SAXSourceService provider class”). - The custom
Provider<?>class is referenced by setting theserviceClassattribute of thecxf:cxfEndpointelement in XML configuration.
- Enables you to access the message body as a streamed XML type—for example,
javax.xml.transform.sax.SAXSource. - No JAX-WS or JAXB stub code required.
- The SOAP body is marshalled into a stream-based
SAXSourcetype. - The SOAP headers are converted into headers in the exchange's In message, of
org.apache.cxf.binding.soap.SoapHeadertype.
Implementing and building a provider-based route Copy linkLink copied to clipboard!
- Define a custom
javax.xml.ws.Provider<StreamType>class (the current demonstration usesSAXSourceas the StreamType type). - Instantiate the Camel CXF endpoint in Spring, using the
cxf:cxfEndpointelement and reference the custom provider class (using theserviceClassattribute). - Implement the route in XML, where you can use the content-based router to sort requests by operation name.
- For each operation, define a processor bean to process the request.
- Define velocity templates for generating the reponse messages.
- Define a custom type converter, to support converting a
Stringmessage body to aSAXSourcemessage body.
Sample provider-based route Copy linkLink copied to clipboard!
CustomerService Web service using the provider-based approach. After sorting the request messages by operation name, an operation-specific processor bean reads the incoming request parameters. Finally, the response messages are generated using Velocity templates.
Figure 40.1. Sample Provider-Based Route
40.2. Create a Provider Implementation Class Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Provider<> class that implements the invoke() method. In fact, the sole purpose of this class is to provide runtime type information for Apache CXF: the invoke() method never gets called!
SAXSource.
The SAXSourceService provider class Copy linkLink copied to clipboard!
SAXSourceService, is as follows:
SAXSourceService, must be annotated by the @WebServiceProvider annotation to mark it as a provider class and can be optionally annotated by the @ServiceMode annotation to select PAYLOAD mode.
40.3. Instantiate the WS Endpoint Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Consumer endpoint—(at the start of a route) represents a Web service instance, which integrates with the route. The type of payload injected into the route depends on the value of the endpoint's
dataFormatoption. - Producer endpoint—represents a special kind of WS client proxy, which converts the current exchange object into an operation invocation on a remote Web service. The format of the current exchange must match the endpoint's
dataFormatsetting.
The cxf:bean: URI syntax Copy linkLink copied to clipboard!
cxf:bean: URI is used to bind an Apache CXF endpoint to a route and has the following general syntax:
cxf:bean:CxfEndpointID[?Options]
cxf:bean:CxfEndpointID[?Options]
CxfEndpointID is the ID of a bean created using the cxf:cxfEndpoint element, which configures the details of the WS endpoint. You can append options to this URI (where the options are described in detail in CXF in the Apache Camel Component Reference Guide ). Provider mode is essentially a variant of PAYLOAD mode: you could specify this mode on the URI (by setting dataFormat=PAYLOAD), but this is not necessary, because PAYLOAD mode is already selected by the @ServiceMode annotation on the custom Provider class.
customer-ws bean, define the route as follows:
<route>
<from uri="cxf:bean:customer-ws"/>
...
</route>
<route>
<from uri="cxf:bean:customer-ws"/>
...
</route>
The cxf:cxfEndpoint element Copy linkLink copied to clipboard!
cxf:cxfEndpoint element is used to define a WS endpoint that binds either to the start (consumer endpoint) or the end (producer endpoint) of a route. For example, to define the customer-ws WS endpoint in provider mode, you define a cxf:cxfEndpoint element as follows:
Specifying the WSDL location Copy linkLink copied to clipboard!
wsdlURL attribute of the cxf:cxfEndpoint element is used to specify the location of the WSDL contract for this endpoint. The WSDL contract is used as the source of metadata for this endpoint.
Specifying the service class Copy linkLink copied to clipboard!
serviceClass attribute must be set to the provider class, SAXSourceService.
40.4. Sort Messages by Operation Name Copy linkLink copied to clipboard!
The operationName header Copy linkLink copied to clipboard!
operationName header to the name of the invoked operation. You can then use this header to sort messages by operation name.
Sorting by operation name Copy linkLink copied to clipboard!
customer-ws-camel-cxf-provider demonstration defines the following route, which uses the content-based router pattern to sort incoming messages, based on the operation name. The when predicates check the value of the operationName header using simple language expressions, sorting messages into invocations on the updateCustomer operation, the lookupCustomer operation, or the getCustomerStatus operation.
40.5. SOAP/HTTP-to-JMS Bridge Use Case Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 40.2. SOAP/HTTP-to-JMS Bridge
Transforming RPC operations to One Way Copy linkLink copied to clipboard!
- The WS client invokes a synchronous operation on the Camel CXF endpoint at the start of the route. The Camel CXF endpoint then creates an initial InOut exchange at the start of the route, where the body of the exchange message contains a payload in XML format.
- The
inOnlyDSL command pushes a copy of the XML payload onto a JMS queue, so that it can be processed offline at some later time. - The
transformDSL command constructs an immediate response to send back to the client, where the response has the form of an XML string. - The route explicitly converts the XML string to the
javax.xml.transform.sax.SAXSourcetype. - The response is sent back to the WS client, thus completing the synchronous operation invocation.
Creating a broker instance Copy linkLink copied to clipboard!
amq:broker element in the Spring XML file, as follows:
persistent attribute set to false, so that the messages are stored only in memory.
Configuring the JMS component Copy linkLink copied to clipboard!
id value of activemq, you are implicitly overriding the component associated with the endpoint URI prefix, activemq:. In other words, your custom ActiveMQComponent instance is used instead of the default ActiveMQComponent instance from the camel-activemq JAR file.
Sample SOAP/HTTP-to-JMS route Copy linkLink copied to clipboard!
updateCustomer operation from the CustomerService SEI, as follows:
Sending to the JMS endpoint in inOnly mode Copy linkLink copied to clipboard!
inOnly DSL command instead of the to DSL command. When you send a message using the to DSL command, the default behavior is to use the same invocation mode as the current exchange. But the current exchange has an InOut MEP, which means that the to DSL command would wait forever for a response message from JMS.
inOnly DSL command into the route.
jmsMessageType=Text, Camel CXF implicitly converts the message payload to an XML string before pushing it onto the JMS queue.
Returning a literal response value Copy linkLink copied to clipboard!
transform DSL command uses an expression to set the body of the exchange's Out message and this message is then used as the response to the client. Your first impulse when defining a response in XML format might be to use a DOM API, but in this example, the response is specified as a string literal. This approach has the advantage of being both efficient and very easy to program.
Type conversion of the response message Copy linkLink copied to clipboard!
javax.xml.transform.sax.SAXSource. In the last step of the route, therefore, you must convert the message body from String type to javax.xml.transform.sax.SAXSource type, by invoking the convertBodyTo DSL command.
SAXSource conversion is provided by a custom type converter, as described in Section 40.7, “TypeConverter for SAXSource”.
40.6. Generating Responses Using Templates Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 40.3. Response Generated by Velocity
Sample template-based route Copy linkLink copied to clipboard!
getCustoemrStatus operation, as follows:
Route processing steps Copy linkLink copied to clipboard!
getCustomerStatus would be processed as follows:
- The route applies an XPath expression to the message in order to extract the customer ID value and then stashes it in the
customerIdheader. - The next step sends the message to the
getCustomerStatusbean, which does whatever processing is required to get the customer status for the specified customer ID. The results from this step are stashed in message headers. - A response is generated using a Velocity template.
- Finally, the XML string generated by the Velocity template must be explicitly converted to the
javax.xml.transform.sax.SAXSourcetype usingconvertBodyTo(which implicitly relies on a type converter).
XPath expressions and SAXSource Copy linkLink copied to clipboard!
getCustomerStatus processor bean Copy linkLink copied to clipboard!
getCustomerStatus processor bean is an instance of the GetCustomerStatus processor class, which is defined as follows:
status and statusMessage are simply set to constant values and stashed in message headers.
getCustomerStatusResponse.vm Velocity template Copy linkLink copied to clipboard!
${header.HeaderName} substitutes the value of a named header.
getCustomerStatus reponse is located in the customer-ws-camel-cxf-provider/src/main/resources directory and it contains the following template script:
<ns2:getCustomerStatusResponse xmlns:ns2="http://demo.fusesource.com/wsdl/CustomerService/">
<status>${headers.status}</status>
<statusMessage>${headers.statusMessage}</statusMessage>
</ns2:getCustomerStatusResponse>
<ns2:getCustomerStatusResponse xmlns:ns2="http://demo.fusesource.com/wsdl/CustomerService/">
<status>${headers.status}</status>
<statusMessage>${headers.statusMessage}</statusMessage>
</ns2:getCustomerStatusResponse>
40.7. TypeConverter for SAXSource Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
String objects to SAXSource objects.
String to SAXSource type converter Copy linkLink copied to clipboard!
String to SAXSource type converter is implemented in the AdditionalConverters class, as follows:
Reference Copy linkLink copied to clipboard!
40.8. Deploy to OSGi Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Bundles are a relatively lightweight deployment option (because dependencies can be shared between deployed bundles).
- OSGi provides sophisticated dependency management, ensuring that only version-consistent dependencies are added to the bundle's classpath.
Using the Maven bundle plug-in Copy linkLink copied to clipboard!
pom.xml file:
- Change the packaging type to
bundle(by editing the value of theproject/packagingelement in the POM). - Add the Maven bundle plug-in to your POM file and configure it as appropriate.
Sample bundle plug-in configuration Copy linkLink copied to clipboard!
Dynamic imports Copy linkLink copied to clipboard!
DynamicImport-Package element). This is a pragmatic way of dealing with the fact that Spring XML files are not terribly well integrated with the Maven bundle plug-in. At build time, the Maven bundle plug-in is not able to figure out which Java classes are required by the Spring XML code. By listing wildcarded package names in the DynamicImport-Package element, however, you allow the OSGi container to figure out which Java classes are needed by the Spring XML code at run time.
DynamicImport-Package headers is not recommended in OSGi, because it short-circuits OSGi version checking. Normally, what should happen is that the Maven bundle plug-in lists the Java packages used at build time, along with their versions, in the Import-Package header. At deploy time, the OSGi container then checks that the available Java packages are compatible with the build time versions listed in the Import-Package header. With dynamic imports, this version checking cannot be performed.
Build and deploy the client bundle Copy linkLink copied to clipboard!
mvn install
mvn install
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-camel-cxf-provider
karaf@root> install -s mvn:com.fusesource.byexample.cxf-webinars/customer-ws-camel-cxf-provider
org.ops4j.pax.url.mvn.localRepository property in the EsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before you can use the mvn: scheme to access Maven artifacts.
Chapter 41. Proxying a Web Service Copy linkLink copied to clipboard!
Abstract
41.1. Proxying with HTTP Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 41.1. Proxy Route with Message in HTTP Format
Alternatives for the consumer endpoint Copy linkLink copied to clipboard!
- Jetty endpoint—is a lightweight Web server. You can use Jetty to handle messages for any HTTP-based protocol, including the commonly-used Web service SOAP/HTTP protocol.
- Camel CXF endpoint in MESSAGE mode—when a Camel CXF endpoint is used in MESSAGE mode, the body of the exchange message is the raw message received from the transport layer (which is HTTP). In other words, the Camel CXF endpoint in MESSAGE mode is equivalent to a Jetty endpoint in the case of HTTP-based protocols.
Consumer endpoint for HTTP Copy linkLink copied to clipboard!
jetty:HttpAddress. To configure the Jetty endpoint to be a proxy for a Web service, use a HttpAddress value that is almost identical to the HTTP address the client connects to, except that Jetty's version of HttpAddress uses the special hostname, 0.0.0.0 (which matches all of the network interfaces on the current machine).
<route>
<from uri="jetty:http://0.0.0.0:9093/Customers?matchOnUriPrefix=true"/>
...
</route>
<route>
<from uri="jetty:http://0.0.0.0:9093/Customers?matchOnUriPrefix=true"/>
...
</route>
matchOnUriPrefix option Copy linkLink copied to clipboard!
http://localhost:9093/Customers would be accepted, but a request sent to http://localhost:9093/Customers/Foo would be rejected. By setting matchOnUriPrefix to true, however, you enable a kind of wildcarding on the context path, so that any context path prefixed by /Customers is accepted.
Alternatives for the producer endpoint Copy linkLink copied to clipboard!
- Jetty HTTP client endpoint—(recommended) the Jetty library implements a HTTP client. In particular, the Jetty HTTP client features support for
HttpClientthread pools, which means that the Jetty implementation scales particularly well. - HTTP endpoint—the HTTP endpoint implements a HTTP client based on the
HttpClient3.x API. - HTTP4 endpoint—the HTTP endpoint implements a HTTP client based on the
HttpClient4.x API.
Producer endpoint for HTTP Copy linkLink copied to clipboard!
uri attribute of the to element at the end of the route to be the address of the remote Web service, as follows:
<route>
...
<to uri="jetty:http://localhost:8083/Customers?bridgeEndpoint=true&throwExceptionOnFailure=false"/>
</route>
<route>
...
<to uri="jetty:http://localhost:8083/Customers?bridgeEndpoint=true&throwExceptionOnFailure=false"/>
</route>
bridgeEndpoint option Copy linkLink copied to clipboard!
bridgeEndpoint option, which you can enable on a HTTP producer endpoint to configure the endpoint appropriately for operating in a HTTP-to-HTTP bridge (as is the case in this demonstration). In particular, when bridgeEndpoint=true, the HTTP endpoint ignores the value of the Exchange.HTTP_URI header, using the HTTP address from the endpoint URI instead.
throwExceptionOnFailure option Copy linkLink copied to clipboard!
throwExceptionOnFailure to false ensures that any HTTP exceptions are relayed back to the original WS client, instead of being thrown within the route.
Handling message headers Copy linkLink copied to clipboard!
CamelHttp* headers set by the consumer endpoint at the start of the route can affect the behavior of the producer endpoint. For this reason, in a bridge application it is advisable to remove the CamelHttp* headers before the message reaches the producer endpoint, as follows:
Outgoing HTTP headers Copy linkLink copied to clipboard!
Camel will be converted into HTTP headers and sent out over the wire by the HTTP producer endpoint. This could have adverse consequences on the behavior of your application, so it is important to be aware of any headers that are set in the exchange object and to remove them, if necessary.
41.2. Proxying with POJO Format Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 41.2. Proxy Route with Message in POJO Format
Consumer endpoint for CXF/POJO Copy linkLink copied to clipboard!
cxf:bean:BeanID URI format to reference the Camel CXF endpoint as follows (where the dataFormat option defaults to POJO):
<route>
<from uri="cxf:bean:customerServiceProxy"/>
...
</route>
<route>
<from uri="cxf:bean:customerServiceProxy"/>
...
</route>
customerServiceProxy, is a Camel CXF/POJO endpoint, which is defined as follows:
Producer endpoint for CXF/POJO Copy linkLink copied to clipboard!
cxf:bean:BeanID URI format to reference the Camel CXF endpoint as follows (where the dataFormat option defaults to POJO):
<route>
...
<to uri="cxf:bean:customerServiceReal"/>
</route>
<route>
...
<to uri="cxf:bean:customerServiceReal"/>
</route>
customerServiceReal, is a Camel CXF/POJO endpoint, which is defined as follows:
41.3. Proxying with PAYLOAD Format Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.w3c.dom.Node object). The key advantate of using PAYLOAD format is that you can easily process the contents of a message, by accessing the message body as an XML document.
Figure 41.3. Proxy Route with Message in PAYLOAD Format
Consumer endpoint for CXF/PAYLOAD Copy linkLink copied to clipboard!
cxf:bean:BeanID URI format to reference the Camel CXF endpoint as follows, where you must set the dataFormat option to PAYLOAD:
<route>
<from uri="cxf:bean:customerServiceProxy?dataFormat=PAYLOAD"/>
...
</route>
<route>
<from uri="cxf:bean:customerServiceProxy?dataFormat=PAYLOAD"/>
...
</route>
customerServiceProxy, is a Camel CXF/PAYLOAD endpoint, which is defined as follows:
Producer endpoint for CXF/PAYLOAD Copy linkLink copied to clipboard!
cxf:bean:BeanID URI format to reference the Camel CXF endpoint as follows, where you must set the dataFormat option to PAYLOAD:
<route>
...
<to uri="cxf:bean:customerServiceReal?dataFormat=PAYLOAD"/>
</route>
<route>
...
<to uri="cxf:bean:customerServiceReal?dataFormat=PAYLOAD"/>
</route>
customerServiceReal, is a Camel CXF/PAYLOAD endpoint, which is defined as follows:
Outgoing HTTP headers Copy linkLink copied to clipboard!
Camel will be converted into HTTP headers and sent out over the wire by the Camel CXF producer endpoint. This could have adverse consequences on the behavior of your application, so it is important to be aware of any headers that are set in the exchange object and to remove them, if necessary.
41.4. Handling HTTP Headers Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
HTTP-based components Copy linkLink copied to clipboard!
camel-http), but also a number of other HTTP-based components, including:
HTTP headers in Camel CXF Copy linkLink copied to clipboard!
POJOPAYLOADMESSAGE
HTTP consumer endpoint Copy linkLink copied to clipboard!
CamelHttp*headers- Several headers with the
CamelHttpprefix are created, which record the status of the incoming message. For details of these internal headers, see HTTP. - HTTP headers
- All of the HTTP headers from the original incoming message are mapped to headers on the exchange's In message.
- URL options (Jetty only)
- The URL options from the original HTTP request URL are mapped to headers on the exchange's In message. For example, given the client request with the URL,
http://myserver/myserver?orderid=123, a Jetty consumer endpoint creates theorderidheader with value123.
HTTP producer endpoint Copy linkLink copied to clipboard!
CamelHttp*- Headers prefixed by
CamelHttpare used to control the behaviour of the HTTP producer endpoint. Any headers of this kind are consumed by the HTTP producer endpoint and the endpoint behaves as directed.NoteHowever,CamelHttpmessage headers are ignored by Camel CXF producer endpoints (but not by Camel CXF-RS producer endpoints). Camel*- All other headers prefixed by
Camelare presumed to be meant for internal use and are not mapped to HTTP headers in the target message (in other words, these headers are ignored). *- All other headers are converted to HTTP headers in the target message, with the exception of the following headers, which are blocked (based on a case-insensitive match):
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Implications for HTTP bridge applications Copy linkLink copied to clipboard!
CamelHttp* headers set by the consumer endpoint at the start of the route can affect the behavior of the producer endpoint. For this reason, in a bridge application it is advisable to remove the CamelHttp* headers, as follows:
from("http://0.0.0.0/context/path")
.removeHeaders("CamelHttp*)
...
.to("http://remoteHost/context/path");
from("http://0.0.0.0/context/path")
.removeHeaders("CamelHttp*)
...
.to("http://remoteHost/context/path");
Setting a custom header filter Copy linkLink copied to clipboard!
headerFilterStrategy option on the endpoint URI. For example, to configure a producer endpoint with the myHeaderFilterStrategy filter, you could use a URI like the following:
http://remoteHost/context/path?headerFilterStrategy=#myHeaderFilterStrategy
http://remoteHost/context/path?headerFilterStrategy=#myHeaderFilterStrategy
myHeaderFilterStrategy is the bean ID of your custom filter instance.
Chapter 42. Filtering SOAP Message Headers Copy linkLink copied to clipboard!
Abstract
42.1. Basic Configuration Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
CxfHeaderFilterStrategy Copy linkLink copied to clipboard!
CxfHeaderFilterStrategy class. Basic configuration of the CxfHeaderFilterStrategy class involves setting one or more of the following options:
relayHeaders option Copy linkLink copied to clipboard!
relayHeaders option can be summarized as follows:
| In-band headers | Out-of-band headers | |
relayHeaders=true, dataFormat=PAYLOAD | Filter | Filter |
relayHeaders=true, dataFormat=POJO | Relay all | Filter |
relayHeaders=false | Block | Block |
In-band headers Copy linkLink copied to clipboard!
Out-of-band headers Copy linkLink copied to clipboard!
Payload format Copy linkLink copied to clipboard!
POJO- (Default) Only out-of-band headers are available for filtering, because the in-band headers have already been processed and removed from the list by CXF. The in-band headers are incorporated into the
MessageContentListin POJO mode. If you require access to headers in POJO mode, you have the option of implementing a custom CXF interceptor or JAX-WS handler. PAYLOAD- In this mode, both in-band and out-of-band headers are available for filtering.
MESSAGE- Not applicable. (In this mode, the message remains in a raw format and the headers are not processed at all.)
Default filter Copy linkLink copied to clipboard!
SoapMessageHeaderFilter, which removes only the SOAP headers that the SOAP specification expects an intermediate Web service to consume. For more details, see the section called “SoapMessageHeaderFilter”.
Overriding the default filter Copy linkLink copied to clipboard!
CxfHeaderFilterStrategy instance by defining a new CxfHeaderFilterStrategy bean and associating it with a CXF endpoint.
Sample relayHeaders configuration Copy linkLink copied to clipboard!
relayHeaders option to create a CxfHeaderFilterStrategy bean that blocks all message headers. The CXF endpoints in the route use the headerFilterStrategy option to install the filter strategy in the endpoint, where the headerFilterStrategy setting has the syntax, headerFilterStrategy=#BeanID.
relayAllMessageHeaders option Copy linkLink copied to clipboard!
relayAllMessageHeaders option is used to propagate all SOAP headers, without applying any filtering (any installed filters would be bypassed). In order to enable this feature, you must set both relayHeaders and relayAllMessageHeaders to true.
Sample relayAllMessageHeaders configuration Copy linkLink copied to clipboard!
propagateAllMessages filter strategy sets both relayHeaders and relayAllMessageHeaders to true.
42.2. Header Filtering Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
CxfHeaderFilterStrategy instance. The filtering mechanism then uses the header's XML namespace to lookup a particular filter, which it then applies to the header.
Filter map Copy linkLink copied to clipboard!
CxfHeaderFilterStrategy instance. For each filter that you install in CxfHeaderFilterStrategy, corresponding entries are made in the filter map, where one or more XML schema namespaces are associated with each filter.
Figure 42.1. Filter Map
Filter behavior Copy linkLink copied to clipboard!
PAYLOAD mode Copy linkLink copied to clipboard!
POJO mode Copy linkLink copied to clipboard!
42.3. Implementing a Custom Filter Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
MessageHeaderFilter Java interface. You must associate a filter with one or more XML schema namespaces (representing the header's namespace) and it is possible to differentiate between request message headers and response message headers.
MessageHeaderFilter interface Copy linkLink copied to clipboard!
MessageHeaderFilter interface is defined in the org.apache.camel.component.cxf.common.header package, as follows:
Implementing the filter() method Copy linkLink copied to clipboard!
MessageHeaderFilter.filter() method is reponsible for applying header filtering. Filtering is applied both before and after an operation is invoked on an endpoint. Hence, there are two directions to which filtering is applied, as follows:
Direction.OUT- When the
directionparameter equalsDirection.OUT, the filter is being applied to a request either leaving a consumer endpoint or entering a producer endpoint (that is, it applies to a WS request message propagating through a route). Direction.IN- When the
directionparameter equalsDirection.IN, the filter is being applied to a response either leaving a producer endpoint or entering a consumer endpoint (that is, it applies to a WS response message being sent back).
headers. Any headers left in the list are propagated.
Binding filters to XML namespaces Copy linkLink copied to clipboard!
getActivationNamespaces() method, which returns the list of bound XML namespaces.
Identifying the namespace to bind to Copy linkLink copied to clipboard!
Example 42.1. Sample Binding Namespaces
soap:binding tag, you can infer that namespace associated with the SOAP binding is http://schemas.xmlsoap.org/wsdl/soap/.
Implementing a custom filter Copy linkLink copied to clipboard!
MessageHeaderFilter interface and implement its methods as described in this section. For example, Example 42.2, “Sample Header Filter Implementation” shows an example of a custom filter, CustomHeaderFilter, that binds to the namespace, http://cxf.apache.org/bindings/custom, and relays all of the headers that pass through it.
Example 42.2. Sample Header Filter Implementation
42.4. Installing Filters Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
messageHeaderFilters property of the CxfHeaderFilterStrategy object. When you initialize this property with a list of message header filters, the header filter strategy combines the specified filters to make a filter map.
messageHeaderFilters property is of type, List<MessageHeaderFilter>.
Installing filters in XML Copy linkLink copied to clipboard!
CxfHeaderFilterStrategy instance, specifying a customized list of header filters in the messageHeaderFilters property. There are two header filters in this example: SoapMessageHeaderFilter and CustomHeaderFilter.
SoapMessageHeaderFilter Copy linkLink copied to clipboard!
SoapMessageHeaderFilter filter, which is the default header filter. This filter is designed to filter standard SOAP headers and is bound to the following XML namespaces:
http://schemas.xmlsoap.org/soap/ http://schemas.xmlsoap.org/wsdl/soap/ http://schemas.xmlsoap.org/wsdl/soap12/
http://schemas.xmlsoap.org/soap/
http://schemas.xmlsoap.org/wsdl/soap/
http://schemas.xmlsoap.org/wsdl/soap12/
soap:actor attribute (SOAP 1.1) or the soap:role attribute (SOAP 1.2) is present and has the value next, the header is removed from the message. Otherwise, the header is propagated.
Namespace clashes Copy linkLink copied to clipboard!
allowFilterNamespaceClash property to true in the CxfHeaderFilterStrategy instance. When this policy is set to true, the nearest to last filter is selected, in the event of a namespace clash.
Part IV. Programming EIP Components Copy linkLink copied to clipboard!
Abstract
Chapter 43. Understanding Message Formats Copy linkLink copied to clipboard!
Abstract
43.1. Exchanges Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 43.1. Exchange Object Passing through a Route
Processor.process() method. This means that the exchange object is directly accessible to the source endpoint, the target endpoint, and all of the processors in between.
The Exchange interface Copy linkLink copied to clipboard!
org.apache.camel.Exchange interface defines methods to access In and Out messages, as shown in Example 43.1, “Exchange Methods”.
Example 43.1. Exchange Methods
Exchange interface, see Section 52.1, “The Exchange Interface”.
Lazy creation of messages Copy linkLink copied to clipboard!
getIn() or getOut()). The lazy message creation semantics are implemented by the org.apache.camel.impl.DefaultExchange class.
getIn() or getOut()), or if you call an accessor with the boolean argument equal to true (that is, getIn(true) or getOut(true)), the default method implementation creates a new message instance, if one does not already exist.
false (that is, getIn(false) or getOut(false)), the default method implementation returns the current message value.[2]
Lazy creation of exchange IDs Copy linkLink copied to clipboard!
getExchangeId() on any exchange to obtain a unique ID for that exchange instance, but the ID is generated only when you actually call the method. The DefaultExchange.getExchangeId() implementation of this method delegates ID generation to the UUID generator that is registered with the CamelContext.
CamelContext, see Section 43.4, “Built-In UUID Generators”.
43.2. Messages Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Message body
- Message headers
- Message attachments
Object) and the message attachments are declared to be of type javax.activation.DataHandler , which can contain arbitrary MIME types. If you need to obtain a concrete representation of the message contents, you can convert the body and headers to another type using the type converter mechanism and, possibly, using the marshalling and unmarshalling mechanism.
The Message interface Copy linkLink copied to clipboard!
org.apache.camel.Message interface defines methods to access the message body, message headers and message attachments, as shown in Example 43.2, “Message Interface”.
Example 43.2. Message Interface
Message interface, see Section 53.1, “The Message Interface”.
Lazy creation of bodies, headers, and attachments Copy linkLink copied to clipboard!
foo message header from the In message:
from("SourceURL")
.filter(header("foo")
.isEqualTo("bar"))
.to("TargetURL");
from("SourceURL")
.filter(header("foo")
.isEqualTo("bar"))
.to("TargetURL");
header("foo") call is executed. At that point, the underlying message implementation parses the headers and populates the header map. The message body is not parsed until you reach the end of the route, at the to("TargetURL") call. At that point, the body is converted into the format required for writing it to the target endpoint, TargetURL.
Lazy creation of message IDs Copy linkLink copied to clipboard!
getMessageId() method. The DefaultExchange.getExchangeId() implementation of this method delegates ID generation to the UUID generator that is registered with the CamelContext.
getMessageId() method implicitly, if the endpoint implements a protocol that requires a unique message ID. In particular, JMS messages normally include a header containing unique message ID, so the JMS component automatically calls getMessageId() to obtain the message ID (this is controlled by the messageIdEnabled option on the JMS endpoint).
CamelContext, see Section 43.4, “Built-In UUID Generators”.
Initial message format Copy linkLink copied to clipboard!
byte[], ByteBuffer, InputStream, or OutputStream. This ensures that the overhead required for creating the initial message is minimal. Where more elaborate message formats are required components usually rely on type converters or marshalling processors.
Type converters Copy linkLink copied to clipboard!
convertBodyTo(Class type) method can be inserted into a route to convert the body of an In message, as follows:
from("SourceURL").convertBodyTo(String.class).to("TargetURL");
from("SourceURL").convertBodyTo(String.class).to("TargetURL");
java.lang.String. The following example shows how to append a string to the end of the In message body:
from("SourceURL").setBody(bodyAs(String.class).append("My Special Signature")).to("TargetURL");
from("SourceURL").setBody(bodyAs(String.class).append("My Special Signature")).to("TargetURL");
from("SourceURL").setBody(body().append("My Special Signature")).to("TargetURL");
from("SourceURL").setBody(body().append("My Special Signature")).to("TargetURL");
append() method automatically converts the message body to a string before appending its argument.
Type conversion methods in Message Copy linkLink copied to clipboard!
org.apache.camel.Message interface exposes some methods that perform type conversion explicitly:
getBody(Class<T> type)—Returns the message body as type,T.getHeader(String name, Class<T> type)—Returns the named header value as type,T.
Converting to XML Copy linkLink copied to clipboard!
byte[], ByteBuffer, String, and so on), the built-in type converter also supports conversion to XML formats. For example, you can convert a message body to the org.w3c.dom.Document type. This conversion is more expensive than the simple conversions, because it involves parsing the entire message and then creating a tree of nodes to represent the XML document structure. You can convert to the following XML document types:
org.w3c.dom.Documentjavax.xml.transform.sax.SAXSource
Marshalling and unmarshalling Copy linkLink copied to clipboard!
marshal()unmarshal()
Example 43.3. Unmarshalling a Java Object
from("file://tmp/appfiles/serialized")
.unmarshal()
.serialization()
.<FurtherProcessing>
.to("TargetURL");
from("file://tmp/appfiles/serialized")
.unmarshal()
.serialization()
.<FurtherProcessing>
.to("TargetURL");
Final message format Copy linkLink copied to clipboard!
byte[] array to an InputStream type.
43.3. Built-In Type Converters Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Message.getBody(Class<T> type) or Message.getHeader(String name, Class<T> type). It is also possible to invoke the master type converter directly. For example, if you have an exchange object, exchange, you could convert a given value to a String as shown in Example 43.4, “Converting a Value to a String”.
Example 43.4. Converting a Value to a String
org.apache.camel.TypeConverter tc = exchange.getContext().getTypeConverter(); String str_value = tc.convertTo(String.class, value);
org.apache.camel.TypeConverter tc = exchange.getContext().getTypeConverter();
String str_value = tc.convertTo(String.class, value);
Basic type converters Copy linkLink copied to clipboard!
java.io.FileStringbyte[]andjava.nio.ByteBufferjava.io.InputStreamandjava.io.OutputStreamjava.io.Readerandjava.io.Writerjava.io.BufferedReaderandjava.io.BufferedWriterjava.io.StringReader
File and String types. The File type can be converted to any of the preceding types, except Reader, Writer, and StringReader. The String type can be converted to File, byte[], ByteBuffer, InputStream, or StringReader. The conversion from String to File works by interpreting the string as a file name. The trio of String, byte[], and ByteBuffer are completely inter-convertible.
byte[] to String and from String to byte[] by setting the Exchange.CHARSET_NAME exchange property in the current exchange. For example, to perform conversions using the UTF-8 character encoding, call exchange.setProperty("Exchange.CHARSET_NAME", "UTF-8"). The supported character sets are described in the java.nio.charset.Charset class.
Collection type converters Copy linkLink copied to clipboard!
Object[]java.util.Setjava.util.List
Map type converters Copy linkLink copied to clipboard!
java.util.Mapjava.util.HashMapjava.util.Hashtablejava.util.Properties
java.util.Set type, where the set elements are of the MapEntry<K,V> type.
DOM type converters Copy linkLink copied to clipboard!
org.w3c.dom.Document—convertible frombyte[],String,java.io.File, andjava.io.InputStream.org.w3c.dom.Nodejavax.xml.transform.dom.DOMSource—convertible fromString.javax.xml.transform.Source—convertible frombyte[]andString.
SAX type converters Copy linkLink copied to clipboard!
javax.xml.transform.sax.SAXSource type, which supports the SAX event-driven XML parser (see the SAX Web site for details). You can convert to SAXSource from the following types:
StringInputStreamSourceStreamSourceDOMSource
enum type converter Copy linkLink copied to clipboard!
String to enum type conversions, where the string value is converted to the matching enum constant from the specified enumeration class (the matching is case-insensitive). This type converter is rarely needed for converting message bodies, but it is frequently used internally by Apache Camel to select particular options.
INFO, is converted into an enum constant:
<to uri="log:foo?level=INFO"/>
<to uri="log:foo?level=INFO"/>
enum type converter is case-insensitive, any of the following alternatives would also work:
<to uri="log:foo?level=info"/> <to uri="log:foo?level=INfo"/> <to uri="log:foo?level=InFo"/>
<to uri="log:foo?level=info"/>
<to uri="log:foo?level=INfo"/>
<to uri="log:foo?level=InFo"/>
Custom type converters Copy linkLink copied to clipboard!
43.4. Built-In UUID Generators Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
CamelContext. This UUID generator is then used whenever Apache Camel needs to generate a unique ID—in particular, the registered UUID generator is called to generate the IDs returned by the Exchange.getExchangeId() and the Message.getMessageId() methods.
SimpleUuidGenerator) for testing purposes.
Provided UUID generators Copy linkLink copied to clipboard!
org.apache.camel.impl.ActiveMQUuidGenerator—(Default) generates the same style of ID as is used by Apache ActiveMQ. This implementation might not be suitable for all applications, because it uses some JDK APIs that are forbidden in the context of cloud computing (such as the Google App Engine).org.apache.camel.impl.SimpleUuidGenerator—implements a simple counter ID, starting at1. The underlying implementation uses thejava.util.concurrent.atomic.AtomicLongtype, so that it is thread-safe.org.apache.camel.impl.JavaUuidGenerator—implements an ID based on thejava.util.UUIDtype. Becausejava.util.UUIDis synchronized, this might affect performance on some highly concurrent systems.
Custom UUID generator Copy linkLink copied to clipboard!
org.apache.camel.spi.UuidGenerator interface, which is shown in Example 43.5, “UuidGenerator Interface”. The generateUuid() must be implemented to return a unique ID string.
Example 43.5. UuidGenerator Interface
Specifying the UUID generator using Java Copy linkLink copied to clipboard!
setUuidGenerator() method on the current CamelContext object. For example, you can register a SimpleUuidGenerator instance with the current CamelContext, as follows:
// Java getContext().setUuidGenerator(new org.apache.camel.impl.SimpleUuidGenerator());
// Java
getContext().setUuidGenerator(new org.apache.camel.impl.SimpleUuidGenerator());
setUuidGenerator() method should be called during startup, before any routes are activated.
Specifying the UUID generator using Spring Copy linkLink copied to clipboard!
bean element. When a camelContext instance is created, it automatically looks up the Spring registry, searching for a bean that implements org.apache.camel.spi.UuidGenerator. For example, you can register a SimpleUuidGenerator instance with the CamelContext as follows:
Chapter 44. Implementing a Processor Copy linkLink copied to clipboard!
Abstract
44.1. Processing Model Copy linkLink copied to clipboard!
Pipelining model Copy linkLink copied to clipboard!
Figure 44.1. Pipelining Model
ProcessorA, ProcessorB, and a producer endpoint, TargetURI.
Example 44.1. Java DSL Pipeline
from(SourceURI).pipeline(ProcessorA, ProcessorB, TargetURI);
from(SourceURI).pipeline(ProcessorA, ProcessorB, TargetURI);
44.2. Implementing a Simple Processor Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Processor interface Copy linkLink copied to clipboard!
org.apache.camel.Processor interface. As shown in Example 44.2, “Processor Interface”, the interface defines a single method, process(), which processes an exchange object.
Example 44.2. Processor Interface
package org.apache.camel;
public interface Processor {
void process(Exchange exchange) throws Exception;
}
package org.apache.camel;
public interface Processor {
void process(Exchange exchange) throws Exception;
}
Implementing the Processor interface Copy linkLink copied to clipboard!
Processor interface and provide the logic for the process() method. Example 44.3, “Simple Processor Implementation” shows the outline of a simple processor implementation.
Example 44.3. Simple Processor Implementation
process() method gets executed before the exchange object is delegated to the next processor in the chain.
Inserting the simple processor into a route Copy linkLink copied to clipboard!
process() DSL command to insert a simple processor into a route. Create an instance of your custom processor and then pass this instance as an argument to the process() method, as follows:
org.apache.camel.Processor myProc = new MyProcessor();
from("SourceURL").process(myProc).to("TargetURL");
org.apache.camel.Processor myProc = new MyProcessor();
from("SourceURL").process(myProc).to("TargetURL");
44.3. Accessing Message Content Copy linkLink copied to clipboard!
Accessing message headers Copy linkLink copied to clipboard!
Exchange.getIn()), and then use the Message interface to retrieve the individual headers (for example, using Message.getHeader()).
Authorization. This example uses the ExchangeHelper.getMandatoryHeader() method, which eliminates the need to test for a null header value.
Example 44.4. Accessing an Authorization Header
Message interface, see Section 43.2, “Messages”.
Accessing the message body Copy linkLink copied to clipboard!
Example 44.5. Accessing the Message Body
Accessing message attachments Copy linkLink copied to clipboard!
Message.getAttachment() method or the Message.getAttachments() method. See Example 43.2, “Message Interface” for more details.
44.4. The ExchangeHelper Class Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.util.ExchangeHelper class is a Apache Camel utility class that provides methods that are useful when implementing a processor.
Resolve an endpoint Copy linkLink copied to clipboard!
resolveEndpoint() method is one of the most useful methods in the ExchangeHelper class. You use it inside a processor to create new Endpoint instances on the fly.
Example 44.6. The resolveEndpoint() Method
resolveEndpoint() is an exchange instance, and the second argument is usually an endpoint URI string. Example 44.7, “Creating a File Endpoint” shows how to create a new file endpoint from an exchange instance exchange
Example 44.7. Creating a File Endpoint
Endpoint file_endp = ExchangeHelper.resolveEndpoint(exchange, "file://tmp/messages/in.xml");
Endpoint file_endp = ExchangeHelper.resolveEndpoint(exchange, "file://tmp/messages/in.xml");
Wrapping the exchange accessors Copy linkLink copied to clipboard!
ExchangeHelper class provides several static methods of the form getMandatoryBeanProperty(), which wrap the corresponding getBeanProperty() methods on the Exchange class. The difference between them is that the original getBeanProperty() accessors return null, if the corresponding property is unavailable, and the getMandatoryBeanProperty() wrapper methods throw a Java exception. The following wrapper methods are implemented in the ExchangeHelper class:
Testing the exchange pattern Copy linkLink copied to clipboard!
ExchangeHelper class provides the following methods:
Get the In message's MIME content type Copy linkLink copied to clipboard!
ExchangeHelper.getContentType(exchange) method. To implement this, the ExchangeHelper object looks up the value of the In message's Content-Type header—this method relies on the underlying component to populate the header value).
Chapter 45. Type Converters Copy linkLink copied to clipboard!
Abstract
45.1. Type Converter Architecture Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Type converter interface Copy linkLink copied to clipboard!
org.apache.camel.TypeConverter interface, which all type converters must implement.
Example 45.1. TypeConverter Interface
package org.apache.camel;
public interface TypeConverter {
<T> T convertTo(Class<T> type, Object value);
}
package org.apache.camel;
public interface TypeConverter {
<T> T convertTo(Class<T> type, Object value);
}
Master type converter Copy linkLink copied to clipboard!
CamelContext object. To obtain a reference to the master type converter, you call the CamelContext.getTypeConverter() method. For example, if you have an exchange object, exchange, you can obtain a reference to the master type converter as shown in Example 45.2, “Getting a Master Type Converter”.
Example 45.2. Getting a Master Type Converter
org.apache.camel.TypeConverter tc = exchange.getContext().getTypeConverter();
org.apache.camel.TypeConverter tc = exchange.getContext().getTypeConverter();
Type converter loader Copy linkLink copied to clipboard!
TypeConverterLoader interface. Apache Camel currently uses only one kind of type converter loader—the annotation type converter loader (of AnnotationTypeConverterLoader type).
Type conversion process Copy linkLink copied to clipboard!
value, to a specified type, toType.
Figure 45.1. Type Conversion Process
- The
CamelContextobject holds a reference to the masterTypeConverterinstance. The first step in the conversion process is to retrieve the master type converter by callingCamelContext.getTypeConverter(). - Type conversion is initiated by calling the
convertTo()method on the master type converter. This method instructs the type converter to convert the data object,value, from its original type to the type specified by thetoTypeargument. - Because the master type converter is a front end for many different slave type converters, it looks up the appropriate slave type converter by checking a registry of type mappings The registry of type converters is keyed by a type mapping pair
(toType, fromType). If a suitable type converter is found in the registry, the master type converter calls the slave'sconvertTo()method and returns the result. - If a suitable type converter cannot be found in the registry, the master type converter loads a new type converter, using the type converter loader.
- The type converter loader searches the available JAR libraries on the classpath to find a suitable type converter. Currently, the loader strategy that is used is implemented by the annotation type converter loader, which attempts to load a class annotated by the
org.apache.camel.Converterannotation. See the section called “Create a TypeConverter file”. - If the type converter loader is successful, a new slave type converter is loaded and entered into the type converter registry. This type converter is then used to convert the
valueargument to thetoTypetype. - If the data is successfully converted, the converted data value is returned. If the conversion does not succeed,
nullis returned.
45.2. Implementing Type Converter Using Annotations Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
How to implement a type converter Copy linkLink copied to clipboard!
Implement an annotated converter class Copy linkLink copied to clipboard!
@Converter annotation. You must annotate the class itself and each of the static methods intended to perform type conversion. Each converter method takes an argument that defines the from type, optionally takes a second Exchange argument, and has a non-void return value that defines the to type. The type converter loader uses Java reflection to find the annotated methods and integrate them into the type converter mechanism. Example 45.3, “Example of an Annotated Converter Class” shows an example of an annotated converter class that defines a converter method for converting from java.io.File to java.io.InputStream and another converter method (with an Exchange argument) for converting from byte[] to String.
Example 45.3. Example of an Annotated Converter Class
toInputStream() method is responsible for performing the conversion from the File type to the InputStream type and the toString() method is responsible for performing the conversion from the byte[] type to the String type.
@Converter annotation.
Create a TypeConverter file Copy linkLink copied to clipboard!
TypeConverter file at the following location:
META-INF/services/org/apache/camel/TypeConverter
META-INF/services/org/apache/camel/TypeConverter
TypeConverter file must contain a comma-separated list of package names identifying the packages that contain type converter classes. For example, if you want the type converter loader to search the com.YourDomain.YourPackageName package for annotated converter classes, the TypeConverter file would have the following contents:
com.YourDomain.YourPackageName
com.YourDomain.YourPackageName
Package the type converter Copy linkLink copied to clipboard!
META-INF directory. Put this JAR file on your classpath to make it available to your Apache Camel application.
Fallback converter method Copy linkLink copied to clipboard!
@Converter annotation, you can optionally define a fallback converter method using the @FallbackConverter annotation. The fallback converter method will only be tried, if the master type converter fails to find a regular converter method in the type registry.
byte[] to String), a fallback converter can potentially perform conversion between any pair of types. It is up to the code in the body of the fallback converter method to figure out which conversions it is able to perform. At run time, if a conversion cannot be performed by a regular converter, the master type converter iterates through every available fallback converter until it finds one that can perform the conversion.
GenericFile object, exploiting the type converters already available in the type converter registry:
45.3. Implementing a Type Converter Directly Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Implement the TypeConverter interface Copy linkLink copied to clipboard!
TypeConverter interface. For example, the following MyOrderTypeConverter class converts an integer value to a MyOrder object, where the integer value is used to initialize the order ID in the MyOrder object.
Add the type converter to the registry Copy linkLink copied to clipboard!
// Add the custom type converter to the type converter registry context.getTypeConverterRegistry().addTypeConverter(MyOrder.class, String.class, new MyOrderTypeConverter());
// Add the custom type converter to the type converter registry
context.getTypeConverterRegistry().addTypeConverter(MyOrder.class, String.class, new MyOrderTypeConverter());
context is the current org.apache.camel.CamelContext instance. The addTypeConverter() method registers the MyOrderTypeConverter class against the specific type conversion, from String.class to MyOrder.class.
Chapter 46. Producer and Consumer Templates Copy linkLink copied to clipboard!
Abstract
46.1. Using the Producer Template Copy linkLink copied to clipboard!
46.1.1. Introduction to the Producer Template Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Exchange object, as a message body, as a message body with a single header setting, and so on) and there are methods to support both the synchronous and the asynchronous style of invocation. Overall, producer template methods can be grouped into the following categories:
Synchronous invocation Copy linkLink copied to clipboard!
sendSuffix() and requestSuffix(). For example, the methods for invoking an endpoint using either the default message exchange pattern (MEP) or an explicitly specified MEP are named send(), sendBody(), and sendBodyAndHeader() (where these methods respectively send an Exchange object, a message body, or a message body and header value). If you want to force the MEP to be InOut (request/reply semantics), you can call the request(), requestBody(), and requestBodyAndHeader() methods instead.
ProducerTemplate instance and use it to send a message body to the activemq:MyQueue endpoint. The example also shows how to send a message body and header value using sendBodyAndHeader().
Synchronous invocation with a processor Copy linkLink copied to clipboard!
send() method with a Processor argument instead of an Exchange argument. In this case, the producer template implicitly asks the specified endpoint to create an Exchange instance (typically, but not always having the InOnly MEP by default). This default exchange is then passed to the processor, which initializes the contents of the exchange object.
MyProcessor processor to the activemq:MyQueue endpoint.
MyProcessor class is implemented as shown in the following example. In addition to setting the In message body (as shown here), you could also initialize message heades and exchange properties.
Asynchronous invocation Copy linkLink copied to clipboard!
asyncSendSuffix() and asyncRequestSuffix(). For example, the methods for invoking an endpoint using either the default message exchange pattern (MEP) or an explicitly specified MEP are named asyncSend() and asyncSendBody() (where these methods respectively send an Exchange object or a message body). If you want to force the MEP to be InOut (request/reply semantics), you can call the asyncRequestBody(), asyncRequestBodyAndHeader(), and asyncRequestBodyAndHeaders() methods instead.
direct:start endpoint. The asyncSend() method returns a java.util.concurrent.Future object, which is used to retrieve the invocation result at a later time.
asyncSendBody() or asyncRequestBody()). In this case, you can use one of the following helper methods to extract the returned message body from the Future object:
<T> T extractFutureBody(Future future, Class<T> type); <T> T extractFutureBody(Future future, long timeout, TimeUnit unit, Class<T> type) throws TimeoutException;
<T> T extractFutureBody(Future future, Class<T> type);
<T> T extractFutureBody(Future future, long timeout, TimeUnit unit, Class<T> type) throws TimeoutException;
extractFutureBody() method blocks until the invocation completes and the reply message is available. The second version of the extractFutureBody() method allows you to specify a timeout. Both methods have a type argument, type, which casts the returned message body to the specified type using a built-in type converter.
asyncRequestBody() method to send a message body to the direct:start endpoint. The blocking extractFutureBody() method is then used to retrieve the reply message body from the Future object.
Asynchronous invocation with a callback Copy linkLink copied to clipboard!
asyncCallback(), asyncCallbackSendBody(), or asyncCallbackRequestBody() methods. In this case, you supply a callback object (of org.apache.camel.impl.SynchronizationAdapter type), which automatically gets invoked in the sub-thread as soon as a reply message arrives.
Synchronization callback interface is defined as follows:
onComplete() method is called on receipt of a normal reply and the onFailure() method is called on receipt of a fault message reply. Only one of these methods gets called back, so you must override both of them to ensure that all types of reply are processed.
direct:start endpoint, where the reply message is processed in the sub-thread by the SynchronizationAdapter callback object.
SynchronizationAdapter class is a default implementation of the Synchronization interface, which you can override to provide your own definitions of the onComplete() and onFailure() callback methods.
asyncCallback() method also returns a Future object—for example:
// Retrieve the reply from the main thread, specifying a timeout Exchange reply = future.get(10, TimeUnit.SECONDS);
// Retrieve the reply from the main thread, specifying a timeout
Exchange reply = future.get(10, TimeUnit.SECONDS);
46.1.2. Synchronous Send Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Send an exchange Copy linkLink copied to clipboard!
send() method is a general-purpose method that sends the contents of an Exchange object to an endpoint, using the message exchange pattern (MEP) of the exchange. The return value is the exchange that you get after it has been processed by the producer endpoint (possibly containing an Out message, depending on the MEP).
send() method for sending an exchange that let you specify the target endpoint in one of the following ways: as the default endpoint, as an endpoint URI, or as an Endpoint object.
Exchange send(Exchange exchange); Exchange send(String endpointUri, Exchange exchange); Exchange send(Endpoint endpoint, Exchange exchange);
Exchange send(Exchange exchange);
Exchange send(String endpointUri, Exchange exchange);
Exchange send(Endpoint endpoint, Exchange exchange);
Send an exchange populated by a processor Copy linkLink copied to clipboard!
send() method is to use a processor to populate a default exchange, instead of supplying the exchange object explicitly (see the section called “Synchronous invocation with a processor” for details).
send() methods for sending an exchange populated by a processor let you specify the target endpoint in one of the following ways: as the default endpoint, as an endpoint URI, or as an Endpoint object. In addition, you can optionally specify the exchange's MEP by supplying the pattern argument, instead of accepting the default.
Send a message body Copy linkLink copied to clipboard!
sendBody() methods to provide the message body as an argument and let the producer template take care of inserting the body into a default exchange object.
sendBody() methods let you specify the target endpoint in one of the following ways: as the default endpoint, as an endpoint URI, or as an Endpoint object. In addition, you can optionally specify the exchange's MEP by supplying the pattern argument, instead of accepting the default. The methods without a pattern argument return void (even though the invocation might give rise to a reply in some cases); and the methods with a pattern argument return either the body of the Out message (if there is one) or the body of the In message (otherwise).
Send a message body and header(s) Copy linkLink copied to clipboard!
sendBodyAndHeader() methods are useful for this kind of header testing. You supply the message body and header setting as arguments to sendBodyAndHeader() and let the producer template take care of inserting the body and header setting into a default exchange object.
sendBodyAndHeader() methods let you specify the target endpoint in one of the following ways: as the default endpoint, as an endpoint URI, or as an Endpoint object. In addition, you can optionally specify the exchange's MEP by supplying the pattern argument, instead of accepting the default. The methods without a pattern argument return void (even though the invocation might give rise to a reply in some cases); and the methods with a pattern argument return either the body of the Out message (if there is one) or the body of the In message (otherwise).
sendBodyAndHeaders() methods are similar to the sendBodyAndHeader() methods, except that instead of supplying just a single header setting, these methods allow you to specify a complete hash map of header settings.
Send a message body and exchange property Copy linkLink copied to clipboard!
sendBodyAndProperty() methods. You supply the message body and property setting as arguments to sendBodyAndProperty() and let the producer template take care of inserting the body and exchange property into a default exchange object.
sendBodyAndProperty() methods let you specify the target endpoint in one of the following ways: as the default endpoint, as an endpoint URI, or as an Endpoint object. In addition, you can optionally specify the exchange's MEP by supplying the pattern argument, instead of accepting the default. The methods without a pattern argument return void (even though the invocation might give rise to a reply in some cases); and the methods with a pattern argument return either the body of the Out message (if there is one) or the body of the In message (otherwise).
46.1.3. Synchronous Request with InOut Pattern Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Request an exchange populated by a processor Copy linkLink copied to clipboard!
request() method is a general-purpose method that uses a processor to populate a default exchange and forces the message exchange pattern to be InOut (so that the invocation obeys request/reply semantics). The return value is the exchange that you get after it has been processed by the producer endpoint, where the Out message contains the reply message.
request() methods for sending an exchange populated by a processor let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object.
Exchange request(String endpointUri, Processor processor); Exchange request(Endpoint endpoint, Processor processor);
Exchange request(String endpointUri, Processor processor);
Exchange request(Endpoint endpoint, Processor processor);
Request a message body Copy linkLink copied to clipboard!
requestBody() methods to provide the request message body as an argument and let the producer template take care of inserting the body into a default exchange object.
requestBody() methods let you specify the target endpoint in one of the following ways: as the default endpoint, as an endpoint URI, or as an Endpoint object. The return value is the body of the reply message (Out message body), which can either be returned as plain Object or converted to a specific type, T, using the built-in type converters (see Section 43.3, “Built-In Type Converters”).
Request a message body and header(s) Copy linkLink copied to clipboard!
requestBodyAndHeader() methods. You supply the message body and header setting as arguments to requestBodyAndHeader() and let the producer template take care of inserting the body and exchange property into a default exchange object.
requestBodyAndHeader() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object. The return value is the body of the reply message (Out message body), which can either be returned as plain Object or converted to a specific type, T, using the built-in type converters (see Section 43.3, “Built-In Type Converters”).
requestBodyAndHeaders() methods are similar to the requestBodyAndHeader() methods, except that instead of supplying just a single header setting, these methods allow you to specify a complete hash map of header settings.
46.1.4. Asynchronous Send Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Send an exchange Copy linkLink copied to clipboard!
asyncSend() method takes an Exchange argument and invokes an endpoint asynchronously, using the message exchange pattern (MEP) of the specified exchange. The return value is a java.util.concurrent.Future object, which is a ticket you can use to collect the reply message at a later time—for details of how to obtain the return value from the Future object, see the section called “Asynchronous invocation”.
asyncSend() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object.
Future<Exchange> asyncSend(String endpointUri, Exchange exchange); Future<Exchange> asyncSend(Endpoint endpoint, Exchange exchange);
Future<Exchange> asyncSend(String endpointUri, Exchange exchange);
Future<Exchange> asyncSend(Endpoint endpoint, Exchange exchange);
Send an exchange populated by a processor Copy linkLink copied to clipboard!
asyncSend() method is to use a processor to populate a default exchange, instead of supplying the exchange object explicitly.
asyncSend() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object.
Future<Exchange> asyncSend(String endpointUri, Processor processor); Future<Exchange> asyncSend(Endpoint endpoint, Processor processor);
Future<Exchange> asyncSend(String endpointUri, Processor processor);
Future<Exchange> asyncSend(Endpoint endpoint, Processor processor);
Send a message body Copy linkLink copied to clipboard!
asyncSendBody() methods to send a message body asynchronously and let the producer template take care of inserting the body into a default exchange object.
asyncSendBody() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object.
Future<Object> asyncSendBody(String endpointUri, Object body); Future<Object> asyncSendBody(Endpoint endpoint, Object body);
Future<Object> asyncSendBody(String endpointUri, Object body);
Future<Object> asyncSendBody(Endpoint endpoint, Object body);
46.1.5. Asynchronous Request with InOut Pattern Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Request a message body Copy linkLink copied to clipboard!
requestBody() methods to provide the request message body as an argument and let the producer template take care of inserting the body into a default exchange object.
asyncRequestBody() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object. The return value that is retrievable from the Future object is the body of the reply message (Out message body), which can be returned either as a plain Object or converted to a specific type, T, using a built-in type converter (see the section called “Asynchronous invocation”).
Request a message body and header(s) Copy linkLink copied to clipboard!
asyncRequestBodyAndHeader() methods. You supply the message body and header setting as arguments to asyncRequestBodyAndHeader() and let the producer template take care of inserting the body and exchange property into a default exchange object.
asyncRequestBodyAndHeader() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object. The return value that is retrievable from the Future object is the body of the reply message (Out message body), which can be returned either as a plain Object or converted to a specific type, T, using a built-in type converter (see the section called “Asynchronous invocation”).
asyncRequestBodyAndHeaders() methods are similar to the asyncRequestBodyAndHeader() methods, except that instead of supplying just a single header setting, these methods allow you to specify a complete hash map of header settings.
46.1.6. Asynchronous Send with Callback Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Send an exchange Copy linkLink copied to clipboard!
asyncCallback() method takes an Exchange argument and invokes an endpoint asynchronously, using the message exchange pattern (MEP) of the specified exchange. This method is similar to the asyncSend() method for exchanges, except that it takes an additional org.apache.camel.spi.Synchronization argument, which is a callback interface with two methods: onComplete() and onFailure(). For details of how to use the Synchronization callback, see the section called “Asynchronous invocation with a callback”.
asyncCallback() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object.
Send an exchange populated by a processor Copy linkLink copied to clipboard!
asyncCallback() method for processors calls a processor to populate a default exchange and forces the message exchange pattern to be InOut (so that the invocation obeys request/reply semantics).
asyncCallback() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object.
Send a message body Copy linkLink copied to clipboard!
asyncCallbackSendBody() methods to send a message body asynchronously and let the producer template take care of inserting the body into a default exchange object.
asyncCallbackSendBody() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object.
Request a message body Copy linkLink copied to clipboard!
asyncCallbackRequestBody() methods to provide the request message body as an argument and let the producer template take care of inserting the body into a default exchange object.
asyncCallbackRequestBody() methods let you specify the target endpoint in one of the following ways: as an endpoint URI, or as an Endpoint object.
46.2. Using the Consumer Template Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Example of polling exchanges Copy linkLink copied to clipboard!
receive(); receive() with a timeout; or receiveNoWait(), which returns immediately. Because a consumer endpoint represents a service, it is also essential to start the service thread by calling start() before you attempt to poll for exchanges.
seda:foo consumer endpoint using the blocking receive() method:
consumer, is instantiated using the CamelContext.createConsumerTemplate() method and the consumer service thread is started by calling ConsumerTemplate.start().
Example of polling message bodies Copy linkLink copied to clipboard!
receiveBody(); receiveBody() with a timeout; or receiveBodyNoWait(), which returns immediately. As in the previous example, it is also essential to start the service thread by calling start() before you attempt to poll for exchanges.
seda:foo consumer endpoint using the blocking receiveBody() method:
Methods for polling exchanges Copy linkLink copied to clipboard!
receive() without a timeout blocks indefinitely; receive() with a timeout blocks for the specified period of milliseconds; and receiveNoWait() is non-blocking. You can specify the consumer endpoint either as an endpoint URI or as an Endpoint instance.
Methods for polling message bodies Copy linkLink copied to clipboard!
receiveBody() without a timeout blocks indefinitely; receiveBody() with a timeout blocks for the specified period of milliseconds; and receiveBodyNoWait() is non-blocking. You can specify the consumer endpoint either as an endpoint URI or as an Endpoint instance. Moreover, by calling the templating forms of these methods, you can convert the returned body to a particular type, T, using a built-in type converter.
Chapter 47. Implementing a Component Copy linkLink copied to clipboard!
Abstract
47.1. Component Architecture Copy linkLink copied to clipboard!
47.1.1. Factory Patterns for a Component Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Component object itself (an instance of org.apache.camel.Component type). You can use the Component object as a factory to create Endpoint objects, which in turn act as factories for creating Consumer, Producer, and Exchange objects. These relationships are summarized in Figure 47.1, “Component Factory Patterns”
Figure 47.1. Component Factory Patterns
Component Copy linkLink copied to clipboard!
Component.createEndpoint() method, which is responsible for creating new endpoints on demand.
Endpoint Copy linkLink copied to clipboard!
org.apache.camel.Endpoint interface. The Endpoint interface defines the following factory methods:
createConsumer()andcreatePollingConsumer()—Creates a consumer endpoint, which represents the source endpoint at the beginning of a route.createProducer()—Creates a producer endpoint, which represents the target endpoint at the end of a route.createExchange()—Creates an exchange object, which encapsulates the messages passed up and down the route.
Consumer Copy linkLink copied to clipboard!
org.apache.camel.Consumer interface. There are a number of different patterns you can follow when implementing a consumer. These patterns are described in Section 47.1.3, “Consumer Patterns and Threading”.
Producer Copy linkLink copied to clipboard!
org.apache.camel.Producer interface. You can optionally implement the producer to support an asynchronous style of processing. See Section 47.1.4, “Asynchronous Processing” for details.
Exchange Copy linkLink copied to clipboard!
org.apache.camel.Exchange interface. The default implementation, DefaultExchange, is sufficient for many component implementations. However, if you want to associated extra data with the exchanges or have the exchanges preform additional processing, it can be useful to customize the exchange implementation.
Message Copy linkLink copied to clipboard!
Exchange object:
- In message—holds the current message.
- Out message—temporarily holds a reply message.
org.apache.camel.Message. It is not always necessary to customize the message implementation—the default implementation, DefaultMessage, is usually adequate.
47.1.2. Using a Component in a Route Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.Processor type. Messages are encapsulated in an exchange object, E, which gets passed from node to node by invoking the process() method. The architecture of the processor pipeline is illustrated in Figure 47.2, “Consumer and Producer Instances in a Route”.
Figure 47.2. Consumer and Producer Instances in a Route
Source endpoint Copy linkLink copied to clipboard!
org.apache.camel.Consumer object. The source endpoint is responsible for accepting incoming request messages and dispatching replies. When constructing the route, Apache Camel creates the appropriate Consumer type based on the component prefix from the endpoint URI, as described in Section 47.1.1, “Factory Patterns for a Component”.
Processors Copy linkLink copied to clipboard!
org.apache.camel.Processor interface). You can insert either standard processors (for example, filter, throttler, or delayer) or insert your own custom processor implementations.
Target endpoint Copy linkLink copied to clipboard!
org.apache.camel.Producer object. Because it comes at the end of a processor pipeline, the producer is also a processor object (implementing the org.apache.camel.Processor interface). The target endpoint is responsible for sending outgoing request messages and receiving incoming replies. When constructing the route, Apache Camel creates the appropriate Producer type based on the component prefix from the endpoint URI.
47.1.3. Consumer Patterns and Threading Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
- Event-driven pattern—The consumer is driven by an external thread.
- Scheduled poll pattern—The consumer is driven by a dedicated thread pool.
- Polling pattern—The threading model is left undefined.
Event-driven pattern Copy linkLink copied to clipboard!
handleNotification() method to initiate request processing—see Example 50.4, “JMXConsumer Implementation” for details.
notify() method.
Figure 47.3. Event-Driven Consumer
- The consumer must implement a method to receive the incoming event (in Figure 47.3, “Event-Driven Consumer” this is represented by the
notify()method). The thread that callsnotify()is normally a separate part of the application, so the consumer's threading policy is externally driven.For example, in the case of the JMX consumer implementation, the consumer implements theNotificationListener.handleNotification()method to receive notifications from JMX. The threads that drive the consumer processing are created within the JMX layer. - In the body of the
notify()method, the consumer first converts the incoming event into an exchange object,E, and then callsprocess()on the next processor in the route, passing the exchange object as its argument.
Scheduled poll pattern Copy linkLink copied to clipboard!
Figure 47.4. Scheduled Poll Consumer
- The scheduled executor service has a pool of threads at its disposal, that can be used to initiate consumer processing. After each scheduled time interval has elapsed, the scheduled executor service attempts to grab a free thread from its pool (there are five threads in the pool by default). If a free thread is available, it uses that thread to call the
poll()method on the consumer. - The consumer's
poll()method is intended to trigger processing of an incoming request. In the body of thepoll()method, the consumer attempts to retrieve an incoming message. If no request is available, thepoll()method returns immediately. - If a request message is available, the consumer inserts it into an exchange object and then calls
process()on the next processor in the route, passing the exchange object as its argument.
Polling pattern Copy linkLink copied to clipboard!
receive()receiveNoWait()receive(long timeout)
Figure 47.5. Polling Consumer
- Processing of an incoming request is initiated whenever one of the consumer's polling methods is called. The mechanism for calling these polling methods is implementation defined.
- In the body of the
receive()method, the consumer attempts to retrieve an incoming request message. If no message is currently available, the behavior depends on which receive method was called.receiveNoWait()returns immediatelyreceive(long timeout)waits for the specified timeout interval[3] before returningreceive()waits until a message is received
- If a request message is available, the consumer inserts it into an exchange object and then calls
process()on the next processor in the route, passing the exchange object as its argument.
47.1.4. Asynchronous Processing Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
process() on a producer, the process() method blocks until a reply is received. In this case, the processor's thread remains blocked until the producer has completed the cycle of sending the request and receiving the reply.
process() call does not block. In this case, you should implement the producer using an asynchronous pattern, which gives the preceding processor the option of invoking a non-blocking version of the process() method.
Synchronous producer Copy linkLink copied to clipboard!
Figure 47.6. Synchronous Producer
- The preceding processor in the pipeline calls the synchronous
process()method on the producer to initiate synchronous processing. The synchronousprocess()method takes a single exchange argument. - In the body of the
process()method, the producer sends the request (In message) to the endpoint. - If required by the exchange pattern, the producer waits for the reply (Out message) to arrive from the endpoint. This step can cause the
process()method to block indefinitely. However, if the exchange pattern does not mandate a reply, theprocess()method can return immediately after sending the request. - When the
process()method returns, the exchange object contains the reply from the synchronous call (an Out message message).
Asynchronous producer Copy linkLink copied to clipboard!
Figure 47.7. Asynchronous Producer
- Before the processor can call the asynchronous
process()method, it must create an asynchronous callback object, which is responsible for processing the exchange on the return portion of the route. For the asynchronous callback, the processor must implement a class that inherits from theAsyncCallbackinterface. - The processor calls the asynchronous
process()method on the producer to initiate asynchronous processing. The asynchronousprocess()method takes two arguments:- an exchange object
- a synchronous callback object
- In the body of the
process()method, the producer creates aRunnableobject that encapsulates the processing code. The producer then delegates the execution of thisRunnableobject to a sub-thread. - The asynchronous
process()method returns, thereby freeing up the processor's thread. The exchange processing continues in a separate sub-thread. - The
Runnableobject sends the In message to the endpoint. - If required by the exchange pattern, the
Runnableobject waits for the reply (Out or Fault message) to arrive from the endpoint. TheRunnableobject remains blocked until the reply is received. - After the reply arrives, the
Runnableobject inserts the reply (Out message) into the exchange object and then callsdone()on the asynchronous callback object. The asynchronous callback is then responsible for processing the reply message (executed in the sub-thread).
47.2. How to Implement a Component Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Which interfaces do you need to implement? Copy linkLink copied to clipboard!
org.apache.camel.Componentorg.apache.camel.Endpointorg.apache.camel.Consumerorg.apache.camel.Producer
org.apache.camel.Exchangeorg.apache.camel.Message
Implementation steps Copy linkLink copied to clipboard!
- Implement the
Componentinterface—A component object acts as an endpoint factory. You extend theDefaultComponentclass and implement thecreateEndpoint()method. - Implement the
Endpointinterface—An endpoint represents a resource identified by a specific URI. The approach taken when implementing an endpoint depends on whether the consumers follow an event-driven pattern, a scheduled poll pattern, or a polling pattern.For an event-driven pattern, implement the endpoint by extending theDefaultEndpointclass and implementing the following methods:createProducer()createConsumer()
For a scheduled poll pattern, implement the endpoint by extending theScheduledPollEndpointclass and implementing the following methods:createProducer()createConsumer()
For a polling pattern, implement the endpoint by extending theDefaultPollingEndpointclass and implementing the following methods:createProducer()createPollConsumer()
- Implement the
Consumerinterface—There are several different approaches you can take to implementing a consumer, depending on which pattern you need to implement (event-driven, scheduled poll, or polling). The consumer implementation is also crucially important for determining the threading model used for processing a message exchange. - Implement the
Producerinterface—To implement a producer, you extend theDefaultProducerclass and implement theprocess()method. - Optionally implement the Exchange or the Message interface—The default implementations of
ExchangeandMessagecan be used directly, but occasionally, you might find it necessary to customize these types.
Installing and configuring the component Copy linkLink copied to clipboard!
- Add the component directly to the CamelContext—The
CamelContext.addComponent()method adds a component programatically. - Add the component using Spring configuration—The standard Spring
beanelement creates a component instance. The bean'sidattribute implicitly defines the component prefix. For details, see Section 47.3.2, “Configuring a Component”. - Configure Apache Camel to auto-discover the component—Auto-discovery, ensures that Apache Camel automatically loads the component on demand. For details, see Section 47.3.1, “Setting Up Auto-Discovery”.
47.3. Auto-Discovery and Configuration Copy linkLink copied to clipboard!
47.3.1. Setting Up Auto-Discovery Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Availability of component classes Copy linkLink copied to clipboard!
Configuring auto-discovery Copy linkLink copied to clipboard!
/META-INF/services/org/apache/camel/component/component-prefix
/META-INF/services/org/apache/camel/component/component-prefix
class=component-class-name
class=component-class-name
Example Copy linkLink copied to clipboard!
/META-INF/services/org/apache/camel/component/ftp
/META-INF/services/org/apache/camel/component/ftp
class=org.apache.camel.component.file.remote.RemoteFileComponent
class=org.apache.camel.component.file.remote.RemoteFileComponent
camel-ftp-Version.jar.
47.3.2. Configuring a Component Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
META-INF/spring/camel-context.xml. To find the component, the component's URI prefix is matched against the ID attribute of a bean element in the Spring configuration. If the component prefix matches a bean element ID, Apache Camel instantiates the referenced class and injects the properties specified in the Spring configuration.
Define bean properties on your component class Copy linkLink copied to clipboard!
getProperty() method and the setProperty() method access the value of property.
Configure the component in Spring Copy linkLink copied to clipboard!
META-INF/spring/camel-context.xml, as shown in Example 47.1, “Configuring a Component in Spring”.
Example 47.1. Configuring a Component in Spring
bean element with ID component-prefix configures the component-class-name component. You can inject properties into the component instance using property elements. For example, the property element in the preceding example would inject the value, propertyValue, into the property property by calling setProperty() on the component.
Examples Copy linkLink copied to clipboard!
jms. These settings are added to the Spring configuration file, camel-context.xml.
Example 47.2. JMS Component Spring Configuration
- 1
- The
CamelContextautomatically instantiates anyRouteBuilderclasses that it finds in the specified Java package, org.apache.camel.example.spring. - 2
- The bean element with ID,
jms, configures the JMS component. The bean ID corresponds to the component's URI prefix. For example, if a route specifies an endpoint with the URI, jms://MyQName, Apache Camel automatically loads the JMS component using the settings from thejmsbean element. - 3
- JMS is just a wrapper for a messaging service. You must specify the concrete implementation of the messaging system by setting the
connectionFactoryproperty on theJmsComponentclass. - 4
- In this example, the concrete implementation of the JMS messaging service is Apache ActiveMQ. The
brokerURLproperty initializes a connection to an ActiveMQ broker instance, where the message broker is embedded in the local Java virtual machine (JVM). If a broker is not already present in the JVM, ActiveMQ will instantiate it with the optionsbroker.persistent=false(the broker does not persist messages) andbroker.useJmx=false(the broker does not open a JMX port).
Chapter 48. Component Interface Copy linkLink copied to clipboard!
Abstract
Component interface.
48.1. The Component Interface Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.Component interface. An instance of Component type provides the entry point into a custom component. That is, all of the other objects in a component are ultimately accessible through the Component instance. Figure 48.1, “Component Inheritance Hierarchy” shows the relevant Java interfaces and classes that make up the Component inheritance hierarchy.
Figure 48.1. Component Inheritance Hierarchy
The Component interface Copy linkLink copied to clipboard!
org.apache.camel.Component interface.
Example 48.1. Component Interface
Component methods Copy linkLink copied to clipboard!
Component interface defines the following methods:
getCamelContext()andsetCamelContext()—References theCamelContextto which thisComponentbelongs. ThesetCamelContext()method is automatically called when you add the component to aCamelContext.createEndpoint()—The factory method that gets called to createEndpointinstances for this component. Theuriparameter is the endpoint URI, which contains the details required to create the endpoint.
48.2. Implementing the Component Interface Copy linkLink copied to clipboard!
The DefaultComponent class Copy linkLink copied to clipboard!
org.apache.camel.impl.DefaultComponent class, which provides some standard functionality and default implementations for some of the methods. In particular, the DefaultComponent class provides support for URI parsing and for creating a scheduled executor (which is used for the scheduled poll pattern).
URI parsing Copy linkLink copied to clipboard!
createEndpoint(String uri) method defined in the base Component interface takes a complete, unparsed endpoint URI as its sole argument. The DefaultComponent class, on the other hand, defines a three-argument version of the createEndpoint() method with the following signature:
uri is the original, unparsed URI; remaining is the part of the URI that remains after stripping off the component prefix at the start and cutting off the query options at the end; and parameters contains the parsed query options. It is this version of the createEndpoint() method that you must override when inheriting from DefaultComponent. This has the advantage that the endpoint URI is already parsed for you.
file component shows how URI parsing works in practice:
file:///tmp/messages/foo?delete=true&moveNamePostfix=.old
file:///tmp/messages/foo?delete=true&moveNamePostfix=.old
createEndpoint():
| Argument | Sample Value |
|---|---|
uri | file:///tmp/messages/foo?delete=true&moveNamePostfix=.old |
remaining | /tmp/messages/foo |
parameters |
Two entries are set in
java.util.Map:
|
Parameter injection Copy linkLink copied to clipboard!
DefaultComponent class automatically injects the parameters for you.
delete and moveNamePostfix. All you must do is define the corresponding bean methods (getters and setters) in the endpoint class:
Disabling endpoint parameter injection Copy linkLink copied to clipboard!
Endpoint class, you can optimize the process of endpoint creation by disabling endpoint parameter injection. To disable parameter injection on endpoints, override the useIntrospectionOnEndpoint() method and implement it to return false, as follows:
protected boolean useIntrospectionOnEndpoint() {
return false;
}
protected boolean useIntrospectionOnEndpoint() {
return false;
}
useIntrospectionOnEndpoint() method does not affect the parameter injection that might be performed on a Consumer class. Parameter injection at that level is controlled by the Endpoint.configureProperties() method (see Section 49.2, “Implementing the Endpoint Interface”).
Scheduled executor service Copy linkLink copied to clipboard!
ExecutorServiceStrategy object that is returned by the CamelContext.getExecutorServiceStrategy() method. For details of the Apache Camel threading model, see Section 2.8, “Threading Model”.
DefaultComponent class provided a getExecutorService() method for creating thread pool instances. Since 2.3, however, the creation of thread pools is now managed centrally by the ExecutorServiceStrategy object.
Validating the URI Copy linkLink copied to clipboard!
validateURI() method from the DefaultComponent class, which has the following signature:
protected void validateURI(String uri,
String path,
Map parameters)
throws ResolveEndpointFailedException;validateURI() should throw the org.apache.camel.ResolveEndpointFailedException exception.
Creating an endpoint Copy linkLink copied to clipboard!
createEndpoint()” outlines how to implement the DefaultComponent.createEndpoint() method, which is responsible for creating endpoint instances on demand.
Example 48.2. Implementation of createEndpoint()
- 1
- The CustomComponent is the name of your custom component class, which is defined by extending the
DefaultComponentclass. - 2
- When extending
DefaultComponent, you must implement thecreateEndpoint()method with three arguments (see the section called “URI parsing”). - 3
- Create an instance of your custom endpoint type, CustomEndpoint, by calling its constructor. At a minimum, this constructor takes a copy of the original URI string,
uri, and a reference to this component instance,this.
Example Copy linkLink copied to clipboard!
FileComponent class.
Example 48.3. FileComponent Implementation
- 1
- Always define a no-argument constructor for the component class in order to facilitate automatic instantiation of the class.
- 2
- A constructor that takes the parent
CamelContextinstance as an argument is convenient when creating a component instance by programming. - 3
- The implementation of the
FileComponent.createEndpoint()method follows the pattern described in Example 48.2, “Implementation ofcreateEndpoint()”. The implementation creates aFileEndpointobject.
SynchronizationRouteAware Interface Copy linkLink copied to clipboard!
SynchronizationRouteAware interface allows you to have callbacks before and after the exchange has been routed.
onBeforeRoute: Invoked before the exchange has been routed by the given route. However, this callback may not get invoked, if you add theSynchronizationRouteAwareimplementation to theUnitOfWork, after starting the route.onAfterRoute: Invoked after the exchange has been routed by the given route. However, if the exchange is being routed through multiple routes, it would generate call backs for each route.This invocation occurs before these callbacks:- The consumer of the route writes any response back to the caller (if in
InOutmode) - The
UnitOfWorkis done by calling eitherSynchronization.onComplete(org.apache.camel.Exchange)orSynchronization.onFailure(org.apache.camel.Exchange)
Chapter 49. Endpoint Interface Copy linkLink copied to clipboard!
Abstract
Endpoint interface, which is an essential step in the implementation of a Apache Camel component.
49.1. The Endpoint Interface Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.Endpoint type encapsulates an endpoint URI, and it also serves as a factory for Consumer, Producer, and Exchange objects. There are three different approaches to implementing an endpoint:
- Event-driven
- scheduled poll
- polling
Endpoint inheritance hierarchy.
Figure 49.1. Endpoint Inheritance Hierarchy
The Endpoint interface Copy linkLink copied to clipboard!
org.apache.camel.Endpoint interface.
Example 49.1. Endpoint Interface
Endpoint methods Copy linkLink copied to clipboard!
Endpoint interface defines the following methods:
isSingleton()—Returnstrue, if you want to ensure that each URI maps to a single endpoint within a CamelContext. When this property istrue, multiple references to the identical URI within your routes always refer to a single endpoint instance. When this property isfalse, on the other hand, multiple references to the same URI within your routes refer to distinct endpoint instances. Each time you refer to the URI in a route, a new endpoint instance is created.getEndpointUri()—Returns the endpoint URI of this endpoint.getEndpointKey()—Used byorg.apache.camel.spi.LifecycleStrategywhen registering the endpoint.getCamelContext()—return a reference to theCamelContextinstance to which this endpoint belongs.setCamelContext()—Sets theCamelContextinstance to which this endpoint belongs.configureProperties()—Stores a copy of the parameter map that is used to inject parameters when creating a newConsumerinstance.isLenientProperties()—Returnstrueto indicate that the URI is allowed to contain unknown parameters (that is, parameters that cannot be injected on theEndpointor theConsumerclass). Normally, this method should be implemented to returnfalse.createExchange()—An overloaded method with the following variants:Exchange createExchange()—Creates a new exchange instance with a default exchange pattern setting.Exchange createExchange(ExchangePattern pattern)—Creates a new exchange instance with the specified exchange pattern.Exchange createExchange(Exchange exchange)—Converts the givenexchangeargument to the type of exchange needed for this endpoint. If the given exchange is not already of the correct type, this method copies it into a new instance of the correct type. A default implementation of this method is provided in theDefaultEndpointclass.
createProducer()—Factory method used to create newProducerinstances.createConsumer()—Factory method to create new event-driven consumer instances. Theprocessorargument is a reference to the first processor in the route.createPollingConsumer()—Factory method to create new polling consumer instances.
Endpoint singletons Copy linkLink copied to clipboard!
isSingleton() to return true.
49.2. Implementing the Endpoint Interface Copy linkLink copied to clipboard!
Alternative ways of implementing an endpoint Copy linkLink copied to clipboard!
Event-driven endpoint implementation Copy linkLink copied to clipboard!
org.apache.camel.impl.DefaultEndpoint, as shown in Example 49.2, “Implementing DefaultEndpoint”.
Example 49.2. Implementing DefaultEndpoint
- 1
- Implement an event-driven custom endpoint, CustomEndpoint, by extending the
DefaultEndpointclass. - 2
- You must have at least one constructor that takes the endpoint URI,
endpointUri, and the parent component reference,component, as arguments. - 3
- Implement the
createProducer()factory method to create producer endpoints. - 4
- Implement the
createConsumer()factory method to create event-driven consumer instances.ImportantDo not override thecreatePollingConsumer()method. - 5
- In general, it is not necessary to override the
createExchange()methods. The implementations inherited fromDefaultEndpointcreate aDefaultExchangeobject by default, which can be used in any Apache Camel component. If you need to initialize some exchange properties in theDefaultExchangeobject, however, it is appropriate to override thecreateExchange()methods here in order to add the exchange property settings.
DefaultEndpoint class provides default implementations of the following methods, which you might find useful when writing your custom endpoint code:
getEndpointUri()—Returns the endpoint URI.getCamelContext()—Returns a reference to theCamelContext.getComponent()—Returns a reference to the parent component.createPollingConsumer()—Creates a polling consumer. The created polling consumer's functionality is based on the event-driven consumer. If you override the event-driven consumer method,createConsumer(), you get a polling consumer implementation for free.createExchange(Exchange e)—Converts the given exchange object,e, to the type required for this endpoint. This method creates a new endpoint using the overriddencreateExchange()endpoints. This ensures that the method also works for custom exchange types.
Scheduled poll endpoint implementation Copy linkLink copied to clipboard!
org.apache.camel.impl.ScheduledPollEndpoint, as shown in Example 49.3, “ScheduledPollEndpoint Implementation”.
Example 49.3. ScheduledPollEndpoint Implementation
- 1
- Implement a scheduled poll custom endpoint, CustomEndpoint, by extending the
ScheduledPollEndpointclass. - 2
- You must to have at least one constructor that takes the endpoint URI,
endpointUri, and the parent component reference,component, as arguments. - 3
- Implement the
createProducer()factory method to create a producer endpoint. - 4
- Implement the
createConsumer()factory method to create a scheduled poll consumer instance.ImportantDo not override thecreatePollingConsumer()method. - 5
- The
configureConsumer()method, defined in theScheduledPollEndpointbase class, is responsible for injecting consumer query options into the consumer. See the section called “Consumer parameter injection”. - 6
- In general, it is not necessary to override the
createExchange()methods. The implementations inherited fromDefaultEndpointcreate aDefaultExchangeobject by default, which can be used in any Apache Camel component. If you need to initialize some exchange properties in theDefaultExchangeobject, however, it is appropriate to override thecreateExchange()methods here in order to add the exchange property settings.
Polling endpoint implementation Copy linkLink copied to clipboard!
org.apache.camel.impl.DefaultPollingEndpoint, as shown in Example 49.4, “DefaultPollingEndpoint Implementation”.
Example 49.4. DefaultPollingEndpoint Implementation
createPollingConsumer() method instead of the createConsumer() method. The consumer instance returned from createPollingConsumer() must inherit from the PollingConsumer interface. For details of how to implement a polling consumer, see the section called “Polling consumer implementation”.
createPollingConsumer() method, the steps for implementing a DefaultPollingEndpoint are similar to the steps for implementing a ScheduledPollEndpoint. See Example 49.3, “ScheduledPollEndpoint Implementation” for details.
Implementing the BrowsableEndpoint interface Copy linkLink copied to clipboard!
org.apache.camel.spi.BrowsableEndpoint interface, as shown in Example 49.5, “BrowsableEndpoint Interface”. It makes sense to implement this interface if the endpoint performs some sort of buffering of incoming events. For example, the Apache Camel SEDA endpoint implements the BrowsableEndpoint interface—see Example 49.6, “SedaEndpoint Implementation”.
Example 49.5. BrowsableEndpoint Interface
Example Copy linkLink copied to clipboard!
SedaEndpoint. The SEDA endpoint is an example of an event-driven endpoint. Incoming events are stored in a FIFO queue (an instance of java.util.concurrent.BlockingQueue) and a SEDA consumer starts up a thread to read and process the events. The events themselves are represented by org.apache.camel.Exchange objects.
Example 49.6. SedaEndpoint Implementation
- 1
- The
SedaEndpointclass follows the pattern for implementing an event-driven endpoint by extending theDefaultEndpointclass. TheSedaEndpointclass also implements theBrowsableEndpointinterface, which provides access to the list of exchange objects in the queue. - 2
- Following the usual pattern for an event-driven consumer,
SedaEndpointdefines a constructor that takes an endpoint argument,endpointUri, and a component reference argument,component. - 3
- Another constructor is provided, which delegates queue creation to the parent component instance.
- 4
- The
createProducer()factory method creates an instance ofCollectionProducer, which is a producer implementation that adds events to the queue. - 5
- The
createConsumer()factory method creates an instance ofSedaConsumer, which is responsible for pulling events off the queue and processing them. - 6
- The
getQueue()method returns a reference to the queue. - 7
- The
isSingleton()method returnstrue, indicating that a single endpoint instance should be created for each unique URI string. - 8
- The
getExchanges()method implements the corresponding abstract method fromBrowsableEndpoint.
Chapter 50. Consumer Interface Copy linkLink copied to clipboard!
Abstract
Consumer interface, which is an essential step in the implementation of a Apache Camel component.
50.1. The Consumer Interface Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.Consumer type represents a source endpoint in a route. There are several different ways of implementing a consumer (see Section 47.1.3, “Consumer Patterns and Threading”), and this degree of flexibility is reflected in the inheritance hierarchy ( see Figure 50.1, “Consumer Inheritance Hierarchy”), which includes several different base classes for implementing a consumer.
Figure 50.1. Consumer Inheritance Hierarchy
Consumer parameter injection Copy linkLink copied to clipboard!
custom prefix:
custom:destination?consumer.myConsumerParam
custom:destination?consumer.myConsumerParam
consumer.*. For the consumer.myConsumerParam parameter, you need to define corresponding setter and getter methods on the Consumer implementation class as follows:
configureConsumer() method in the implementation of Endpoint.createConsumer(). See the section called “Scheduled poll endpoint implementation”). Example 50.1, “FileEndpoint createConsumer() Implementation” shows an example of a createConsumer() method implementation, taken from the FileEndpoint class in the file component:
Example 50.1. FileEndpoint createConsumer() Implementation
- When the endpoint is created, the default implementation of
DefaultComponent.createEndpoint(String uri)parses the URI to extract the consumer parameters, and stores them in the endpoint instance by callingScheduledPollEndpoint.configureProperties(). - When
createConsumer()is called, the method implementation callsconfigureConsumer()to inject the consumer parameters (see Example 50.1, “FileEndpoint createConsumer() Implementation”). - The
configureConsumer()method uses Java reflection to call the setter methods whose names match the relevant options after theconsumer.prefix has been stripped off.
Scheduled poll parameters Copy linkLink copied to clipboard!
| Name | Default | Description |
|---|---|---|
initialDelay | 1000 | Delay, in milliseconds, before the first poll. |
delay | 500 | Depends on the value of the useFixedDelay flag (time unit is milliseconds). |
useFixedDelay | false |
If
false, the delay parameter is interpreted as the polling period. Polls will occur at initialDelay, initialDelay+delay, initialDelay+2*delay, and so on.
If
true, the delay parameter is interpreted as the time elapsed between the previous execution and the next execution. Polls will occur at initialDelay, initialDelay+[ProcessingTime]+delay, and so on. Where ProcessingTime is the time taken to process an exchange object in the current thread.
|
Converting between event-driven and polling consumers Copy linkLink copied to clipboard!
org.apache.camel.impl.EventDrivenPollingConsumer—Converts an event-driven consumer into a polling consumer instance.org.apache.camel.impl.DefaultScheduledPollConsumer—Converts a polling consumer into an event-driven consumer instance.
Endpoint type. The Endpoint interface defines the following two methods for creating a consumer instance:
createConsumer() returns an event-driven consumer and createPollingConsumer() returns a polling consumer. You would only implement one these methods. For example, if you are following the event-driven pattern for your consumer, you would implement the createConsumer() method provide a method implementation for createPollingConsumer() that simply raises an exception. With the help of the conversion classes, however, Apache Camel is able to provide a more useful default implementation.
DefaultEndpoint and implementing the createConsumer() method. The implementation of createPollingConsumer() is inherited from DefaultEndpoint, where it is defined as follows:
public PollingConsumer<E> createPollingConsumer() throws Exception {
return new EventDrivenPollingConsumer<E>(this);
}
public PollingConsumer<E> createPollingConsumer() throws Exception {
return new EventDrivenPollingConsumer<E>(this);
}
EventDrivenPollingConsumer constructor takes a reference to the event-driven consumer, this, effectively wrapping it and converting it into a polling consumer. To implement the conversion, the EventDrivenPollingConsumer instance buffers incoming events and makes them available on demand through the receive(), the receive(long timeout), and the receiveNoWait() methods.
DefaultPollingEndpoint and implementing the createPollingConsumer() method. In this case, the implementation of the createConsumer() method is inherited from DefaultPollingEndpoint, and the default implementation returns a DefaultScheduledPollConsumer instance (which converts the polling consumer into an event-driven consumer).
ShutdownPrepared interface Copy linkLink copied to clipboard!
org.apache.camel.spi.ShutdownPrepared interface, which enables your custom consumer endpoint to receive shutdown notifications.
ShutdownPrepared interface.
Example 50.2. ShutdownPrepared Interface
ShutdownPrepared interface defines the following methods:
prepareShutdown- Receives notifications to shut down the consumer endpoint in one or two phases, as follows:
- Graceful shutdown—where the
forcedargument has the valuefalse. Attempt to clean up resources gracefully. For example, by stopping threads gracefully. - Forced shutdown—where the
forcedargument has the valuetrue. This means that the shutdown has timed out, so you must clean up resources more aggressively. This is the last chance to clean up resources before the process exits.
ShutdownAware interface Copy linkLink copied to clipboard!
org.apache.camel.spi.ShutdownAware interface, which interacts with the graceful shutdown mechanism, enabling a consumer to ask for extra time to shut down. This is typically needed for components such as SEDA, which can have pending exchanges stored in an internal queue. Normally, you would want to process all of the exchanges in the queue before shutting down the SEDA consumer.
ShutdownAware interface.
Example 50.3. ShutdownAware Interface
ShutdownAware interface defines the following methods:
deferShutdown- Return
truefrom this method, if you want to delay shutdown of the consumer. TheshutdownRunningTaskargument is anenumwhich can take either of the following values:ShutdownRunningTask.CompleteCurrentTaskOnly—finish processing the exchanges that are currently being processed by the consumer's thread pool, but do not attempt to process any more exchanges than that.ShutdownRunningTask.CompleteAllTasks—process all of the pending exchanges. For example, in the case of the SEDA component, the consumer would process all of the exchanges from its incoming queue.
getPendingExchangesSize- Indicates how many exchanges remain to be processed by the consumer. A zero value indicates that processing is finished and the consumer can be shut down.
ShutdownAware methods, see Example 50.7, “Custom Threading Implementation”.
50.2. Implementing the Consumer Interface Copy linkLink copied to clipboard!
Alternative ways of implementing a consumer Copy linkLink copied to clipboard!
Event-driven consumer implementation Copy linkLink copied to clipboard!
JMXConsumer class, which is taken from the Apache Camel JMX component implementation. The JMXConsumer class is an example of an event-driven consumer, which is implemented by inheriting from the org.apache.camel.impl.DefaultConsumer class. In the case of the JMXConsumer example, events are represented by calls on the NotificationListener.handleNotification() method, which is a standard way of receiving JMX events. In order to receive these JMX events, it is necessary to implement the NotificationListener interface and override the handleNotification() method, as shown in Example 50.4, “JMXConsumer Implementation”.
Example 50.4. JMXConsumer Implementation
- 1
- The
JMXConsumerpattern follows the usual pattern for event-driven consumers by extending theDefaultConsumerclass. Additionally, because this consumer is designed to receive events from JMX (which are represented by JMX notifications), it is necessary to implement theNotificationListenerinterface. - 2
- You must implement at least one constructor that takes a reference to the parent endpoint,
endpoint, and a reference to the next processor in the chain,processor, as arguments. - 3
- The
handleNotification()method (which is defined inNotificationListener) is automatically invoked by JMX whenever a JMX notification arrives. The body of this method should contain the code that performs the consumer's event processing. Because thehandleNotification()call originates from the JMX layer, the consumer's threading model is implicitly controlled by the JMX layer, not by theJMXConsumerclass.NoteThehandleNotification()method is specific to the JMX example. When implementing your own event-driven consumer, you must identify an analogous event listener method to implement in your custom consumer. - 4
- This line of code combines two steps. First, the JMX notification object is converted into an exchange object, which is the generic representation of an event in Apache Camel. Then the newly created exchange object is passed to the next processor in the route (invoked synchronously).
- 5
- The
handleException()method is implemented by theDefaultConsumerbase class. By default, it handles exceptions using theorg.apache.camel.impl.LoggingExceptionHandlerclass.
Scheduled poll consumer implementation Copy linkLink copied to clipboard!
java.util.concurrent.ScheduledExecutorService. To receive the generated polling events, you must implement the ScheduledPollConsumer.poll() method (see Section 47.1.3, “Consumer Patterns and Threading”).
ScheduledPollConsumer class.
Example 50.5. ScheduledPollConsumer Implementation
- 1
- Implement a scheduled poll consumer class, CustomConsumer, by extending the
org.apache.camel.impl.ScheduledPollConsumerclass. - 2
- You must implement at least one constructor that takes a reference to the parent endpoint,
endpoint, and a reference to the next processor in the chain,processor, as arguments. - 3
- Override the
poll()method to receive the scheduled polling events. This is where you should put the code that retrieves and processes incoming events (represented by exchange objects). - 4
- In this example, the event is processed synchronously. If you want to process events asynchronously, you should use a reference to an asynchronous processor instead, by calling
getAsyncProcessor(). For details of how to process events asynchronously, see Section 47.1.4, “Asynchronous Processing”. - 5
- (Optional) If you want some lines of code to execute as the consumer is starting up, override the
doStart()method as shown. - 6
- (Optional) If you want some lines of code to execute as the consumer is stopping, override the
doStop()method as shown.
Polling consumer implementation Copy linkLink copied to clipboard!
PollingConsumerSupport class.
Example 50.6. PollingConsumerSupport Implementation
- 1
- Implement your polling consumer class, CustomConsumer, by extending the
org.apache.camel.impl.PollingConsumerSupportclass. - 2
- You must implement at least one constructor that takes a reference to the parent endpoint,
endpoint, as an argument. A polling consumer does not need a reference to a processor instance. - 3
- The
receiveNoWait()method should implement a non-blocking algorithm for retrieving an event (exchange object). If no event is available, it should returnnull. - 4
- The
receive()method should implement a blocking algorithm for retrieving an event. This method can block indefinitely, if events remain unavailable. - 5
- The
receive(long timeout)method implements an algorithm that can block for as long as the specified timeout (typically specified in units of milliseconds). - 6
- If you want to insert code that executes while a consumer is starting up or shutting down, implement the
doStart()method and thedoStop()method, respectively.
Custom threading implementation Copy linkLink copied to clipboard!
Consumer interface directly and write the threading code yourself. When writing the threading code, however, it is important that you comply with the standard Apache Camel threading model, as described in Section 2.8, “Threading Model”.
camel-core implements its own consumer threading, which is consistent with the Apache Camel threading model. Example 50.7, “Custom Threading Implementation” shows an outline of how the SedaConsumer class implements its threading.
Example 50.7. Custom Threading Implementation
- 1
- The
SedaConsumerclass is implemented by extending theorg.apache.camel.impl.ServiceSupportclass and implementing theConsumer,Runnable, andShutdownAwareinterfaces. - 2
- Implement the
Runnable.run()method to define what the consumer does while it is running in a thread. In this case, the consumer runs in a loop, polling the queue for new exchanges and then processing the exchanges in the latter part of the queue. - 3
- The
doStart()method is inherited fromServiceSupport. You override this method in order to define what the consumer does when it starts up. - 4
- Instead of creating threads directly, you should create a thread pool using the
ExecutorServiceStrategyobject that is registered with theCamelContext. This is important, because it enables Apache Camel to implement centralized management of threads and support such features as graceful shutdown.For details, see Section 2.8, “Threading Model”. - 5
- Kick off the threads by calling the
ExecutorService.execute()methodpoolSizetimes. - 6
- The
doStop()method is inherited fromServiceSupport. You override this method in order to define what the consumer does when it shuts down. - 7
- Shut down the thread pool, which is represented by the
executorinstance.
Chapter 51. Producer Interface Copy linkLink copied to clipboard!
Abstract
Producer interface, which is an essential step in the implementation of a Apache Camel component.
51.1. The Producer Interface Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.Producer type represents a target endpoint in a route. The role of the producer is to send requests (In messages) to a specific physical endpoint and to receive the corresponding response (Out or Fault message). A Producer object is essentially a special kind of Processor that appears at the end of a processor chain (equivalent to a route). Figure 51.1, “Producer Inheritance Hierarchy” shows the inheritance hierarchy for producers.
Figure 51.1. Producer Inheritance Hierarchy
The Producer interface Copy linkLink copied to clipboard!
org.apache.camel.Producer interface.
Example 51.1. Producer Interface
Producer methods Copy linkLink copied to clipboard!
Producer interface defines the following methods:
process()(inherited from Processor)—The most important method. A producer is essentially a special type of processor that sends a request to an endpoint, instead of forwarding the exchange object to another processor. By overriding theprocess()method, you define how the producer sends and receives messages to and from the relevant endpoint.getEndpoint()—Returns a reference to the parent endpoint instance.createExchange()—These overloaded methods are analogous to the corresponding methods defined in theEndpointinterface. Normally, these methods delegate to the corresponding methods defined on the parentEndpointinstance (this is what theDefaultEndpointclass does by default). Occasionally, you might need to override these methods.
Asynchronous processing Copy linkLink copied to clipboard!
process() method returns without delay. See Section 47.1.4, “Asynchronous Processing”.
org.apache.camel.AsyncProcessor interface. On its own, this is not enough to ensure that the asynchronous processing model will be used: it is also necessary for the preceding processor in the chain to call the asynchronous version of the process() method. The definition of the AsyncProcessor interface is shown in Example 51.2, “AsyncProcessor Interface”.
Example 51.2. AsyncProcessor Interface
package org.apache.camel;
public interface AsyncProcessor extends Processor {
boolean process(Exchange exchange, AsyncCallback callback);
}
package org.apache.camel;
public interface AsyncProcessor extends Processor {
boolean process(Exchange exchange, AsyncCallback callback);
}
process() method takes an extra argument, callback, of org.apache.camel.AsyncCallback type. The corresponding AsyncCallback interface is defined as shown in Example 51.3, “AsyncCallback Interface”.
Example 51.3. AsyncCallback Interface
package org.apache.camel;
public interface AsyncCallback {
void done(boolean doneSynchronously);
}
package org.apache.camel;
public interface AsyncCallback {
void done(boolean doneSynchronously);
}
AsyncProcessor.process() must provide an implementation of AsyncCallback to receive the notification that processing has finished. The AsyncCallback.done() method takes a boolean argument that indicates whether the processing was performed synchronously or not. Normally, the flag would be false, to indicate asynchronous processing. In some cases, however, it can make sense for the producer not to process asynchronously (in spite of being asked to do so). For example, if the producer knows that the processing of the exchange will complete rapidly, it could optimise the processing by doing it synchronously. In this case, the doneSynchronously flag should be set to true.
ExchangeHelper class Copy linkLink copied to clipboard!
org.apache.camel.util.ExchangeHelper utility class. For full details of the ExchangeHelper class, see Section 44.4, “The ExchangeHelper Class”.
51.2. Implementing the Producer Interface Copy linkLink copied to clipboard!
Alternative ways of implementing a producer Copy linkLink copied to clipboard!
How to implement a synchronous producer Copy linkLink copied to clipboard!
Producer.process() blocks until a reply is received.
Example 51.4. DefaultProducer Implementation
- 1
- Implement a custom synchronous producer class, CustomProducer, by extending the
org.apache.camel.impl.DefaultProducerclass. - 2
- Implement a constructor that takes a reference to the parent endpoint.
- 3
- The
process()method implementation represents the core of the producer code. The implementation of theprocess()method is entirely dependent on the type of component that you are implementing. In outline, theprocess()method is normally implemented as follows:- If the exchange contains an In message, and if this is consistent with the specified exchange pattern, then send the In message to the designated endpoint.
- If the exchange pattern anticipates the receipt of an Out message, then wait until the Out message has been received. This typically causes the
process()method to block for a significant length of time. - When a reply is received, call
exchange.setOut()to attach the reply to the exchange object. If the reply contains a fault message, set the fault flag on the Out message usingMessage.setFault(true).
How to implement an asynchronous producer Copy linkLink copied to clipboard!
process() method and an asynchronous process() method (which takes an additional AsyncCallback argument).
Example 51.5. CollectionProducer Implementation
- 1
- Implement a custom asynchronous producer class, CustomProducer, by extending the
org.apache.camel.impl.DefaultProducerclass, and implementing theAsyncProcessorinterface. - 2
- Implement a constructor that takes a reference to the parent endpoint.
- 3
- Implement the synchronous
process()method. - 4
- Implement the asynchronous
process()method. You can implement the asynchronous method in several ways. The approach shown here is to create ajava.lang.Runnableinstance,task, that represents the code that runs in a sub-thread. You then use the Java threading API to run the task in a sub-thread (for example, by creating a new thread or by allocating the task to an existing thread pool). - 5
- Normally, you return
falsefrom the asynchronousprocess()method, to indicate that the exchange was processed asynchronously. - 6
- The CustomProducer
Taskclass encapsulates the processing code that runs in a sub-thread. This class must store a copy of theExchangeobject,exchange, and theAsyncCallbackobject,callback, as private member variables. - 7
- The
run()method contains the code that sends the In message to the producer endpoint and waits to receive the reply, if any. After receiving the reply (Out message or Fault message) and inserting it into the exchange object, you must callcallback.done()to notify the caller that processing is complete.
Chapter 52. Exchange Interface Copy linkLink copied to clipboard!
Abstract
Exchange interface. Since the refactoring of the camel-core module performed in Apache Camel 2.0, there is no longer any necessity to define custom exchange types. The DefaultExchange implementation can now be used in all cases.
52.1. The Exchange Interface Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.Exchange type encapsulates the current message passing through a route, with additional metadata encoded as exchange properties.
DefaultExchange, is always used.
Figure 52.1. Exchange Inheritance Hierarchy
The Exchange interface Copy linkLink copied to clipboard!
org.apache.camel.Exchange interface.
Example 52.1. Exchange Interface
Exchange methods Copy linkLink copied to clipboard!
Exchange interface defines the following methods:
getPattern(),setPattern()—The exchange pattern can be one of the values enumerated inorg.apache.camel.ExchangePattern. The following exchange pattern values are supported:InOnlyRobustInOnlyInOutInOptionalOutOutOnlyRobustOutOnlyOutInOutOptionalIn
setProperty(),getProperty(),getProperties(),removeProperty(),hasProperties()—Use the property setter and getter methods to associate named properties with the exchange instance. The properties consist of miscellaneous metadata that you might need for your component implementation.setIn(),getIn()—Setter and getter methods for the In message.ThegetIn()implementation provided by theDefaultExchangeclass implements lazy creation semantics: if the In message is null whengetIn()is called, theDefaultExchangeclass creates a default In message.setOut(),getOut(),hasOut()—Setter and getter methods for the Out message.ThegetOut()method implicitly supports lazy creation of an Out message. That is, if the current Out message isnull, a new message instance is automatically created.setException(),getException()—Getter and setter methods for an exception object (ofThrowabletype).isFailed()—Returnstrue, if the exchange failed either due to an exception or due to a fault.isTransacted()—Returnstrue, if the exchange is transacted.isRollback()—Returnstrue, if the exchange is marked for rollback.getContext()—Returns a reference to the associatedCamelContextinstance.copy()—Creates a new, identical (apart from the exchange ID) copy of the current custom exchange object. The body and headers of the In message, the Out message (if any), and the Fault message (if any) are also copied by this operation.setFromEndpoint(),getFromEndpoint()—Getter and setter methods for the consumer endpoint that orginated this message (which is typically the endpoint appearing in thefrom()DSL command at the start of a route).setFromRouteId(),getFromRouteId()—Getters and setters for the route ID that originated this exchange. ThegetFromRouteId()method should only be called internally.setUnitOfWork(),getUnitOfWork()—Getter and setter methods for theorg.apache.camel.spi.UnitOfWorkbean property. This property is only required for exchanges that can participate in a transaction.setExchangeId(),getExchangeId()—Getter and setter methods for the exchange ID. Whether or not a custom component uses and exchange ID is an implementation detail.addOnCompletion()—Adds anorg.apache.camel.spi.Synchronizationcallback object, which gets called when processing of the exchange has completed.handoverCompletions()—Hands over all of the OnCompletion callback objects to the specified exchange object.
Chapter 53. Message Interface Copy linkLink copied to clipboard!
Abstract
Message interface, which is an optional step in the implementation of a Apache Camel component.
53.1. The Message Interface Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.Message type can represent any kind of message (In or Out). Figure 53.1, “Message Inheritance Hierarchy” shows the inheritance hierarchy for the message type. You do not always need to implement a custom message type for a component. In many cases, the default implementation, DefaultMessage, is adequate.
Figure 53.1. Message Inheritance Hierarchy
The Message interface Copy linkLink copied to clipboard!
org.apache.camel.Message interface.
Example 53.1. Message Interface
Message methods Copy linkLink copied to clipboard!
Message interface defines the following methods:
setMessageId(),getMessageId()—Getter and setter methods for the message ID. Whether or not you need to use a message ID in your custom component is an implementation detail.getExchange()—Returns a reference to the parent exchange object.isFault(),setFault()—Getter and setter methods for the fault flag, which indicates whether or not this message is a fault message.getHeader(),getHeaders(),setHeader(),setHeaders(),removeHeader(),hasHeaders()—Getter and setter methods for the message headers. In general, these message headers can be used either to store actual header data, or to store miscellaneous metadata.getBody(),getMandatoryBody(),setBody()—Getter and setter methods for the message body. The getMandatoryBody() accessor guarantees that the returned body is non-null, otherwise theInvalidPayloadExceptionexception is thrown.getAttachment(),getAttachments(),getAttachmentNames(),removeAttachment(),addAttachment(),setAttachments(),hasAttachments()—Methods to get, set, add, and remove attachments.copy()—Creates a new, identical (including the message ID) copy of the current custom message object.copyFrom()—Copies the complete contents (including the message ID) of the specified generic message object,message, into the current message instance. Because this method must be able to copy from any message type, it copies the generic message properties, but not the custom properties.createExchangeId()—Returns the unique ID for this exchange, if the message implementation is capable of providing an ID; otherwise, returnnull.
53.2. Implementing the Message Interface Copy linkLink copied to clipboard!
How to implement a custom message Copy linkLink copied to clipboard!
DefaultMessage class.
Example 53.2. Custom Message Implementation
- 1
- Implements a custom message class, CustomMessage, by extending the
org.apache.camel.impl.DefaultMessageclass. - 2
- Typically, you need a default constructor that creates a message with default properties.
- 3
- Override the
toString()method to customize message stringification. - 4
- The
newInstance()method is called from inside theMessageSupport.copy()method. Customization of thenewInstance()method should focus on copying all of the custom properties of the current message instance into the new message instance. TheMessageSupport.copy()method copies the generic message properties by callingcopyFrom(). - 5
- The
createBody()method works in conjunction with theMessageSupport.getBody()method to implement lazy access to the message body. By default, the message body isnull. It is only when the application code tries to access the body (by callinggetBody()), that the body should be created. TheMessageSupport.getBody()automatically callscreateBody(), when the message body is accessed for the first time. - 6
- The
populateInitialHeaders()method works in conjunction with the header getter and setter methods to implement lazy access to the message headers. This method parses the message to extract any message headers and inserts them into the hash map,map. ThepopulateInitialHeaders()method is automatically called when a user attempts to access a header (or headers) for the first time (by callinggetHeader(),getHeaders(),setHeader(), orsetHeaders()). - 7
- The
populateInitialAttachments()method works in conjunction with the attachment getter and setter methods to implement lazy access to the attachments. This method extracts the message attachments and inserts them into the hash map,map. ThepopulateInitialAttachments()method is automatically called when a user attempts to access an attachment (or attachments) for the first time by callinggetAttachment(),getAttachments(),getAttachmentNames(), oraddAttachment().
Part V. The API Component Framework Copy linkLink copied to clipboard!
Abstract
Chapter 54. Introduction to the API Component Framework Copy linkLink copied to clipboard!
Abstract
54.1. What is the API Component Framework? Copy linkLink copied to clipboard!
Motivation Copy linkLink copied to clipboard!
Turning APIs into components Copy linkLink copied to clipboard!
Generic URI format Copy linkLink copied to clipboard!
scheme://endpoint-prefix/endpoint?Option1=Value1&...&OptionN=ValueN
scheme://endpoint-prefix/endpoint?Option1=Value1&...&OptionN=ValueN
scheme is the default URI scheme defined by the component; endpoint-prefix is a short API name, which maps to one of the classes or interfaces from the wrapped Java API; endpoint maps to a method name; and the URI options map to method argument names.
URI format for a single API class Copy linkLink copied to clipboard!
endpoint-prefix part of the URI becomes redundant, and you can specify the URI in the following, shorter format:
scheme://endpoint?Option1=Value1&...&OptionN=ValueN
scheme://endpoint?Option1=Value1&...&OptionN=ValueN
apiName element blank in the configuration of the API component Maven plug-in.
Reflection and metadata Copy linkLink copied to clipboard!
Javadoc Copy linkLink copied to clipboard!
maven-javadoc-plugin) and, in many cases, is already provided in a third-party library.
Method signature files Copy linkLink copied to clipboard!
What does the framework consist of? Copy linkLink copied to clipboard!
- A Maven archetype
- The
camel-archetype-api-componentMaven archetype is used to generate skeleton code for the component implementation. - A Maven plug-in
- The
camel-api-component-maven-pluginMaven plug-in is responsible for generating the code that implements the mapping between the Java API and the endpoint URI syntax. - Specialized base classes
- To support the programming model of the API component framework, the Apache Camel core provides a specialized API in the
org.apache.camel.util.componentpackage. Amongst other things, this API provides specialized base classes for the component, endpoint, consumer, and producer classes.
54.2. How to use the Framework Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Figure 54.1. Using the API Component Framework
Java API Copy linkLink copied to clipboard!
- Implement the Java API yourself (though this typically would involve a lot of work and is generally not the preferred approach).
- Use a third-party Java API. For example, the Apache Camel Box component is based on the third-party Box Java SDK library.
- Generate the Java API from a language-neutral interface. For example, the Apache Camel LinkedIn component obtains its Java API by converting a WADL description of its REST services to Java (using the Apache CXF
wadl2javatool).
Javadoc metadata Copy linkLink copied to clipboard!
maven-javadoc-plugin Maven plug-in.
java.util.List<String> is supported, but java.util.List<java.util.List<String>> is not. The workaround is to specify the nested generic type as java.util.List<java.util.List> in a signature file.
Signature file metadata Copy linkLink copied to clipboard!
- You must create one signature file for each proxy class (Java API class).
- The method signatures must not include a
raisesclause. All exceptions raised at runtime are wrapped in aRuntimeCamelExceptionand returned from the endpoint. - Class names that specify the type of an argument must be fully-qualified class names (except for the
java.lang.*types). There is no mechanism for importing package names. - Currently, there is a limitation in the signature parser, such that generic nesting is not supported. For example,
java.util.List<String>is supported, whereasjava.util.List<java.util.List<String>>is not. The workaround is to specify the nested generic type asjava.util.List<java.util.List>.
public String sayHi(); public String greetMe(String name); public String greetUs(String name1, String name2);
public String sayHi();
public String greetMe(String name);
public String greetUs(String name1, String name2);
Generate starting code with the Maven archetype Copy linkLink copied to clipboard!
camel-archetype-api-component Maven archetype. For details of how to run the archetype, see Section 55.1, “Generate Code with the Maven Archetype”.
ProjectName directory:
ProjectName-api- This project contains the Java API, which forms the basis of the API component. When you build this project, it packages up the Java API in a Maven bundle and generates the requisite Javadoc as well. If the Java API and Javadoc are already provided by a third-party, however, you do not need this sub-project.
ProjectName-component- This project contains the skeleton code for the API component.
Edit component classes Copy linkLink copied to clipboard!
ProjectName-component to develop your own component implementation. The following generated classes make up the core of the skeleton implementation:
ComponentNameComponent ComponentNameEndpoint ComponentNameConsumer ComponentNameProducer ComponentNameConfiguration
ComponentNameComponent
ComponentNameEndpoint
ComponentNameConsumer
ComponentNameProducer
ComponentNameConfiguration
Customize POM files Copy linkLink copied to clipboard!
camel-api-component-maven-plugin Maven plug-in.
Configure the camel-api-component-maven-plugin Copy linkLink copied to clipboard!
camel-api-component-maven-plugin Maven plug-in. This plug-in is responsible for generating the mapping between API methods and endpoint URIs, and by editing the plug-in configuration, you can customize the mapping.
camel-api-component-maven-plugin plug-in configuration shows a minimal configuration for an API class called ExampleJavadocHello:
hello-javadoc API name is mapped to the ExampleJavadocHello class, which means you can invoke methods from this class using URIs of the form, scheme://hello-javadoc/endpoint. The presence of the fromJavadoc element indicates that the ExampleJavadocHello class gets its metadata from Javadoc.
OSGi bundle configuration Copy linkLink copied to clipboard!
ProjectName-component/pom.xml, is configured to package the component as an OSGi bundle. The component POM includes a sample configuration of the maven-bundle-plugin. You should customize the configuration of the maven-bundle-plugin plug-in, to ensure that Maven generates a properly configured OSGi bundle for your component.
Build the component Copy linkLink copied to clipboard!
camel-api-component-maven-plugin plug-in automatically generates the API mapping classes (which define the mapping between the Java API and the endpoint URI syntax), placing them into the target/generated-classes project subdirectory. When you are dealing with a large and complex Java API, this generated code actually constitutes the bulk of the component source code.
Chapter 55. Getting Started with the Framework Copy linkLink copied to clipboard!
Abstract
camel-archetype-api-component Maven archetype.
55.1. Generate Code with the Maven Archetype Copy linkLink copied to clipboard!
Maven archetypes Copy linkLink copied to clipboard!
The API component Maven archetype Copy linkLink copied to clipboard!
camel-archetype-api-component, that can generate starting point code for your own API component implementation. This is the recommended approach to start creating your own API component.
Prerequisites Copy linkLink copied to clipboard!
camel-archetype-api-component archetype are that Apache Maven is installed and the Maven settings.xml file is configured to use the standard JBoss Fuse repositories. For more details, see appendix "Red Hat JBoss A-MQ Maven Repositories" in "Installation on Apache Karaf".
Invoke the Maven archetype Copy linkLink copied to clipboard!
Example component, which uses the example URI scheme, invoke the camel-archetype-api-component archetype to generate a new Maven project, as follows:
\, at the end of each line represents line continuation, which works only on Linux and UNIX platforms. On Windows platforms, remove the backslash and put the arguments all on a single line.
Options Copy linkLink copied to clipboard!
-DName=Value. Most of the options should be set as shown in the preceding mvn archetype:generate command, but a few of the options can be modified, to customize the generated project. The following table shows the options that you can use to customize the generated API component project:
| Name | Description |
|---|---|
groupId | (Generic Maven option) Specifies the group ID of the generated Maven project. By default, this value also defines the Java package name for the generated classes. Hence, it is a good idea to choose this value to match the Java package name that you want. |
artifactId | (Generic Maven option) Specifies the artifact ID of the generated Maven project. |
name | The name of the API component. This value is used for generating class names in the generated code (hence, it is recommended that the name should start with a capital letter). |
scheme | The default scheme to use in URIs for this component. You should make sure that this scheme does not conflict with the scheme of any existing Camel components. |
archetypeVersion | (Generic Maven option) Ideally, this should be the Apache Camel version used by the container where you plan to deploy the component. If necessary, however, you can also modify the versions of Maven dependencies after you have generated the project. |
Structure of the generated project Copy linkLink copied to clipboard!
camel-api-example, which contains the new Maven project. If you look inside the camel-api-example directory, you will see that it has the following general structure:
camel-api-example/
pom.xml
camel-api-example-api/
camel-api-example-component/
camel-api-example/
pom.xml
camel-api-example-api/
camel-api-example-component/
pom.xml, which is configured to build two sub-projects, as follows:
- camel-api-example-api
- The API sub-project (named as
ArtifactId-api) holds the Java API which you are about to turn into a component. If you are basing the API component on a Java API that you wrote yourself, you can put the Java API code directly into this project.The API sub-project can be used for one or more of the following purposes:- To package up the Java API code (if it is not already available as a Maven package).
- To generate Javadoc for the Java API (providing the needed metadata for the API component framework).
- To generate the Java API code from an API description (for example, from a WADL description of a REST API).
In some cases, however, you might not need to perform any of these tasks. For example, if the API component is based on a third-party API, which already provides the Java API and Javadoc in a Maven package. In such cases, you can delete the API sub-project. - camel-api-example-component
- The component sub-project (named as
ArtifactId-component) holds the implementation of the new API component. This includes the component implementation classes and the configuration of thecamel-api-component-mavenplug-in (which generates the API mapping classes from the Java API).
55.2. Generated API Sub-Project Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-api-example/camel-api-example-api project directory. In this section, we take a closer look at the generated example code and describe how it works.
Sample Java API Copy linkLink copied to clipboard!
ExampleJavadocHello and ExampleFileHello.
ExampleJavadocHello class Copy linkLink copied to clipboard!
ExampleJavadocHello class from the sample Java API. As the name of the class suggests, this particular class is used to show how you can supply mapping metadata from Javadoc.
Example 55.1. ExampleJavadocHello class
ExampleFileHello class Copy linkLink copied to clipboard!
ExampleFileHello class from the sample Java API. As the name of the class suggests, this particular class is used to show how you can supply mapping metadata from a signature file.
Example 55.2. ExampleFileHello class
Generating the Javadoc metadata for ExampleJavadocHello Copy linkLink copied to clipboard!
ExampleJavadocHello is provided as Javadoc, it is necessary to generate Javadoc for the sample Java API and install it into the camel-api-example-api Maven artifact. The API POM file, camel-api-example-api/pom.xml, configures the maven-javadoc-plugin to perform this step automatically during the Maven build.
55.3. Generated Component Sub-Project Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-api-example/camel-api-example-component project directory. In this section, we take a closer look at the generated example code and describe how it works.
Providing the Java API in the component POM Copy linkLink copied to clipboard!
camel-api-example-component/pom.xml, as follows:
Providing the Javadoc metadata in the component POM Copy linkLink copied to clipboard!
- The Maven coordinates for the Javadoc are almost the same as for the Java API, except that you must also specify a
classifierelement, as follows:<classifier>javadoc</classifier>
<classifier>javadoc</classifier>Copy to Clipboard Copied! Toggle word wrap Toggle overflow - You must declare the Javadoc to have
providedscope, as follows:<scope>provided</scope>
<scope>provided</scope>Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Defining the file metadata for Example File Hello Copy linkLink copied to clipboard!
ExampleFileHello is provided in a signature file. In general, this file must be created manually, but it has quite a simple format, which consists of a list of method signatures (one on each line). The example code provides the signature file, file-sig-api.txt, in the directory, camel-api-example-component/signatures, which has the following contents:
public String sayHi(); public String greetMe(String name); public String greetUs(String name1, String name2);
public String sayHi();
public String greetMe(String name);
public String greetUs(String name1, String name2);
Configuring the API mapping Copy linkLink copied to clipboard!
camel-api-component-maven-plugin Maven plug-in, which is configured in the component POM. The following extract from the component POM shows how the camel-api-component-maven-plugin plug-in is configured:
configuration element, which contains a single apis child element to configure the classes of the Java API. Each API class is configured by an api element, as follows:
apiName- The API name is a short name for the API class and is used as the
endpoint-prefixpart of an endpoint URI.NoteIf the API consists of just a single Java class, you can leave theapiNameelement empty, so that theendpoint-prefixbecomes redundant, and you can then specify the endpoint URI using the format shown in the section called “URI format for a single API class”. proxyClass- The proxy class element specifies the fully-qualified name of the API class.
fromJavadoc- If the API class is accompanied by Javadoc metadata, you must indicate this by including the
fromJavadocelement and the Javadoc itself must also be specified in the Maven file, as aprovideddependency (see the section called “Providing the Javadoc metadata in the component POM”). fromSignatureFile- If the API class is accompanied by signature file metadata, you must indicate this by including the
fromSignatureFileelement, where the content of this element specifies the location of the signature file.NoteThe signature files do not get included in the final package built by Maven, because these files are needed only at build time, not at run time.
Generated component implementation Copy linkLink copied to clipboard!
camel-api-example-component/src/main/java directory:
ExampleComponent- Represents the component itself. This class acts as a factory for endpoint instances (for example, instances of
ExampleEndpoint). ExampleEndpoint- Represents an endpoint URI. This class acts as a factory for consumer endpoints (for example,
ExampleConsumer) and as a factory for producer endpoints (for example,ExampleProducer). ExampleConsumer- Represents a concrete instance of a consumer endpoint, which is capable of consuming messages from the location specified in the endpoint URI.
ExampleProducer- Represents a concrete instance of a producer endpoint, which is capable of sending messages to the location specified in the endpoint URI.
ExampleConfiguration- Can be used to define endpoint URI options. The URI options defined by this configuration class are not tied to any specific API class. That is, you can combine these URI options with any of the API classes or methods. This can be useful, for example, if you need to declare username and password credentials in order to connect to the remote service. The primary purpose of the
ExampleConfigurationclass is to provide values for parameters required to instantiate API classes, or classes that implement API interfaces. For example, these could be constructor parameters, or parameter values for a factory method or class.To implement a URI option,option, in this class, all that you need to do is implement the pair of accessor methods,getOptionandsetOption. The component framework automatically parses the endpoint URI and injects the option values at run time.
ExampleComponent class Copy linkLink copied to clipboard!
ExampleComponent class is defined as follows:
createEndpoint, which creates new endpoint instances. Typically, you do not need to change any of the default code in the component class. If there are any other objects with the same life cycle as this component, however, you might want to make those objects available from the component class (for example, by adding a methods to create those objects or by injecting those objects into the component).
ExampleEndpoint class Copy linkLink copied to clipboard!
ExampleEndpoint class is defined as follows:
endpoint-prefix appearing in the URI (recall that a URI has the general form, scheme://endpoint-prefix/endpoint).
ExampleConsumer class Copy linkLink copied to clipboard!
ExampleConsumer class is defined as follows:
ExampleProducer class Copy linkLink copied to clipboard!
ExampleProducer class is defined as follows:
ExampleConfiguration class Copy linkLink copied to clipboard!
ExampleConfiguration class is defined as follows:
option, to this class, define a field of the appropriate type, and implement a corresponding pair of accessor methods, getOption and setOption. The component framework automatically parses the endpoint URI and injects the option values at run time.
URI format Copy linkLink copied to clipboard!
scheme://endpoint-prefix/endpoint?Option1=Value1&...&OptionN=ValueN
scheme://endpoint-prefix/endpoint?Option1=Value1&...&OptionN=ValueN
ExampleJavadocHello.greetMe("Jane Doe"), the URI would be constructed, as follows:
- [scheme]
- The API component scheme, as specified when you generated the code with the Maven archetype. In this case, the scheme is
example. - [endpoint-prefix]
- The API name, which maps to the API class defined by the
camel-api-component-maven-pluginMaven plug-in configuration. For theExampleJavadocHelloclass, the relevant configuration is:Copy to Clipboard Copied! Toggle word wrap Toggle overflow Which shows that the requiredendpoint-prefixishello-javadoc. - [endpoint]
- The
endpointmaps to the method name, which isgreetMe. - [Option1=Value1]
- The URI options specify method parameters. The
greetMe(String name)method takes the single parameter,name, which can be specified asname=Jane%20Doe. If you want to define default values for options, you can do this by overriding theinterceptPropertiesmethod (see Section 55.4, “Programming Model”).
ExampleJavadocHello.greetMe("Jane Doe") with the following URI:
example://hello-javadoc/greetMe?name=Jane%20Doe
example://hello-javadoc/greetMe?name=Jane%20Doe
Default component instance Copy linkLink copied to clipboard!
example URI scheme to the default component instance, the Maven archetype creates the following file under the camel-api-example-component sub-project:
src/main/resources/META-INF/services/org/apache/camel/component/example
src/main/resources/META-INF/services/org/apache/camel/component/example
example URI scheme. Whenever you use an example:// URI in a route, Camel searches the classpath to look for the corresponding example resource file. The example file has the following contents:
class=org.jboss.fuse.example.ExampleComponent
class=org.jboss.fuse.example.ExampleComponent
ExampleComponent component. The only time you would need to edit this file is if you refactor the name of the component class.
55.4. Programming Model Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
org.apache.camel.util.component package. These base classes define some methods which you can (optionally) override when you are implementing your component. In this section, we provide a brief description of those methods and how you might use them in your own component implementation.
Component methods to implement Copy linkLink copied to clipboard!
Component class:
doStart()- (Optional) A callback to create resources for the component during a cold start. An alternative approach is to adopt the strategy of lazy initialization (creating resources only when they are needed). In fact, lazy initialization is often the best strategy, so the
doStartmethod is often not needed. doStop()- (Optional) A callback to invoke code while the component is stopping. Stopping a component means that all of its resources are shut down, internal state is deleted, caches are cleared, and so on.NoteCamel guarantees that
doStopis always called when the currentCamelContextshuts down, even if the correspondingdoStartwas never called. doShutdown- (Optional) A callback to invoke code while the
CamelContextis shutting down. Whereas a stopped component can be restarted (with the semantics of a cold start), a component that gets shut down is completely finished. Hence, this callback represents the last chance to free up any resources belonging to the component.
What else to implement in the Component class? Copy linkLink copied to clipboard!
Component class is the natural place to hold references to objects that have the same (or similar) life cycle to the component object itself. For example, if a component uses OAuth security, it would be natural to hold references to the required OAuth objects in the Component class and to define methods in the Component class for creating the OAuth objects.
Endpoint methods to implement Copy linkLink copied to clipboard!
Endpoint class, as follows:
afterConfigureProperties()- The main thing you need to do in this method is to create the appropriate type of proxy class (API class), to match the API name. The API name (which has already been extracted from the endpoint URI) is available either through the inherited
apiNamefield or through thegetApiNameaccessor. Typically, you would do a switch on theapiNamefield to create the corresponding proxy class. For example:Copy to Clipboard Copied! Toggle word wrap Toggle overflow getApiProxy(ApiMethod method, Map<String, Object> args)- Override this method to return the proxy instance that you created in
afterConfigureProperties. For example:@Override public Object getApiProxy(ApiMethod method, Map<String, Object> args) { return apiProxy; }@Override public Object getApiProxy(ApiMethod method, Map<String, Object> args) { return apiProxy; }Copy to Clipboard Copied! Toggle word wrap Toggle overflow In special cases, you might want to make the choice of proxy dependent on the API method and arguments. ThegetApiProxygives you the flexibility to take this approach, if required. doStart()- (Optional) A callback to create resources during a cold start. Has the same semantics as
Component.doStart(). doStop()- (Optional) A callback to invoke code while the component is stopping. Has the same semantics as
Component.doStop(). doShutdown- (Optional) A callback to invoke code while the component is shutting down. Has the same semantics as
Component.doShutdown(). interceptPropertyNames(Set<String> propertyNames)- (Optional) The API component framework uses the endpoint URI and supplied option values to determine which method to invoke (ambiguity could be due to overloading and aliases). If the component internally adds options or method parameters, however, the framework might need help in order to determine the right method to invoke. In this case, you must override the
interceptPropertyNamesmethod and add the extra (hidden or implicit) options to thepropertyNamesset. When the complete list of method parameters are provided in thepropertyNamesset, the framework will be able to identify the right method to invoke.NoteYou can override this method at the level of theEndpoint,ProducerorConsumerclass. The basic rule is, if an option affects both producer endpoints and consumer endpoints, override the method in theEndpointclass. interceptProperties(Map<String,Object> properties)- (Optional) By overriding this method, you can modify or set the actual values of the options, before the API method is invoked. For example, you could use this method to set default values for some options, if necessary. In practice, it is often necessary to override both the
interceptPropertyNamesmethod and theinterceptPropertymethod.NoteYou can override this method at the level of theEndpoint,ProducerorConsumerclass. The basic rule is, if an option affects both producer endpoints and consumer endpoints, override the method in theEndpointclass.
Consumer methods to implement Copy linkLink copied to clipboard!
Consumer class, as follows:
interceptPropertyNames(Set<String> propertyNames)- (Optional) The semantics of this method are similar to
Endpoint.interceptPropertyNames interceptProperties(Map<String,Object> properties)- (Optional) The semantics of this method are similar to
Endpoint.interceptProperties doInvokeMethod(Map<String, Object> args)- (Optional) Overriding this method enables you to intercept the invocation of the Java API method. The most common reason for overriding this method is to customize the error handling around the method invocation. For example, a typical approach to overriding
doInvokeMethodis shown in the following code fragment:Copy to Clipboard Copied! Toggle word wrap Toggle overflow You should invokedoInvokeMethodon the super-class, at some point in this implementation, to ensure that the Java API method gets invoked. interceptResult(Object methodResult, Exchange resultExchange)- (Optional) Do some additional processing on the result of the API method invocation. For example, you could add custom headers to the Camel exchange object,
resultExchange, at this point. Object splitResult(Object result)- (Optional) By default, if the result of the method API invocation is a
java.util.Collectionobject or a Java array, the API component framework splits the result into multiple exchange objects (so that a single invocation result is converted into multiple messages).If you want to change the default behaviour, you can override thesplitResultmethod in the consumer endpoint. Theresultargument contains the result of the API message invocation. If you want to split the result, you should return an array type.NoteYou can also switch off the default splitting behaviour by settingconsumer.splitResult=falseon the endpoint URI.
Producer methods to implement Copy linkLink copied to clipboard!
Producer class, as follows:
interceptPropertyNames(Set<String> propertyNames)- (Optional) The semantics of this method are similar to
Endpoint.interceptPropertyNames interceptProperties(Map<String,Object> properties)- (Optional) The semantics of this method are similar to
Endpoint.interceptProperties doInvokeMethod(Map<String, Object> args)- (Optional) The semantics of this method are similar to
Consumer.doInvokeMethod. interceptResult(Object methodResult, Exchange resultExchange)- (Optional) The semantics of this method are similar to
Consumer.interceptResult.
Producer.splitResult() method is never called, so it is not possible to split an API method result in the same way as you can for a consumer endpoint. To get a similar effect for a producer endpoint, you can use Camel's split() DSL command (one of the standard enterprise integration patterns) to split Collection or array results.
Consumer polling and threading model Copy linkLink copied to clipboard!
55.5. Sample Component Implementations Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
Box.com Copy linkLink copied to clipboard!
LinkedIn Copy linkLink copied to clipboard!
wadl2java Maven plug-in to generate a Java API, which can then be wrapped using the API component framework.
GoogleDrive Copy linkLink copied to clipboard!
doInvoke method in the consumer and the producer.
Olingo2 Copy linkLink copied to clipboard!
Chapter 56. Configuring the API Component Maven Plug-In Copy linkLink copied to clipboard!
Abstract
56.1. Overview of the Plug-In Configuration Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
camel-api-component-maven-plugin, is to generate the API mapping classes, which implement the mapping between endpoint URIs and API method invocations. By editing the configuration of the API component Maven plug-in, you can customize various aspects of the API mapping.
Location of the generated code Copy linkLink copied to clipboard!
ProjectName-component/target/generated-sources/camel-component
ProjectName-component/target/generated-sources/camel-component
Prerequisites Copy linkLink copied to clipboard!
provided scope).
Setting up the plug-in Copy linkLink copied to clipboard!
ProjectName-component/pom.xml file, which you can then customize for your project. The main aspects of the plug-in set-up are, as follows:
- Maven dependencies must be declared for the requisite Java API and for the Javadoc metadata.
- The plug-in's base configuration is declared in the
pluginManagementscope (which also defines the version of the plug-in to use). - The plug-in instance itself is declared and configured.
- The
build-helper-mavenplug-in is configured to pick up the generated sources from thetarget/generated-sources/camel-componentdirectory and include them in the Maven build.
Example base configuration Copy linkLink copied to clipboard!
pluginManagement scope when the code has been generated using the API component archetype:
pluginManagement scope provides default settings for the plug-in. It does not actually create an instance of a plug-in, but its default settings will be used by any API component plug-in instance.
Base configuration Copy linkLink copied to clipboard!
version element), the preceding base configuration specifies the following configuration properties:
scheme- The URI scheme for this API component.
componentName- The name of this API component (which is also used as a prefix for generated class names).
componentPackage- Specifies the Java package containing the classes generated by the API component Maven archetype. This package is also exported by the default
maven-bundle-pluginconfiguration. Hence, if you want a class to be publicly visible, you should place it in this Java package. outPackage- Specifies the Java package where the generated API mapping classes are placed (when they are generated by the API component Maven plug-in). By default, this has the value of the
componentNameproperty, with the addition of the.internalsuffix. This package is declared as private by the defaultmaven-bundle-pluginconfiguration. Hence, if you want a class to be private, you should place it in this Java package.
Example instance configuration Copy linkLink copied to clipboard!
Basic mapping configuration Copy linkLink copied to clipboard!
configuration element, which contains a single apis child element to configure the classes of the Java API. Each API class is configured by an api element, as follows:
apiName- The API name is a short name for the API class and is used as the
endpoint-prefixpart of an endpoint URI.NoteIf the API consists of just a single Java class, you can leave theapiNameelement empty, so that theendpoint-prefixbecomes redundant, and you can then specify the endpoint URI using the format shown in the section called “URI format for a single API class”. proxyClass- This element specifies the fully-qualified name of the API class.
fromJavadoc- If the API class is accompanied by Javadoc metadata, you must indicate this by including the
fromJavadocelement and the Javadoc itself must also be specified in the Maven file, as aprovideddependency. fromSignatureFile- If the API class is accompanied by signature file metadata, you must indicate this by including the
fromSignatureFileelement, where the content of this element specifies the location of the signature file.NoteThe signature files do not get included in the final package built by Maven, because these files are needed only at build time, not at run time.
Customizing the API mapping Copy linkLink copied to clipboard!
- Method aliases—you can define additional names (aliases) for an API method using the
aliasesconfiguration element. For details, see Section 56.3, “Method Aliases”. - Nullable options—you can use the
nullableOptionsconfiguration element to declare method arguments that default tonull. For details, see Section 56.4, “Nullable Options”. - Argument name substitution—due to the way the API mapping is implemented, the arguments from all of the methods in a particular API class belong to the same namespace. If two arguments with the same name are declared to be of different type, this leads to a clash. To avoid such name clashes, you can use the
substitutionsconfiguration element to rename method arguments (as they would appear in a URI). For details, see Section 56.5, “Argument Name Substitution”. - Excluding arguments—when it comes to mapping Java arguments to URI options, you might sometimes want to exclude certain arguments from the mapping. You can filter out unwanted arguments by specifying either the
excludeConfigNameselement or theexcludeConfigTypeselement. For details, see Section 56.6, “Excluded Arguments”. - Extra options—sometimes you might want to define extra options, which are not part of the Java API. You can do this using the
extraOptionsconfiguration element.
Configuring Javadoc metadata Copy linkLink copied to clipboard!
Configuring signature file metadata Copy linkLink copied to clipboard!
fromSignatureFile is used to specify the location of the corresponding signature file. It has no special options.
56.2. Javadoc Options Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
fromJavadoc element with no options. But in cases where you do not want to include the entire Java API in your API mapping, you can filter the Javadoc metadata to customize the content. In other words, because the API component Maven plug-in generates the API mapping by iterating over the Javadoc metadata, it is possible to customize the scope of the generated API mapping by filtering out unwanted parts of the Javadoc metadata.
Syntax Copy linkLink copied to clipboard!
fromJavadoc element can be configured with optional child elements, as follows:
Scope Copy linkLink copied to clipboard!
fromJavadoc element can optionally appear as a child of the apis element and/or as a child of api elements:
fromJavadoc element at the following scopes:
- As a child of an
apielement—thefromJavadocoptions apply only to the API class specified by theapielement. - As a child of the
apiselement—thefromJavadocoptions apply to all API classes by default, but can be overridden at theapilevel.
Options Copy linkLink copied to clipboard!
fromJavadoc:
excludePackages- Specifies a regular expression (
java.util.regexsyntax) for excluding Java packages from the API mapping model. All package names that match the regular expression are excluded; and all classes derived from the excluded classes are also ignored. Default value isjavax?\.lang.*. excludeClasses- Specifies a regular expression (
java.util.regexsyntax) for excluding API base classes from the API mapping. All class names that match the regular expression are excluded; and all classes derived from the excluded classes are also ignored. excludeMethods- Specifies a regular expression (
java.util.regexsyntax) for excluding methods from the API mapping model. includeMethods- Specifies a regular expression (
java.util.regexsyntax) for including methods from the API mapping model. includeStaticMethods- If
true, static methods will also be included in the API mapping model. Default isfalse.
56.3. Method Aliases Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
widget) to be used as an alias for an accessor method (such as getWidget or setWidget).
Syntax Copy linkLink copied to clipboard!
aliases element can be defined with one or more alias child elements, as follows:
MethodPattern is a regular expression (java.util.regex syntax) for matching method names from the Java API, and the pattern typically includes capturing groups. The Alias is the replacement expression (for use in a URI), which can use the text from the preceding capturing groups (for example, specified as $1, $2, or $3 for the text from the first, second, or third capturing group).
Scope Copy linkLink copied to clipboard!
aliases element can optionally appear as a child of the apis element and/or as a child of api elements:
aliases element at the following scopes:
- As a child of an
apielement—thealiasesmappings apply only to the API class specified by theapielement. - As a child of the
apiselement—thealiasesmappings apply to all API classes by default, but can be overridden at theapilevel.
Example Copy linkLink copied to clipboard!
widget as an alias for either of the methods getWidget or setWidget. Note the use of a capturing group, (.+), to capture the latter part of the method name (for example, Widget).
56.4. Nullable Options Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
null. But this is not allowed by default. If you want to allow some of your method arguments from the Java API to take null values, you must declare this explicitly using the nullableOptions element.
Syntax Copy linkLink copied to clipboard!
nullableOptions element can be defined with one or more nullableOption child elements, as follows:
<nullableOptions> <nullableOption>ArgumentName</nullableOption> ... </nullableOptions>
<nullableOptions>
<nullableOption>ArgumentName</nullableOption>
...
</nullableOptions>
ArgumentName is the name of a method argument from the Java API.
Scope Copy linkLink copied to clipboard!
nullableOptions element can optionally appear as a child of the apis element and/or as a child of api elements:
nullableOptions element at the following scopes:
- As a child of an
apielement—thenullableOptionsmappings apply only to the API class specified by theapielement. - As a child of the
apiselement—thenullableOptionsmappings apply to all API classes by default, but can be overridden at theapilevel.
Example Copy linkLink copied to clipboard!
CompaniesResource proxy class from the Apache Camel LinkedIn component:
56.5. Argument Name Substitution Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
public void doSomething(int id, String name); public void doSomethingElse(int id, String name);
public void doSomething(int id, String name);
public void doSomethingElse(int id, String name);
camel-api-component-maven-plugin generates the configuration class, ProxyClassEndpointConfiguration, which contains getter and setter methods for all of the arguments in the ProxyClass class. For example, given the preceding methods, the plug-in would generate the following getter and setter methods in the configuration class:
public int getId(); public void setId(int id); public String getName(); public void setName(String name);
public int getId();
public void setId(int id);
public String getName();
public void setName(String name);
id argument appears multiple times as different types, as in the following example:
public void doSomething(int id, String name); public void doSomethingElse(int id, String name); public String lookupByID(String id);
public void doSomething(int id, String name);
public void doSomethingElse(int id, String name);
public String lookupByID(String id);
getId method that returns int and a getId method that returns String in the same scope. The solution to this problem is to use argument name substitution to customize the mapping of argument names to URI option names.
Syntax Copy linkLink copied to clipboard!
substitutions element can be defined with one or more substitution child elements, as follows:
argType element and the replaceWithType element are optional and can be omitted.
Scope Copy linkLink copied to clipboard!
substitutions element can optionally appear as a child of the apis element and/or as a child of api elements:
substitutions element at the following scopes:
- As a child of an
apielement—thesubstitutionsapply only to the API class specified by theapielement. - As a child of the
apiselement—thesubstitutionsapply to all API classes by default, but can be overridden at theapilevel.
Child elements Copy linkLink copied to clipboard!
substitution element can be defined with the following child elements:
method- Specifies a regular expression (
java.util.regexsyntax) to match a method name from the Java API. argName- Specifies a regular expression (
java.util.regexsyntax) to match an argument name from the matched method, where the pattern typically includes capturing groups. argType- (Optional) Specifies a regular expression (
java.util.regexsyntax) to match the type of the argument. If you set thereplaceWithTypeoption totrue, you would typically use capturing groups in this regular expression. replacement- Given a particular match of the
methodpattern,argNamepattern, and (optionally)argTypepattern, thereplacementelement defines the substitute argument name (for use in a URI). The replacement text can be constructed using strings captured from theargNameregular expression pattern (using the syntax,$1,$2,$3to insert the first, second, or third capturing group, respectively). Alternatively, the replacement text can be constructed using strings captured from theargTyperegular expression pattern, if you set thereplaceWithTypeoption totrue. replaceWithType- When
true, specifies that the replacement text is constructed using strings captured from theargTyperegular expression. Defaults tofalse.
Example Copy linkLink copied to clipboard!
java.lang.String type, by adding the suffix, Param to the argument name:
public String greetUs(String name1, String name2);
public String greetUs(String name1, String name2);
name1Param and name2Param, in the endpoint URI.
56.6. Excluded Arguments Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
excludeConfigNames element or the excludeConfigTypes element in the camel-api-component-maven-plugin plug-in configuration.
Syntax Copy linkLink copied to clipboard!
excludeConfigNames element and the excludeConfigTypes element are specified as follows:
<excludeConfigNames>ArgumentNamePattern</excludeConfigNames> <excludeConfigTypes>TypeNamePattern</excludeConfigTypes>
<excludeConfigNames>ArgumentNamePattern</excludeConfigNames>
<excludeConfigTypes>TypeNamePattern</excludeConfigTypes>
ArgumentNamePattern and TypeNamePattern are regular expressions that match the argument name and the argument type, respectively.
Scope Copy linkLink copied to clipboard!
excludeConfigNames element and the excludeConfigTypes element can optionally appear as children of the apis element and/or as children of api elements:
excludeConfigNames element and the excludeConfigTypes element at the following scopes:
- As a child of an
apielement—the exclusions apply only to the API class specified by theapielement. - As a child of the
apiselement—the exclusions apply to all API classes by default, but can be overridden at theapilevel.
Elements Copy linkLink copied to clipboard!
excludeConfigNames- Specifies a regular expression (
java.util.regexsyntax) for excluding arguments, based on matching the argument name. excludeConfigTypes- Specifies a regular expression (
java.util.regexsyntax) for excluding arguments, based on matching the argument type.
56.7. Extra Options Copy linkLink copied to clipboard!
Overview Copy linkLink copied to clipboard!
extraOptions options are usually used to either compute or hide complex API parameters by providing simpler options instead. For example, the API method might take a POJO option, that could be provided more easily as parts of the POJO in the URI. The component could do this by adding the parts as extra options, and creating the POJO parameter internally. To complete the implementation of these extra options, you also need to override the interceptProperties method in the EndpointConsumer and/or EndpointProducer classes (see Section 55.4, “Programming Model”).
Syntax Copy linkLink copied to clipboard!
extraOptions element can be defined with one or more extraOption child elements, as follows:
TypeName is the fully-qualified type name of the extra option and OptionName is the name of the extra URI option.
Scope Copy linkLink copied to clipboard!
extraOptions element can optionally appear as a child of the apis element and/or as a child of api elements:
extraOptions element at the following scopes:
- As a child of an
apielement—theextraOptionsapply only to the API class specified by theapielement. - As a child of the
apiselement—theextraOptionsapply to all API classes by default, but can be overridden at theapilevel.
Child elements Copy linkLink copied to clipboard!
extraOptions element can be defined with the following child elements:
type- Specifies the fully-qualified type name of the extra option.
name- Specifies the option name, as it would appear in an endpoint URI.
Example Copy linkLink copied to clipboard!
customOption, which is of java.util.list<String> type:
Index Copy linkLink copied to clipboard!
Symbols
- @Converter, Implement an annotated converter class
A
- AsyncCallback, Asynchronous processing
- asynchronous producer
- implementing, How to implement an asynchronous producer
- AsyncProcessor, Asynchronous processing
- auto-discovery
- configuration, Configuring auto-discovery
C
- Component
- createEndpoint(), URI parsing
- definition, The Component interface
- methods, Component methods
- component prefix, Component
- components, Component
- bean properties, Define bean properties on your component class
- configuring, Installing and configuring the component
- implementation steps, Implementation steps
- installing, Installing and configuring the component
- interfaces to implement, Which interfaces do you need to implement?
- parameter injection, Parameter injection
- Spring configuration, Configure the component in Spring
- Consumer, Consumer
- consumers, Consumer
- event-driven, Event-driven pattern, Implementation steps
- polling, Polling pattern, Implementation steps
- scheduled, Scheduled poll pattern, Implementation steps
- threading, Overview
D
- DefaultComponent
- createEndpoint(), URI parsing
- DefaultEndpoint, Event-driven endpoint implementation
- createExchange(), Event-driven endpoint implementation
- createPollingConsumer(), Event-driven endpoint implementation
- getCamelConext(), Event-driven endpoint implementation
- getComponent(), Event-driven endpoint implementation
- getEndpointUri(), Event-driven endpoint implementation
E
- Endpoint, Endpoint
- createConsumer(), Endpoint methods
- createExchange(), Endpoint methods
- createPollingConsumer(), Endpoint methods
- createProducer(), Endpoint methods
- getCamelContext(), Endpoint methods
- getEndpointURI(), Endpoint methods
- interface definition, The Endpoint interface
- isLenientProperties(), Endpoint methods
- isSingleton(), Endpoint methods
- setCamelContext(), Endpoint methods
- endpoint
- event-driven, Event-driven endpoint implementation
- scheduled, Scheduled poll endpoint implementation
- endpoints, Endpoint
- Exchange, Exchange, The Exchange interface
- copy(), Exchange methods
- getExchangeId(), Exchange methods
- getIn(), Accessing message headers, Exchange methods
- getOut(), Exchange methods
- getPattern(), Exchange methods
- getProperties(), Exchange methods
- getProperty(), Exchange methods
- getUnitOfWork(), Exchange methods
- removeProperty(), Exchange methods
- setExchangeId(), Exchange methods
- setIn(), Exchange methods
- setOut(), Exchange methods
- setProperty(), Exchange methods
- setUnitOfWork(), Exchange methods
- exchange
- in capable, Testing the exchange pattern
- out capable, Testing the exchange pattern
- exchange properties
- accessing, Wrapping the exchange accessors
- ExchangeHelper, The ExchangeHelper Class
- getContentType(), Get the In message's MIME content type
- getMandatoryHeader(), Accessing message headers, Wrapping the exchange accessors
- getMandatoryInBody(), Wrapping the exchange accessors
- getMandatoryOutBody(), Wrapping the exchange accessors
- getMandatoryProperty(), Wrapping the exchange accessors
- isInCapable(), Testing the exchange pattern
- isOutCapable(), Testing the exchange pattern
- resolveEndpoint(), Resolve an endpoint
- exchanges, Exchange
I
- in message
- MIME type, Get the In message's MIME content type
M
- Message, Message
- getHeader(), Accessing message headers
- message headers
- accessing, Accessing message headers
- messages, Message
P
- performer, Overview
- pipeline, Pipelining model
- Processor, Processor interface
- implementing, Implementing the Processor interface
- producer, Producer
- Producer, Producer
- createExchange(), Producer methods
- getEndpoint(), Producer methods
- process(), Producer methods
- producers
- asynchronous, Asynchronous producer
- synchronous, Synchronous producer
S
- ScheduledPollEndpoint, Scheduled poll endpoint implementation
- simple processor
- implementing, Implementing the Processor interface
- synchronous producer
- implementing, How to implement a synchronous producer
T
- type conversion
- runtime process, Type conversion process
- type converter
- annotating the implementation, Implement an annotated converter class
- discovery file, Create a TypeConverter file
- implementation steps, How to implement a type converter
- mater, Master type converter
- packaging, Package the type converter
- slave, Master type converter
- TypeConverter, Type converter interface
- TypeConverterLoader, Type converter loader
U
- useIntrospectionOnEndpoint(), Disabling endpoint parameter injection
W
- wire tap pattern, System Management
Legal Notice Copy linkLink copied to clipboard!
Trademark Disclaimer