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