Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simulate while loop in Mule 3.4

I need a while loop in my Mule Flow to load data in chunks from a custom DAO (I use an Expression Transformer to access the DAO) until he does not provide any more items. (I don't know the total amount of items the DAO provides.) There is no build-in while loop in Mule 3.4.

My first Idea was to use a recursive backreference in a SubFlow. The SubFlow calls itself until the work is done. But I ge a springframework exception for an "unresolvable circular reference". A Flow cannot call itself.

My next Idea was to write a Custom Transformer and inject the SubFlow to call in a loop. I use some techics David Dossot described in his answer for this question: https://stackoverflow.com/a/16532977/2629741

The Problem I have is not only that the flowVars from the original Flow are not accessable in the SubFlow but also that I get an exception if I try to set a flowVar (and I use flowVars for the communication between the original Flow and the SubFlow):

org.mule.api.transformer.TransformerMessagingException: null (java.lang.NullPointerException). Message payload is of type: NullPayload

My Question ist: How do I make the flowVars from the original Flow accessable in the SubFlow (and vice versa) I called inside a Custom Transformer (see class Loop below)?

The Mule flow:

<flow name="test_loopFlow1" doc:name="test_loopFlow1">
    <vm:inbound-endpoint exchange-pattern="request-response" path="test_loop" doc:name="VM"/>
    <custom-transformer class="com.example.transformer.Loop" doc:name="Java">
        <spring:property name="flow" ref="loopTask"/>
    </custom-transformer>
</flow>
<sub-flow name="loopTask" doc:name="loopTask">
    <logger message="loop" level="WARN" doc:name="Logger"/>
    <set-variable variableName="stop" value="true" doc:name="set flowVar"/>
</sub-flow>

Loop Transformer:

public class Loop
extends AbstractMessageTransformer
implements FlowConstructAware
{
   private InterceptingChainLifecycleWrapper _flow = null;

   public void setFlow(
      final Object value
   ) {
      this._flow = InterceptingChainLifecycleWrapper.class.cast(value);
   }

   @Override
   public Object transformMessage(
      final MuleMessage message,
      final String outputEncoding
   ) throws TransformerException
   {
      try {
         final MuleEvent muleEvent = new DefaultMuleEvent(
            message,
            MessageExchangePattern.REQUEST_RESPONSE,
            this.flowConstruct
         );
         message.setInvocationProperty("stop", "false");
         do {
            /*final MuleEvent resultEvent =*/ this._flow.process(muleEvent);
         } while(
            ((String) message.getInvocationProperty("stop")).equals("false")
         );

      } catch (final MuleException e) {
         throw new TransformerException(
            MessageFactory.createStaticMessage("SubFlow exception."),
            this
         );
      }
      return message;
   }

   FlowConstruct flowConstruct;
   @Override
   public void setFlowConstruct(final FlowConstruct flowConstruct)
   {
      this.flowConstruct = flowConstruct;
   }
}

Unit Test:

public class LoopTest
   extends FunctionalTestCase
{
   private LocalMuleClient _muleClient = null;

   public LoopTest(
   ) throws Exception
   {
      super.setUpMuleContext();
      this._muleClient = new DefaultLocalMuleClient(
         AbstractMuleContextTestCase.muleContext
      );
   }

   @Override
   protected String getConfigResources(
   ) {
      return "src/main/app/test_loop.xml";
   }

   @Test
   public void testVm(
   ) throws Exception
   {
      this._muleClient.send("vm://test_loop", null, null);
   }
}
like image 475
Frank Olschewski Avatar asked Dec 08 '22 11:12

Frank Olschewski


1 Answers

A much simple approach that does not require any java code would be:

<flow name="stackoverflowFlow1" doc:name="stackoverflowFlow1">
        <vm:inbound-endpoint exchange-pattern="one-way" path="in" doc:name="VM"/>
        <set-variable variableName="#['counter']" value="#[0]" doc:name="Variable"/>
        <flow-ref name="stackoverflowFlow2" doc:name="Flow Reference"/>
    </flow>
    <flow name="stackoverflowFlow2" doc:name="stackoverflowFlow2">
        <logger level="INFO" doc:name="Logger"/>
        <set-variable variableName="counter" value="#[flowVars['counter']+1]" doc:name="Variable"/>
        <choice doc:name="Choice">
            <when expression="#[flowVars['counter']==10]">
                <logger level="INFO" doc:name="Logger"/>
            </when>
            <otherwise>
                <flow-ref name="stackoverflowFlow2" doc:name="Flow Reference"/>
            </otherwise>
        </choice>
    </flow>

In this case I'm stopping the the while after 10 iterations

like image 148
genjosanzo Avatar answered Dec 26 '22 17:12

genjosanzo