Languages Supported AppendixTo support flexible and powerful Enterprise Integration Patterns Camel supports various Languages to create an Expression or Predicate within either the Routing Domain Specific Language or the Xml Configuration. The following languages are supported Bean LanguageThe purpose of the Bean Language is to be able to implement an Expression or Predicate using a simple method on a bean. So the idea is you specify a bean name which will then be resolved in the Registry such as the Spring ApplicationContext then a method is invoked to evaluate the Expression or Predicate. If no method name is provided then one is attempted to be chosen using the rules for Bean Binding; using the type of the message body and using any annotations on the bean methods. The Bean Binding rules are used to bind the Message Exchange to the method parameters; so you can annotate the bean to extract headers or other expressions such as XPath or XQuery from the message. Using Bean Expressions from the Java DSLfrom("activemq:topic:OrdersTopic"). filter().method("myBean", "isGoldCustomer"). to("activemq:BigSpendersQueue"); Using Bean Expressions from XML<route> <from uri="activemq:topic:OrdersTopic"/> <filter> <method bean="myBean" method="isGoldCustomer"/> <to uri="activemq:BigSpendersQueue"/> </filter> </route> Writing the expression beanThe bean in the above examples is just any old Java Bean with a method called isGoldCustomer() that returns some object that is easily converted to a boolean value in this case, as its used as a predicate. So we could implement it like this... public class MyBean { public boolean isGoldCustomer(Exchange exchange) { ... } } We can also use the Bean Integration annotations. For example you could do... public boolean isGoldCustomer(String body) {...} or public boolean isGoldCustomer(@Header(name = "foo") Integer fooHeader) {...} So you can bind parameters of the method to the Exchange, the Message or individual headers, properties, the body or other expressions. Non registry beansThe Bean Language also supports invoking beans that isn't registered in the Registry. This is usable for quickly to invoke a bean from Java DSL where you don't need to register the bean in the Registry such as the Spring ApplicationContext. Camel can instantiate the bean and invoke the method if given a class or invoke an already existing instance. This is illustrated from the example below:
from("activemq:topic:OrdersTopic").
filter().expression(BeanLanguage(MyBean.class, "isGoldCustomer")).
to("activemq:BigSpendersQueue");
The 2nd parameter isGoldCustomer is an optional parameter to explicit set the method name to invoke. If not provided Camel will try to invoke the best suited method. If case of ambiguity Camel will thrown an Exception. In these situations the 2nd parameter can solve this problem. Also the code is more readable if the method name is provided. The 1st parameter can also be an existing instance of a Bean such as: private MyBean my; from("activemq:topic:OrdersTopic"). filter().expression(BeanLanguage.bean(my, "isGoldCustomer")). to("activemq:BigSpendersQueue"); In Camel 2.2 onwards you can avoid the BeanLanguage and have it just as: private MyBean my; from("activemq:topic:OrdersTopic"). filter().expression(bean(my, "isGoldCustomer")). to("activemq:BigSpendersQueue"); Which also can be done in a bit shorter and nice way: private MyBean my; from("activemq:topic:OrdersTopic"). filter().method(my, "isGoldCustomer"). to("activemq:BigSpendersQueue"); Other examplesWe have some test cases you can look at if it'll help
DependenciesThe Bean language is part of camel-core. Constant Expression LanguageThe Constant Expression Language is really just a way to specify constant strings as a type of expression. Example usageThe setHeader element of the Spring DSL can utilize a constant expression like: <route> <from uri="seda:a"/> <setHeader headerName="theHeader"> <constant>the value</constant> </setHeader> <to uri="mock:b"/> </route> in this case, the Message coming from the seda:a Endpoint will have 'theHeader' header set to the constant value 'the value'. And the same example using Java DSL: from("seda:a").setHeader("theHeader", constant("the value")).to("mock:b"); DependenciesThe Constant language is part of camel-core. ELCamel supports the unified JSP and JSF Expression Language via the JUEL to allow an Expression or Predicate to be used in the DSL or Xml Configuration. For example you could use EL inside a Message Filter in XML <route> <from uri="seda:foo"/> <filter> <el>${in.headers.foo == 'bar'}</el> <to uri="seda:bar"/> </filter> </route> You could also use slightly different syntax, e.g. if the header name is not a valid identifier: <route> <from uri="seda:foo"/> <filter> <el>${in.headers['My Header'] == 'bar'}</el> <to uri="seda:bar"/> </filter> </route> You could use EL to create an Predicate in a Message Filter or as an Expression for a Recipient List Variables
SamplesYou can use EL dot notation to invoke operations. If you for instance have a body that contains a POJO that has a getFamiliyName method then you can construct the syntax as follows:
"$in.body.familyName"
DependenciesTo use EL in your camel routes you need to add the a dependency on camel-juel which implements the EL language. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-juel</artifactId> <version>x.x.x</version> </dependency> Otherwise you'll also need to include JUEL. Header Expression LanguageThe Header Expression Language allows you to extract values of named headers. Example usageThe recipientList element of the Spring DSL can utilize a header expression like: <route> <from uri="direct:a" /> <!-- use comma as a delimiter for String based values --> <recipientList delimiter=","> <header>myHeader</header> </recipientList> </route> In this case, the list of recipients are contained in the header 'myHeader'. And the same example in Java DSL: from("direct:a").recipientList(header("myHeader")); And with a slightly different syntax where you use the builder to the fullest (i.e. avoid using parameters but using stacked operations, notice that header is not a parameter but a stacked method call) from("direct:a").recipientList().header("myHeader"); DependenciesThe Header language is part of camel-core. JXPathCamel supports JXPath to allow XPath expressions to be used on beans in an Expression or Predicate to be used in the DSL or Xml Configuration. For example you could use JXPath to create an Predicate in a Message Filter or as an Expression for a Recipient List. You can use XPath expressions directly using smart completion in your IDE as follows from("queue:foo").filter(). jxpath("/in/body/foo"). to("queue:bar") Variables
Options
Using XML configurationIf you prefer to configure your routes in your Spring XML file then you can use JXPath expressions as follows <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> <camelContext id="camel" xmlns="http://activemq.apache.org/camel/schema/spring"> <route> <from uri="activemq:MyQueue"/> <filter> <jxpath>in/body/name = 'James'</xpath> <to uri="mqseries:SomeOtherQueue"/> </filter> </route> </camelContext> </beans> ExamplesHere is a simple example using a JXPath expression as a predicate in a Message Filter from("direct:start"). filter().jxpath("in/body/name='James'"). to("mock:result"); JXPath injectionYou can use Bean Integration to invoke a method on a bean and use various languages such as JXPath to extract a value from the message and bind it to a method parameter. For example public class Foo { @MessageDriven(uri = "activemq:my.queue") public void doSomething(@JXPath("in/body/foo") String correlationID, @Body String body) { // process the inbound message here } } Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").jxpath("resource:classpath:myjxpath.txt") DependenciesTo use JXpath in your camel routes you need to add the a dependency on camel-jxpath which implements the JXpath language. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jxpath</artifactId> <version>x.x.x</version> </dependency> Otherwise, you'll also need Commons JXPath. MvelCamel allows Mvel to be used as an Expression or Predicate the DSL or Xml Configuration. You could use Mvel to create an Predicate in a Message Filter or as an Expression for a Recipient List You can use Mvel dot notation to invoke operations. If you for instance have a body that contains a POJO that has a getFamiliyName method then you can construct the syntax as follows: "request.body.familyName" // or "getRequest().getBody().getFamilyName()" Variables
SamplesFor example you could use Mvel inside a Message Filter in XML <route> <from uri="seda:foo"/> <filter> <mvel>request.headers.foo == 'bar'</mvel> <to uri="seda:bar"/> </filter> </route> And the sample using Java DSL: from("seda:foo").filter().mvel("request.headers.foo == 'bar'").to("seda:bar"); Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").mvel("resource:classpath:script.mvel") DependenciesTo use Mvel in your camel routes you need to add the a dependency on camel-mvel which implements the Mvel language. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-mvel</artifactId> <version>x.x.x</version> </dependency> Otherwise, you'll also need MVEL OGNLCamel allows OGNL to be used as an Expression or Predicate the DSL or Xml Configuration. You could use OGNL to create an Predicate in a Message Filter or as an Expression for a Recipient List You can use OGNL dot notation to invoke operations. If you for instance have a body that contains a POJO that has a getFamiliyName method then you can construct the syntax as follows: "request.body.familyName" // or "getRequest().getBody().getFamilyName()" Variables
SamplesFor example you could use OGNL inside a Message Filter in XML <route> <from uri="seda:foo"/> <filter> <ognl>request.headers.foo == 'bar'</ognl> <to uri="seda:bar"/> </filter> </route> And the sample using Java DSL: from("seda:foo").filter().ognl("request.headers.foo == 'bar'").to("seda:bar"); Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").ognl("resource:classpath:myognl.txt") DependenciesTo use OGNL in your camel routes you need to add the a dependency on camel-ognl which implements the OGNL language. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-ognl</artifactId> <version>x.x.x</version> </dependency> Otherwise, you'll also need OGNL Property Expression LanguageThe Property Expression Language allows you to extract values of named exchange properties. Example usageThe recipientList element of the Spring DSL can utilize a property expression like: <route> <from uri="direct:a" /> <recipientList> <property>myProperty</property> </recipientList> </route> In this case, the list of recipients are contained in the property 'myProperty'. And the same example in Java DSL: from("direct:a").recipientList(property("myProperty")); And with a slightly different syntax where you use the builder to the fullest (i.e. avoid using parameters but using stacked operations, notice that property is not a parameter but a stacked method call) from("direct:a").recipientList().property("myProperty"); DependenciesThe Property language is part of camel-core. Scripting LanguagesCamel supports a number of scripting languages which can be used to create an Expression or Predicate via the standard JSR 223 which is a standard part of Java 6. The following scripting languages are integrated into the DSL:
However any JSR 223 scripting language can be used using the generic DSL methods. ScriptContextThe JSR-223 scripting languages ScriptContext is pre configured with the following attributes all set at ENGINE_SCOPE:
AttributesYou can add your own attributes with the attribute(name, value) DSL method, such as: In the sample below we add an attribute user that is an object we already have instantiated as myUser. This object has a getFirstName() method that we want to set as header on the message. We use the groovy language to concat the first and last name into a single string that is returned. from("direct:in").setHeader("name").groovy("'$user.firstName $user.lastName'").attribute("user", myUser).to("seda:users"); Any scripting languageCamel can run any JSR-223 scripting languages using the script DSL method such as: from("direct:in").setHeader("firstName").script("jaskel", "user.firstName").attribute("user", myUser).to("seda:users"); This is a bit different using the Spring DSL where you use the expression element that doesn't support setting attributes (yet):
<from uri="direct:in"/>
<setHeader headerName="firstName">
<expression language="jaskel">user.firstName</expression>
</setHeader>
<to uri="seda:users"/>
You can also use predicates e.g. in a Filter:
<filter>
<language language="beanshell">request.getHeaders().get("Foo").equals("Bar")</language>
<to uri="direct:next" />
</filter>
See Scripting Languages for the list of languages with explicit DSL support. Some languages without specific DSL support but known to work with these generic methods include:
Additional arguments to ScriptingEngineAvailable as of Camel 2.8 You can provide additional arguments to the ScriptingEngine using a header on the Camel message with the key CamelScriptArguments. public void testArgumentsExample() throws Exception { if (!ScriptTestHelper.canRunTestOnThisPlatform()) { return; } getMockEndpoint("mock:result").expectedMessageCount(0); getMockEndpoint("mock:unmatched").expectedMessageCount(1); // additional arguments to ScriptEngine Map<String, Object> arguments = new HashMap<String, Object>(); arguments.put("foo", "bar"); arguments.put("baz", 7); // those additional arguments is provided as a header on the Camel Message template.sendBodyAndHeader("direct:start", "hello", ScriptBuilder.ARGUMENTS, arguments); assertMockEndpointsSatisfied(); } Using properties functionAvailable as of Camel 2.9 If you need to use the Properties component from a script to lookup property placeholders, then its a bit cumbersome to do so. .setHeader("myHeader").groovy("context.resolvePropertyPlaceholders('{{' + request.headers.get('foo') + '}}')") From Camel 2.9 onwards you can now use the properties function and the same example is simpler: .setHeader("myHeader").groovy("properties.resolve(request.headers.get('foo'))") Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").groovy("resource:classpath:mygroovy.groovy") DependenciesTo use scripting languages in your camel routes you need to add the a dependency on camel-script which integrates the JSR-223 scripting engine. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-script</artifactId> <version>x.x.x</version> </dependency> See AlsoBeanShellCamel supports BeanShell among other Scripting Languages to allow an Expression or Predicate to be used in the DSL or Xml Configuration. To use a BeanShell expression use the following Java code:
...choice()
.when(script("beanshell", "request.getHeaders().get(\"foo\").equals(\"bar\")"))
.to("...")
Or the something like this in your Spring XML: <filter> <language language="beanshell">request.getHeaders().get("Foo") == null</language> ...
You could follow the examples above to create an Predicate in a Message Filter or as an Expression for a Recipient List ScriptContextThe JSR-223 scripting languages ScriptContext is pre configured with the following attributes all set at ENGINE_SCOPE:
AttributesYou can add your own attributes with the attribute(name, value) DSL method, such as: In the sample below we add an attribute user that is an object we already have instantiated as myUser. This object has a getFirstName() method that we want to set as header on the message. We use the groovy language to concat the first and last name into a single string that is returned. from("direct:in").setHeader("name").groovy("'$user.firstName $user.lastName'").attribute("user", myUser).to("seda:users"); Any scripting languageCamel can run any JSR-223 scripting languages using the script DSL method such as: from("direct:in").setHeader("firstName").script("jaskel", "user.firstName").attribute("user", myUser).to("seda:users"); This is a bit different using the Spring DSL where you use the expression element that doesn't support setting attributes (yet):
<from uri="direct:in"/>
<setHeader headerName="firstName">
<expression language="jaskel">user.firstName</expression>
</setHeader>
<to uri="seda:users"/>
You can also use predicates e.g. in a Filter:
<filter>
<language language="beanshell">request.getHeaders().get("Foo").equals("Bar")</language>
<to uri="direct:next" />
</filter>
See Scripting Languages for the list of languages with explicit DSL support. Some languages without specific DSL support but known to work with these generic methods include:
Additional arguments to ScriptingEngineAvailable as of Camel 2.8 You can provide additional arguments to the ScriptingEngine using a header on the Camel message with the key CamelScriptArguments. public void testArgumentsExample() throws Exception { if (!ScriptTestHelper.canRunTestOnThisPlatform()) { return; } getMockEndpoint("mock:result").expectedMessageCount(0); getMockEndpoint("mock:unmatched").expectedMessageCount(1); // additional arguments to ScriptEngine Map<String, Object> arguments = new HashMap<String, Object>(); arguments.put("foo", "bar"); arguments.put("baz", 7); // those additional arguments is provided as a header on the Camel Message template.sendBodyAndHeader("direct:start", "hello", ScriptBuilder.ARGUMENTS, arguments); assertMockEndpointsSatisfied(); } Using properties functionAvailable as of Camel 2.9 If you need to use the Properties component from a script to lookup property placeholders, then its a bit cumbersome to do so. .setHeader("myHeader").groovy("context.resolvePropertyPlaceholders('{{' + request.headers.get('foo') + '}}')") From Camel 2.9 onwards you can now use the properties function and the same example is simpler: .setHeader("myHeader").groovy("properties.resolve(request.headers.get('foo'))") Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").groovy("resource:classpath:mygroovy.groovy") DependenciesTo use scripting languages in your camel routes you need to add the a dependency on camel-script which integrates the JSR-223 scripting engine. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-script</artifactId> <version>x.x.x</version> </dependency> JavaScriptCamel supports JavaScript/ECMAScript among other Scripting Languages to allow an Expression or Predicate to be used in the DSL or Xml Configuration. To use a JavaScript expression use the following Java code
... javaScript("someJavaScriptExpression") ...
For example you could use the javaScript function to create an Predicate in a Message Filter or as an Expression for a Recipient List ExampleIn the sample below we use JavaScript to create a Predicate use in the route path, to route exchanges from admin users to a special queue.
from("direct:start")
.choice()
.when().javaScript("request.headers.get('user') == 'admin'").to("seda:adminQueue")
.otherwise()
.to("seda:regularQueue");
And a Spring DSL sample as well:
<route>
<from uri="direct:start"/>
<choice>
<when>
<javaScript>request.headers.get('user') == 'admin'</javaScript>
<to uri="seda:adminQueue"/>
</when>
<otherwise>
<to uri="seda:regularQueue"/>
</otherwise>
</choice>
</route>
ScriptContextThe JSR-223 scripting languages ScriptContext is pre configured with the following attributes all set at ENGINE_SCOPE:
AttributesYou can add your own attributes with the attribute(name, value) DSL method, such as: In the sample below we add an attribute user that is an object we already have instantiated as myUser. This object has a getFirstName() method that we want to set as header on the message. We use the groovy language to concat the first and last name into a single string that is returned. from("direct:in").setHeader("name").groovy("'$user.firstName $user.lastName'").attribute("user", myUser).to("seda:users"); Any scripting languageCamel can run any JSR-223 scripting languages using the script DSL method such as: from("direct:in").setHeader("firstName").script("jaskel", "user.firstName").attribute("user", myUser).to("seda:users"); This is a bit different using the Spring DSL where you use the expression element that doesn't support setting attributes (yet):
<from uri="direct:in"/>
<setHeader headerName="firstName">
<expression language="jaskel">user.firstName</expression>
</setHeader>
<to uri="seda:users"/>
You can also use predicates e.g. in a Filter:
<filter>
<language language="beanshell">request.getHeaders().get("Foo").equals("Bar")</language>
<to uri="direct:next" />
</filter>
See Scripting Languages for the list of languages with explicit DSL support. Some languages without specific DSL support but known to work with these generic methods include:
Additional arguments to ScriptingEngineAvailable as of Camel 2.8 You can provide additional arguments to the ScriptingEngine using a header on the Camel message with the key CamelScriptArguments. public void testArgumentsExample() throws Exception { if (!ScriptTestHelper.canRunTestOnThisPlatform()) { return; } getMockEndpoint("mock:result").expectedMessageCount(0); getMockEndpoint("mock:unmatched").expectedMessageCount(1); // additional arguments to ScriptEngine Map<String, Object> arguments = new HashMap<String, Object>(); arguments.put("foo", "bar"); arguments.put("baz", 7); // those additional arguments is provided as a header on the Camel Message template.sendBodyAndHeader("direct:start", "hello", ScriptBuilder.ARGUMENTS, arguments); assertMockEndpointsSatisfied(); } Using properties functionAvailable as of Camel 2.9 If you need to use the Properties component from a script to lookup property placeholders, then its a bit cumbersome to do so. .setHeader("myHeader").groovy("context.resolvePropertyPlaceholders('{{' + request.headers.get('foo') + '}}')") From Camel 2.9 onwards you can now use the properties function and the same example is simpler: .setHeader("myHeader").groovy("properties.resolve(request.headers.get('foo'))") Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").groovy("resource:classpath:mygroovy.groovy") DependenciesTo use scripting languages in your camel routes you need to add the a dependency on camel-script which integrates the JSR-223 scripting engine. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-script</artifactId> <version>x.x.x</version> </dependency> GroovyCamel supports Groovy among other Scripting Languages to allow an Expression or Predicate to be used in the DSL or Xml Configuration. To use a Groovy expression use the following Java code
... groovy("someGroovyExpression") ...
For example you could use the groovy function to create an Predicate in a Message Filter or as an Expression for a Recipient List Example// lets route if a line item is over $100 from("queue:foo").filter(groovy("request.lineItems.any { i -> i.value > 100 }")).to("queue:bar") And the Spring DSL:
<route>
<from uri="queue:foo"/>
<filter>
<groovy>request.lineItems.any { i -> i.value > 100 }</groovy>
<to uri="queue:bar"/>
</filter>
</route>
ScriptContextThe JSR-223 scripting languages ScriptContext is pre configured with the following attributes all set at ENGINE_SCOPE:
AttributesYou can add your own attributes with the attribute(name, value) DSL method, such as: In the sample below we add an attribute user that is an object we already have instantiated as myUser. This object has a getFirstName() method that we want to set as header on the message. We use the groovy language to concat the first and last name into a single string that is returned. from("direct:in").setHeader("name").groovy("'$user.firstName $user.lastName'").attribute("user", myUser).to("seda:users"); Any scripting languageCamel can run any JSR-223 scripting languages using the script DSL method such as: from("direct:in").setHeader("firstName").script("jaskel", "user.firstName").attribute("user", myUser).to("seda:users"); This is a bit different using the Spring DSL where you use the expression element that doesn't support setting attributes (yet):
<from uri="direct:in"/>
<setHeader headerName="firstName">
<expression language="jaskel">user.firstName</expression>
</setHeader>
<to uri="seda:users"/>
You can also use predicates e.g. in a Filter:
<filter>
<language language="beanshell">request.getHeaders().get("Foo").equals("Bar")</language>
<to uri="direct:next" />
</filter>
See Scripting Languages for the list of languages with explicit DSL support. Some languages without specific DSL support but known to work with these generic methods include:
Additional arguments to ScriptingEngineAvailable as of Camel 2.8 You can provide additional arguments to the ScriptingEngine using a header on the Camel message with the key CamelScriptArguments. public void testArgumentsExample() throws Exception { if (!ScriptTestHelper.canRunTestOnThisPlatform()) { return; } getMockEndpoint("mock:result").expectedMessageCount(0); getMockEndpoint("mock:unmatched").expectedMessageCount(1); // additional arguments to ScriptEngine Map<String, Object> arguments = new HashMap<String, Object>(); arguments.put("foo", "bar"); arguments.put("baz", 7); // those additional arguments is provided as a header on the Camel Message template.sendBodyAndHeader("direct:start", "hello", ScriptBuilder.ARGUMENTS, arguments); assertMockEndpointsSatisfied(); } Using properties functionAvailable as of Camel 2.9 If you need to use the Properties component from a script to lookup property placeholders, then its a bit cumbersome to do so. .setHeader("myHeader").groovy("context.resolvePropertyPlaceholders('{{' + request.headers.get('foo') + '}}')") From Camel 2.9 onwards you can now use the properties function and the same example is simpler: .setHeader("myHeader").groovy("properties.resolve(request.headers.get('foo'))") Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").groovy("resource:classpath:mygroovy.groovy") DependenciesTo use scripting languages in your camel routes you need to add the a dependency on camel-script which integrates the JSR-223 scripting engine. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-script</artifactId> <version>x.x.x</version> </dependency> PythonCamel supports Python among other Scripting Languages to allow an Expression or Predicate to be used in the DSL or Xml Configuration. To use a Python expression use the following Java code
... python("somePythonExpression") ...
For example you could use the python function to create an Predicate in a Message Filter or as an Expression for a Recipient List ExampleIn the sample below we use Python to create a Predicate use in the route path, to route exchanges from admin users to a special queue.
from("direct:start")
.choice()
.when().python("request.headers['user'] == 'admin'").to("seda:adminQueue")
.otherwise()
.to("seda:regularQueue");
And a Spring DSL sample as well:
<route>
<from uri="direct:start"/>
<choice>
<when>
<python>request.headers['user'] == 'admin'</python>
<to uri="seda:adminQueue"/>
</when>
<otherwise>
<to uri="seda:regularQueue"/>
</otherwise>
</choice>
</route>
ScriptContextThe JSR-223 scripting languages ScriptContext is pre configured with the following attributes all set at ENGINE_SCOPE:
AttributesYou can add your own attributes with the attribute(name, value) DSL method, such as: In the sample below we add an attribute user that is an object we already have instantiated as myUser. This object has a getFirstName() method that we want to set as header on the message. We use the groovy language to concat the first and last name into a single string that is returned. from("direct:in").setHeader("name").groovy("'$user.firstName $user.lastName'").attribute("user", myUser).to("seda:users"); Any scripting languageCamel can run any JSR-223 scripting languages using the script DSL method such as: from("direct:in").setHeader("firstName").script("jaskel", "user.firstName").attribute("user", myUser).to("seda:users"); This is a bit different using the Spring DSL where you use the expression element that doesn't support setting attributes (yet):
<from uri="direct:in"/>
<setHeader headerName="firstName">
<expression language="jaskel">user.firstName</expression>
</setHeader>
<to uri="seda:users"/>
You can also use predicates e.g. in a Filter:
<filter>
<language language="beanshell">request.getHeaders().get("Foo").equals("Bar")</language>
<to uri="direct:next" />
</filter>
See Scripting Languages for the list of languages with explicit DSL support. Some languages without specific DSL support but known to work with these generic methods include:
Additional arguments to ScriptingEngineAvailable as of Camel 2.8 You can provide additional arguments to the ScriptingEngine using a header on the Camel message with the key CamelScriptArguments. public void testArgumentsExample() throws Exception { if (!ScriptTestHelper.canRunTestOnThisPlatform()) { return; } getMockEndpoint("mock:result").expectedMessageCount(0); getMockEndpoint("mock:unmatched").expectedMessageCount(1); // additional arguments to ScriptEngine Map<String, Object> arguments = new HashMap<String, Object>(); arguments.put("foo", "bar"); arguments.put("baz", 7); // those additional arguments is provided as a header on the Camel Message template.sendBodyAndHeader("direct:start", "hello", ScriptBuilder.ARGUMENTS, arguments); assertMockEndpointsSatisfied(); } Using properties functionAvailable as of Camel 2.9 If you need to use the Properties component from a script to lookup property placeholders, then its a bit cumbersome to do so. .setHeader("myHeader").groovy("context.resolvePropertyPlaceholders('{{' + request.headers.get('foo') + '}}')") From Camel 2.9 onwards you can now use the properties function and the same example is simpler: .setHeader("myHeader").groovy("properties.resolve(request.headers.get('foo'))") Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").groovy("resource:classpath:mygroovy.groovy") DependenciesTo use scripting languages in your camel routes you need to add the a dependency on camel-script which integrates the JSR-223 scripting engine. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-script</artifactId> <version>x.x.x</version> </dependency> PHPCamel supports PHP among other Scripting Languages to allow an Expression or Predicate to be used in the DSL or Xml Configuration. To use a PHP expression use the following Java code
... php("somePHPExpression") ...
For example you could use the php function to create an Predicate in a Message Filter or as an Expression for a Recipient List ScriptContextThe JSR-223 scripting languages ScriptContext is pre configured with the following attributes all set at ENGINE_SCOPE:
AttributesYou can add your own attributes with the attribute(name, value) DSL method, such as: In the sample below we add an attribute user that is an object we already have instantiated as myUser. This object has a getFirstName() method that we want to set as header on the message. We use the groovy language to concat the first and last name into a single string that is returned. from("direct:in").setHeader("name").groovy("'$user.firstName $user.lastName'").attribute("user", myUser).to("seda:users"); Any scripting languageCamel can run any JSR-223 scripting languages using the script DSL method such as: from("direct:in").setHeader("firstName").script("jaskel", "user.firstName").attribute("user", myUser).to("seda:users"); This is a bit different using the Spring DSL where you use the expression element that doesn't support setting attributes (yet):
<from uri="direct:in"/>
<setHeader headerName="firstName">
<expression language="jaskel">user.firstName</expression>
</setHeader>
<to uri="seda:users"/>
You can also use predicates e.g. in a Filter:
<filter>
<language language="beanshell">request.getHeaders().get("Foo").equals("Bar")</language>
<to uri="direct:next" />
</filter>
See Scripting Languages for the list of languages with explicit DSL support. Some languages without specific DSL support but known to work with these generic methods include:
Additional arguments to ScriptingEngineAvailable as of Camel 2.8 You can provide additional arguments to the ScriptingEngine using a header on the Camel message with the key CamelScriptArguments. public void testArgumentsExample() throws Exception { if (!ScriptTestHelper.canRunTestOnThisPlatform()) { return; } getMockEndpoint("mock:result").expectedMessageCount(0); getMockEndpoint("mock:unmatched").expectedMessageCount(1); // additional arguments to ScriptEngine Map<String, Object> arguments = new HashMap<String, Object>(); arguments.put("foo", "bar"); arguments.put("baz", 7); // those additional arguments is provided as a header on the Camel Message template.sendBodyAndHeader("direct:start", "hello", ScriptBuilder.ARGUMENTS, arguments); assertMockEndpointsSatisfied(); } Using properties functionAvailable as of Camel 2.9 If you need to use the Properties component from a script to lookup property placeholders, then its a bit cumbersome to do so. .setHeader("myHeader").groovy("context.resolvePropertyPlaceholders('{{' + request.headers.get('foo') + '}}')") From Camel 2.9 onwards you can now use the properties function and the same example is simpler: .setHeader("myHeader").groovy("properties.resolve(request.headers.get('foo'))") Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").groovy("resource:classpath:mygroovy.groovy") DependenciesTo use scripting languages in your camel routes you need to add the a dependency on camel-script which integrates the JSR-223 scripting engine. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-script</artifactId> <version>x.x.x</version> </dependency> RubyCamel supports Ruby among other Scripting Languages to allow an Expression or Predicate to be used in the DSL or Xml Configuration. To use a Ruby expression use the following Java code
... ruby("someRubyExpression") ...
For example you could use the ruby function to create an Predicate in a Message Filter or as an Expression for a Recipient List ExampleIn the sample below we use Ruby to create a Predicate use in the route path, to route exchanges from admin users to a special queue.
from("direct:start")
.choice()
.when().ruby("$request.headers['user'] == 'admin'").to("seda:adminQueue")
.otherwise()
.to("seda:regularQueue");
And a Spring DSL sample as well:
<route>
<from uri="direct:start"/>
<choice>
<when>
<ruby>$request.headers['user'] == 'admin'</ruby>
<to uri="seda:adminQueue"/>
</when>
<otherwise>
<to uri="seda:regularQueue"/>
</otherwise>
</choice>
</route>
ScriptContextThe JSR-223 scripting languages ScriptContext is pre configured with the following attributes all set at ENGINE_SCOPE:
AttributesYou can add your own attributes with the attribute(name, value) DSL method, such as: In the sample below we add an attribute user that is an object we already have instantiated as myUser. This object has a getFirstName() method that we want to set as header on the message. We use the groovy language to concat the first and last name into a single string that is returned. from("direct:in").setHeader("name").groovy("'$user.firstName $user.lastName'").attribute("user", myUser).to("seda:users"); Any scripting languageCamel can run any JSR-223 scripting languages using the script DSL method such as: from("direct:in").setHeader("firstName").script("jaskel", "user.firstName").attribute("user", myUser).to("seda:users"); This is a bit different using the Spring DSL where you use the expression element that doesn't support setting attributes (yet):
<from uri="direct:in"/>
<setHeader headerName="firstName">
<expression language="jaskel">user.firstName</expression>
</setHeader>
<to uri="seda:users"/>
You can also use predicates e.g. in a Filter:
<filter>
<language language="beanshell">request.getHeaders().get("Foo").equals("Bar")</language>
<to uri="direct:next" />
</filter>
See Scripting Languages for the list of languages with explicit DSL support. Some languages without specific DSL support but known to work with these generic methods include:
Additional arguments to ScriptingEngineAvailable as of Camel 2.8 You can provide additional arguments to the ScriptingEngine using a header on the Camel message with the key CamelScriptArguments. public void testArgumentsExample() throws Exception { if (!ScriptTestHelper.canRunTestOnThisPlatform()) { return; } getMockEndpoint("mock:result").expectedMessageCount(0); getMockEndpoint("mock:unmatched").expectedMessageCount(1); // additional arguments to ScriptEngine Map<String, Object> arguments = new HashMap<String, Object>(); arguments.put("foo", "bar"); arguments.put("baz", 7); // those additional arguments is provided as a header on the Camel Message template.sendBodyAndHeader("direct:start", "hello", ScriptBuilder.ARGUMENTS, arguments); assertMockEndpointsSatisfied(); } Using properties functionAvailable as of Camel 2.9 If you need to use the Properties component from a script to lookup property placeholders, then its a bit cumbersome to do so. .setHeader("myHeader").groovy("context.resolvePropertyPlaceholders('{{' + request.headers.get('foo') + '}}')") From Camel 2.9 onwards you can now use the properties function and the same example is simpler: .setHeader("myHeader").groovy("properties.resolve(request.headers.get('foo'))") Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").groovy("resource:classpath:mygroovy.groovy") DependenciesTo use scripting languages in your camel routes you need to add the a dependency on camel-script which integrates the JSR-223 scripting engine. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-script</artifactId> <version>x.x.x</version> </dependency> Simple Expression LanguageThe Simple Expression Language was a really simple language you can use, but has since grown more powerful. Its primarily intended for being a really small and simple language for evaluating Expression and Predicate without requiring any new dependencies or knowledge of XPath; so its ideal for testing in camel-core. Its ideal to cover 95% of the common use cases when you need a little bit of expression based script in your Camel routes. However for much more complex use cases you are generally recommended to choose a more expressive and powerful language such as:
The simple language uses ${body} placeholders for complex expressions where the expression contains constant literals. The ${ } placeholders can be omitted if the expression is only the token itself.
To get the body of the in message: "body", or "in.body" or "${body}". A complex expression must use ${ } placeholders, such as: "Hello ${in.header.name} how are you?". You can have multiple functions in the same expression: "Hello ${in.header.name} this is ${in.header.me} speaking". Variables
OGNL expression supportAvailable as of Camel 2.3 The Simple and Bean language now supports a Camel OGNL notation for invoking beans in a chain like fashion. Then you can use Camel OGNL notation to access the address object: simple("${body.address}") simple("${body.address.street}") simple("${body.address.zip}") Camel understands the shorthand names for getters, but you can invoke any method or use the real name such as: simple("${body.address}") simple("${body.getAddress.getStreet}") simple("${body.address.getZip}") simple("${body.doSomething}") You can also use the null safe operator (?.) to avoid NPE if for example the body does NOT have an address
simple("${body?.address?.street}")
Its also possible to index in Map or List types, so you can do:
simple("${body[foo].name}")
To assume the body is Map based and lookup the value with foo as key, and invoke the getName method on that value.
You can access the Map or List objects directly using their key name (with or without dots) : simple("${body[foo]}") simple("${body[this.is.foo]}") Suppose there was no value with the key foo then you can use the null safe operator to avoid the NPE as shown:
simple("${body[foo]?.name}")
You can also access List types, for example to get lines from the address you can do: simple("${body.address.lines[0]}") simple("${body.address.lines[1]}") simple("${body.address.lines[2]}") There is a special last keyword which can be used to get the last value from a list.
simple("${body.address.lines[last]}")
And to get the 2nd last you can subtract a number, so we can use last-1 to indicate this:
simple("${body.address.lines[last-1]}")
And the 3rd last is of course:
simple("${body.address.lines[last-2]}")
And yes you can combine this with the operator support as shown below:
simple("${body.address.zip} > 1000")
Operator supportThe parser is limited to only support a single operator. To enable it the left value must be enclosed in ${ }. The syntax is:
${leftValue} OP rightValue
Where the rightValue can be a String literal enclosed in ' ', null, a constant value or another expression enclosed in ${ }.
Camel will automatically type convert the rightValue type to the leftValue type, so its able to eg. convert a string into a numeric so you can use > comparison for numeric values. The following operators are supported:
And the following unary operators can be used:
And the following logical operators can be used to group expressions:
The syntax for AND is:
${leftValue} OP rightValue and ${leftValue} OP rightValue
And the syntax for OR is:
${leftValue} OP rightValue or ${leftValue} OP rightValue
Some examples: simple("${in.header.foo} == 'foo'") // here Camel will type convert '100' into the type of in.header.bar and if its an Integer '100' will also be converter to an Integer simple("${in.header.bar} == '100'") simple("${in.header.bar} == 100") // 100 will be converter to the type of in.header.bar so we can do > comparison simple("${in.header.bar} > 100")
// testing for null simple("${in.header.baz} == null") // testing for not null simple("${in.header.baz} != null") And a bit more advanced example where the right value is another expression simple("${in.header.date} == ${date:now:yyyyMMdd}") simple("${in.header.type} == ${bean:orderService?method=getOrderType}") And an example with contains, testing if the title contains the word Camel
simple("${in.header.title} contains 'Camel'")
And an example with regex, testing if the number header is a 4 digit value:
simple("${in.header.number} regex '\\d{4}'")
And finally an example if the header equals any of the values in the list. Each element must be separated by comma, and no space around.
simple("${in.header.type} in 'gold,silver'")
And for all the last 3 we also support the negate test using not:
simple("${in.header.type} not in 'gold,silver'")
And you can test if the type is a certain instance, eg for instance a String
simple("${in.header.type} is 'java.lang.String'")
We have added a shorthand for all java.lang types so you can write it as:
simple("${in.header.type} is 'String'")
Ranges are also supported. The range interval requires numbers and both from and end are inclusive. For instance to test whether a value is between 100 and 199:
simple("${in.header.number} range 100..199")
Notice we use .. in the range without spaces. Its based on the same syntax as Groovy. From Camel 2.9 onwards the range value must be in single quotes
simple("${in.header.number} range '100..199'")
Using and / orIf you have two expressions you can combine them with the and or or operator.
For instance:
simple("${in.header.title} contains 'Camel' and ${in.header.type'} == 'gold'")
And of course the or is also supported. The sample would be:
simple("${in.header.title} contains 'Camel' or ${in.header.type'} == 'gold'")
Notice: Currently and or or can only be used once in a simple language expression. This might change in the future.
simple("${in.header.title} contains 'Camel' and ${in.header.type'} == 'gold' and ${in.header.number} range 100..200")
SamplesIn the Spring XML sample below we filter based on a header value:
<from uri="seda:orders">
<filter>
<simple>${in.header.foo}</simple>
<to uri="mock:fooOrders"/>
</filter>
</from>
The Simple language can be used for the predicate test above in the Message Filter pattern, where we test if the in message has a foo header (a header with the key foo exists). If the expression evaluates to true then the message is routed to the mock:fooOrders endpoint, otherwise its lost in the deep blue sea The same example in Java DSL:
from("seda:orders")
.filter().simple("${in.header.foo}").to("seda:fooOrders");
You can also use the simple language for simple text concatenations such as: from("direct:hello").transform().simple("Hello ${in.header.user} how are you?").to("mock:reply"); Notice that we must use ${ } placeholders in the expression now to allow Camel to parse it correctly. And this sample uses the date command to output current date. from("direct:hello").transform().simple("The today is ${date:now:yyyyMMdd} and its a great day.").to("mock:reply"); And in the sample below we invoke the bean language to invoke a method on a bean to be included in the returned string: from("direct:order").transform().simple("OrderId: ${bean:orderIdGenerator}").to("mock:reply"); Where orderIdGenerator is the id of the bean registered in the Registry. If using Spring then its the Spring bean id. If we want to declare which method to invoke on the order id generator bean we must prepend .method name such as below where we invoke the generateId method. from("direct:order").transform().simple("OrderId: ${bean:orderIdGenerator.generateId}").to("mock:reply"); We can use the ?method=methodname option that we are familiar with the Bean component itself: from("direct:order").transform().simple("OrderId: ${bean:orderIdGenerator?method=generateId}").to("mock:reply"); And from Camel 2.3 onwards you can also convert the body to a given type, for example to ensure its a String you can do: <transform> <simple>Hello ${bodyAs(String)} how are you?</simple> </transform> There are a few types which have a shorthand notation, so we can use String instead of java.lang.String. These are: byte[], String, Integer, Long. All other types must use their FQN name, e.g. org.w3c.dom.Document. Its also possible to lookup a value from a header Map in Camel 2.3 onwards: <transform> <simple>The gold value is ${header.type[gold]}</simple> </transform> In the code above we lookup the header with name type and regard it as a java.util.Map and we then lookup with the key gold and return the value. From Camel 2.9 onwards you can nest functions, such as shown below: <setHeader headerName="myHeader"> <simple>${properties:${header.someKey}}</simple> </setHeader> Referring to constants or enumsAvailable as of Camel 2.11 Suppose you have an enum for customers public enum Customer { GOLD, SILVER, BRONZE } And in a Content Based Router we can use the Simple language to refer to this enum, to check the message which enum it matches. from("direct:start") .choice() .when().simple("${header.customer} == ${type:org.apache.camel.processor.Customer.GOLD}") .to("mock:gold") .when().simple("${header.customer} == ${type:org.apache.camel.processor.Customer.SILVER}") .to("mock:silver") .otherwise() .to("mock:other"); Using new lines or tabs in XML DSLsAvailable as of Camel 2.9.3 From Camel 2.9.3 onwards its easier to specify new lines or tabs in XML DSLs as you can escape the value now <transform> <simple>The following text\nis on a new line</simple> </transform> Setting result typeAvailable as of Camel 2.8 You can now provide a result type to the Simple expression, which means the result of the evaluation will be converted to the desired type. This is most useable to define types such as booleans, integers, etc. For example to set a header as a boolean type you can do: .setHeader("cool", simple("true", Boolean.class)) And in XML DSL
<setHeader headerName="cool">
<!-- use resultType to indicate that the type should be a java.lang.Boolean -->
<simple resultType="java.lang.Boolean">true</simple>
</setHeader>
Changing function start and end tokensAvailable as of Camel 2.9.1 You can configure the function start and end tokens - ${ } using the setters changeFunctionStartToken and changeFunctionEndToken on SimpleLanguage, using Java code. From Spring XML you can define a <bean> tag with the new changed tokens in the properties as shown below:
<!-- configure Simple to use custom prefix/suffix tokens -->
<bean id="simple" class="org.apache.camel.language.simple.SimpleLanguage">
<property name="functionStartToken" value="["/>
<property name="functionEndToken" value="]"/>
</bean>
In the example above we use [ ] as the changed tokens. Notice by changing the start/end token you change those in all the Camel applications which share the same camel-core on their classpath. Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").simple("resource:classpath:mysimple.txt") DependenciesThe Simple language is part of camel-core. File Expression Language
The File Expression Language is an extension to the Simple language, adding file related capabilities. These capabilities are related to common use cases working with file path and names. The goal is to allow expressions to be used with the File and FTP components for setting dynamic file patterns for both consumer and producer. SyntaxThis language is an extension to the Simple language so the Simple syntax applies also. So the table below only lists the additional. All the file tokens use the same expression name as the method on the java.io.File object, for instance file:absolute refers to the java.io.File.getAbsolute() method. Notice that not all expressions are supported by the current Exchange. For instance the FTP component supports some of the options, where as the File component supports all of them.
File token exampleRelative pathsWe have a java.io.File handle for the file hello.txt in the following relative directory: .\filelanguage\test. And we configure our endpoint to use this starting directory .\filelanguage. The file tokens will return as:
Absolute pathsWe have a java.io.File handle for the file hello.txt in the following absolute directory: \workspace\camel\camel-core\target\filelanguage\test. And we configure out endpoint to use the absolute starting directory \workspace\camel\camel-core\target\filelanguage. The file tokens will return as:
SamplesYou can enter a fixed Constant expression such as myfile.txt:
fileName="myfile.txt"
Lets assume we use the file consumer to read files and want to move the read files to backup folder with the current date as a sub folder. This can be archieved using an expression like:
fileName="backup/${date:now:yyyyMMdd}/${file:name.noext}.bak"
relative folder names are also supported so suppose the backup folder should be a sibling folder then you can append .. as:
fileName="../backup/${date:now:yyyyMMdd}/${file:name.noext}.bak"
As this is an extension to the Simple language we have access to all the goodies from this language also, so in this use case we want to use the in.header.type as a parameter in the dynamic expression:
fileName="../backup/${date:now:yyyyMMdd}/type-${in.header.type}/backup-of-${file:name.noext}.bak"
If you have a custom Date you want to use in the expression then Camel supports retrieving dates from the message header.
fileName="orders/order-${in.header.customerId}-${date:in.header.orderDate:yyyyMMdd}.xml"
And finally we can also use a bean expression to invoke a POJO class that generates some String output (or convertible to String) to be used:
fileName="uniquefile-${bean:myguidgenerator.generateid}.txt"
And of course all this can be combined in one expression where you can use the File Language, Simple and the Bean language in one combined expression. This is pretty powerful for those common file path patterns. Using Spring PropertyPlaceholderConfigurer together with the File componentIn Camel you can use the File Language directly from the Simple language which makes a Content Based Router easier to do in Spring XML, where we can route based on file extensions as shown below: <from uri="file://input/orders"/> <choice> <when> <simple>${file:ext} == 'txt'</simple> <to uri="bean:orderService?method=handleTextFiles"/> </when> <when> <simple>${file:ext} == 'xml'</simple> <to uri="bean:orderService?method=handleXmlFiles"/> </when> <otherwise> <to uri="bean:orderService?method=handleOtherFiles"/> </otherwise> </choice> If you use the fileName option on the File endpoint to set a dynamic filename using the File Language then make sure you bundle-context.xml <bean id="propertyPlaceholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:bundle-context.cfg" /> </bean> <bean id="sampleRoute" class="SampleRoute"> <property name="fromEndpoint" value="${fromEndpoint}" /> <property name="toEndpoint" value="${toEndpoint}" /> </bean> bundle-context.cfg
fromEndpoint=activemq:queue:test
toEndpoint=file://fileRoute/out?fileName=test-$simple{date:now:yyyyMMdd}.txt
Notice how we use the $simple{ } syntax in the toEndpoint above. org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'sampleRoute' defined in class path resource [bundle-context.xml]: Could not resolve placeholder 'date:now:yyyyMMdd' DependenciesThe File language is part of camel-core. SQL LanguageThe SQL support is added by JoSQL and is primarily used for performing SQL queries on in-memory objects. If you prefer to perform actual database queries then check out the JPA component.
To use SQL in your camel routes you need to add the a dependency on camel-josql which implements the SQL language. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-josql</artifactId> <version>2.5.0</version> </dependency> Camel supports SQL to allow an Expression or Predicate to be used in the DSL or Xml Configuration. For example you could use SQL to create an Predicate in a Message Filter or as an Expression for a Recipient List. from("queue:foo").setBody().sql("select * from MyType").to("queue:bar") And the spring DSL: <from uri="queue:foo"/> <setBody> <sql>select * from MyType</sql> </setBody> <to uri="queue:bar"/> Variables
Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").sql("resource:classpath:mysql.sql") XPathCamel supports XPath to allow an Expression or Predicate to be used in the DSL or Xml Configuration. For example you could use XPath to create an Predicate in a Message Filter or as an Expression for a Recipient List. from("queue:foo"). filter().xpath("//foo")). to("queue:bar") from("queue:foo"). choice().xpath("//foo")).to("queue:bar"). otherwise().to("queue:others"); NamespacesYou can easily use namespaces with XPath expressions using the Namespaces helper class. Namespaces ns = new Namespaces("c", "http://acme.com/cheese"); from("direct:start").filter(). xpath("/c:person[@name='James']", ns). to("mock:result"); VariablesVariables in XPath is defined in different namespaces. The default namespace is http://camel.apache.org/schema/spring.
Camel will resolve variables according to either:
Namespace givenIf the namespace is given then Camel is instructed exactly what to return. However when resolving either in or out Camel will try to resolve a header with the given local part first, and return it. If the local part has the value body then the body is returned instead. No namespace givenIf there is no namespace given then Camel resolves only based on the local part. Camel will try to resolve a variable in the following steps:
FunctionsCamel adds the following XPath functions that can be used to access the exchange:
Notice: function:properties and function:simple is not supported when the return type is a NodeSet, such as when using with a Splitter EIP. Here's an example showing some of these functions in use. 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"); And the new functions introduced in Camel 2.5: // setup properties component PropertiesComponent properties = new PropertiesComponent(); properties.setLocation("classpath:org/apache/camel/builder/xml/myprop.properties"); context.addComponent("properties", properties); // myprop.properties contains the following properties // foo=Camel // bar=Kong from("direct:in").choice() // $type is a variable for the header with key type // here we use the properties function to lookup foo from the properties files // which at runtime will be evaluted to 'Camel' .when().xpath("$type = function:properties('foo')") .to("mock:camel") // here we use the simple language to evaluate the expression // which at runtime will be evaluated to 'Donkey Kong' .when().xpath("//name = function:simple('Donkey ${properties:bar}')") .to("mock:donkey") .otherwise() .to("mock:other") .end(); Using XML configurationIf you prefer to configure your routes in your Spring XML file then you can use XPath expressions as follows <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> <camelContext id="camel" xmlns="http://activemq.apache.org/camel/schema/spring" xmlns:foo="http://example.com/person"> <route> <from uri="activemq:MyQueue"/> <filter> <xpath>/foo:person[@name='James']</xpath> <to uri="mqseries:SomeOtherQueue"/> </filter> </route> </camelContext> </beans> Notice how we can reuse the namespace prefixes, foo in this case, in the XPath expression for easier namespace based XPath expressions! See also this discussion on the mailinglist about using your own namespaces with xpath Setting result typeThe XPath expression will return a result type using native XML objects such as org.w3c.dom.NodeList. But many times you want a result type to be a String. To do this you have to instruct the XPath which result type to use. In Java DSL: xpath("/foo:person/@id", String.class) In Spring DSL you use the resultType attribute to provide a fully qualified classname: <xpath resultType="java.lang.String">/foo:person/@id</xpath> In @XPath:
@XPath(value = "concat('foo-',//order/name/)", resultType = String.class) String name)
Where we use the xpath function concat to prefix the order name with foo-. In this case we have to specify that we want a String as result type so the concat function works. Using XPath on HeadersAvailable as of Camel 2.11 Some users may have XML stored in a header. To apply an XPath to a header's value you can do this by defining the 'headerName' attribute. In XML DSL: <camelContext id="xpathHeaderNameTest" xmlns="http://camel.apache.org/schema/blueprint"> <route> <from uri="direct:in"/> <choice> <when> <!-- use headerName attribute to refer to a header --> <xpath headerName="invoiceDetails">/invoice/@orderType = 'premium'</xpath> <to uri="mock:premium"/> </when> <when> <!-- use headerName attribute to refer to a header --> <xpath headerName="invoiceDetails">/invoice/@orderType = 'standard'</xpath> <to uri="mock:standard"/> </when> <otherwise> <to uri="mock:unknown"/> </otherwise> </choice> </route> </camelContext> ExamplesHere is a simple example using an XPath expression as a predicate in a Message Filter from("direct:start"). filter().xpath("/person[@name='James']"). to("mock:result"); If you have a standard set of namespaces you wish to work with and wish to share them across many different XPath expressions you can use the NamespaceBuilder as shown in this example // lets define the namespaces we'll need in our filters Namespaces ns = new Namespaces("c", "http://acme.com/cheese") .add("xsd", "http://www.w3.org/2001/XMLSchema"); // now lets create an xpath based Message Filter from("direct:start"). filter(ns.xpath("/c:person[@name='James']")). to("mock:result"); In this sample we have a choice construct. The first choice evaulates if the message has a header key type that has the value Camel. from("direct:in").choice() // using $headerName is special notation in Camel to get the header key .when().xpath("$type = 'Camel'") .to("mock:camel") // here we test for the body name tag .when().xpath("//name = 'Kong'") .to("mock:donkey") .otherwise() .to("mock:other") .end(); And the spring XML equivalent of the route: <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="direct:in"/> <choice> <when> <xpath>$type = 'Camel'</xpath> <to uri="mock:camel"/> </when> <when> <xpath>//name = 'Kong'</xpath> <to uri="mock:donkey"/> </when> <otherwise> <to uri="mock:other"/> </otherwise> </choice> </route> </camelContext> XPath injectionYou can use Bean Integration to invoke a method on a bean and use various languages such as XPath to extract a value from the message and bind it to a method parameter. The default XPath annotation has SOAP and XML namespaces available. If you want to use your own namespace URIs in an XPath expression you can use your own copy of the XPath annotation to create whatever namespace prefixes you want to use. import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.w3c.dom.NodeList; import org.apache.camel.component.bean.XPathAnnotationExpressionFactory; import org.apache.camel.language.LanguageAnnotation; import org.apache.camel.language.NamespacePrefix; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @LanguageAnnotation(language = "xpath", factory = XPathAnnotationExpressionFactory.class) public @interface MyXPath { String value(); // You can add the namespaces as the default value of the annotation NamespacePrefix[] namespaces() default { @NamespacePrefix(prefix = "n1", uri = "http://example.org/ns1"), @NamespacePrefix(prefix = "n2", uri = "http://example.org/ns2")}; Class<?> resultType() default NodeList.class; } i.e. cut and paste upper code to your own project in a different package and/or annotation name then add whatever namespace prefix/uris you want in scope when you use your annotation on a method parameter. Then when you use your annotation on a method parameter all the namespaces you want will be available for use in your XPath expression. For example public class Foo { @MessageDriven(uri = "activemq:my.queue") public void doSomething(@MyXPath("/ns1:foo/ns2:bar/text()") String correlationID, @Body String body) { // process the inbound message here } } Using XPathBuilder without an ExchangeAvailable as of Camel 2.3 You can now use the org.apache.camel.builder.XPathBuilder without the need for an Exchange. This comes handy if you want to use it as a helper to do custom xpath evaluations. It requires that you pass in a CamelContext since a lot of the moving parts inside the XPathBuilder requires access to the Camel Type Converter and hence why CamelContext is needed. For example you can do something like this: boolean matches = XPathBuilder.xpath("/foo/bar/@xyz").matches(context, "<foo><bar xyz='cheese'/></foo>")); This will match the given predicate. You can also evaluate for example as shown in the following three examples:
String name = XPathBuilder.xpath("foo/bar").evaluate(context, "<foo><bar>cheese</bar></foo>", String.class);
Integer number = XPathBuilder.xpath("foo/bar").evaluate(context, "<foo><bar>123</bar></foo>", Integer.class);
Boolean bool = XPathBuilder.xpath("foo/bar").evaluate(context, "<foo><bar>true</bar></foo>", Boolean.class);
Evaluating with a String result is a common requirement and thus you can do it a bit simpler:
String name = XPathBuilder.xpath("foo/bar").evaluate(context, "<foo><bar>cheese</bar></foo>");
Using Saxon with XPathBuilderAvailable as of Camel 2.3 You need to add camel-saxon as dependency to your project. Its now easier to use Saxon with the XPathBuilder which can be done in several ways as shown below. Using a factory // create a Saxon factory XPathFactory fac = new net.sf.saxon.xpath.XPathFactoryImpl(); // create a builder to evaluate the xpath using the saxon factory XPathBuilder builder = XPathBuilder.xpath("tokenize(/foo/bar, '_')[2]").factory(fac); // evaluate as a String result String result = builder.evaluate(context, "<foo><bar>abc_def_ghi</bar></foo>"); assertEquals("def", result); Using ObjectModel // create a builder to evaluate the xpath using saxon based on its object model uri XPathBuilder builder = XPathBuilder.xpath("tokenize(/foo/bar, '_')[2]").objectModel("http://saxon.sf.net/jaxp/xpath/om"); // evaluate as a String result String result = builder.evaluate(context, "<foo><bar>abc_def_ghi</bar></foo>"); assertEquals("def", result); The easy one // create a builder to evaluate the xpath using saxon XPathBuilder builder = XPathBuilder.xpath("tokenize(/foo/bar, '_')[2]").saxon(); // evaluate as a String result String result = builder.evaluate(context, "<foo><bar>abc_def_ghi</bar></foo>"); assertEquals("def", result); Setting a custom XPathFactory using System PropertyAvailable as of Camel 2.3 Camel now supports reading the JVM system property javax.xml.xpath.XPathFactory that can be used to set a custom XPathFactory to use. This unit test shows how this can be done to use Saxon instead: // set system property with the XPath factory to use which is Saxon System.setProperty(XPathFactory.DEFAULT_PROPERTY_NAME + ":" + "http://saxon.sf.net/jaxp/xpath/om", "net.sf.saxon.xpath.XPathFactoryImpl"); // create a builder to evaluate the xpath using saxon XPathBuilder builder = XPathBuilder.xpath("tokenize(/foo/bar, '_')[2]"); // evaluate as a String result String result = builder.evaluate(context, "<foo><bar>abc_def_ghi</bar></foo>"); assertEquals("def", result); Camel will log at INFO level if it uses a non default XPathFactory such as:
XPathBuilder INFO Using system property javax.xml.xpath.XPathFactory:http://saxon.sf.net/jaxp/xpath/om with value:
net.sf.saxon.xpath.XPathFactoryImpl when creating XPathFactory
To use Apache Xerces you can configure the system property -Djavax.xml.xpath.XPathFactory=org.apache.xpath.jaxp.XPathFactoryImpl Enabling Saxon from Spring DSLAvailable as of Camel 2.10 Similarly to Java DSL, to enable Saxon from Spring DSL you have three options: Specifying the factory <xpath factoryRef="saxonFactory" resultType="java.lang.String">current-dateTime()</xpath> Specifying the object model <xpath objectModel="http://saxon.sf.net/jaxp/xpath/om" resultType="java.lang.String">current-dateTime()</xpath> Shortcut <xpath saxon="true" resultType="java.lang.String">current-dateTime()</xpath> Namespace auditing to aid debuggingAvailable as of Camel 2.10 A large number of XPath-related issues that users frequently face are linked to the usage of namespaces. You may have some misalignment between the namespaces present in your message and those that your XPath expression is aware of or referencing. XPath predicates or expressions that are unable to locate the XML elements and attributes due to namespaces issues may simply look like "they are not working", when in reality all there is to it is a lack of namespace definition. Namespaces in XML are completely necessary, and while we would love to simplify their usage by implementing some magic or voodoo to wire namespaces automatically, truth is that any action down this path would disagree with the standards and would greatly hinder interoperability. Therefore, the utmost we can do is assist you in debugging such issues by adding two new features to the XPath Expression Language and are thus accesible from both predicates and expressions. Logging the Namespace Context of your XPath expression/predicateEvery time a new XPath expression is created in the internal pool, Camel will log the namespace context of the expression under the org.apache.camel.builder.xml.XPathBuilder logger. Since Camel represents Namespace Contexts in a hierarchical fashion (parent-child relationships), the entire tree is output in a recursive manner with the following format:
[me: {prefix -> namespace}, {prefix -> namespace}], [parent: [me: {prefix -> namespace}, {prefix -> namespace}], [parent: [me: {prefix -> namespace}]]]
Any of these options can be used to activate this logging:
Auditing namespacesCamel is able to discover and dump all namespaces present on every incoming message before evaluating an XPath expression, providing all the richness of information you need to help you analyse and pinpoint possible namespace issues. To achieve this, it in turn internally uses another specially tailored XPath expression to extract all namespace mappings that appear in the message, displaying the prefix and the full namespace URI(s) for each individual mapping. Some points to take into account:
You can enable this option in Java DSL and Spring DSL. Java DSL: XPathBuilder.xpath("/foo:person/@id", String.class).logNamespaces() Spring DSL: <xpath logNamespaces="true" resultType="String">/foo:person/@id</xpath> The result of the auditing will be appear at the INFO level under the org.apache.camel.builder.xml.XPathBuilder logger and will look like the following:
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]}
Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").xpath("resource:classpath:myxpath.txt", String.class) DependenciesThe XPath language is part of camel-core. XQueryCamel supports XQuery to allow an Expression or Predicate to be used in the DSL or Xml Configuration. For example you could use XQuery to create an Predicate in a Message Filter or as an Expression for a Recipient List. Options
Examplesfrom("queue:foo").filter(). xquery("//foo"). to("queue:bar") You can also use functions inside your query, in which case you need an explicit type conversion (or you will get a org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR) by passing the Class as a second argument to the xquery() method. from("direct:start"). recipientList().xquery("concat('mock:foo.', /person/@city)", String.class); VariablesThe IN message body will be set as the contextItem. Besides this these Variables is also added as parameters:
Using XML configurationIf you prefer to configure your routes in your Spring XML file then you can use XPath expressions as follows <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:foo="http://example.com/person" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> <camelContext id="camel" xmlns="http://activemq.apache.org/camel/schema/spring"> <route> <from uri="activemq:MyQueue"/> <filter> <xquery>/foo:person[@name='James']</xquery> <to uri="mqseries:SomeOtherQueue"/> </filter> </route> </camelContext> </beans> Notice how we can reuse the namespace prefixes, foo in this case, in the XPath expression for easier namespace based XQuery expressions! When you use functions in your XQuery expression you need an explicit type conversion which is done in the xml configuration via the @type attribute:
<xquery type="java.lang.String">concat('mock:foo.', /person/@city)</xquery>
Using XQuery as an endpointSometimes an XQuery expression can be quite large; it can essentally be used for Templating. So you may want to use an XQuery Endpoint so you can route using XQuery templates. The following example shows how to take a message of an ActiveMQ queue (MyQueue) and transform it using XQuery and send it to MQSeries. <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="activemq:MyQueue"/> <to uri="xquery:com/acme/someTransform.xquery"/> <to uri="mqseries:SomeOtherQueue"/> </route> </camelContext> ExamplesHere is a simple example using an XQuery expression as a predicate in a Message Filter from("direct:start").filter().xquery("/person[@name='James']").to("mock:result"); This example uses XQuery with namespaces as a predicate in a Message Filter Namespaces ns = new Namespaces("c", "http://acme.com/cheese"); from("direct:start"). filter().xquery("/c:person[@name='James']", ns). to("mock:result"); Learning XQueryXQuery is a very powerful language for querying, searching, sorting and returning XML. For help learning XQuery try these tutorials
You might also find the XQuery function reference useful Loading script from external resourceAvailable as of Camel 2.11 You can externalize the script and have Camel load it from a resource such as "classpath:", "file:", or "http:". .setHeader("myHeader").xquery("resource:classpath:myxquery.txt", String.class) DependenciesTo use XQuery in your camel routes you need to add the a dependency on camel-saxon which implements the XQuery language. If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions). <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-saxon</artifactId> <version>x.x.x</version> </dependency> |