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).
Fuse Mediation Router 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 shows an overview of the basic syntax for
defining local routing rules.
A local rule always starts with a
from("
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,
EndpointURL
")filter()
). You typically finish off the rule with a
to("
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 EndpointURL
")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 |
A local rule always starts by defining a consumer endpoint, using
from("
, and typically (but
not always) ends by defining a producer endpoint, using
EndpointURL
")to("
. The endpoint URLs,
EndpointURL
")EndpointURL
, can use any of the components configured at deploy
time. For example, you could use a file endpoint,
file:MyMessageDirectory
, a Apache CXF endpoint,
cxf:MyServiceName
, or an Apache ActiveMQ endpoint,
activemq:queue:MyQName
. For a complete list of component types, see
EIP Component Reference.
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 of
Object
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 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 Endpoints.
Exchange properties—a list of named properties containing metadata for the current message.
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, Fuse Mediation Router 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
.
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 Aggregator.
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 includes
a filter()
processor that takes an xpath()
predicate
as its argument.
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 ????).