View Javadoc

1   /*
2    * $Id: AbstractPipeline.java 22864 2011-09-05 17:18:46Z 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.construct;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleException;
16  import org.mule.api.construct.FlowConstructInvalidException;
17  import org.mule.api.construct.Pipeline;
18  import org.mule.api.endpoint.InboundEndpoint;
19  import org.mule.api.processor.MessageProcessor;
20  import org.mule.api.processor.MessageProcessorBuilder;
21  import org.mule.api.processor.MessageProcessorChainBuilder;
22  import org.mule.api.processor.ProcessingStrategy;
23  import org.mule.api.source.CompositeMessageSource;
24  import org.mule.api.source.MessageSource;
25  import org.mule.config.i18n.CoreMessages;
26  import org.mule.construct.flow.DefaultFlowProcessingStrategy;
27  import org.mule.processor.AbstractInterceptingMessageProcessor;
28  import org.mule.processor.chain.DefaultMessageProcessorChainBuilder;
29  import org.mule.processor.strategy.AsynchronousProcessingStrategy;
30  import org.mule.processor.strategy.SynchronousProcessingStrategy;
31  
32  import java.util.Collections;
33  import java.util.List;
34  
35  /**
36   * Abstract implementation of {@link AbstractFlowConstruct} that allows a list of {@link MessageProcessor}s
37   * that will be used to process messages to be configured. These MessageProcessors are chained together using
38   * the {@link DefaultMessageProcessorChainBuilder}.
39   * <p/>
40   * If no message processors are configured then the source message is simply returned.
41   */
42  public abstract class AbstractPipeline extends AbstractFlowConstruct implements Pipeline
43  {
44      protected MessageSource messageSource;
45      protected MessageProcessor pipeline;
46  
47      protected List<MessageProcessor> messageProcessors = Collections.emptyList();
48  
49      protected ProcessingStrategy processingStrategy;
50  
51      public AbstractPipeline(String name, MuleContext muleContext)
52      {
53          super(name, muleContext);
54          processingStrategy = new SynchronousProcessingStrategy();
55      }
56  
57      /**
58       * Creates a {@link MessageProcessor} that will process messages from the configured {@link MessageSource}
59       * .
60       * <p>
61       * The default implementation of this methods uses a {@link DefaultMessageProcessorChainBuilder} and
62       * allows a chain of {@link MessageProcessor}s to be configured using the
63       * {@link #configureMessageProcessors(org.mule.api.processor.MessageProcessorChainBuilder)} method but if
64       * you wish to use another {@link MessageProcessorBuilder} or just a single {@link MessageProcessor} then
65       * this method can be overridden and return a single {@link MessageProcessor} instead.
66       */
67      protected MessageProcessor createPipeline() throws MuleException
68      {
69          DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder(this);
70          builder.setName("'" + getName() + "' processor chain");
71          configurePreProcessors(builder);
72          configureMessageProcessors(builder);
73          configurePostProcessors(builder);
74          return builder.build();
75      }
76  
77      protected void configurePreProcessors(MessageProcessorChainBuilder builder) throws MuleException
78      {
79          // Template method
80      }
81  
82      protected void configurePostProcessors(MessageProcessorChainBuilder builder) throws MuleException
83      {
84          // Template method
85      }
86  
87      @Override
88      public void setMessageProcessors(List<MessageProcessor> messageProcessors)
89      {
90          this.messageProcessors = messageProcessors;
91      }
92  
93      @Override
94      public List<MessageProcessor> getMessageProcessors()
95      {
96          return messageProcessors;
97      }
98  
99      @Override
100     public MessageSource getMessageSource()
101     {
102         return messageSource;
103     }
104 
105     @Override
106     public void setMessageSource(MessageSource messageSource)
107     {
108         this.messageSource = messageSource;
109     }
110 
111     @Override
112     public ProcessingStrategy getProcessingStrategy()
113     {
114         return processingStrategy;
115     }
116 
117     @Override
118     public void setProcessingStrategy(ProcessingStrategy processingStrategy)
119     {
120         this.processingStrategy = processingStrategy;
121     }
122     
123     @Override
124     protected void doInitialise() throws MuleException
125     {
126         super.doInitialise();
127 
128         pipeline = createPipeline();
129 
130         if (messageSource != null)
131         {
132             // Wrap chain to decouple lifecycle
133             messageSource.setListener(new AbstractInterceptingMessageProcessor()
134             {
135                 @Override
136                 public MuleEvent process(MuleEvent event) throws MuleException
137                 {
138                     return pipeline.process(event);
139                 }
140             });
141         }
142 
143         injectFlowConstructMuleContext(messageSource);
144         injectFlowConstructMuleContext(pipeline);
145         initialiseIfInitialisable(messageSource);
146         initialiseIfInitialisable(pipeline);
147     }
148 
149     protected void configureMessageProcessors(MessageProcessorChainBuilder builder) throws MuleException
150     {
151         getProcessingStrategy().configureProcessors(getMessageProcessors(),
152             new ProcessingStrategy.StageNameSource()
153             {
154                 @Override
155                 public String getName()
156                 {
157                     return AbstractPipeline.this.getName();
158                 }
159             }, builder, muleContext);
160     }
161     
162     @Override
163     protected void validateConstruct() throws FlowConstructInvalidException
164     {
165         super.validateConstruct();
166 
167         // Ensure that inbound endpoints are compatible with processing strategy.
168         boolean userConfiguredAsyncProcessingStrategy = processingStrategy instanceof AsynchronousProcessingStrategy
169                                                         && !(processingStrategy instanceof DefaultFlowProcessingStrategy);
170 
171         if (userConfiguredAsyncProcessingStrategy && !isMessageSourceCompatibleWithAsync(messageSource))
172         {
173             throw new FlowConstructInvalidException(
174                 CoreMessages.createStaticMessage("One of the inbound endpoint configured on this Flow is not compatible with an asynchronous processing strategy.  Either because it is request-response or has a transaction defined."),
175                 this);
176         }
177     }
178 
179     private boolean isMessageSourceCompatibleWithAsync(MessageSource source)
180     {
181         if (source instanceof InboundEndpoint)
182         {
183             InboundEndpoint endpoint = ((InboundEndpoint) source);
184             return !endpoint.getExchangePattern().hasResponse()
185                    && !endpoint.getTransactionConfig().isConfigured();
186         }
187         else if (messageSource instanceof CompositeMessageSource)
188         {
189             for (MessageSource childSource : ((CompositeMessageSource) source).getSources())
190             {
191                 if (!isMessageSourceCompatibleWithAsync(childSource))
192                 {
193                     return false;
194                 }
195             }
196             return true;
197         }
198         else
199         {
200             return true;
201         }
202     }
203 
204     @Override
205     protected void doStart() throws MuleException
206     {
207         super.doStart();
208         startIfStartable(pipeline);
209         startIfStartable(messageSource);
210     }
211 
212     @Override
213     protected void doStop() throws MuleException
214     {
215         stopIfStoppable(messageSource);
216         stopIfStoppable(pipeline);
217         super.doStop();
218     }
219 
220     @Override
221     protected void doDispose()
222     {
223         disposeIfDisposable(pipeline);
224         disposeIfDisposable(messageSource);
225         super.doDispose();
226     }
227 }