Вы находитесь на странице: 1из 20

MueE B3T tr l l S uoi a

1. Home . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1 Creating an Application Using the Mule IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Creating an Application Using Maven . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Creating a Configuration File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4 Testing Your Mule Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.5 Introducing Message Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.6 Understanding Advanced Message Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2 2 5 6 11 13 16

Mule ESB 3 Tutorial
This book provides a tutorial on how to develop Mule ESB 3 applications. It covers the essentials, such as using the Mule IDE, writing a configuration file, routing messages, and testing your application. It also covers advanced topics such as developing Mule applications using Maven and using advanced message routing.

Using the Mule IDE

If you're curious about how to use the Mule IDE, this topic will help you get started with this tool.

Working with Maven

Maven can help you develop Mule applications, so if you are ready to plunge into this new world, this topic is a must-read.

Creating Configuration Files

Creating configuration files is at the heart of Mule development. Read this topic to learn the basics of how to do this.

How to Test Your Application

Testing is part and parcel of application development. Learn the Mule approach to testing here.

Message Routing
If you are ready to start moving data around your Mule application, this topic will help you understand the basics.

Advanced Message Routing

Routing messages can get complicated. Read this topic to learn some of the deeper, lesser-known methods of message routing with Mule.

Creating an Application Using the Mule IDE

Creating an Application Using the Mule IDE
[ Create the Application ] [ Run the Application ] [ Create a Configuration File for the New Application ] [ Use Eclipse Tools for Adding Elements ] [ Package and Deploy the JAR and Configuration File ] The simplest way to create an application in Mule ESB is to use the Mule IDE with Eclipse. The Mule IDE allows you to quickly start a new project, which you can base on one of the existing examples, or just create a new configuration file by selecting the transports you want to use. This lesson walks you through creating a new application called myHelloApp, which will be based on the Hello World Example, running the application, and creating a new configuration file for the project.

Mule IDE 2.1 is required to support Mule 3 but Mule 3's new Application Model and Hot Deployment capabilities are not yet natively supported by the Mule IDE. If you would like to use the Mule IDE with these features, please see the documentation on Hot Deployment using the Mule IDE.

Create the Application


1. 2. 3. 4.

In Eclipse Workbench, choose File > New > Project, expand the Mule folder and select Mule Project, and then click Next. Enter the name myHelloApp, ensuring that there is no space in the project name. Ensure that Mule 3 is your default Mule distribution or selected as the project specific one. Click Add sample project content and select the Hello example.

1. Click Next, and then click the Libraries tab and verify that the Java 5 or later library is installed and available on the build path. 2. Click Finish to have the Mule IDE generate your project. You will now see the myHelloApp project in the navigation pane on the left. You can expand its folders to see the source code, configuration files, and more. Let's run the application to see it in action.

Run the Application

1. In the Package Explorer, expand the src/main/app directory, and right-click the mule-config.xml configuration file. 2. Choose Run As > Mule Server. A new run configuration is created automatically and the server is started. The application runs, initializing Mule. After the Mule splash screen appears in the console window, open a web browser with this url: http://localhost:8888?name=Ross The server should respond with "Hello Ross, how are you?" If you get any other response, check the log in the console window for any errors.

Create a Configuration File for the New Application

Now let's create a new configuration file for the myHelloApp. Instead of using the HTTP and Servlet transports and a browser to interact with the application, let's change the configuration to use the System I/O (also called STDIO) and VM transports. For simplicity, we'll call the new configuration file my-hello-config.xml. 1. Choose File > New > Other, expand the Mule folder and select Mule Configuration, and then click Next. 2. Click Browse..., expand the myHelloApp project, select the src/main/app directory, and then click OK. 3. Change the default name from mule-config.xml to my-hello-config.xml. You can use any name you like, as long as it is unique within the project and has an .xml extension. If you use the name of an existing file, it will overwrite that file. 4. Select the System I/O (also called STDIO) and VM transports, leave Spring Config selected, and then click Finish.

Mule IDE creates the configuration file in the src/main/app directory of the myHelloApp project. It adds the namespaces for the STDIO and VM transports.

Use Eclipse Tools for Adding Elements

