tag:blogger.com,1999:blog-60138481380975896522024-03-19T06:51:09.200+01:00Mario KlaverSolution Architect - Rotterdam (The Netherlands)Mario Klaverhttp://www.blogger.com/profile/06182993183711324484noreply@blogger.comBlogger3125tag:blogger.com,1999:blog-6013848138097589652.post-2946404973516714022009-08-12T16:05:00.010+02:002009-08-12T16:38:58.384+02:009 Reasons to Consider Mule as your ESB<p>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.<br /></p><br /><h4>1. Mule is Open Source</h4><br /><p>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 <em>start small</em>.</p><br /><p>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.<br /></p><br /><p>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.<br /></p><br /><h4>2. Mule is Mature</h4><br /><p>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.<br /></p><br /><h4>3. Mule's Architecture</h4><br /><p>Mule ESB is based on a proven set of best practices. Mule implements many of the patterns described in <em>Enterprise Integration Patterns</em>, by Gregor Hohpe and Bobby Woolf.<br /></p><br /><p>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.</P><p>Mule adopted Spring 2 as its configuration and wiring framework. This makes integration with Spring and all of Spring features really easy.<br /></p><br /><h4>4. Mule is based on Standards</h4><br /><p>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.<p><br /><p><em>Security</em> - 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 <em>Acegi</em>, <em>Spring Security</em>, <em>JAAS</em> and <em>WS-Security</em>. </p><br /><p><em>Transactions</em> - 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.</p><br /><p><em>Monitoring</em> - Mule comes with agents to check the health of your components through <em>Java Management Extensions (JMX)</em> technology.</p><br /><h4>5. Mule's different Messaging Styles</h4><br /><p>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:</p><br /><li>Asynchronous</li><br /><li>Request Response</li> <br /><li>Synchronous</li><br /><li>Async Request Response</li><br /><br /><p>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.<br /></p><br /><h4>6. Mule is Expandable</h4><br /><p>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.</p><br /><p>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.</p><br /><h4>7. Mule's Tool Support</h4><br /><p><em>Mule IDE 2.0</em> is a development and testing environment based on Eclipse. With Mule IDE it is easy to:</p><br /><li>Create a new Mule project in Eclipse</li><br /><li>Create and edit Mule configuration file</li><br /><li>Running and debugging your Mule project in Eclipse</li><br /><br /><p>You can use <em>Maven</em> 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:</p><br /><li><em>Project Archetype</em> for creating a standalone Mule application.</li><br /><li><em>Module Archetype</em> for creating a new module, such as XML or scripting support.</li> <br /><li><em>Transport Archetype</em> for creating a new transport, such as JMS or CXF.</li><br /><li><em>Example Archetype</em> for creating a new example to help other users get up and running quickly. </li><br /><br /><p>Mule provides a <em>Test Compatibility Kit</em> to test various aspects of your Mule project, including integration tests of your Mule configurations. Components can be easily mocked.</p><br /><h4>8. Mule is well Documented</h4><br /><p>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.</p><br /><p>If this is not enough, multiple books are available (among them <em>Open Source ESBs in Action</em> and the recently published <em>Mule in Action</em>) which provides you with hands-on examples and in-depth knowledge of the product. <br /></p><br /><h4>9. Mule has an Active Community</h4><br /><p>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.</p><br /><p>So, do you agree with these reasons? Did I forget something? If so, please leave me a note.<br /></p>Mario Klaverhttp://www.blogger.com/profile/06182993183711324484noreply@blogger.com5tag:blogger.com,1999:blog-6013848138097589652.post-58205161617477440762009-07-24T16:08:00.003+02:002009-08-12T16:39:24.747+02:00Mule, show me the exception, please<p><b>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.</b></p><br /><p><b>The setting</b><br />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. </p><br /><p>Easy, right? (well actually it is, I'll come to that later).</p><br /><p>Since I like to visualize things, let's take a look at an example config file, below:</p><br /><p><code><mule><br /> ...<br /> <custom-transformer name="HttpRequestToParamMap"<br /> class="org.mule.transport....HttpRequestBodyToParamMap"/><br /> <br /> <expression-transformer name="MapToServiceParams"><br /> <return-argument evaluator="map-payload" <br /> expression="text"/><br /> <return-argument evaluator="map-payload" <br /> expression="delim" optional="true"/><br /> </expression-transformer><br /> <br /> <model name="ExceptionHandling"><br /> <service name="inputService"><br /> <inbound><br /> <inbound-endpoint <br /> address="http://localhost:7777/textcasing" <br /> transformer-refs="HttpRequestToParamMap" <br /> synchronous="true"/><br /> </inbound><br /> <outbound><br /> <pass-through-router><br /> <outbound-endpoint <br /> transformer-refs="MapToServiceParams" <br /> address="wsdl-cxf:<br /> http://www.dataaccess.com/<br /> webservicesserver/textcasing.wso?<br /> wsdl&method=TitleCaseWordsWithToken"<br /> synchronous="true"/><br /> </pass-through-router><br /> </outbound><br /> </service><br /> </model><br /></mule></code></p><br /><p>In the example a service is defined with an http <span style="font-family:courier new;">inbound-endpoint</span>, which takes two parameters: <span style="font-family:courier new;">text</span> and <span style="font-family:courier new;">delim</span>. The parameters will be transformed and the SOAP service <span style="font-family:courier new;">TitleCaseWordsWithToken</span> will be called with these parameters. So if you go to your browser and type: </p><br /><p><code>http://localhost:7777/textcasing?text=This%20is%20a%20text&delim=-</code></p><br /><p>The service will return: </p><br /><p><code>This-Is-A-Test</code></p><br /><p><b>The Problem</b><br />So far, so good. But what if, for example, You forget to specify the parameter <span style="font-family:courier new;">delim</span>, which is required. The webservice will return a SOAP Fault. If you don't configure anything, the caller will either see nothing (<span style="font-family:courier new;">NullPayload</span>) 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 <i>'most innovative approach I have ever seen'</i> ;-) ), but unfortunately they all failed.</p><br /><p><b>The Solution</b><br />The solution brought to me by Puneet Gupta is as simple as elegant. Since the exception is stored in the <span style="font-family:courier new;">MuleMessage</span> (in the property <span style="font-family:courier new;">exceptionPayload</span>), use a transformer to transform the exception to the proper response message.</p><br /><p><code>public class ErrorTransformer extends <br /> AbstractMessageAwareTransformer {<br /> private ExceptionHandlerStrategy<br /> exceptionHandlerStrategy;<br /> <br /> @Override<br /> public Object transform(MuleMessage message, <br /> String outputEncoding) throws <br /> TransformerException {<br /> if (message.getExceptionPayload() != null) {<br /> // Remove HTTP_STATUS <br /> message.removeProperty<br /> (HttpConnector.HTTP_STATUS_PROPERTY);<br /><br /> ExceptionPayload exceptionPayload = <br /> message.getExceptionPayload();<br /><br /> // Strategy builds custom Error Message<br /> Object payload = <br /> exceptionHandlerStrategy.<br /> handleException(<br /> message, <br /> exceptionPayload.getException(), <br /> exceptionPayload.getRootException());<br /> <br /> // Set the error message / soap fault as payload<br /> message.setPayload(payload);<br /> <br /> // Remove exception payload<br /> message.setExceptionPayload(null);<br /> }<br /> <br /> return message;<br /> }<br />}</code></p><br /><p>Now you only need to configure this transformer as a <span style="font-family:courier new;">responseTransformer</span> in your inbound endpoint:</p><br /><p><code><custom-transformer name="ErrorTransformer"<br /> class="nl.endpoint.mule.exception.ErrorTransformer" /><br />...<br /><inbound><br /> <inbound-endpoint <br /> address="http://localhost:7777/textcasing" ... <br /> <b>responseTransformer-refs="ErrorTransformer"</b>/><br /></inbound></code></p><br /><p><b>Other solutions</b><br />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.<br /></p><br /><p>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.</p>Mario Klaverhttp://www.blogger.com/profile/06182993183711324484noreply@blogger.com4tag:blogger.com,1999:blog-6013848138097589652.post-56363550538236135892009-05-27T21:14:00.039+02:002009-08-12T16:39:48.206+02:00Mule: Log request and response messages of synchronous call<p>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?</p><br /><p>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. </p><br /><p>A typical way to do this in Mule is with the <span style="font-family:courier new;">wire-tap-router</span>. This inbound router allows you to route certain events to a different endpoint as well as to the component (see figure below).</p><br /><img id="BLOGGER_PHOTO_ID_5340620836136701426" style="DISPLAY: block; MARGIN: 0px auto 10px; WIDTH: 320px; CURSOR: hand; HEIGHT: 86px; TEXT-ALIGN: center" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgzHgm5GnYnI9I3UxQaQ6VlvrnYLyyZtjMQV9wYPr72Mw3Xpn-69JzVDHpOPStp89PuAOKQ6naX8gICLNdeqy2NWsLFoYh3X3F_pGfKlDNKd1Nfpfno6KZAt0buFjT5Z1IFlPGFc90CUM/s320/Wiretap%2520Router.jpg" border="0" /><br /><p>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 <span style="font-family:courier new;">async-reply router</span>.</p><br /><p><pre class="brush: xml;"><br /><model name="LogExample"><br /> <service name="WebServiceBridge"><br /> <inbound><br /> <inbound-endpoint address="${inbound.uri}" synchronous="true" /><br /> </inbound><br /> <outbound><br /> <pass-through-router><br /> <vm:outbound-endpoint path="request-channel" <br /> transformer-refs="ObjectToString SetRequestMessageProperty"/><br /> </pass-through-router><br /> </outbound><br /> <async-reply><br /> <vm:inbound-endpoint path="back-channel" /><br /> <single-async-reply-router /><br /> </async-reply><br /> </service><br /></pre></p><br /><p>As you can see, the inbound endpoint is synchronous, while the outbound endpoint isn't. The service further defines a <span style="font-family:courier new;">single-async-reply-router</span>, 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.</p><br /><p>The next service that is defined is the request flow:</p><br /><p><pre class="brush: xml;"><br /> <service name="RequestFlow"><br /> <inbound><br /> <vm:inbound-endpoint path="request-channel"/><br /> <wire-tap-router> <br /> <vm:outbound-endpoint path="log-channel"/><br /> </wire-tap-router><br /> </inbound><br /> <outbound><br /> <chaining-router><br /> <outbound-endpoint name="webservice" address="${outbound.uri}" <br /> synchronous="true"/><br /> <vm:outbound-endpoint path="response-channel" <br /> transformer-refs="ObjectToString SetResponseMessageProperty"/><br /> </chaining-router><br /> </outbound><br /> </service><br /></pre></p><br /><p>A <span style="font-family:courier new;">wire-tap-router</span> is configured on the inbound-endpoint. All events are passed to the log-channel. A <span style="font-family:courier new;">chaining-router</span> is used to first send the request to the actual webservice and then send the response from the webservice to the response-channel.</p><br /><p>The next service is the response flow:</p><br /><p><pre class="brush: xml;"><br /> <service name="ResponseFlow"><br /> <inbound><br /> <vm:inbound-endpoint path="response-channel" /><br /> <wire-tap-router><br /> <vm:outbound-endpoint path="log-channel"/><br /> </wire-tap-router><br /> </inbound><br /> <outbound><br /> <pass-through-router><br /> <vm:outbound-endpoint path="back-channel"/><br /> </pass-through-router><br /> </outbound><br /> </service><br /></pre></p><br /><p>As you can see, the event is again send to the log-channel through the <span style="font-family:courier new;">wire-tap-router</span> as well as to the back-channel (and thus to the client).</p><br /><p>The last service we have to define is the log flow:</p><br /><p><pre class="brush: xml;"><br /> <service name="LogFlow"><br /> <inbound><br /> <vm:inbound-endpoint path="log-channel"/><br /> <custom-inbound-router <br /> class="nl.endpoint.mule.router.RequestResponseAggregator"/><br /> </inbound><br /> <component><br /> <spring-object bean="LogComponent" /><br /> </component><br /> </service><br /></model><br /></pre></p><br /><p>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 <span style="font-family:courier new;">SetRequestMessageProperty</span> and <span style="font-family:courier new;">SetResponseMessageProperty</span>. Both set a property to the MuleMessage indicating whether the message contains the request event or the response event. The former is shown below:</p><br /><p><pre class="brush: xml;"><br /><message-properties-transformer <br /> name="SetRequestMessageProperty"><br /> <add-message-properties><br /> <spring:entry key="MessageType" value="Request"/><br /> </add-message-properties><br /></message-properties-transformer><br /></pre></p><br /><p>The <span style="font-family:courier new;">SetResponseMessageProperty</span> is configured the same way.</p><br /><p>Now the aggregator is pretty straight forward and listed below. The <span style="font-family:courier new;">RequestResponseAggregator</span> extends <span style="font-family:courier new;">AbstractEventAggregator</span>. Therefore the method <span style="font-family:courier new;">getCorrelatorCallback</span> has to be implemented. This method returns a new <span style="font-family:courier new;">EventCorrelatorCallback</span>. In the method <span style="font-family:courier new;">aggregateEvents</span>, the property 'MessageType' is checked.</p><br /><pre class="brush: java"><br />public class RequestResponseAggregator extends AbstractEventAggregator {<br /> @Override<br /> protected EventCorrelatorCallback getCorrelatorCallback() {<br /> return new EventCorrelatorCallback() {<br /> @SuppressWarnings("unchecked")<br /> public MuleMessage aggregateEvents(EventGroup events) <br /> throws RoutingException {<br /> Iterator<MuleEvent> iterator = events.iterator();<br /> while(iterator.hasNext()) {<br /> MuleEvent event = iterator.next();<br /> MuleMessage message = event.getMessage();<br /> // Check message type<br /> if ("Request".equals(message.getProperty("MessageType"))) {<br /> // This is the request<br /> } else {<br /> // This is the response<br /> }<br /> }<br /> <br /> return new DefaultMuleMessage(...);<br /> }<br /> <br /> public EventGroup createEventGroup(MuleEvent event, Object correlationId) {<br /> return new EventGroup(correlationId, 2);<br /> }<br /> <br /> public boolean shouldAggregateEvents(EventGroup events) {<br /> return events.expectedSize() == events.size();<br /> }<br /> };<br /> }<br />}<br /></pre><br /><p>Hope this clarifies how to deal with logging of request and response messages in synchronous flows. </p><br /><p>My next blog will be about another common question in the Mule mailing list: <a href="/2009/05/mule-show-me-exception-please.html">Exception Handling</a>.</p>Mario Klaverhttp://www.blogger.com/profile/06182993183711324484noreply@blogger.com8