LibraryLink ToToggle FramesPrintFeedback

Basic Java DSL Syntax

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 2.1 shows an overview of the basic syntax for defining local routing rules.


A local rule always starts with a from("EndpointURL") method, which specifies the source of messages 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 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]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.

A local rule always starts by defining a source endpoint, using from("EndpointURL"), and typically (but not always) ends by defining a target endpoint, using to("EndpointURL"). The endpoint URLs, EndpointURL, can use any of the components configured at deploy time. For example, you can 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 http://camel.apache.org/components.html.

A processor is a method that can access and modify the stream of messages passing through a rule. If a message is part of a remote procedure call (InOut call), the processor can potentially act on the messages flowing in both directions. It can act on request messages, flowing from source to target; and it can act on reply messages, flowing from target back to source (see Message exchanges). Processors can take expression or predicate arguments, that modify their behavior. For example, the rule shown in Figure 2.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. You do not have to be concerned about which type to pass to an expression argument, because arguments are usually automatically converted to the required type. For example, you can usually just pass a string into an expression argument. Predicate expressions are useful for defining conditional behavior in a route. 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 Languages for Expressions and Predicates).

When a router rule is activated, it can process messages passing in either direction: from source to target or from target back to source. For example, if a router rule is mediating a remote procedure call (RPC), the rule processes requests, replies, and faults. How do you manage message correlation in this case? One of the most effective and straightforward ways is to use a message exchange object as the basis for processing messages. FUSE Mediation Router uses message exchange objects (of org.apache.camel.Exchange type) in its API for processing router rules.

The basic idea of the message exchange is that, instead of accessing requests, replies, and faults separately, you encapsulate the correlated messages inside a single object (an Exchange object). Message correlation now becomes trivial from the perspective of a processor, because correlated messages are encapsulated in a single Exchange object and processors gain access to messages through the Exchange object.

Using an Exchange object makes it easy to generalize message processing to different message exchange patterns. For example, an asynchronous protocol might define a message exchange pattern that consists of a single message that flows from the source to the target (an In message). An RPC protocol, on the other hand, might define a message exchange pattern that consists of a request message correlated with either a reply or a fault message. Currently, FUSE Mediation Router supports the following message exchange patterns:

Where these message exchange patterns are represented by constants in the enumeration type, org.apache.camel.ExchangePattern.