1
2
3
4
5
6
7 package org.mule.construct;
8
9 import org.mule.api.MuleContext;
10 import org.mule.api.MuleEvent;
11 import org.mule.api.MuleException;
12 import org.mule.api.config.ThreadingProfile;
13 import org.mule.api.construct.FlowConstruct;
14 import org.mule.api.construct.FlowConstructAware;
15 import org.mule.api.construct.FlowConstructInvalidException;
16 import org.mule.api.context.MuleContextAware;
17 import org.mule.api.exception.MessagingExceptionHandler;
18 import org.mule.api.lifecycle.Disposable;
19 import org.mule.api.lifecycle.Initialisable;
20 import org.mule.api.lifecycle.InitialisationException;
21 import org.mule.api.lifecycle.Lifecycle;
22 import org.mule.api.lifecycle.LifecycleCallback;
23 import org.mule.api.lifecycle.LifecycleException;
24 import org.mule.api.lifecycle.LifecycleState;
25 import org.mule.api.lifecycle.Startable;
26 import org.mule.api.lifecycle.Stoppable;
27 import org.mule.api.processor.MessageProcessor;
28 import org.mule.api.processor.MessageProcessorBuilder;
29 import org.mule.api.processor.MessageProcessorChain;
30 import org.mule.api.processor.MessageProcessorChainBuilder;
31 import org.mule.api.routing.MessageInfoMapping;
32 import org.mule.api.source.MessageSource;
33 import org.mule.config.i18n.CoreMessages;
34 import org.mule.exception.DefaultServiceExceptionStrategy;
35 import org.mule.lifecycle.EmptyLifecycleCallback;
36 import org.mule.management.stats.FlowConstructStatistics;
37 import org.mule.processor.AbstractFilteringMessageProcessor;
38 import org.mule.processor.AbstractInterceptingMessageProcessor;
39 import org.mule.processor.chain.DefaultMessageProcessorChainBuilder;
40 import org.mule.routing.MuleMessageInfoMapping;
41 import org.mule.util.ClassUtils;
42
43 import java.beans.ExceptionListener;
44
45 import org.apache.commons.logging.Log;
46 import org.apache.commons.logging.LogFactory;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public abstract class AbstractFlowConstruct implements FlowConstruct, Lifecycle
69 {
70 protected transient Log logger = LogFactory.getLog(getClass());
71
72 protected String name;
73 protected MessageSource messageSource;
74 protected MessageProcessorChain messageProcessorChain;
75 protected MessagingExceptionHandler exceptionListener;
76 protected final FlowConstructLifecycleManager lifecycleManager;
77 protected final MuleContext muleContext;
78 protected FlowConstructStatistics statistics;
79 protected MessageInfoMapping messageInfoMapping = new MuleMessageInfoMapping();
80 protected ThreadingProfile threadingProfile;
81 private boolean canProcessMessage = false;
82
83
84
85
86 public static final String INITIAL_STATE_STOPPED = "stopped";
87 public static final String INITIAL_STATE_STARTED = "started";
88
89
90
91
92
93 protected String initialState = INITIAL_STATE_STARTED;
94
95 public AbstractFlowConstruct(String name, MuleContext muleContext)
96 {
97 this.muleContext = muleContext;
98 this.name = name;
99 this.lifecycleManager = new FlowConstructLifecycleManager(this, muleContext);
100 this.exceptionListener = new DefaultServiceExceptionStrategy(muleContext);
101 }
102
103 public final void initialise() throws InitialisationException
104 {
105 try
106 {
107 lifecycleManager.fireInitialisePhase(new LifecycleCallback<FlowConstruct>()
108 {
109 public void onTransition(String phaseName, FlowConstruct object) throws MuleException
110 {
111 createMessageProcessor();
112
113 if (messageSource != null)
114 {
115
116 messageSource.setListener(new AbstractInterceptingMessageProcessor()
117 {
118 public MuleEvent process(MuleEvent event) throws MuleException
119 {
120 return messageProcessorChain.process(event);
121 }
122 });
123 }
124
125 injectFlowConstructMuleContext(messageSource);
126 injectFlowConstructMuleContext(messageProcessorChain);
127 injectFlowConstructMuleContext(exceptionListener);
128 initialiseIfInitialisable(messageSource);
129 initialiseIfInitialisable(messageProcessorChain);
130 initialiseIfInitialisable(exceptionListener);
131
132 doInitialise();
133
134 validateConstruct();
135 }
136 });
137
138 }
139 catch (InitialisationException e)
140 {
141 throw e;
142 }
143 catch (MuleException e)
144 {
145 throw new InitialisationException(e, this);
146 }
147 }
148
149 public final void start() throws MuleException
150 {
151
152 if(!isStopped() && initialState.equals(INITIAL_STATE_STOPPED))
153 {
154 lifecycleManager.fireStartPhase(new EmptyLifecycleCallback<FlowConstruct>());
155 lifecycleManager.fireStopPhase(new EmptyLifecycleCallback<FlowConstruct>());
156
157 logger.info("Flow " + name + " has not been started (initial state = 'stopped')");
158 return;
159 }
160
161 lifecycleManager.fireStartPhase(new LifecycleCallback<FlowConstruct>()
162 {
163 public void onTransition(String phaseName, FlowConstruct object) throws MuleException
164 {
165 startIfStartable(messageProcessorChain);
166 startIfStartable(exceptionListener);
167 canProcessMessage = true;
168 startIfStartable(messageSource);
169 doStart();
170 }
171 });
172 }
173
174 public final void stop() throws MuleException
175 {
176 lifecycleManager.fireStopPhase(new LifecycleCallback<FlowConstruct>()
177 {
178 public void onTransition(String phaseName, FlowConstruct object) throws MuleException
179 {
180 try
181 {
182 stopIfStoppable(messageSource);
183 }
184 finally
185 {
186 canProcessMessage = false;
187 }
188 stopIfStoppable(messageProcessorChain);
189 stopIfStoppable(exceptionListener);
190 doStop();
191 }
192 });
193 }
194
195 public final void dispose()
196 {
197 try
198 {
199 if (isStarted())
200 {
201 stop();
202 }
203
204 lifecycleManager.fireDisposePhase(new LifecycleCallback<FlowConstruct>()
205 {
206 public void onTransition(String phaseName, FlowConstruct object) throws MuleException
207 {
208 disposeIfDisposable(messageProcessorChain);
209 disposeIfDisposable(exceptionListener);
210 disposeIfDisposable(messageSource);
211 doDispose();
212 }
213 });
214 }
215 catch (MuleException e)
216 {
217 logger.error("Failed to stop service: " + name, e);
218 }
219 }
220
221 public ThreadingProfile getThreadingProfile()
222 {
223 return threadingProfile;
224 }
225
226 public boolean isStarted()
227 {
228 return lifecycleManager.getState().isStarted();
229 }
230
231 public boolean isStopped()
232 {
233 return lifecycleManager.getState().isStopped();
234 }
235
236 public boolean isStopping()
237 {
238 return lifecycleManager.getState().isStopping();
239 }
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255 protected void createMessageProcessor() throws MuleException
256 {
257 DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder(this);
258 builder.setName("'" + getName() + "' processor chain");
259 configureMessageProcessors(builder);
260 messageProcessorChain = builder.build();
261 }
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277 protected abstract void configureMessageProcessors(MessageProcessorChainBuilder builder) throws MuleException;
278
279 public String getName()
280 {
281 return name;
282 }
283
284 public MessagingExceptionHandler getExceptionListener()
285 {
286 return exceptionListener;
287 }
288
289 public void setExceptionListener(MessagingExceptionHandler exceptionListener)
290 {
291 this.exceptionListener = exceptionListener;
292 }
293
294 public String getInitialState()
295 {
296 return initialState;
297 }
298
299 public void setInitialState(String initialState)
300 {
301 this.initialState = initialState;
302 }
303
304 public LifecycleState getLifecycleState()
305 {
306 return lifecycleManager.getState();
307 }
308
309 public MuleContext getMuleContext()
310 {
311 return muleContext;
312 }
313
314 public MessageSource getMessageSource()
315 {
316 return messageSource;
317 }
318
319 public void setMessageSource(MessageSource messageSource)
320 {
321 this.messageSource = messageSource;
322 }
323
324 public FlowConstructStatistics getStatistics()
325 {
326 return statistics;
327 }
328
329 public MessageInfoMapping getMessageInfoMapping()
330 {
331 return messageInfoMapping;
332 }
333
334 public void setMessageInfoMapping(MessageInfoMapping messageInfoMapping)
335 {
336 this.messageInfoMapping = messageInfoMapping;
337 }
338
339 protected void doInitialise() throws InitialisationException
340 {
341 int threadPoolSize = threadingProfile == null ? 0 : threadingProfile.getMaxThreadsActive();
342 statistics = new FlowConstructStatistics(getConstructType(), name, threadPoolSize);
343 statistics.setEnabled(muleContext.getStatistics().isEnabled());
344 muleContext.getStatistics().add(statistics);
345 }
346
347 protected void doStart() throws MuleException
348 {
349
350 }
351
352 protected void doStop() throws MuleException
353 {
354
355 }
356
357 protected void doDispose()
358 {
359 muleContext.getStatistics().remove(statistics);
360 }
361
362
363
364
365
366
367
368 protected void validateConstruct() throws FlowConstructInvalidException
369 {
370
371 }
372
373 protected void injectFlowConstructMuleContext(Object candidate)
374 {
375 if (candidate instanceof FlowConstructAware)
376 {
377 ((FlowConstructAware) candidate).setFlowConstruct(this);
378 }
379 if (candidate instanceof MuleContextAware)
380 {
381 ((MuleContextAware) candidate).setMuleContext(muleContext);
382 }
383 }
384
385 @Override
386 public String toString()
387 {
388 return String.format("%s{%s}", ClassUtils.getSimpleName(this.getClass()), getName());
389 }
390
391 protected void initialiseIfInitialisable(Object candidate) throws InitialisationException
392 {
393 if (candidate instanceof Initialisable)
394 {
395 ((Initialisable) candidate).initialise();
396 }
397 }
398
399 protected void startIfStartable(Object candidate) throws MuleException
400 {
401 if (candidate instanceof Startable)
402 {
403 ((Startable) candidate).start();
404 }
405 }
406
407 protected void stopIfStoppable(Object candidate) throws MuleException
408 {
409 if (candidate instanceof Stoppable)
410 {
411 ((Stoppable) candidate).stop();
412 }
413 }
414
415 protected void disposeIfDisposable(Object candidate)
416 {
417 if (candidate instanceof Disposable)
418 {
419 ((Disposable) candidate).dispose();
420 }
421 }
422
423 public MessageProcessorChain getMessageProcessorChain()
424 {
425 return this.messageProcessorChain;
426 }
427
428
429
430
431 public abstract String getConstructType();
432
433 public class ProcessIfPipelineStartedMessageProcessor extends AbstractFilteringMessageProcessor
434 {
435
436 @Override
437 protected boolean accept(MuleEvent event)
438 {
439 return canProcessMessage;
440 }
441
442 @Override
443 protected MuleEvent handleUnaccepted(MuleEvent event) throws LifecycleException
444 {
445 throw new LifecycleException(CoreMessages.isStopped(getName()), event.getMessage());
446 }
447 }
448 }