9 Reasons to Consider Mule as your ESB

Mule ESB is a widely used open source enterprise service bus. In this post I'll give you 9 reasons why you should consider Mule ESB for your integration challenges.


1. Mule is Open Source


Wait, wait. Before you wave away this post as total bullshit, I really believe a Service-Oriented Architecture (SOA) and in particular a product like an ESB can benefit from open source. When you (or your company) decide to go for a SOA, a considerable amount of money is already invested in the current application landscape. To migrate this landscape to a SOA in one big bang is not do-able both in terms of investment and time. So the advice is to start small.


Start by implementing a couple of generic utility services, then connect one application, from one application to one department, etc. The same holds for investments. Why spend a huge amount on license costs when you only have a couple of services or applications connected to it? Especially in a time like this, where cost reduction seems to be priority number 1. Mule is highly scalable allowing you to start small and connect more applications over time.


Another advantage of open source, is of course no vendor lock-in. The ability to adjust or extend the code to your needs. I will come to that later.


2. Mule is Mature


Ross Mason started the project in 2003. Mule 1.0 was ready by 2005. The current stable release is Mule 2.2.1 and it's only a matter of time before Mule 3.0 will be released. Mule is running in production environments at thousands of customers. Of all the open source ESB initiatives, I dare to say that Mule is by far the most mature one.


3. Mule's Architecture


Mule ESB is based on a proven set of best practices. Mule implements many of the patterns described in Enterprise Integration Patterns, by Gregor Hohpe and Bobby Woolf.


Mule's core is designed as an event-driven framework combined with a unified representation of messages, so called Universal Message Object (UMO). The key idea behind the UMO API is to unify the logic and model representations while keeping them isolated from the underlying transports. This made it easy to build all the required features of the ESB: message routing, data transformation and protocol adaptation.

Mule adopted Spring 2 as its configuration and wiring framework. This makes integration with Spring and all of Spring features really easy.


4. Mule is based on Standards


Mule is based on standards and common frameworks. I will only mention a couple over here as the list is too long to mention totally.


Security - Mule allows you to authenticate requests via endpoints using transport-specific or generic authentication methods. It also allows you to control method-level authorization on your service components. The Security Manager is responsible for authenticating requests based on one or more security providers. All security is pluggable via the Mule security API , so you can easily plug in custom implementations. Examples of security implementations are Acegi, Spring Security, JAAS and WS-Security.


Transactions - Mule's transaction framework is agnostic to the underlying transaction manager. The transaction could be a JDBC transaction, XA transaction, or a JMS transaction or message acknowledgment. All transaction types can be handled the same way.


Monitoring - Mule comes with agents to check the health of your components through Java Management Extensions (JMX) technology.


5. Mule's different Messaging Styles