Now we'll use the Eclipse tools to add elements to the new configuration file. Open the new configuration file in the Eclipse editor. You can add global elements anywhere below the namespace declarations, which are at the top of the file. You can add services within a <model> element, and then add local routers, filters, endpoints, and transformers to the services. Eclipse provides a fast and error-proof method for entering these elements. Simply click anywhere between the opening and closing tags of an element, then press Ctrl+space to see a list of the available elements. Double-click the element in the list that you want, and Eclipse enters the opening and closing tags for that element. You can also hover over a tag to see a description of the element and its supported attributes. To add System I/O so that you can interact with the application from the console, copy the body (the content below the namespace declarations) of the default mule-config.xml example configuration to your new configuration file. Then make the following changes. Add a connector configuration and declare another custom transformer for STDIN:

<stdio:connector name="SystemStreamConnector" promptMessageCode="3" resourceBundle="messages.hello-example-messages" messageDelayTime="1000"/>

<custom-transformer name="StdinToNameString" class="org.mule.example.hello.StdinToNameString"/>

Append or replace the http and servlet inbound endpoints in the Hello World flow with a stdio one (if you append it, make sure you also declare the applicable namespaces for http and servlet transports):

<stdio:inbound-endpoint system="IN" exchange-pattern="one-way"> <transformer ref ="StdinToNameString"/> </stdio:inbound-endpoint>

Add a stdio outbound endpoint to the Hello World flow between the choice element and the default exception strategy:

<stdio:outbound-endpoint system="OUT" exchange-pattern="one-way"> <transformer ref="ChatStringToString" /> </stdio:outbound-endpoint>

Package and Deploy the JAR and Configuration File

After you have finished creating your Mule application, you can deploy it by packaging up the application in a JAR file and then copying the JAR and configuration file to your Mule instance(s). Since the Mule IDE does not yet natively support the new deployment structure of Mule 3, you will need to do the packaging manually to conform to the Mule application format. Alternatively, you can follow the instructions for Hot Deployment using the Mule IDE.

Creating an Application Using Maven

Creating an Application Using Maven
[ Create a New Project ] [ Build the Application ] Mule's integrated support for the Maven project management tool means that you can quickly and easily create a new Mule project right from the command line. This lesson walks you through creating a new application called myHelloApp, which will be based on the Hello World Example, running the application, and creating a new configuration file for the project. For information on downloading, installing and setting up Maven with Mule, see Setting Up the Development Environment and Using Maven.

Maven 3.0 (beta) is not currently supported with Mule. Maven 2.0.x and 2.2.x are the recommended versions to use with Mule.

Mule provides a Maven archetype (project wizard) for creating new Mule projects. Before you can use it, you must sdd the following to the file settings.xml (usually in your Maven conf or $HOME/.m2 directory) so that Maven will allow you to execute Mule plug-ins. settings.xml

<settings> <pluginGroups> <pluginGroup>org.mule.tools</pluginGroup> </pluginGroups> ... </settings>

Create a New Project

We are going to create a new project called 'myHelloApp'. Navigate to the parent directory where you want to create this new project. Next, you will execute the archetype and generate the code. If this is your first time running this command, Maven will download the archetype for you.

> mvn mule-project-archetype:create -DartifactId=myHelloApp -DmuleVersion=3.0.0 The wizard will ask you a number of questions. For an explanation of these see the project archetype documentation. Enter org/mule/example as the Java package path.

org/mule/example When you get to the transports question, please specify the http and vm tranports.


Next, it will ask you which modules to include. Please enter at least one module name (note this is a limitation of the archetype, you must specify at least one item). Maven will now create a skeleton project structure for you. You can now browse the myHelloApp project structure. It should look like this:
myHelloApp --assembly.xml --pom.xml --MULE-README.txt --src/main --resources/mule-config.xml --java/org/mule/example/myhelloapp --src/test --resources/myhelloapp-functiona-test-config.xml --java/org/mule/example/myhelloapp/MyHelloAppTestCase.java

Build the Application

mvn package This will build your project, run the tests, and construct a mule application archive named myhelloapp-1.0-SNAPSHOT.zip. Now just copy this archive to you {$MULE_HOME/apps} directory and start mule - {$MULE_HOME/bin/mule}. Mule will detect your application archive and automatically deploy it. If there are any errors in your configuration you will need to correct the, repackage and copy the archive over again. To deploy your application to additional Mule instances, you can repeat the last two steps for each instance.

Creating a Configuration File

