Mule Message Exchange Pattern Example

0

Message exchange pattern (MEP) defines the way both sides of the endpoint, sender and receiver, interact with each other. If the MEP is not explicitly specified then the endpoint will use its own default value, for example, it is one-way for JDBC whereas request-response for HTTP. There are two MEPs.

  1. One-way – won’t return any response
  2. Request-response – will return a response in the same thread

Both MEPs can be used on inbound and outbound endpoints.

  1. Inbound endpoints – one-way means mule won’t return a response to the caller but request-response will.
  2. Outbound endpoints – one-way means mule won’t wait for a response from the callee but if it is request-response it will

Inbound endpoint as one-way

In our first example, we will use an inbound endpoint with exchange pattern set to one-way. Since it is one-way, there won’t be any response from the endpoint.

muleContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vm="http://www.mulesoft.org/schema/mule/vm"
	xmlns:spring="http://www.springframework.org/schema/beans" xmlns:test="http://www.mulesoft.org/schema/mule/test"
	xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/test http://www.mulesoft.org/schema/mule/test/current/mule-test.xsd 
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd      
       http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/3.8/mule-vm.xsd
       http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.8/mule.xsd 
       ">
	<flow name="flow1">
		<vm:inbound-endpoint path="in1" exchange-pattern="one-way" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow1(append_to_in1)" />
		</custom-transformer>
	</flow>
</mule>

The custom transformer appends a message. We can also see the the thread processing it.

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());
        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;
    }
}

one-way inbound endpoint

What happens if we have a client waiting for a response?

Let’s start the flow by sending a message to the inbound endpoint in1.

MuleMessage message = muleClient.send("vm://in1", payload, null);

The mule client calls a one-way service expecting a response. Since the endpoint won’t return any response, the client will be sent an empty payload as the response.

MuleMessageExchangeExample:

package com.javarticles.mule;

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 MuleMessageExchangeExample {
    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);
            String payload = "XYZ-";
            MuleMessage message = muleClient.send("vm://in1", payload, null);
            System.out.println("Response: " + message.getPayloadAsString());            
        } finally {
            ctx.dispose();
        }
    }
}

The message is transformed but since no response is expected the transformer returns a Null-Payload instead of null.
Output:

WARN  2017-03-08 09:40:03,970 [main]org.mule.transport.vm.VMMessageReceiver: MuleClient.send() was used but inbound endpoint vm://in1 is not 'request-response'.  No response will be returned.
flow1.stage1.02: before transform XYZ-
flow1.stage1.02: after transform XYZ-flow1(append_to_in1)
Response: {NullPayload}

Outbound endpoint as one-way

In our next example, we will have two flows. A message can move from one flow to another using an outbound endpoint. This time will have the outbound endpoint as one-way.

muleContext.xml:

	<flow name="flow2">
		<vm:inbound-endpoint path="in2" exchange-pattern="request-response" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow2(append_to_in2)" />
		</custom-transformer>
		<vm:outbound-endpoint path="out" exchange-pattern="one-way" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow2(append_to_out_reponse)" />
		</custom-transformer>		
	</flow>
	
	<flow name="flow3">
		<vm:inbound-endpoint path="out" exchange-pattern="request-response" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow3(append_to_out)" />
		</custom-transformer>
	</flow>	

Send a payload to inbound point in2.

message = muleClient.send("vm://in2", payload, null);
System.out.println("Response: " + message.getPayloadAsString());

Message sent to inbound endpoint in2 is processed by a custom transformer and is then pushed to an outbound endpoint which is one-way exchange pattern. The message sent to outbound endpoint is processed by another flow flow3. After the message is sent to outbound endpoint, it is further transformed.
As you can see from the below output, since outbound endpoint out is of one-way, mule simply disregarded the response returned from flow3 where the source of message is out as inbound endpoint.

Output:

main: before transform XYZ-
main: after transform XYZ-flow2(append_to_in2)
main: before transform XYZ-flow2(append_to_in2)
main: after transform XYZ-flow2(append_to_in2)flow2(append_to_out_reponse)
Response: XYZ-flow2(append_to_in2)flow2(append_to_out_reponse)

Below mule context XML is similar to the current example but the an additional response element.

muleContext.xml:

	<flow name="flow6">
		<vm:inbound-endpoint path="in4" exchange-pattern="request-response" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow6(append_to_in4)" />
		</custom-transformer>
		<response>
			<custom-transformer class="com.javarticles.mule.CustomTransformer">
				<spring:property name="append" value="flow6(append_to_in4_reponse)" />
			</custom-transformer>
		</response>
		<vm:outbound-endpoint path="out_res" exchange-pattern="one-way" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow6(append_to_out_reponse)" />
		</custom-transformer>		
	</flow>	
	
	<flow name="flow7">
		<vm:inbound-endpoint path="out_res" exchange-pattern="request-response" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow7(append_to_out_res)" />
		</custom-transformer>
	</flow>

Output:

main: before transform XYZ-
main: after transform XYZ-flow6(append_to_in4)
main: before transform XYZ-flow6(append_to_in4)
main: after transform XYZ-flow6(append_to_in4)flow6(append_to_out_reponse)
main: before transform XYZ-flow6(append_to_in4)flow6(append_to_out_reponse)
main: after transform XYZ-flow6(append_to_in4)flow6(append_to_out_reponse)flow6(append_to_in4_reponse)
Response: XYZ-flow6(append_to_in4)flow6(append_to_out_reponse)flow6(append_to_in4_reponse)

Null response during the flow

In our next example, we will see what happens if one if the message processor returns a null payload. In the below mule context XML, exchange pattern of outbound endpoint out_on_res is specified as request-response. The response has to come from flow5 but the inbound point out-no-res defined there is a one-way so outbound endpoint out_on_res will end up returning a null payload.

muleContext.xml:

        <flow name="flow4">
		<vm:inbound-endpoint path="in3" exchange-pattern="request-response" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow4(append_to_in3)" />
		</custom-transformer>
		<response>
			<custom-transformer class="com.javarticles.mule.CustomTransformer">
				<spring:property name="append" value="flow4(append_to_in3_reponse)" />
			</custom-transformer>
		</response>
		<vm:outbound-endpoint path="out_no_res" exchange-pattern="request-response" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow4(append_to_out_reponse)" />
		</custom-transformer>		
	</flow>	
	
	<flow name="flow5">
		<vm:inbound-endpoint path="out_no_res" exchange-pattern="one-way" />
		<custom-transformer class="com.javarticles.mule.CustomTransformer">
			<spring:property name="append" value="flow3(append_to_out_no_res)" />
		</custom-transformer>
	</flow>	

Send a payload to trigger the flow.

message = muleClient.send("vm://in3", payload, null);
System.out.println("Response: " + message.getPayloadAsString());

Since the message processor out_no_res returns null, no further processing happens in the flow. Even the response phase is not fired but note that the message sent to the outbound endpoint results in an asynchronous processing of flow5.

Output:

main: before transform XYZ-
main: after transform XYZ-flow4(append_to_in3)
Response: {NullPayload}
flow5.stage1.02: before transform XYZ-flow4(append_to_in3)
flow5.stage1.02: after transform XYZ-flow4(append_to_in3)flow3(append_to_out_no_res)

Download the source code

This was an example of Mule Message Exchange Pattern.

You can download the source code here: muleMessageExchangePatternExample.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.