Mule provides a platform to develop and host your integration solutions. Whether this is in an EAI environment, a SOA or an EDA. With the different messaging styles Mule supports, you can choose yourself how to best use Mule in your own environment. The following messaging styles are supported:


  • Asynchronous

  • Request Response

  • Synchronous

  • Async Request Response


  • The messages that are passed from endpoint to endpoint are not bound to XML. It can be anything from a POJO to a binary image files.


    6. Mule is Expandable


    Mule's core is designed with expandability in mind. These so called pluggable modules provide support for a wide range of transports or add extra features, such as distributed transactions, security, or management. Mule comes with a whole bunch of transports (CXF, Axis, HTTP, JMS, JDBC, Email, FTP, to name a few), transformers, routers (chaining, multicasting, filtering, exception-based, etc.) and filters. New modules become available regularly. As an example, this week a SAP transport has been implemented.


    If the transport, filter, transformer or router you need is not available it's easy to implement your own by implementing the required interfaces or extending one of the available ones.


    7. Mule's Tool Support


    Mule IDE 2.0 is a development and testing environment based on Eclipse. With Mule IDE it is easy to:


  • Create a new Mule project in Eclipse

  • Create and edit Mule configuration file

  • Running and debugging your Mule project in Eclipse


  • You can use Maven to quickly set up and configure your Mule project. Mule provides four archetypes that create template files, including all the necessary Java boilerplate and detailed implementation instructions in comments, helping you get started quickly:


  • Project Archetype for creating a standalone Mule application.

  • Module Archetype for creating a new module, such as XML or scripting support.

  • Transport Archetype for creating a new transport, such as JMS or CXF.

  • Example Archetype for creating a new example to help other users get up and running quickly.


  • Mule provides a Test Compatibility Kit to test various aspects of your Mule project, including integration tests of your Mule configurations. Components can be easily mocked.


    8. Mule is well Documented


    Normally the lack of documentation is an often heard complain about open source initiatives. Mule ESB provides an excellent User Guide describing all kinds of topics, from simple ones as how to configure a transport or router to the more advanced topics like performance tuning.


    If this is not enough, multiple books are available (among them Open Source ESBs in Action and the recently published Mule in Action) which provides you with hands-on examples and in-depth knowledge of the product.


    9. Mule has an Active Community


    All those transports, filters, routers and transformers can be a bit overwhelming when starting with Mule. Don't worry; mule can lean on a highly active community. When you have a question, drop it in the forum and you will get an instant solution to your problem or tips on how to solve it or where to look.


    So, do you agree with these reasons? Did I forget something? If so, please leave me a note.



    |

    • Digg
    • Del.icio.us
    • StumbleUpon
    • Reddit
    • Twitter
    • RSS

    Mule, show me the exception, please

    Do you know the feeling that you think what you want is really simple, but can't get it to work? You start searching the forums and google is your best friend. But even a best friend doesn't always know the answer. The worst part of it all is that most of the time the answer IS really simple. You just needed to figure it out.


    The setting
    A couple of month ago, I was struggling with how to send a proper response to the client in case an exception occurs in mule (or any of the services attached to it). We use mule as a proxy for our external webservices. Mule handles among others authentication/authorization, logging, auditing and transformation and routing features. If for example authentication fails or the connection to an external webservice is down, a SoapFault needed to be returned to the calling party.


    Easy, right? (well actually it is, I'll come to that later).


    Since I like to visualize things, let's take a look at an example config file, below:


    <mule>
       ...
       <custom-transformer name="HttpRequestToParamMap"
          class="org.mule.transport....HttpRequestBodyToParamMap"/>
       
       <expression-transformer name="MapToServiceParams">
          <return-argument evaluator="map-payload"
             expression="text"/>
          <return-argument evaluator="map-payload"
             expression="delim" optional="true"/>
       </expression-transformer>
       
       <model name="ExceptionHandling">
          <service name="inputService">
             <inbound>
                <inbound-endpoint
                   address="http://localhost:7777/textcasing"
                   transformer-refs="HttpRequestToParamMap"
                   synchronous="true"/>
             </inbound>
             <outbound>
                <pass-through-router>
                   <outbound-endpoint
                      transformer-refs="MapToServiceParams"
                      address="wsdl-cxf:
                         http://www.dataaccess.com/
                         webservicesserver/textcasing.wso?
                         wsdl&method=TitleCaseWordsWithToken"
                      synchronous="true"/>
                </pass-through-router>
             </outbound>
          </service>
       </model>
    </mule>


    In the example a service is defined with an http inbound-endpoint, which takes two parameters: text and delim. The parameters will be transformed and the SOAP service TitleCaseWordsWithToken will be called with these parameters. So if you go to your browser and type:


    http://localhost:7777/textcasing?text=This%20is%20a%20text&delim=-


    The service will return:


    This-Is-A-Test


    The Problem
    So far, so good. But what if, for example, You forget to specify the parameter delim, which is required. The webservice will return a SOAP Fault. If you don't configure anything, the caller will either see nothing (NullPayload) or the incoming message, depending on the point where the exception is thrown. But you want to inform the requester. I'm not gonna bore you with the different solutions I've tried (one of them was mentioned 'most innovative approach I have ever seen' ;-) ), but unfortunately they all failed.


    The Solution
    The solution brought to me by Puneet Gupta is as simple as elegant. Since the exception is stored in the MuleMessage (in the property exceptionPayload), use a transformer to transform the exception to the proper response message.


    public class ErrorTransformer extends
                   AbstractMessageAwareTransformer {
       private ExceptionHandlerStrategy
                exceptionHandlerStrategy;

       @Override
       public Object transform(MuleMessage message,
             String outputEncoding) throws
                TransformerException {
          if (message.getExceptionPayload() != null) {
             // Remove HTTP_STATUS
             message.removeProperty
                   (HttpConnector.HTTP_STATUS_PROPERTY);

             ExceptionPayload exceptionPayload =
                   message.getExceptionPayload();

             // Strategy builds custom Error Message
             Object payload =
                   exceptionHandlerStrategy.
                      handleException(
                         message,
                         exceptionPayload.getException(),
                         exceptionPayload.getRootException());

             // Set the error message / soap fault as payload
             message.setPayload(payload);

             // Remove exception payload
             message.setExceptionPayload(null);
          }

          return message;
       }
    }


    Now you only need to configure this transformer as a responseTransformer in your inbound endpoint:


    <custom-transformer name="ErrorTransformer"
       class="nl.endpoint.mule.exception.ErrorTransformer" />
    ...
    <inbound>
       <inbound-endpoint
          address="http://localhost:7777/textcasing" ...
          responseTransformer-refs="ErrorTransformer"/>
    </inbound>


    Other solutions
    If you are working with SOAP messages, another good alternative would be to use the cxf transport instead of the http transport. The cxf transport automatically translates the Exceptions to proper SOAP Faults.


    As I start seeing the same question over and over on the mule forum, I decided to spend a blogpost on it. So, for all those people searching for the same answer, I hope your search stops here. Otherwise leave me a note.



    |

    • Digg
    • Del.icio.us
    • StumbleUpon
    • Reddit
    • Twitter
    • RSS

    Mule: Log request and response messages of synchronous call

    Suppose you have a SOAP webservice running and you want to log all requests and responses to the webservice. How can you establish this using Mule ESB?


    I have seen this question a lot on the mule mailinglist, and so far I have only seen answers that partially describe the solution, but I have never seen a complete example. So, this will be the topic of my first technical blog.


    A typical way to do this in Mule is with the wire-tap-router. This inbound router allows you to route certain events to a different endpoint as well as to the component (see figure below).



    So, what's the problem, you might think. Well, the router only taps incoming events, so this will not work for the response messages of a synchronous call. The solution is to transform the synchronous call to an asynchronous one. This can be accomplished by the async-reply router.



    <model name="LogExample">
    <service name="WebServiceBridge">
    <inbound>
    <inbound-endpoint address="${inbound.uri}" synchronous="true" />
    </inbound>
    <outbound>
    <pass-through-router>
    <vm:outbound-endpoint path="request-channel"
    transformer-refs="ObjectToString SetRequestMessageProperty"/>
    </pass-through-router>
    </outbound>
    <async-reply>
    <vm:inbound-endpoint path="back-channel" />
    <single-async-reply-router />
    </async-reply>
    </service>


    As you can see, the inbound endpoint is synchronous, while the outbound endpoint isn't. The service further defines a single-async-reply-router, which means that the first message that is received is returned to the inbound-endpoint. The outbound router routes the events to the request-channel. Don't mind the transformers that are defined yet, those are explained later.


    The next service that is defined is the request flow:



    <service name="RequestFlow">
    <inbound>
    <vm:inbound-endpoint path="request-channel"/>
    <wire-tap-router>
    <vm:outbound-endpoint path="log-channel"/>
    </wire-tap-router>
    </inbound>
    <outbound>
    <chaining-router>
    <outbound-endpoint name="webservice" address="${outbound.uri}"
    synchronous="true"/>
    <vm:outbound-endpoint path="response-channel"
    transformer-refs="ObjectToString SetResponseMessageProperty"/>
    </chaining-router>
    </outbound>
    </service>


    A wire-tap-router is configured on the inbound-endpoint. All events are passed to the log-channel. A chaining-router is used to first send the request to the actual webservice and then send the response from the webservice to the response-channel.


    The next service is the response flow:



    <service name="ResponseFlow">
    <inbound>
    <vm:inbound-endpoint path="response-channel" />
    <wire-tap-router>
    <vm:outbound-endpoint path="log-channel"/>
    </wire-tap-router>
    </inbound>
    <outbound>
    <pass-through-router>
    <vm:outbound-endpoint path="back-channel"/>
    </pass-through-router>
    </outbound>
    </service>


    As you can see, the event is again send to the log-channel through the wire-tap-router as well as to the back-channel (and thus to the client).


    The last service we have to define is the log flow:



    <service name="LogFlow">
    <inbound>
    <vm:inbound-endpoint path="log-channel"/>
    <custom-inbound-router
    class="nl.endpoint.mule.router.RequestResponseAggregator"/>
    </inbound>
    <component>
    <spring-object bean="LogComponent" />
    </component>
    </service>
    </model>


    An aggregator is used to collect both the request and the response and hand them as a set to the LogComponent. This is only necessary if you want to handle the request and response as one message (you can also choose to log them separately). So, how can the aggregator make a distinction between the request and the response message? This is done by the transformers SetRequestMessageProperty and SetResponseMessageProperty. Both set a property to the MuleMessage indicating whether the message contains the request event or the response event. The former is shown below:



    <message-properties-transformer
    name="SetRequestMessageProperty">
    <add-message-properties>
    <spring:entry key="MessageType" value="Request"/>
    </add-message-properties>
    </message-properties-transformer>


    The SetResponseMessageProperty is configured the same way.


    Now the aggregator is pretty straight forward and listed below. The RequestResponseAggregator extends AbstractEventAggregator. Therefore the method getCorrelatorCallback has to be implemented. This method returns a new EventCorrelatorCallback. In the method aggregateEvents, the property 'MessageType' is checked.



    public class RequestResponseAggregator extends AbstractEventAggregator {
    @Override
    protected EventCorrelatorCallback getCorrelatorCallback() {
    return new EventCorrelatorCallback() {
    @SuppressWarnings("unchecked")
    public MuleMessage aggregateEvents(EventGroup events)
    throws RoutingException {
    Iterator<MuleEvent> iterator = events.iterator();
    while(iterator.hasNext()) {
    MuleEvent event = iterator.next();
    MuleMessage message = event.getMessage();
    // Check message type
    if ("Request".equals(message.getProperty("MessageType"))) {
    // This is the request
    } else {
    // This is the response
    }
    }

    return new DefaultMuleMessage(...);
    }

    public EventGroup createEventGroup(MuleEvent event, Object correlationId) {
    return new EventGroup(correlationId, 2);
    }

    public boolean shouldAggregateEvents(EventGroup events) {
    return events.expectedSize() == events.size();
    }
    };
    }
    }

    Hope this clarifies how to deal with logging of request and response messages in synchronous flows.


    My next blog will be about another common question in the Mule mailing list: Exception Handling.



    |

    • Digg
    • Del.icio.us
    • StumbleUpon
    • Reddit
    • Twitter
    • RSS