Creating a Configuration File
[ Add the XML Declaration and Namespaces ] [ Add the Description ] [ Configure Global Connectors ] [ Configure Global Custom Transformers ] [ Configure Models and Services ] [ Configure Error Handling ] [ Configure the Final Service ] [ View the Full Example ] [ Run the Application ] Creating a Mule ESB application is as simple as creating a configuration file and pointing to a Java class that performs any required custom logic on the messages that come through. Although the easiest way to create a Mule configuration file is to use the Mule IDE as described in Creating an Application Using the Mule IDE, Lesson Three provides you with the information you need to create the file manually in any XML editor or IDE and helps you understand all the elements involved. You will walk through creating a configuration file for the Hello World application. You can then run Mule using this file and the compiled Java classes. To get started, create an empty Mule Project using the Mule IDE or Maven project archetype and open a new, empty mule-config.xml file in your favorite editor.

Add the XML Declaration and Namespaces

First, the XML declaration goes at the top of the file:

<?xml version="1.0" encoding="UTF-8"?>

Next, in the <mule> element, you declare the namespace for the core Mule schema, XSI, Spring, and the transports and modules you want to use. In this example, we're using the HTTP and VM transports. You then use the XSI namespace to declare the locations of the schemas. For example:

<mule xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xsi:schemaLocation=" http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.0/mule.xsd http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/3.0/mule-http.xsd http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/3.0/mule-vm.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

The HTTP transport will allow a user to interact with the application using any http client, including a web browser.

Add the Description

Optionally, you can add the <description> element with a description of this configuration file. If you are creating only one configuration file for your entire application, the description could be about the entire application.

<description>The Hello World sample application has two components: 1. The Greeter component that adds a greeting to the message it receives 2. The ChitChatter component that adds some additional conversation to the message it receives A message is triggered by input through an http endpoint and the outbound message is also written out through the http response. This configuration also demonstrates user and system error handling. User error handling returns an error message to the end user. System error handling logs errors. </description>

Configure Global Connectors

While there are several ways in Mule to configure a transport, the best practice is to use the <connector> element to define a global connector configuration, which you can then reference in multiple places. The <connector> element must be prefixed by the namespace of its transport. For example, the following connector will be available to endpoints that use the STDIO transport:

<stdio:connector name="SystemStreamConnector" promptMessageCode="3" resourceBundle="messages.hello-example-messages" messageDelayTime="1000"/>

The example does not use the STDIO transport, so you do not need to add the above connector to your configuration.

Because we have only one connector defined for the STDIO transport, this connector will be used by default whenever we create an STDIO transport. If we defined multiple STDIO connectors, you would use the connector-ref attribute on the endpoint to specify the one you want to use. To see which attributes you can set for a connector, go to the transport's reference page by clicking its name on the Available Transports page.

Configure Global Custom Transformers

Similarly, if you want to configure custom transformers that you can reference from multiple places, add them to the configuration now. Because we're going to send the string through HTTP, we need a transformer that will convert it from an HTTP request to a name string. The Hello World example includes a Java class that performs this transformation, which you configure as follows:

<custom-transformer name="HttpRequestToNameString" class= "org.mule.example.myhelloapp.HttpRequestToNameString"/>

It also uses several other transformers that format the message payload and convert it to the datatype expected by each component:

<custom-transformer name="StringToNameString" class= "org.mule.example.myhelloapp.StringToNameString"/> <custom-transformer name="NameStringToChatString" class= "org.mule.example.myhelloapp.NameStringToChatString"/> <custom-transformer name="ChatStringToString" class= "org.mule.example.myhelloapp.ChatStringToString"/> <custom-transformer name="ExceptionToString" class="org.mule.example.myhelloapp.ExceptionToString" />

Go ahead and add all of the above transformer declarations to your mule configuration after the <description> element.

Configure Models and Services

You are now ready to add your services, which is where you specify your components that do the actual work. Services are contained within models, so you add the <model> tag first:

<model name="myHelloApp"> ...services will go here

Now, start configuring your services by adding <service> tags with a name attribute that contains a unique name for the service. The Hello World example has four services, each of which has an <inbound> section, a <component>, and an <outbound> section in that order. For details on the elements you can configure in a service, see the Service Configuration Reference.

Configure the Inbound Section

Let's add the inbound section for the GreeterUMO service first:

<service name="GreeterUMO"> <inbound> <inbound-endpoint address="http://localhost:8888" transformer-refs="HttpRequestToNameString" exchange-pattern="request-response"> <not-filter> <wildcard-filter pattern="/favicon.ico"/> </not-filter> </inbound-endpoint> </inbound>

