View Javadoc

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