Beruflich Dokumente
Kultur Dokumente
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
Home
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.
Message Routing
If you are ready to start moving data around your Mule application, this topic will help you understand the basics.
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.
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.
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.
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):
Add a stdio outbound endpoint to the Hello World flow between the choice element and the default exception strategy:
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
> 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.
http,vm
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
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.
<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>
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.
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.
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.
<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.
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; } }
<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.
<!-- 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.
<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>
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:
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.
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:
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()); }
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).
Overview
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.
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>
Summary
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.
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.
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.