Notice that within the inbound section, we've specified the inbound endpoint. The inbound endpoint defines which messages this service will handle by specifying the following: The transport. In this case, it's HTTP. Where the message originates. In this case, it's http://localhost:8888 can receive messages using standard HTTP GET request. The transformer to use. Here we reference one of the global transformers we defined earlier in the configuration. that will convert the HTTP request to a NameString object. No connector is referenced so the default HTTP connector will be used. The exchange pattern to follow. HTTP expects a synchronous response, so we specify the request-response pattern. This inbound endpoint specifies that only messages that are received on http://localhost:8888 will be received by this service, and they will be transformed by the HttpRequestToNameString transformer before they are passed to the component. A filter is configured to explicitly exclude any request for the favicon.ico from being processed by the service. There is no inbound router specified, so all messages received on this endpoint will be processed by the service.

Configure the Component

The component is the next element to configure. The component can be a plain Java class, Spring Bean, JSR-223 script, web service, or anything that can perform logic on the messages. In this example, our component is a POJO, so you specify the class in the <component> tag:

<component class="org.mule.example.myhelloapp.Greeter"/>

By default, Mule automatically discovers the correct method in the Java class to execute (the entry point) by matching the return type on the transformer (in this case, NameString) to the methods in the component. For information on other ways of resolving the entry point, see Entry Point. The code for the Greeter component is below.

package org.mule.example.myhelloapp; /** * <code>Greeter</code> expects a valid <code>NameString</code> object. If invalid, * an exception is created and returned. The outbound router will filter exceptions * as user errors and return the messages to the original requester accordingly. */ public class Greeter { private String greeting = ""; public Greeter() { greeting = LocaleMessage.getGreetingPart1(); } public Object greet(NameString person) { Object payload = person; if (person.isValid()) { person.setGreeting(greeting); } else { payload = new Exception(LocaleMessage.getInvalidUserNameError()); } return payload; } }

Configure the Outbound Section

Now we need to specify what the service will do after the component has finished with it. We specify this in the outbound section. In this case, we want to use an outbound router to send the message to one service if the message was processed successfully and to a different service if the message had errors. To do this, we use filtering routers, each of which specifies a) the outbound endpoint where the message will go next, and b) the criteria the message must meet to be routed there. If a message does not meet the criteria of the first router, it's checked against the second router's criteria, and so on until there's a match.

<outbound> <filtering-router> <vm:outbound-endpoint path="chitchatter" exchange-pattern="request-response"/> <payload-type-filter expectedType="org.mule.example.myhelloapp.NameString"/> </filtering-router> <filtering-router> <vm:outbound-endpoint path="userErrorHandler" exchange-pattern="request-response"/> <payload-type-filter expectedType="java.lang.Exception"/> </filtering-router> </outbound>

In this case, if the message payload was transformed correctly into a NameString object, the first router sends it to the chitchatter path using the VM transport. VM is an internal messaging service that routes messages between services running inside the same JVM for faster processing. If you deploy your services on separate Mule instances instead, you could easily replace this with a JMS provider. If the message was not transformed correctly and the payload contains an exception, the message is routed to the userErrorHandler path using the VM transport. When you configure the services that will handle the message in each of these cases, you must ensure that they specify chitchatter or userErrorHandler as the path on their inbound endpoints.

Configure Error Handling

Mule provides support for error handling for unexpected errors. Exception strategies allow you to handle messages when there is a system error:

<!-- Route unexpected errors to separate error handler --> <default-service-exception-strategy> <vm:outbound-endpoint path="systemErrorHandler" exchange-pattern="one-way"/> </default-service-exception-strategy></service>

In the Hello World example, user errors are routed back to the caller and system errors are routed to system.err. These error-handling services are defined below:

<!-- This error handler returns user error messages to caller. Errors could also be routed elsewhere, e.g. into an error file, send via email to a list, stored in a database, etc. --> <service name="UserErrorHandler"> <inbound> <vm:inbound-endpoint path="userErrorHandler" responseTransformer-refs="ExceptionToString" exchange-pattern="request-response"/> </inbound> </service>

The UserErrorHandler just transforms the message using the response transformer and returns it to the caller.

<!-- Handle any unexpected errors. Errors could also be routed elsewhere, e.g. into an error file, send via email to a list, stored in a database, etc. --> <flow name="SystemErrorHandler"> <vm:inbound-endpoint path="systemErrorHandler" exchange-pattern="request-response"/> <outbound-endpoint address="stdio://ERR" exchange-pattern="one-way"/> </flow>

