View Javadoc

1   /*
2    * $Id: AbstractComponent.java 19944 2010-10-15 15:59:52Z aperepel $
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.component;
12  
13  import org.mule.DefaultMuleEvent;
14  import org.mule.DefaultMuleMessage;
15  import org.mule.OptimizedRequestContext;
16  import org.mule.VoidResult;
17  import org.mule.api.MuleContext;
18  import org.mule.api.MuleEvent;
19  import org.mule.api.MuleException;
20  import org.mule.api.MuleMessage;
21  import org.mule.api.component.Component;
22  import org.mule.api.construct.FlowConstruct;
23  import org.mule.api.context.MuleContextAware;
24  import org.mule.api.context.notification.ServerNotificationHandler;
25  import org.mule.api.interceptor.Interceptor;
26  import org.mule.api.lifecycle.Initialisable;
27  import org.mule.api.lifecycle.InitialisationException;
28  import org.mule.api.lifecycle.Lifecycle;
29  import org.mule.api.lifecycle.LifecycleException;
30  import org.mule.api.processor.MessageProcessor;
31  import org.mule.api.processor.MessageProcessorChain;
32  import org.mule.api.transformer.Transformer;
33  import org.mule.config.i18n.CoreMessages;
34  import org.mule.config.i18n.MessageFactory;
35  import org.mule.context.notification.ComponentMessageNotification;
36  import org.mule.context.notification.OptimisedNotificationHandler;
37  import org.mule.management.stats.ComponentStatistics;
38  import org.mule.processor.chain.DefaultMessageProcessorChainBuilder;
39  import org.mule.transformer.TransformerTemplate;
40  import org.mule.transport.NullPayload;
41  
42  import java.util.ArrayList;
43  import java.util.Collections;
44  import java.util.List;
45  
46  import org.apache.commons.logging.Log;
47  import org.apache.commons.logging.LogFactory;
48  
49  /**
50   * Abstract {@link Component} to be used by all {@link Component} implementations.
51   */
52  public abstract class AbstractComponent implements Component, MuleContextAware, Lifecycle
53  {
54  
55      /**
56       * logger used by this class
57       */
58      protected final Log logger = LogFactory.getLog(this.getClass());
59  
60      protected FlowConstruct flowConstruct;
61      protected ComponentStatistics statistics = null;
62      protected ServerNotificationHandler notificationHandler;
63      protected List<Interceptor> interceptors = new ArrayList<Interceptor>();
64      protected MessageProcessorChain interceptorChain;
65      protected MuleContext muleContext;
66  
67      public void setMuleContext(MuleContext context)
68      {
69          this.muleContext = context;
70      }
71  
72      public List<Interceptor> getInterceptors()
73      {
74          return interceptors;
75      }
76  
77      public void setInterceptors(List<Interceptor> interceptors)
78      {
79          this.interceptors = interceptors;
80      }
81  
82      public AbstractComponent()
83      {
84          statistics = new ComponentStatistics();
85      }
86  
87      private MuleEvent invokeInternal(MuleEvent event) throws MuleException
88      {
89          // Ensure we have event in ThreadLocal
90          OptimizedRequestContext.unsafeSetEvent(event);
91  
92          if (logger.isTraceEnabled())
93          {
94              logger.trace(String.format("Invoking %s component for service %s",
95                                         this.getClass().getName(), flowConstruct.getName()));
96          }
97  
98          if (!flowConstruct.getLifecycleState().isStarted() || flowConstruct.getLifecycleState().isStopping())
99          {
100             throw new LifecycleException(CoreMessages.isStopped(flowConstruct.getName()), this);
101         }
102 
103         // Invoke component implementation and gather statistics
104         try
105         {
106             fireComponentNotification(event.getMessage(), ComponentMessageNotification.COMPONENT_PRE_INVOKE);
107 
108             long startTime = 0;
109             if (statistics.isEnabled())
110             {
111                 startTime = System.currentTimeMillis();
112             }
113 
114             Object result = doInvoke(event);
115 
116             if (statistics.isEnabled())
117             {
118                 statistics.addExecutionTime(System.currentTimeMillis() - startTime);
119             }
120 
121             MuleEvent resultEvent = createResultEvent(event, result);
122             // Components only have access to the original event, so propogate the stop further processing 
123             resultEvent.setStopFurtherProcessing(event.isStopFurtherProcessing());
124             fireComponentNotification(resultEvent.getMessage(), ComponentMessageNotification.COMPONENT_POST_INVOKE);
125 
126             return resultEvent;
127         }
128         catch (MuleException me)
129         {
130             throw me;
131         }
132         catch (Exception e)
133         {
134             throw new ComponentException(CoreMessages.failedToInvoke(this.toString()), event,
135                                          this, e);
136         }
137     }
138 
139     public MuleEvent process(MuleEvent event) throws MuleException
140     {
141         if (interceptorChain == null)
142         {
143             return invokeInternal(event);
144         }
145         else
146         {
147             return interceptorChain.process(event);
148         }
149     }
150 
151     protected MuleEvent createResultEvent(MuleEvent event, Object result) throws MuleException
152     {
153         if (result instanceof MuleMessage)
154         {
155             return new DefaultMuleEvent((MuleMessage) result, event);
156         }
157         else if (result instanceof VoidResult)
158         {
159             return event;
160         }
161         else if (result != null)
162         {
163             event.getMessage().applyTransformers(
164                     event, Collections.<Transformer>singletonList(new TransformerTemplate(
165                     new TransformerTemplate.OverwitePayloadCallback(result))));
166             return event;
167         }
168         else
169         {
170             return new DefaultMuleEvent(new DefaultMuleMessage(NullPayload.getInstance(), muleContext), event);
171         }
172     }
173 
174     protected abstract Object doInvoke(MuleEvent event) throws Exception;
175 
176     @Override
177     public String toString()
178     {
179         StringBuilder buf = new StringBuilder(this.getClass().getName());
180 
181         if (flowConstruct != null)
182         {
183             buf.append(" component for: ").append(flowConstruct.toString());
184         }
185         else
186         {
187             buf.append(" no component");
188         }
189 
190         return buf.toString();
191     }
192 
193     public void release()
194     {
195         // nothing to do
196     }
197 
198     public ComponentStatistics getStatistics()
199     {
200         return statistics;
201     }
202 
203     public void setFlowConstruct(FlowConstruct flowConstruct)
204     {
205         this.flowConstruct = flowConstruct;
206         //lifecycleState = service.getLifecycleManager().getState();
207     }
208 
209     public FlowConstruct getFlowConstruct()
210     {
211         return flowConstruct;
212     }
213 
214     public final void initialise() throws InitialisationException
215     {
216         if (logger.isInfoEnabled())
217         {
218             logger.info("Initialising: " + this);
219         }
220         if (flowConstruct == null)
221         {
222             throw new InitialisationException(
223                     MessageFactory.createStaticMessage("Component has not been initialized properly, no service."),
224                     this);
225         }
226 
227         DefaultMessageProcessorChainBuilder chainBuilder = new DefaultMessageProcessorChainBuilder(flowConstruct);
228         for (Interceptor interceptor : interceptors)
229         {
230             chainBuilder.chain(interceptor);
231         }
232         chainBuilder.chain(new MessageProcessor()
233         {
234             public MuleEvent process(MuleEvent event) throws MuleException
235             {
236                 return invokeInternal(event);
237             }
238         });
239 
240         try
241         {
242             interceptorChain = chainBuilder.build();
243             if (interceptorChain instanceof Initialisable)
244             {
245                 ((Initialisable) interceptorChain).initialise();
246             }
247         }
248         catch (MuleException e)
249         {
250             throw new InitialisationException(e, this);
251         }
252 
253         doInitialise();
254     }
255 
256     protected void doInitialise() throws InitialisationException
257     {
258         // Default implementation is no-op
259     }
260 
261     public void dispose()
262     {
263         if (flowConstruct.getLifecycleState().isDisposed())
264         {
265             return;
266         }
267 
268         try
269         {
270             // TODO is this needed, doesn't the service manage this?
271             if (flowConstruct.getLifecycleState().isStarted())
272             {
273                 stop();
274             }
275         }
276         catch (MuleException e)
277         {
278             logger.error(CoreMessages.failedToStop(toString()));
279         }
280         try
281         {
282             doDispose();
283 
284         }
285         catch (Exception e)
286         {
287             logger.warn(CoreMessages.failedToDispose(toString()), e);
288         }
289     }
290 
291     protected void doDispose()
292     {
293         // Default implementation is no-op
294     }
295 
296     public void stop() throws MuleException
297     {
298         if (flowConstruct.getLifecycleState().isStopped())
299         {
300             return;
301         }
302         if (logger.isInfoEnabled())
303         {
304             logger.info("Stopping: " + this);
305         }
306         doStop();
307     }
308 
309     protected void doStart() throws MuleException
310     {
311         // Default implementation is no-op
312     }
313 
314     public void start() throws MuleException
315     {
316         if (flowConstruct.getLifecycleState().isStarted())
317         {
318             return;
319         }
320 
321         if (logger.isInfoEnabled())
322         {
323             logger.info("Starting: " + this);
324         }
325         notificationHandler = new OptimisedNotificationHandler(muleContext.getNotificationManager(),
326                                                                ComponentMessageNotification.class);
327         doStart();
328     }
329 
330     protected void doStop() throws MuleException
331     {
332         // Default implementation is no-op
333     }
334 
335     protected void fireComponentNotification(MuleMessage message, int action)
336     {
337         if (notificationHandler != null && notificationHandler.isNotificationEnabled(ComponentMessageNotification.class))
338         {
339             notificationHandler.fireNotification(new ComponentMessageNotification(message, this, flowConstruct, action));
340         }
341     }
342 
343 }