Mule default exception strategy

0

In this article, we will look into what happens when one of the message processor throws an exception. How mule handles exception? Our first strategy would be the default exception strategy.

Implicit exception strategy

In our first example, there won’t be any explicit exception handler.

muleContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<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:vm="http://www.mulesoft.org/schema/mule/vm"
      xsi:schemaLocation="
               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
               http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
               http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd">
    
    <flow name="noDefaultExceptionFlow">muleDefaultExceptionStrategyExample
        <vm:inbound-endpoint path="in1" exchange-pattern="one-way"/>
        <custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="xyz" />
		</custom-transformer>	
		<custom-processor class="com.javarticles.mule.MuleCustomProcessor"/> 
        <response>
            <vm:outbound-endpoint path="out"/>
        </response>		
    </flow>
    
</mule>

Let’s define a transformer that throws exception of the payload is ‘INVALID_INPUT’.

CustomTransformer:

package com.javarticles.mule;

import org.mule.api.MuleMessage;
import org.mule.transformer.AbstractMessageTransformer;

public class CustomTransformer extends AbstractMessageTransformer {
    private String append;

    @Override
    public Object transformMessage(MuleMessage message, String encoding) {
        System.out.println(Thread.currentThread().getName() + ": before transform " + message.getPayload());
        if (message.getPayload().equals(MuleDefaultExceptionStrategyExample.INVALID_INPUT)) {
            throw new RuntimeException("Invalid input!");
        }
        message.setPayload(message.getPayload() + append);
        System.out.println(Thread.currentThread().getName() + ": after transform " + message.getPayload());
        return message;
    }

    public String getAppend() {
        return append;
    }

    public void setAppend(String append) {
        this.append = append;
    }
}

We also define another custom processor right after the transformation.

MuleCustomProcessor:

package com.javarticles.mule;

import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.api.processor.MessageProcessor;

public class MuleCustomProcessor implements MessageProcessor {

    public MuleEvent process(MuleEvent inEvent) throws MuleException {
        MuleMessage message = inEvent.getMessage();
        Object o = message.getPayload();   
        System.out.println(Thread.currentThread().getName() + ": Process Payload: " + o);
        return inEvent;
    }

}

In order to trigger the flow that leads to an exception, we post message ‘INVALID_INPUT’.

MuleNoDefaultExceptionStrategyExample:

package com.javarticles.mule;

import org.mule.DefaultMuleMessage;
import org.mule.api.MuleContext;
import org.mule.api.MuleMessage;
import org.mule.api.context.MuleContextBuilder;
import org.mule.api.context.MuleContextFactory;
import org.mule.config.DefaultMuleConfiguration;
import org.mule.config.spring.SpringXmlConfigurationBuilder;
import org.mule.context.DefaultMuleContextBuilder;
import org.mule.context.DefaultMuleContextFactory;
import org.mule.module.client.MuleClient;

public class MuleNoDefaultExceptionStrategyExample {
    public static final String INVALID_INPUT = "INVALID_INPUT"; 
    public static void main(String[] args) throws Exception {
        DefaultMuleConfiguration dmc = new DefaultMuleConfiguration();
        dmc.setId("muleexample");
        dmc.setWorkingDirectory("/esb/mule");
        SpringXmlConfigurationBuilder configBuilder = new SpringXmlConfigurationBuilder(
                "muleContext.xml");
        MuleContextBuilder contextBuilder = new DefaultMuleContextBuilder();
        contextBuilder.setMuleConfiguration(dmc);
        MuleContextFactory contextFactory = new DefaultMuleContextFactory();
        MuleContext ctx = contextFactory.createMuleContext(configBuilder,
                contextBuilder);
        ctx.start();
        try {
            MuleClient muleClient = new MuleClient(ctx);
            MuleMessage msg = new DefaultMuleMessage(INVALID_INPUT, ctx);                  
            msg = new DefaultMuleMessage(INVALID_INPUT, ctx);
            muleClient.dispatch("vm://in1", msg);
            MuleMessage response = muleClient.request("vm://out", 5000);            
            System.out.println("has response: " + (response != null));
        } finally {
            ctx.dispose();
        }
    }    
}

As you can see from the output below, there is a always an implicit default exception strategy provided by Mule which simply logs the exception. If a transaction is involved, it will rollback. Since the transformer throws an exception, the message is not passed further to the processor.

Output:

noDefaultExceptionFlow.stage1.02: before transform INVALID_INPUT
ERROR 2017-05-26 17:42:01,185 [noDefaultExceptionFlow.stage1.02] org.mule.exception.DefaultMessagingExceptionStrategy: 
********************************************************************************
Message               : Invalid input! (java.lang.RuntimeException).
Element               : /noDefaultExceptionFlow/processors/0 @ muleexample:muleContext.xml:13
--------------------------------------------------------------------------------
Exception stack is:
Invalid input! (java.lang.RuntimeException). (org.mule.api.transformer.TransformerMessagingException)
  com.javarticles.mule.CustomTransformer.transformMessage(CustomTransformer.java:13)
  org.mule.transformer.AbstractMessageTransformer.transform(AbstractMessageTransformer.java:141)
  org.mule.transformer.AbstractMessageTransformer.transform(AbstractMessageTransformer.java:89)
  org.mule.DefaultMuleMessage.transformMessage(DefaultMuleMessage.java:1585)
  (39 more...)

  (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************

has response: false

Explicit default exception strategy

In the next example, we will configure a default exception exception strategy within the flow using <default-exception-strategy>.
If any exception in the flow, the message is delivered to an outbound endpoint called “handleException”.

muleContext.xml:

    <flow name="defaultExceptionFlow">
        <vm:inbound-endpoint path="in" exchange-pattern="one-way"/>
        <custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="xyz" />
		</custom-transformer>	
		<custom-processor class="com.javarticles.mule.MuleCustomProcessor"/> 
        <default-exception-strategy>
            <vm:outbound-endpoint path="handleException"/>
        </default-exception-strategy>
    </flow>

    <flow name="handleExceptionFlow">
        <vm:inbound-endpoint path="handleException" exchange-pattern="one-way"/>
		<custom-processor class="com.javarticles.mule.ExceptionHandler"/> 
		<vm:outbound-endpoint path="out"/>
    </flow>

Any exception message posted to endpoint ‘vm:\\handleException’ will be passed on to the below handler.

ExceptionHandler:

package com.javarticles.mule;

import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.processor.MessageProcessor;

public class ExceptionHandler implements MessageProcessor {

    public MuleEvent process(MuleEvent event) throws MuleException {
        System.out.println("Handle exception!");
        return event;
    }

}

We will first pass an INVALID_INPUT and then pass a normal payload so that we can see how mule handles the exception one differently.

MuleDefaultExceptionStrategyExample:

package com.javarticles.mule;

import org.mule.DefaultMuleMessage;
import org.mule.api.MuleContext;
import org.mule.api.MuleMessage;
import org.mule.api.context.MuleContextBuilder;
import org.mule.api.context.MuleContextFactory;
import org.mule.config.DefaultMuleConfiguration;
import org.mule.config.spring.SpringXmlConfigurationBuilder;
import org.mule.context.DefaultMuleContextBuilder;
import org.mule.context.DefaultMuleContextFactory;
import org.mule.message.ExceptionMessage;
import org.mule.module.client.MuleClient;

public class MuleDefaultExceptionStrategyExample {
    public static final String INVALID_INPUT = "INVALID_INPUT"; 
    public static void main(String[] args) throws Exception {
        DefaultMuleConfiguration dmc = new DefaultMuleConfiguration();
        dmc.setId("muleexample");
        dmc.setWorkingDirectory("/esb/mule");
        SpringXmlConfigurationBuilder configBuilder = new SpringXmlConfigurationBuilder(
                "muleContext.xml");
        MuleContextBuilder contextBuilder = new DefaultMuleContextBuilder();
        contextBuilder.setMuleConfiguration(dmc);
        MuleContextFactory contextFactory = new DefaultMuleContextFactory();
        MuleContext ctx = contextFactory.createMuleContext(configBuilder,
                contextBuilder);
        ctx.start();
        try {
            MuleClient muleClient = new MuleClient(ctx);
            MuleMessage msg = new DefaultMuleMessage(INVALID_INPUT, ctx);                  
            
            muleClient.dispatch("vm://in", msg);
            MuleMessage exception = muleClient.request("vm://out", 5000);
            System.out.println("Is there an exception? " + (exception != null));
            ExceptionMessage exceptionMessage = (ExceptionMessage) exception.getPayload();
            System.out.println("Exception: " + exceptionMessage.getException());
            System.out.println("Payload: " + exceptionMessage.getPayload());
            
            msg = new DefaultMuleMessage("123", ctx);
            muleClient.dispatch("vm://in", msg);
            exception = muleClient.request("vm://out", 5000);
            System.out.println("Is there an exception? " + (exception != null));

        } finally {
            ctx.dispose();
        }
    }    
}

In case of any exception, the payload is passed on to the exception handler. The payload is now of type ExceptionMessage. One can retrieve the exception and the original payload from it. The The successful payload passes thru the transformer as well as the processor.

Output:

defaultExceptionFlow.stage1.02: before transform INVALID_INPUT
ERROR 2017-05-26 17:45:10,244 [defaultExceptionFlow.stage1.02] org.mule.exception.DefaultMessagingExceptionStrategy: 
********************************************************************************
Message               : Invalid input! (java.lang.RuntimeException).
Element               : /defaultExceptionFlow/processors/0 @ muleexample:muleContext.xml:24
--------------------------------------------------------------------------------
Exception stack is:
Invalid input! (java.lang.RuntimeException). (org.mule.api.transformer.TransformerMessagingException)
  com.javarticles.mule.CustomTransformer.transformMessage(CustomTransformer.java:13)
  org.mule.transformer.AbstractMessageTransformer.transform(AbstractMessageTransformer.java:141)
  org.mule.transformer.AbstractMessageTransformer.transform(AbstractMessageTransformer.java:89)
  org.mule.DefaultMuleMessage.transformMessage(DefaultMuleMessage.java:1585)
  (39 more...)

  (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************

Handle exception!
Is there an exception? true
Exception: org.mule.api.transformer.TransformerMessagingException: Invalid input! (java.lang.RuntimeException).
Payload: INVALID_INPUT
defaultExceptionFlow.stage1.02: before transform 123
defaultExceptionFlow.stage1.02: after transform 123xyz
defaultExceptionFlow.stage1.02: Process Payload: 123xyz

Download the source code

This was an example about Mule’s default exception strategy.

You can download the source code here: muleDefaultExceptionStrategyExample.zip

About Author

Ram’s expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring.
You can reach him at [email protected]

Comments are closed.