The SystemErrorHandler uses a new construct in Mule 3 called <flow>. Flow-based configuration allows a more flexible model than service and can be useful for processing messages where the service-based model is not required. In this case, there is no component or outbound router, just an inbound and outbound endpoint that re-routes all messages to STDERR.

Configure the Final Service

There is one last service in the example: the ChitChat service. This service transforms the message, adds text to it and returns it to the caller. Again, we use the simpler flow construct to specify the inbound endpoint and component. In this case there is no outbound. Instead of using an outbound endpoint, we're simply going to configure a response transformer, which will transform the string after the component is done with it and send it back to the caller, namely the HTTP endpoint. Therefore, you add the response transformer and declare the request-response exchange pattern.

<flow name="ChitChat"> <vm:inbound-endpoint path="chitchatter" transformer-refs="NameStringToChatString" responseTransformer-refs="ChatStringToString" exchange-pattern="request-response"/> <component class="org.mule.example.myhelloapp.ChitChatter"/> </flow>

The code for the ChitChatter component is below:

package org.mule.example.myhelloapp; public class ChitChatter { private String chitchat = ""; public ChitChatter() { chitchat = LocaleMessage.getGreetingPart2(); } public void chat(ChatString string) { string.append(chitchat); } }

Lastly, end the file with the closing </model> and </mule> tags:

... </model> </mule>

View the Full Example

To see the entire configuration file and source code for this example, navigate to the examples/hello/src directory under your Mule home directory or create a new project from the Hello World example using the Mule IDE (See Creating an Application Using the Mule IDE). The configuration file is included in examples/hello/src/main/apps and the custom classes referenced in the configuration file are included with the example under the examples/hello/src/main/java directory.

Run the Application

To run the application, the custom classes must be compiled and the entire application packaged into a Mule application archive. Follow the directions in Creating an Application Using the Mule IDE (Mule IDE) or Creating an Application Using Maven (Maven) to package and deploy your application to Mule.

Testing Your Mule Application

Testing Your Mule Application
[ Test the Application ] [ Create an HTML Interface ] [ Unit Test Cases ] [ Functional Test Case ] This lesson builds on Creating a Configuration File and shows you how to test the Hello World example using a web page and Mule's functional test framework.

Test the Application

It's time to test the application. This assumes you previously packaged and deployed the application to Mule. 1. Open a web browser and enter the URL http://localhost:8888/?name=Ross. This URL passed "Ross" to the endpoint http://localhost:8888, which was picked up and processed by the GreeterUMO service. It then passed the message to the ChitChat service for processing, which sent it back to the calling endpoint, where it was displayed in the web browser.

Create an HTML Interface

Because it's unlikely that users would enter their names as part of a URL string, you could create an HTML page that prompts users for their

names and submits it via a form. For example, create a simple page with the following code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Get Name</title> </head> <body> <form method="GET" action="http://localhost:8888"> <input type="text" name="name"/> <input type="submit" value="Submit Name" /> </form><br /> </body> </html>

Now, with the Hello World application still running, launch this HTML page in a web browser. It should look like this: Enter your name, and then click Submit Name. It displays the greeting with your name.

Unit Test Cases

Most custom objects in Mule are POJOs, so unit testing is easy. If you examine the test cases in the Hello World example, you'll see how the various components and transformers are easily tested with standard unit tests.

Functional Test Case

Because Mule ESB is light-weight and embeddable, it is easy to run an entire Mule Server inside a test case. Mule provides an abstract JUnit test case called org.mule.tck.FunctionalTestCase that runs Mule inside a test case and manages the lifecycle of the server. The org.mule.tck.functional package contains a number of supporting classes for functionally testing Mule code, including FunctionalTestComponent. More detail on Functional Testing with Mule can be found in the documentation. This means, a test case can be used to test a flow. If you used the Maven archetype to create your project, then you already have a skeleton test case and configuration file. The test case looks like this:

package org.mule.example.myhelloapp; import import import import org.mule.api.MuleMessage; org.mule.module.client.MuleClient; org.mule.tck.FunctionalTestCase; org.mule.transport.NullPayload;

