The Babel Camel Basics part exposes which basic statement may be defined.
In Babel Camel, the base interface which models a message which passes through the route is called Message. A Message contains a payload called body. From Camel point of view, a Babel Message may be understood as the in Message of an Exchange with required methods to read and write the Exchange properties.
For more details, please have a look at the Camel Message Specification
A simple route without changing or routing the message. The output will be the same as the input.
import io.xtech.babel.camel.builder.RouteBuilder
val routeDef = new RouteBuilder {
//sends what is received in the direct
// endpoint to the mock endpoint
from("direct:input").to("mock:output")
}
The producer may set the exchange as InOnly by setting the second argument of to, to false. This would override the default behaviour of the producer.
import io.xtech.babel.camel.builder.RouteBuilder
val routeDef = new RouteBuilder {
//the mock endpoint is set in InOnly Exchange Pattern
from("direct:input").to("mock:output", false)
}
The producer may set the exchange as InOut by setting the second argument of to, to true. This would override the default behaviour of the producer.
import io.xtech.babel.camel.builder.RouteBuilder
val routeDef = new RouteBuilder {
//the mock endpoint is set in InOut Exchange Pattern
from("direct:input").to("mock:output", true)
}
The routeId will give an id to the route, then this id can be used for the monitoring or during testing.
val routeBuilder = new RouteBuilder {
from("direct:input").
//the routeId of this route will be "bla"
routeId("bla").
//the routeId keyword needs to be at the beginning of the route
// (enforced by the Babel DSL)
to("mock:output")
}
The routeId can not be specified as null nor an empty string.
val route = new RouteBuilder {
from("direct:input").
//a routeId may not be empty
routeId("") must throwA[IllegalArgumentException]
}
val route = new RouteBuilder {
from("direct:input").
//a routeId may not be null
routeId(null) must throwA[IllegalArgumentException]
}
Note
The routeId keyword is member of a set of keywords which should follow directly the from keyword or any keyword of this set.
A basic example with type transformation. The keyword as will coerce the type of the message passing within a route to a given type.
val routeDef = new RouteBuilder {
//message bodies are converted to String if required
from("direct:input").as[String]
//the processBody concatenates received String with "4"
.processBody(_ + "4")
//sends the concatenated string to the mock endpoint
.to("mock:output")
}
A basic example with type requirement. The requireAs will type the exchange body for the next keyword and will accept only a message with the given type.
import io.xtech.babel.camel.builder.RouteBuilder
val routeDef = new RouteBuilder {
//Input Message bodies should be of type String
// or would throw an Exception
from("direct:input").requireAs[String].
processBody(_ + "4").to("mock:output")
}
val producer = camelContext.createProducerTemplate()
producer.sendBody("direct:input", 123) must throwA[CamelExecutionException]
The requiredAs lets you ensure you will always receive the expected body type. For example, the following may not work.
import io.xtech.babel.camel.builder.RouteBuilder
val routeDef = new RouteBuilder {
//no input Message may satisfies both type constraints,
// thus any message sent would throw an Exception.
from("direct:input").requireAs[String].requireAs[Int].
to("mock:output")
}
val producer = camelContext.createProducerTemplate()
producer.sendBody("direct:input", "123") must throwA[CamelExecutionException]
Warning
Camel also provides tools to handle data type at runtime (which may be referred to as “runtime typing”). This may cause the regular typing to modify your data after the requireAs keyword depending on your ecosystem. Unfortunately, there is no way for Babel to prevent such variable behaviour.
With a log, you can log a defined string (which may use Camel Simple Expression Language) and define:
import io.xtech.babel.camel.builder.RouteBuilder
import org.apache.camel.LoggingLevel
val routeBuilder = new RouteBuilder {
from("direct:input")
//logs to the Trace level message such as "received ID-3423 -> toto"
.log(LoggingLevel.TRACE, "my.cool.toto", "foo", "received: ${id} -> ${body}")
//logs to the Info level message such as "ID-3423 -> toto"
.log(LoggingLevel.INFO, "${id} -> ${body}")
.to("mock:output")
}
With a sub, you can define the following steps as part of a new route.
val routeBuilder = new RouteBuilder {
from("direct:input").
to("mock:before").
//defines a new route called "subroute" which
// will send its incoming message to the next mock endpoint
sub("subroute").
to("mock:after")
}
This example would just create two routes:
Thus, sub may be seen as an inline channel. The first goal of the sub route is to separate, at runtime, the two routes in a proper manner without requiring more than required code. The sub routes may also be interesting for example in Error Handling.
Callbacks may be added to a given route in order to manage its lifecycle such as :
var success: Boolean = false
val routeBuilder = new RouteBuilder {
from("direct:input").
//As the route is initialing, the success variable is set to true
onInit(route => success = true).
to("mock:output")
}
Concerning the exchange lifecycle :
var success: Boolean = false
val routeBuilder = new RouteBuilder {
from("direct:input").
//At each time an exchange reach the end of the route,
// the success variable is set to true
onExchangeDone((exchange, route) => success = true).
to("mock:output")
}
Moreover, you may prevent a route from being started automatically using the noAutoStartup keyword.
val routeBuilder = new RouteBuilder {
from("direct:input").routeId("babel").
//The route is told not starting with the Camel Context
// but wait until beeing started especially.
noAutoStartup.
to("mock:output")
}