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.MuleEvent;
10  import org.mule.api.MuleException;
11  import org.mule.api.construct.FlowConstruct;
12  import org.mule.api.construct.FlowConstructAware;
13  import org.mule.api.context.MuleContextAware;
14  import org.mule.api.endpoint.ImmutableEndpoint;
15  import org.mule.api.lifecycle.Disposable;
16  import org.mule.api.lifecycle.Initialisable;
17  import org.mule.api.lifecycle.InitialisationException;
18  import org.mule.api.lifecycle.Lifecycle;
19  import org.mule.api.lifecycle.Startable;
20  import org.mule.api.lifecycle.Stoppable;
21  import org.mule.api.processor.MessageProcessor;
22  import org.mule.api.processor.MessageProcessorChain;
23  import org.mule.api.processor.policy.AroundPolicy;
24  import org.mule.api.processor.policy.Policies;
25  import org.mule.api.processor.policy.PolicyInvocation;
26  import org.mule.endpoint.EndpointAware;
27  import org.mule.processor.AbstractInterceptingMessageProcessor;
28  import org.mule.util.StringUtils;
29  
30  import java.util.Iterator;
31  import java.util.List;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  /**
37   * Builder needs to return a composite rather than the first MessageProcessor in the chain. This is so that if
38   * this chain is nested in another chain the next MessageProcessor in the parent chain is not injected into
39   * the first in the nested chain.
40   */
41  public abstract class AbstractMessageProcessorChain extends AbstractInterceptingMessageProcessor
42                                                      implements MessageProcessorChain, Lifecycle, FlowConstructAware, MuleContextAware, EndpointAware
43  {
44      protected final transient Log log = LogFactory.getLog(getClass());
45      protected String name;
46      protected List<MessageProcessor> processors;
47      private final Policies policies = new Policies(this);
48  
49      public AbstractMessageProcessorChain(String name, List<MessageProcessor> processors)
50      {
51          this.name = name;
52          this.processors = processors;
53      }
54  
55      public MuleEvent process(MuleEvent event) throws MuleException
56      {
57          if (log.isDebugEnabled())
58          {
59              log.debug(String.format("Invoking %s with event %s", this, event));
60          }
61          if (event == null)
62          {
63              return null;
64          }
65  
66          final List<AroundPolicy> activePolicies = policies.list();
67          MuleEvent result;
68          if (!activePolicies.isEmpty())
69          {
70              // if there's a policy, adapt, so it can call through to the doProcess() method
71              // TODO I hate to do this, and there are no method delegates in java.
72              // This doProcess() must be abstracted into some chain processor which has the logic,
73              // and have the chain handle the plumbing only
74              PolicyInvocation invocation = new PolicyInvocation(event, activePolicies, new MessageProcessor()
75              {
76                  public MuleEvent process(MuleEvent event) throws MuleException
77                  {
78                      return doProcess(event);
79                  }
80              });
81              final AroundPolicy entryPoint = activePolicies.get(0);
82              result = entryPoint.invoke(invocation);
83          }
84          else
85          {
86              // direct invocation
87              result = doProcess(event);
88          }
89          return processNext(result);
90      }
91  
92      protected abstract MuleEvent doProcess(MuleEvent event) throws MuleException;
93  
94      public void initialise() throws InitialisationException
95      {
96          for (MessageProcessor processor : processors)
97          {
98              // MULE-5002 TODO review MP Lifecycle
99              if (processor instanceof Initialisable /* && !(processor instanceof Transformer) */)
100             {
101                 ((Initialisable) processor).initialise();
102             }
103         }
104     }
105 
106     public void start() throws MuleException
107     {
108         for (MessageProcessor processor : processors)
109         {
110             if (processor instanceof Startable)
111             {
112                 ((Startable) processor).start();
113             }
114         }
115     }
116 
117     public void stop() throws MuleException
118     {
119         for (MessageProcessor processor : processors)
120         {
121             if (processor instanceof Stoppable)
122             {
123                 ((Stoppable) processor).stop();
124             }
125         }
126     }
127 
128     public void dispose()
129     {
130         for (MessageProcessor processor : processors)
131         {
132             if (processor instanceof Disposable)
133             {
134                 ((Disposable) processor).dispose();
135             }
136         }
137         processors.clear();
138     }
139 
140     public void setFlowConstruct(FlowConstruct flowConstruct)
141     {
142         for (MessageProcessor processor : processors)
143         {
144             if (processor instanceof FlowConstructAware)
145             {
146                 ((FlowConstructAware) processor).setFlowConstruct(flowConstruct);
147             }
148         }
149     }
150 
151     public String getName()
152     {
153         return name;
154     }
155 
156     @Override
157     public String toString()
158     {
159         StringBuilder string = new StringBuilder();
160         string.append(getClass().getSimpleName());
161         if (StringUtils.isNotBlank(name))
162         {
163             string.append(String.format(" '%s' ", name));
164         }
165 
166         Iterator<MessageProcessor> mpIterator = processors.iterator();
167 
168         final String nl = String.format("%n");
169 
170         for (AroundPolicy policy : policies.list())
171         {
172             string.append(String.format("%n  -- policy [%s]: %s", policy.getName(), policy));
173         }
174 
175         // TODO have it print the nested structure with indents increasing for nested MPCs
176         if (mpIterator.hasNext())
177         {
178             string.append(String.format("%n[ "));
179             while (mpIterator.hasNext())
180             {
181                 MessageProcessor mp = mpIterator.next();
182                 final String indented = StringUtils.replace(mp.toString(), nl, String.format("%n  "));
183                 string.append(String.format("%n  %s", indented));
184                 if (mpIterator.hasNext())
185                 {
186                     string.append(", ");
187                 }
188             }
189             string.append(String.format("%n]"));
190         }
191 
192         return string.toString();
193     }
194 
195     public void setEndpoint(ImmutableEndpoint endpoint)
196     {
197         for (MessageProcessor processor : processors)
198         {
199             if (processor instanceof EndpointAware)
200             {
201                  ((EndpointAware) processor).setEndpoint(endpoint);
202             }
203         }
204     }
205 
206     public List<MessageProcessor> getMessageProcessors()
207     {
208         return processors;
209     }
210 
211     public Policies getPolicies()
212     {
213         return policies;
214     }
215 }