public class MyHelloAppTestCase extends FunctionalTestCase { protected String getConfigResources() { //TODO You'll need to edit this file to make the test applicable to your module return "myhelloapp-functional-test-config.xml"; } public void testMyHelloApp() throws Exception { MuleClient client = new MuleClient(muleContext); MuleMessage result = client.send("vm://in", "some data", null); assertNotNull(result); assertNull(result.getExceptionPayload()); assertFalse(result.getPayload() instanceof NullPayload); //TODO Assert the correct data has been received assertEquals("some data Received", result.getPayloadAsString()); } }

First replace the generated configuration file with the one you created for the application. We will now include an inbound VM endpoint which we'll use to test the application. Add the following to the inbound element of your GreeterUMO service in the test configuration:

<vm:inbound-endpoint path="greeter" transformer-refs="StringToNameString" exchange-pattern= "request-response"/>

Now let's modify the test case to call this endpoint and assert the result:

public void testMyHelloApp() throws Exception { MuleClient client = new MuleClient(muleContext); MuleMessage result = client.send("vm://greeter", "Ross", null); assertNotNull(result); assertNull(result.getExceptionPayload()); assertFalse(result.getPayload() instanceof NullPayload); //TODO Assert the correct data has been received assertEquals("Hello Ross, how are you?", result.getPayloadAsString()); }

That's it. If you execute the test case it should pass.

This simple example assumes the English locale and is not testing for different locales. If you are in a different locale, you will need to modify the verification string to match the one created for your locale.

For more information on all topics related to configuring and using Mule, see the Mule User's Guide (login required).

Introducing Message Routing

Introducing Message Routing
[ Overview ] [ Selecting a Message Style ] [ Summary ] This lesson provides an introduction to message routing and describes when to use the different message styles.

Message routers control how messages are routed among the services in your Mule ESB application. Following is a description of the key concepts: Inbound routers control how a service handles incoming messages, such as selectively consuming only those messages that meet specific criteria or grouping messages together that share a group ID before forwarding them on. Outbound routers control how a message is dispatched after the service has processed it, such as sending it to a list of recipients or splitting up the message and sending the parts to different endpoints. Asynchronous reply routers are used in request/response scenarios where message traffic is triggered by a request and the traffic needs to be consolidated before a response is given. The classic example of this is where a request is made and tasks are executed in parallel. Each task must finish executing and the results processed before a response can be sent back. Catch-all strategies are invoked if no routing path can be found for the current message. An inbound or outbound endpoint can be associated with a catch-all strategy so that any orphaned messages can be caught and routed to a common location. Filters provide the logic used to invoke a particular router. Filters can be combined using the logic filters AndFilter, OrFilter, and NotFilter. Not all routers need to use filters, but all routers support them.

Selecting a Message Style

When wiring your Mule services together, new users sometimes get confused about when to use an outbound router and when it's sufficient to simply get a reply. The exchange-pattern attribute in Mule is how you explicitly define the message style you want. It is important to know that

each transport has a default exchange pattern that will be enforced if you do not specify one. Following is a description of the message styles you can use in Mule. Asynchronous If you simply want to put a message on a SEDA queue after processing it, and no response to the caller is required, you can use the asynchronous message style as defined by the one-way exchange pattern. You should specify this on both the inbound and outbound endpoints. For example:

<model name="Asynchronous_Message_Pattern"> <service name="AsynchronousService"> <inbound> <jms:inbound-endpoint queue="test.in" exchange-pattern="one-way"/> </inbound> <component class="org.myorg.WidgetHandler" /> <outbound> <pass-through-router> <jms:outbound-endpoint queue="test.out" exchange-pattern="one-way"> <pass-through-router> </outbound> </service> </model>

Request-Response In simple scenarios that require a response, a service receives a request on a synchronous inbound endpoint, processes the request, and then sends it back to the caller as a reply. For example, if a user enters a value in an HTML form, and you want to transform that value and display the results in the same page, you can simply configure a synchronous inbound endpoint on the service that does the transformation. This scenario does not use an outbound router. This is the request-response message style and is defined using the request-response exchange pattern.

For example:

<model name="Request-Response_Message_Pattern"> <service name="SynchronousService"> <inbound> <http:inbound-endpoint host="localhost" port="8080" path="/mule/services" exchange-pattern= "request-response"/> </inbound> <component class="org.myorg.WidgetHandler" /> </service> </model>

Synchronous If you need to pass the message to a second service for additional processing, you would configure an outbound router on the first service to pass the message to the second service. After the second service processes the message, the first service sends it back to the caller as a reply. This is the synchronous message style To enable this you would put the request-response exchange pattern on both the inbound and outbound endpoints.

For example:

<model name="Synchronous_Message_Pattern"> <service name="SynchronousService"> <inbound> <jms:inbound-endpoint queue="test.in" exchange-pattern="request-response"/> </inbound> <component class="org.myorg.WidgetHandler" /> <outbound> <chaining-router> <jms:outbound-endpoint queue="test.out" exchange-pattern="request-response"/> </chaining-router> </outbound> </service> <service> <inbound> <jms:inbound-endpoint queue="test.out" exchange-pattern="request-response"/> </inbound> <component class="org.myorg.WidgetPackager" /> </service> </model>

Asynchronous Request-Response In the most complex scenario, you can enable request-response messaging and allow the back-end process to be forked to invoke other services, returning a reply asynchronously based on the results of multiple service invocations. You can set the inbound endpoint's exchange-pattern attribute to one-way, since the response will be handled by the asynchronous reply router, unless you also want to send a response to the caller. This is the asynchronous request-response message style.

In the following example, a request comes in on an HTTP endpoint, is broadcast to two endpoints using the Multicast router, and the results are sent asynchronously to a JMS endpoint.

<model name="Async_Request-Response_Message_Pattern"> <service name="AsyncRequestResponseService"> <inbound> <http:inbound-endpoint host="localhost" port="8080" path="/mule/services" exchange-pattern= "one-way"/> </inbound> <component class="org.myorg.WidgetHandler" /> <async-reply timeout="5000"> <collection-async-reply-router/> <jms:inbound-endpoint queue="reply.queue" exchange-pattern="one-way"/> </async-reply> <outbound> <multicasting-router> <reply-to address="jms://reply.queue"/> <jms:outbound-endpoint queue="service1" exchange-pattern="one-way"/> <jms:outbound-endpoint queue="service2" exchange-pattern="one-way"/> </multicasting-router> </outbound> </service> </model>

This section described the different message styles you can use. For complete information, see Service Messaging Styles in the Mule User's Guide. Now that you understand which message styles to use for routing in different scenarios, Understanding Advanced Message Routing describes several routers you can use for achieving finer control over message routing.

Understanding Advanced Message Routing

Understanding Advanced Message Routing
[ Filtering Messages ] [ Chaining Outbound Endpoints Together ] [ Splitting Messages ] [ Processing a Message Only Once ] This lesson builds on Introducing Message Routing and shows you how to use specific message routers to control how a message is routed through your application.

Filtering Messages
You can control which messages a service handles by using filters. The Selective Consumer Router works on inbound endpoints to control which messages that service will process. The Filtering Router works on outbound endpoints to control which messages the service sends along to the next endpoint. You can use a combination of these approaches to control the message flow. For example, if you only want to process messages that don't have errors, you can use a selective consumer to ensure that only those with the result code "success" are processed. You can then use a Catch-all Strategy to forward all other messages to another endpoint for error handling:

<inbound> <selective-consumer-router> <mulexml:jxpath-filter expression="msg/header/resultcode = 'success'"/> </selective-consumer-router> <forwarding-catch-all-strategy> <jms:endpoint topic="error.topic" exchange-pattern="one-way"/> </forwarding-catch-all-strategy> </inbound>

If you want the service to process all messages but then want to specify criteria to determine where the message is sent next, you can use filtering outbound routers. In the following example, messages that contain an exception are sent to the system administrator's email address, messages whose payload contains a specific string are sent to the string queue, and all other messages are picked up by the forwarding catch-all router and sent to an error queue:

<outbound> <forwarding-catch-all-strategy> <jms:outbound-endpoint queue="error.queue" exchange-pattern="one-way"/> </forwarding-catch-all-strategy> <filtering-router> <smtp:outbound-endpoint to="ross@muleumo.org" exchange-pattern="one-way"/> <payload-type-filter expectedType="java.lang.Exception"/> </filtering-router> <filtering-router> <jms:outbound-endpoint queue="string.queue" exchange-pattern="one-way"/> <and-filter> <payload-type-filter expectedType="java.lang.String"/> <regex-filter pattern="the quick brown (.*)"/> </and-filter> </filtering-router> </outbound>

Similar routers are the forwarding router, which allows you to process some messages and selectively forward others, and the wiretap router, which allows you to process all messages and send them on as normal but also send a copy to another endpoint. For more information, see Inbound Routers in the Mule User's Guide.

Chaining Outbound Endpoints Together

Let's assume we have a validation service, and if the message fails validation, the message and its exception are forwarded to another service AND the message and its exception are returned to the caller. You could achieve this using the chaining router, which is a fast and lightweight configuration for sending a message to an endpoint and then sending the result of that endpoint to another endpoint. For example:

<chaining-router> <vm:outbound-endpoint path="ValidationService" exchange-pattern="request-response"/>

<vm:outbound-endpoint path="ValidationError" exchange-pattern="request-response"> <exception-type-filter expectedType="java.lang.Exception"/> </vm:outbound-endpoint> </chaining-router>

You can also use the chaining router to perform protocol bridging to a single outbound endpoint. Unlike the pass-through router, the chaining router always returns a response. For example:

<service name="HttpProxyService"> <inbound> <!-- WSDL URL: http://localhost:8888/stockquote.asmx?wsdl --> <inbound-endpoint address="http://localhost:8888" exchange-pattern="request-response"/> </inbound> <outbound> <chaining-router> <outbound-endpoint address="http://www.webservicex.net#\[header:http.request\]" exchange-pattern="request-response"/> </chaining-router> </outbound> </service>

Splitting Messages
A message splitter can be used to break down an outgoing message into parts and dispatch those parts over different endpoints configured on the router. For example, in an order-processing application, you might want to send different parts of the message to different services for processing. You could do this using one of the following routers: List Message Splitter: accepts a list of objects that will be routed to different endpoints. For example:

<outbound> <list-message-splitter-router"> <jms:outbound-endpoint queue="order.queue" exchange-pattern="one-way"> <payload-type-filter expectedType="com.foo.Order"/> </jms:outbound-endpoint> <jms:outbound-endpoint queue="item.queue" exchange-pattern="one-way"> <payload-type-filter expectedType="com.foo.Item"/> </jms:outbound-endpoint> </list-message-splitter-router> </outbound>

Filtering XML Message Splitter: similar to the List Message Splitter but operates on XML documents. For example:

<outbound> <mulexml:filter-based-splitter splitExpression="root/nodes" validateSchema="true" externalSchemaLocation="/com/example/TheSchema.xsd"> <vm:outbound-endpoint path="order" exchange-pattern="one-way"> <payload-type-filter expectedType="com.foo.Order"/> </vm:outbound-endpoint> <vm:outbound-endpoint path="item" exchange-pattern="one-way"> <payload-type-filter expectedType="com.foo.Item"/> </vm:outbound-endpoint> </mulexml:filter-based-splitter> </outbound>

Expression Splitter Router: similar to the List Message Splitter but splits the message based on an expression that returns one or more message parts. For example:

<outbound> <expression-splitter-router evaluator="xpath" expression="/mule:mule/mule:model/mule:service" disableRoundRobin="true" failIfNoMatch="false"> <outbound-endpoint ref="service1"> <expression-filter evaluator="xpath" expression="/mule:service/@name = 'service splitter'"/> </outbound-endpoint> <outbound-endpoint ref="service2"> <expression-filter evaluator="xpath" expression="/mule:service/@name = 'round robin deterministic'"/> </outbound-endpoint> </expression-splitter-router> </outbound>

You could also split a message into parts to improve performance. The Round Robin Message Splitter splits the message into parts and sends them to endpoints in a round-robin approach. The Message Chunking Router splits a single message into a number of fixed-length messages that will all be routed to the same endpoint. After splitting messages, you use the Message Chunking Aggregator to aggregate the message parts back together again. The aggregator uses the correlation ID, which is set by the outbound router, to identify which parts belong to the same message.

<inbound> <message-chunking-aggregator-router> <expression-message-info-mapping correlationIdExpression="#[header:correlation]"/> <payload-type-filter expectedType="org.foo.some.Object"/> </message-chunking-aggregator-router> </inbound>

Processing a Message Only Once

The Idempotent Receiver ensures that only unique messages are received by a service by checking the unique message ID of the incoming message. The ID can be generated from the message using an expression defined in the idExpression attribute. By default, the expression used is #[message:id], which means the underlying endpoint must support unique message IDs for this to work. In the following example, a unique ID is a combination of the message ID and the contents of the label field in the header, and the IDs are then written to a simple text file to keep track of which messages have already been processed:

<inbound> <idempotent-receiver-router idExpression="#[message:id]-#[header:label]"> <simple-text-file-store directory="./idempotent"/> </idempotent-receiver-router> </inbound>