1.2. Basic Java DSL Syntax
What is a DSL?
A Domain Specific Language (DSL) is a mini-language designed for a special purpose. A DSL does not have to be logically complete but needs enough expressive power to describe problems adequately in the chosen domain. Typically, a DSL does not require a dedicated parser, interpreter, or compiler. A DSL can piggyback on top of an existing object-oriented host language, provided DSL constructs map cleanly to constructs in the host language API.
Consider the following sequence of commands in a hypothetical DSL:
command01; command02; command03;
You can map these commands to Java method invocations, as follows:
command01().command02().command03()
You can even map blocks to Java method invocations. For example:
command01().startBlock().command02().command03().endBlock()
The DSL syntax is implicitly defined by the data types of the host language API. For example, the return type of a Java method determines which methods you can legally invoke next (equivalent to the next command in the DSL).
Router rule syntax
Apache Camel defines a router DSL for defining routing rules. You can use this DSL to define rules in the body of a
RouteBuilder.configure()
implementation. Figure 1.1, “Local Routing Rules” shows an overview of the basic syntax for defining local routing rules.
Figure 1.1. Local Routing Rules
A local rule always starts with a
from("EndpointURL")
method, which specifies the source of messages (consumer endpoint) for the routing rule. You can then add an arbitrarily long chain of processors to the rule (for example, filter()
). You typically finish off the rule with a to("EndpointURL")
method, which specifies the target (producer endpoint) for the messages that pass through the rule. However, it is not always necessary to end a rule with to()
. There are alternative ways of specifying the message target in a rule.
Note
You can also define a global routing rule, by starting the rule with a special processor type (such as
intercept()
, exception()
, or errorHandler()
). Global rules are outside the scope of this guide.
Consumers and producers
A local rule always starts by defining a consumer endpoint, using
from("EndpointURL")
, and typically (but not always) ends by defining a producer endpoint, using to("EndpointURL")
. The endpoint URLs, EndpointURL, can use any of the components configured at deploy time. For example, you could use a file endpoint, file:MyMessageDirectory
, an Apache CXF endpoint, cxf:MyServiceName
, or an Apache ActiveMQ endpoint, activemq:queue:MyQName
. For a complete list of component types, see .
Exchanges
An exchange object consists of a message, augmented by metadata. Exchanges are of central importance in Apache Camel, because the exchange is the standard form in which messages are propagated through routing rules. The main constituents of an exchange are, as follows:
- In message—is the current message encapsulated by the exchange. As the exchange progresses through a route, this message may be modified. So the In message at the start of a route is typically not the same as the In message at the end of the route. The
org.apache.camel.Message
type provides a generic model of a message, with the following parts:- Body.
- Headers.
- Attachments.
It is important to realize that this is a generic model of a message. Apache Camel supports a large variety of protocols and endpoint types. Hence, it is not possible to standardize the format of the message body or the message headers. For example, the body of a JMS message would have a completely different format to the body of a HTTP message or a Web services message. For this reason, the body and the headers are declared to be ofObject
type. The original content of the body and the headers is then determined by the endpoint that created the exchange instance (that is, the endpoint appearing in thefrom()
command). - Out message—is a temporary holding area for a reply message or for a transformed message. Certain processing nodes (in particular, the
to()
command) can modify the current message by treating the In message as a request, sending it to a producer endpoint, and then receiving a reply from that endpoint. The reply message is then inserted into the Out message slot in the exchange.Normally, if an Out message has been set by the current node, Apache Camel modifies the exchange as follows before passing it to the next node in the route: the old In message is discarded and the Out message is moved to the In message slot. Thus, the reply becomes the new current message. For a more detailed discussion of how Apache Camel connects nodes together in a route, see Section 2.1, “Pipeline Processing”.There is one special case where an Out message is treated differently, however. If the consumer endpoint at the start of a route is expecting a reply message, the Out message at the very end of the route is taken to be the consumer endpoint's reply message (and, what is more, in this case the final node must create an Out message or the consumer endpoint would hang) . - Message exchange pattern (MEP)—affects the interaction between the exchange and endpoints in the route, as follows:
- Consumer endpoint—the consumer endpoint that creates the original exchange sets the initial value of the MEP. The initial value indicates whether the consumer endpoint expects to receive a reply (for example, the InOut MEP) or not (for example, the InOnly MEP).
- Producer endpoints—the MEP affects the producer endpoints that the exchange encounters along the route (for example, when an exchange passes through a
to()
node). For example, if the current MEP is InOnly, ato()
node would not expect to receive a reply from the endpoint. Sometimes you need to change the current MEP in order to customize the exchange's interaction with a producer endpoint. For more details, see Section 1.4, “Endpoints”.
- Exchange properties—a list of named properties containing metadata for the current message.
Message exchange patterns
Using an
Exchange
object makes it easy to generalize message processing to different message exchange patterns. For example, an asynchronous protocol might define an MEP that consists of a single message that flows from the consumer endpoint to the producer endpoint (an InOnly MEP). An RPC protocol, on the other hand, might define an MEP that consists of a request message and a reply message (an InOut MEP). Currently, Apache Camel supports the following MEPs:
InOnly
RobustInOnly
InOut
InOptionalOut
OutOnly
RobustOutOnly
OutIn
OutOptionalIn
Where these message exchange patterns are represented by constants in the enumeration type,
org.apache.camel.ExchangePattern
.
Grouped exchanges
Sometimes it is useful to have a single exchange that encapsulates multiple exchange instances. For this purpose, you can use a grouped exchange. A grouped exchange is essentially an exchange instance that contains a
java.util.List
of Exchange
objects stored in the Exchange.GROUPED_EXCHANGE
exchange property. For an example of how to use grouped exchanges, see Section 7.5, “Aggregator”.
Processors
A processor is a node in a route that can access and modify the stream of exchanges passing through the route. Processors can take expression or predicate arguments, that modify their behavior. For example, the rule shown in Figure 1.1, “Local Routing Rules” includes a
filter()
processor that takes an xpath()
predicate as its argument.
Expressions and predicates
Expressions (evaluating to strings or other data types) and predicates (evaluating to true or false) occur frequently as arguments to the built-in processor types. For example, the following filter rule propagates In messages, only if the
foo
header is equal to the value bar
:
from("seda:a").filter(header("foo").isEqualTo("bar")).to("seda:b");
Where the filter is qualified by the predicate,
header("foo").isEqualTo("bar")
. To construct more sophisticated predicates and expressions, based on the message content, you can use one of the expression and predicate languages (see Expression and Predicate Languages).