View Javadoc

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