blob: 8f3c126914438da0ff065562f3baa9c0429318d0 [file] [log] [blame]
[[GroovyDSL-AbouttheGroovyDSL]]
About the Groovy DSL
^^^^^^^^^^^^^^^^^^^^
The Groovy DSL implementation is built on top of the existing Java-based
link:dsl.html[DSL], but it additionally allows to use Groovy language
features in your routes, particularly
http://www.groovy-lang.org/closures.html[Closures] acting as
link:processor.html[Processor], link:expression.html[Expression],
link:predicate.html[Predicate], or link:aggregator.html[Aggregation
Strategy]. +
With the Groovy DSL you write your RouteBuilder classes entirely in
Groovy, while the link:scripting-languages.html[scripting component]
allows to embed small scripts into Java routes. The Groovy DSL requires
Groovy 2.0 or newer and is available as of *Camel 2.11*.
[[GroovyDSL-Introduction]]
Introduction
^^^^^^^^^^^^
Because Groovy is syntactically very similar to Java, you can write your
Groovy routes just like Java routes. The same Java DSL classes are being
used, with the exception that some of the DSL classes get extended with
a bunch of new methods at runtime. This is achieved by turning
camel-groovy into a Groovy
http://docs.codehaus.org/display/GROOVY/Creating+an+extension+module[Extension
Module] that defines extension methods on existing classes.
The majority of the extension methods allow
http://www.groovy-lang.org/closures.html[Closures] to be used as
parameters e.g. for expressions, predicates, processors. The following
example reverses a string in the message body and then prints the value
to System.out:
*MyRouteBuilder.groovy*
[source,java]
-----------------------------------------
...
from('direct:test')
.transform { it.in.body.reverse() }
.process { println it.in.body }
...
-----------------------------------------
The corresponding route in Java would look something like this:
*MyRouteBuilder.java*
[source,java]
-----------------------------------------------------------------------------------------
...
from("direct:test")
.transform(new Expression() {
@Override
public Object evaluate(Exchange e) {
return new StringBuffer(e.getIn().getBody().toString()).reverse().toString();
}
})
.process(new Processor() {
@Override
public void process(Exchange e) {
System.out.println(e.getIn().getBody());
}
});
...
-----------------------------------------------------------------------------------------
[[GroovyDSL-DevelopingwiththeGroovyDSL]]
Developing with the Groovy DSL
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To be able to use the Groovy DSL in your camel routes you need to add
the a dependency on *camel-groovy* which implements the Groovy DSL.
If you use Maven you can 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).
[source,xml]
---------------------------------------
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-groovy</artifactId>
<version>2.11.0</version>
</dependency>
---------------------------------------
Additionally you need to make sure that the Groovy classes will be
compiled. You can either use gmaven for this or, particularly with mixed
projects containing Java and Groovy code, you might want to use the
http://groovy.codehaus.org/Groovy-Eclipse+compiler+plugin+for+Maven[Groovy
Eclipse compiler]:
[source,xml]
--------------------------------------------------------
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerId>groovy-eclipse-compiler</compilerId>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-compiler</artifactId>
<version>2.7.0-01</version>
</dependency>
</dependencies>
</plugin>
--------------------------------------------------------
As Eclipse user, you might want to configure the Maven Eclipse plugin in
a way so that your project is set up correctly for using
http://groovy.codehaus.org/Eclipse+Plugin[Eclipse Plugin for Groovy]
when `mvn eclipse:eclipse` is executed:
[source,xml]
----------------------------------------------------------------------------------------
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<additionalProjectnatures>
<projectnature>org.eclipse.jdt.groovy.core.groovyNature</projectnature>
</additionalProjectnatures>
<classpathContainers>
<classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
<classpathContainer>GROOVY_DSL_SUPPORT</classpathContainer>
</classpathContainers>
</configuration>
</plugin>
----------------------------------------------------------------------------------------
[[GroovyDSL-UsingClosuresinyourroutes]]
Using Closures in your routes
+++++++++++++++++++++++++++++
Groovy closures can be used to write concise implementations of Camel
processors, expressions, predicates, and aggregation strategies. It is
recommended to keep more complicated implementations of these objects in
their own classes, e.g. to be able to test them more easily and not to
clutter up your routes with business logic.
[[GroovyDSL-ProcessorClosures]]
Processor Closures
All Java DSL parameters of type `org.apache.camel.Processor` can be
replaced by a closure that accepts an object of type
`org.apache.camel.Exchange` as only parameter. The return value of the
closure is disregarded. All closures may also refer to variables not
listed in their parameter list. Example:
[source,java]
------------------------------------------------------------------------------
...
private String someValue
...
from('direct:test')
.process { Exchange exchange -> println (exchange.in.body + someValue) }
.process { println (it.in.body + someValue) } // equivalent
...
------------------------------------------------------------------------------
[[GroovyDSL-ExpressionClosures]]
Expression Closures
All Java DSL parameters of type `org.apache.camel.Expression` can be
replaced by a closure that accepts an object of type
`org.apache.camel.Exchange` as only parameter. The return value of the
closure is the result of the expression. Example:
[source,java]
-----------------------------------------------------
...
private String someValue
...
from('direct:test')
.transform { it.in.body.reverse() + someValue }
.setHeader("myHeader") { someValue.reverse() }
...
-----------------------------------------------------
[[GroovyDSL-PredicateClosures]]
Predicate Closures
All Java DSL parameters of type `org.apache.camel.Predicate` can be
replaced by a closure that accepts an object of type
`org.apache.camel.Exchange` as only parameter. The return value of the
closure is translated into a boolean value representing the result of
the predicate. Example:
[source,java]
------------------------------------------------------
...
private String someValue
// This time, the closure is stored in a variable
def pred = { Exchange e -> e.in.body != someValue }
...
from('direct:test')
.filter(pred)
...
------------------------------------------------------
[[GroovyDSL-AggregationStrategyClosures]]
Aggregation Strategy Closures
Java DSL parameters of type
`org.apache.camel.processor.aggregate.AggregationStrategy` can be
replaced by a closure that accepts two objects of type
`org.apache.camel.Exchange` representing the two Exchanges to be
aggregated. The return value of the closure must be the aggregated
Exchange. Example:
[source,java]
-------------------------------------------------------------------------
...
private String separator
...
from('direct:test1')
.enrich('direct:enrich') { Exchange original, Exchange resource ->
original.in.body += resource.in.body + separator
original // don't forget to return resulting exchange
}
...
-------------------------------------------------------------------------
[[GroovyDSL-Genericclosurebridges]]
Generic closure bridges
In addition to the above-mentioned DSL extensions, you can use closures
even if no DSL method signature with closure parameters is available.
Assuming there's no `filter(Closure)` method, you could instead write:
[source,java]
---------------------------------------------------------
...
private String someValue
// This time, the closure is stored in a variable
def pred = { Exchange e -> e.in.body != someValue }
...
from('direct:test')
// predicate(Closure) -> org.apache.camel.Predicate
.filter(predicate(pred))
...
---------------------------------------------------------
Similarly, `expression(Closure)` returns a Camel expression,
`processor(Closure)` returns a Processor, and `aggregator(Closure)`
returns an AggregationStrategy.
[[GroovyDSL-UsingGroovyXMLprocessing]]
Using Groovy XML processing
+++++++++++++++++++++++++++
Groovy provides special http://groovy-lang.org/processing-xml.html[XML
processing support] through its `XmlParser`, `XmlNodePrinter` and
`XmlSlurper` classes. camel-groovy provides two
link:data-format.html[data formats] to use these classes directly in
your routes.
*Unmarshal XML with XmlParser*
[source,java]
-----------------------------------------------------
...
from('direct:test1')
.unmarshal().gnode()
// message body is now of type groovy.util.Node
...
-----------------------------------------------------
By default, XML processing is _namespace-aware_. You can change this by
providing a boolean `false` parameter.
*Unmarshal XML with XmlSlurper*
[source,java]
---------------------------------------------------------------------------
...
from('direct:test1')
.unmarshal().gpath(false) // explicitly namespace-unaware
// message body is now of type groovy.util.slurpersupport.GPathResult
...
---------------------------------------------------------------------------
Currently, marshalling is only supported for `groovy.util.Node` objects.
*Marshal XML with XmlNodePrinter*
[source,java]
------------------------------------------------------
...
from('direct:test1')
// message body must be of type groovy.util.Node
.marshal().gnode()
...
------------------------------------------------------
[[GroovyDSL-UsingGroovyGStrings]]
Using Groovy GStrings
+++++++++++++++++++++
Groovy
http://docs.groovy-lang.org/latest/html/documentation/index.html#all-strings[GStrings]
are declared inside double-quotes and can contain arbitrary Groovy
expressions like accessing properties or calling methods, e.g.
[source,java]
-----------------------------------------
def x = "It is currently ${ new Date() }"
-----------------------------------------
Because GStrings aren't Strings, camel-groovy adds the necessary
link:type-converter.html[TypeConverter] to automatically turn them into
the required type.
[[GroovyDSL-CustomDSLextensions]]
Custom DSL extensions
+++++++++++++++++++++
You can easily define your custom extensions - be it as a Java DSL
extension for your Groovy routes or for any other class unrelated to
Camel. All you have to do is to write your extension methods and provide
a extension module descriptor - the details are described in the
http://www.groovy-lang.org/metaprogramming.html#_extension_modules[Groovy
documentation]. And as long as you don't require other extension
methods, you can even use plain Java code to achieve this! +
As an example, let's write two DSL extensions to make commonly used DSL
methods more concise:
*MyExtension.java*
[source,java]
-------------------------------------------------------------------------------------------------------------------------------
import org.apache.camel.Endpoint;
import org.apache.camel.Predicate;
public final class MyExtension {
private MyExtension() {
// Utility Class
}
// Set the id of a route to its consumer URI
public static RouteDefinition fromId(RouteDefinition delegate, String uri) {
return delegate.from(uri).routeId(uri);
}
public static RouteDefinition fromId(RouteDefinition delegate, Endpoint endpoint) {
return delegate.from(endpoint).routeId(endpoint.getEndpointUri());
}
// Make common choice pattern more concise
public static ProcessorDefinition<?> fork(ProcessorDefinition<?> delegate, String uri1, String uri2, Predicate predicate) {
return delegate.choice().when(predicate).to(uri1).otherwise().to(uri2);
}
}
-------------------------------------------------------------------------------------------------------------------------------
Add a corresponding extension module descriptor to `META-INF/services`:
*META-INF/services/org.codehaus.groovy.runtime.ExtensionModule*
[source,java]
----------------------------
moduleName=my-extension
moduleVersion=2.11
extensionClasses=MyExtension
staticExtensionClasses=
----------------------------
And now your Groovy route can look like this:
*MyRoute.groovy*
[source,java]
------------------------------------------------------------
...
fromId('direct:test1')
.fork('direct:null','direct:not-null',body().isNull())
...
------------------------------------------------------------
Using the plain Java DSL, the route would look something like this:
*MyRoute.java*
[source,java]
-----------------------------------
...
from("direct:test1")
.routeId("direct:test1")
.choice()
.when(body().isNull())
.to("direct:null")
.otherwise()
.to("direct:not-null");
...
-----------------------------------