View Javadoc

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