One of the big architectural changes in Mule 3 is that everything has become a Message Processor1. What is a message processor? It’s a very simple interface for anything which takes a Mule message2 and does something with it (transforms it, filters it, splits it, etc.). One of the big advantages to everything implementing this simple interface is that message processors can be chained together in any order, there can be any number of them, and they can easily be swapped around. This sort of thing was not at all possible prior to Mule 3.
In the case of endpoints, the following message processors are allowed:
- Security Filters
- Custom Message Processors
You can put any number of these message processors as child elements on an endpoint (inbound or outbound), and they will get applied in the order in which they are listed to any message passing through that endpoint.
In the case of a synchronous outbound endpoint, there is a response message involved, and so any number of message processors can also be put inside a response wrapper and will get applied to the response message in the order in which they are listed.
Note that any of these elements could be declared locally (i.e., in-line in the endpoint) or globally (and referenced via a ref=”foo” attribute).
<http:outbound-endpoint address="localhost:60215" exchange-pattern="request-response"> <transformer ref="TransformerA" /> <message-filter> <wildcard-filter pattern="*:A" /> </message-filter> <processor ref="ProcessorB" /> <response> <append-string-transformer message=":C" /> <message-filter> <wildcard-filter pattern="*service2*" /> </message-filter> <custom-processor class="org.mule.tck.testmodels.mule.TestMessageProcessor"> <spring:property name="label" value="D" /> </custom-processor> </response> </http:outbound-endpoint>
This is an outbound synchronous endpoint3 which applies three message processors to the outgoing message: a global transformer, a wildcard filter, and a global custom processor. It then applies three more message processors to the response message: a locally-defined transformer, another wildcard filter, and a locally-defined custom processor.
<jms:outbound-endpoint queue="in4" exchange-pattern="one-way"> <wire-tap> <jms:outbound-endpoint queue="wiretap1" exchange-pattern="one-way"> <processor ref="AddMetaInfo" /> </jms:outbound-endpoint> </wire-tap> <custom-splitter class="org.mule.test.integration.endpoints.CommaSplitter" /> <!-- The processors below get applied to each new message from the splitter --> <transformer ref="TransformerA" /> <transformer ref="TransformerB" /> <custom-processor class="org.mule.tck.testmodels.mule.TestMessageProcessor"> <spring:property name="label" value="A" /> </custom-processor> <transformer ref="TransformerC" /> <processor ref="ProcessorD" /> </jms:outbound-endpoint>
This is an outbound asynchronous endpoint3 which applies a whole chain of message processors to incoming messages. First a wire-tap router sends a copy of the original message to a monitoring queue after applying another global processor. Then a custom message splitter splits the message into parts, and the four remaining processors get applied to each new message from the splitter.
For backwards-compatibility, we have left the endpoint attributes transformer-refs and responseTransformer-refs. Although use of these is deprecated for 3.0, if used, they will be applied after any other message processors. For example, the following Mule 2.2 configuration:
<inbound-endpoint transformer-refs="TransformerB" responseTransformer-refs="TransformerD TransformerE"> <processor ref="ProcessorA" /> <response> <processor ref="ProcessorC" /> </response> </inbound-endpoint>
would be equivalent to the following Mule 3.0 configuration:
<inbound-endpoint> <processor ref="ProcessorA" /> <processor ref="TransformerB" /> <response> <processor ref="ProcessorC" /> <processor ref="TransformerD" /> <processor ref="TransformerE" /> </response> </inbound-endpoint>
Note that in Mule 3 we are now able to clearly define a chain of message processing steps and see exactly what is being applied and in which order. This was unfortunately not the case in previous versions of Mule where transformers and filters were defined as attributes on the endpoint or the router. This was especially painful in the case of web services, where it was not clear whether transformers and filters were applied before or after SOAP marshalling/demarshalling occurs. Stay tuned for upcoming posts about simplified configuration of web services in Mule 3.
1. See “Mule 3 Architecture: Introducing the Message Processor”
2. Technically a MuleEvent, which is the MuleMessage plus some additional flow context information.
3. Note that the “synchronous” attribute on endpoints has been replaced in Mule 3 by a Message Exchange Pattern, see “Goodbye sync, hello exchange pattern”