View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.processor.chain;
8   
9   import org.mule.api.MuleException;
10  import org.mule.api.construct.FlowConstruct;
11  import org.mule.api.processor.InterceptingMessageProcessor;
12  import org.mule.api.processor.MessageProcessor;
13  import org.mule.api.processor.MessageProcessorBuilder;
14  import org.mule.api.processor.MessageProcessorChain;
15  
16  import java.util.ArrayList;
17  import java.util.Collections;
18  import java.util.LinkedList;
19  import java.util.List;
20  
21  /**
22   * <p>
23   * Constructs a chain of {@link MessageProcessor}s and wraps the invocation of the chain in a composite
24   * MessageProcessor. Both MessageProcessors and InterceptingMessageProcessor's can be chained together
25   * arbitrarily in a single chain. InterceptingMessageProcessors simply intercept the next MessageProcessor in
26   * the chain. When other non-intercepting MessageProcessors are used an adapter is used internally to chain
27   * the MessageProcessor with the next in the chain.
28   * </p>
29   * <p>
30   * The MessageProcessor instance that this builder builds can be nested in other chains as required.
31   * </p>
32   */
33  public class DefaultMessageProcessorChainBuilder extends AbstractMessageProcessorChainBuilder
34  {
35  
36      public DefaultMessageProcessorChainBuilder()
37      {
38          // empty
39      }
40  
41      public DefaultMessageProcessorChainBuilder(FlowConstruct flowConstruct)
42      {
43          this.flowConstruct = flowConstruct;
44      }
45  
46      /**
47       * This builder supports the chaining together of message processors that intercept and also those that
48       * don't. While one can iterate over message processor intercepting message processors need to be chained
49       * together. One solution is make all message processors intercepting (via adaption) and chain them all
50       * together, this results in huge stack traces and recursive calls with adaptor. The alternative is to
51       * build the chain in such a way that we iterate when we can and chain where we need to. <br>
52       * We iterate over the list of message processor to be chained together in reverse order collecting up
53       * those that can be iterated over in a temporary list, as soon as we have an intercepting message
54       * processor we create a DefaultMessageProcessorChain using the temporary list and set it as a listener of
55       * the intercepting message processor and then we continue with the algorithm
56       */
57      public MessageProcessorChain build() throws MuleException
58      {
59          LinkedList<MessageProcessor> tempList = new LinkedList<MessageProcessor>();
60  
61          // Start from last but one message processor and work backwards
62          for (int i = processors.size() - 1; i >= 0; i--)
63          {
64              MessageProcessor processor = initializeMessageProcessor(processors.get(i));
65              if (processor instanceof InterceptingMessageProcessor)
66              {
67                  InterceptingMessageProcessor interceptingProcessor = (InterceptingMessageProcessor) processor;
68                  // Processor is intercepting so we can't simply iterate
69                  if (i + 1 < processors.size())
70                  {
71                      // The current processor is not the last in the list
72                      if (tempList.isEmpty())
73                      {
74                          interceptingProcessor.setListener(initializeMessageProcessor(processors.get(i + 1)));
75                      }
76                      else if (tempList.size() == 1)
77                      {
78                          interceptingProcessor.setListener(tempList.get(0));
79                      }
80                      else
81                      {
82                          final DefaultMessageProcessorChain chain = new DefaultMessageProcessorChain(
83                              "(inner iterating chain) of " + name, new ArrayList<MessageProcessor>(tempList));
84                          interceptingProcessor.setListener(chain);
85                      }
86                  }
87                  tempList = new LinkedList<MessageProcessor>(Collections.singletonList(processor));
88              }
89              else
90              {
91                  // Processor is not intercepting so we can invoke it using iteration
92                  // (add to temp list)
93                  tempList.addFirst(initializeMessageProcessor(processor));
94              }
95          }
96          // Create the final chain using the current tempList after reserve iteration is complete. This temp
97          // list contains the first n processors in the chain that are not intercepting.. with processor n+1
98          // having been injected as the listener of processor n
99          final DefaultMessageProcessorChain chain = new DefaultMessageProcessorChain(name,
100             new ArrayList<MessageProcessor>(tempList));
101 
102         // Wrap with something that can apply lifecycle to all processors which are otherwise not visable from
103         // DefaultMessageProcessorChain
104         return new InterceptingChainLifecycleWrapper(chain, processors, "wrapper for " + name);
105     }
106 
107     public DefaultMessageProcessorChainBuilder chain(MessageProcessor... processors)
108     {
109         for (MessageProcessor messageProcessor : processors)
110         {
111             this.processors.add(messageProcessor);
112         }
113         return this;
114     }
115 
116     public DefaultMessageProcessorChainBuilder chain(List<MessageProcessor> processors)
117     {
118         if (processors != null)
119         {
120             this.processors.addAll(processors);
121         }
122         return this;
123     }
124 
125     public DefaultMessageProcessorChainBuilder chain(MessageProcessorBuilder... builders)
126     {
127         for (MessageProcessorBuilder messageProcessorBuilder : builders)
128         {
129             this.processors.add(messageProcessorBuilder);
130         }
131         return this;
132     }
133 
134     public DefaultMessageProcessorChainBuilder chainBefore(MessageProcessor processor)
135     {
136         this.processors.add(0, processor);
137         return this;
138     }
139 
140     public DefaultMessageProcessorChainBuilder chainBefore(MessageProcessorBuilder builder)
141     {
142         this.processors.add(0, builder);
143         return this;
144     }
145 }