torsdag 23 januari 2014

Quick tip: Howto log business events to console inside of Mule Studio

As you might have noticed there is no default way of logging Business events to the console log during development of Mule flows in Mule Studio without having to deploy and monitor them through the Mule management console.

This issue is described in the following JIRA:

I tried many things and discussed the matter with my colleague Pontus Ullgren who came up with a solution I could use.

The tip of the day is hence howto implement your own Listener which can handle the matter.

First you need to setup the flow with your custom business event. Something like this:

      <flow doc:name="Business_event_logging" name="Business_event_logging">  
           <http:inbound-endpoint host="localhost" port="8090" path="test" doc:name="HTTP" exchange-pattern="request-response"/>  
           <message-filter doc:name="Filter favicon">  
                <not-filter>  
                     <wildcard-filter pattern="/favicon.ico" caseSensitive="true"/>  
                </not-filter>  
           </message-filter>  
           <tracking:custom-event event-name="MyUserBusinessEvent" doc:name="Custom Business event">  
                <tracking:meta-data key="User_Firstname" value="Jon" />  
                <tracking:meta-data key="User_Lastname" value="Åkerström" />  
                <tracking:meta-data key="User_Action" value="#[message.payload]"/>    
           </tracking:custom-event>  
      </flow>       

Then you need to in your configuration xml also configure a notification listener referencing to your own Listener component.

   <spring:beans>   
     <spring:bean class="se.redpill.mulecomponents.BusinessEventHandlerListener" id="notificationListener">   
   </spring:bean></spring:beans>   
   <notifications>   
     <notification-listener ref="notificationListener">   
   </notification-listener></notifications>   

Then to be able to log the events when they happen, simply implement your own Listener by implementing the EventNotificationListener interface and take appropriate actions i.e log when the onNotification is called.

 package se.redpill.mulecomponents;  
 import org.apache.commons.logging.Log;  
 import org.apache.commons.logging.LogFactory;  
 import org.mule.api.MuleContext;  
 import org.mule.api.context.MuleContextAware;  
 import com.mulesoft.mule.tracking.event.EventNotification;  
 import com.mulesoft.mule.tracking.event.EventNotificationListener;
  
 public class BusinessEventHandlerListener implements EventNotificationListener<EventNotification>, MuleContextAware {  
   MuleContext context;  
   protected static final Log LOGGER = LogFactory.getLog("MEEE");  
      @Override  
      public void onNotification(EventNotification notification) {  
           LOGGER.debug("Event notification: " + notification.toString());  
           LOGGER.debug("Event DATA:" + notification.getMetaDatas().toString());  
      }  
      @Override  
      public void setMuleContext(MuleContext context) {  
           this.context = context;  
      }  
 }  


Finally make sure that you in your log4j.properties file specify log level DEBUG globally or for the appropriate class to actually see the Business event and it's data.

The code is now also availble on Pontus Ullgrens GIT repo:
https://github.com/ullgren/my-mule-examples/tree/master/trackbuissnessevents

tisdag 21 januari 2014

Quick tip: Howto get rid of REST client failed to route to service, Socket connection closed or Http Headers too large.

A common issue during development of a Mule RESTful webservice client is that calls to the service is denied with error messages similar to "Failed to route..." or "java.net.SocketException: Connection reset" although you have specified correct endpoint address in your <http:outbound-endpoint>.

If the REST service in fact is not called (check with logging or breakpoint) and a traffic analyser like Wireshark or similar tells you its a HTTP "Bad request" or similar allthough the TCP traffic looks correct, you might have an issue with your HTTP headers.

In fact this is quite often related to the fact that Mule by default automatically transforms Mule headers to HTTP headers in the transport and vice versa. This is a very nice feature if you need to for example call a REST service and still keep sessionid or if splitted data is sent to the service for each item and you need to keep correlationids to perform aggregations on the result data further down the flow.
However the MULE_SESSION header is quite large and different vendors of different application servers like JBoss or Tomcat has different settings on maximum allowed sizes of the headers although the HTTP specs has no such limitation. This is often what causes the request to become a "Bad request" i.e to large headers.

The tip of the day is hence to set up a global connector which configures inbound or outbound endpoints to use a NullSessionHandler simply by overriding the default sessionHandler like this:

 <http:connector name="ConnectorWithoutMuleSession" doc:name="HTTP/HTTPS_Nosession">  
           <service-overrides sessionHandler="org.mule.session.NullSessionHandler"/>  
 </http:connector>  

In your flow you can now reference this connector either from an outbound endpoint which will avoid sending the MULE_SESSION header or on an inbound endpoint which will avoid processing the MULE_SESSION header on incoming messages.

Like this:

 <http:outbound-endpoint method="GET" exchange-pattern="request-response" address="${flow.myserviceurl}" contentType="application/json" doc:name="HTTP_out" connector-ref="ConnectorWithoutMuleSession"/>