View Javadoc

1   /*
2    * $Id: AbstractComponent.java 12247 2008-07-07 21:25:01Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.OptimizedRequestContext;
14  import org.mule.api.DefaultMuleException;
15  import org.mule.api.MuleEvent;
16  import org.mule.api.MuleException;
17  import org.mule.api.MuleMessage;
18  import org.mule.api.component.Component;
19  import org.mule.api.context.notification.ServerNotificationHandler;
20  import org.mule.api.endpoint.InboundEndpoint;
21  import org.mule.api.lifecycle.DisposeException;
22  import org.mule.api.lifecycle.InitialisationException;
23  import org.mule.api.service.Service;
24  import org.mule.api.service.ServiceException;
25  import org.mule.config.i18n.CoreMessages;
26  import org.mule.config.i18n.MessageFactory;
27  import org.mule.context.notification.ComponentMessageNotification;
28  import org.mule.context.notification.OptimisedNotificationHandler;
29  import org.mule.management.stats.ComponentStatistics;
30  
31  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  /**
37   * Abstract {@link Component} to be used by all {@link Component} implementations.
38   */
39  public abstract class AbstractComponent implements Component
40  {
41  
42      /**
43       * logger used by this class
44       */
45      protected final Log logger = LogFactory.getLog(this.getClass());
46  
47      protected Service service;
48      protected ComponentStatistics statistics = null;
49      protected final AtomicBoolean started = new AtomicBoolean(false);
50      protected final AtomicBoolean stopping = new AtomicBoolean(false);
51      protected final AtomicBoolean initialised = new AtomicBoolean(false);
52      protected final AtomicBoolean disposing = new AtomicBoolean(false);
53      protected final AtomicBoolean disposed = new AtomicBoolean(false);
54      protected ServerNotificationHandler notificationHandler;
55  
56      public AbstractComponent()
57      {
58          statistics = new ComponentStatistics();
59      }
60  
61      public MuleMessage onCall(MuleEvent event) throws MuleException
62      {
63          // Ensure we have event in ThreadLocal
64          OptimizedRequestContext.unsafeSetEvent(event);
65  
66          if (logger.isTraceEnabled())
67          {
68              logger.trace("Invoking " + this.getClass().getName() + "component for service " + service.getName());
69          }
70  
71          // Do some checks: i) check component is not disposed, ii) that it is started
72          // and iii) that the event's endpoint is an inbound endpoint.
73          checkDisposed();
74          if (!(event.getEndpoint() instanceof InboundEndpoint))
75          {
76              throw new IllegalStateException(
77                      "Unable to process outbound event, components only process incoming events.");
78          }
79          if (stopping.get() || !started.get())
80          {
81              throw new DefaultMuleException(CoreMessages.componentIsStopped(service.getName()));
82          }
83  
84          // Invoke component implementation and gather statistics
85          try
86          {
87  
88              fireComponentNotification(event.getMessage(), ComponentMessageNotification.COMPONENT_PRE_INVOKE);
89  
90              long startTime = 0;
91              if (statistics.isEnabled())
92              {
93                  startTime = System.currentTimeMillis();
94              }
95  
96              MuleMessage result = doOnCall(event);
97  
98              if (statistics.isEnabled())
99              {
100                 statistics.addExecutionTime(System.currentTimeMillis() - startTime);
101             }
102 
103             fireComponentNotification(result, ComponentMessageNotification.COMPONENT_POST_INVOKE);
104 
105             return result;
106         }
107         catch (MuleException me)
108         {
109             throw me;
110         }
111         catch (Exception e)
112         {
113             throw new ServiceException(CoreMessages.failedToInvoke(this.toString()), event.getMessage(), service, e);
114         }
115     }
116 
117     protected abstract MuleMessage doOnCall(MuleEvent event) throws Exception;
118 
119     public String toString()
120     {
121         return this.getClass().getName() + " component for: " + service.toString();
122     }
123 
124     public void release()
125     {
126         // nothing to do
127     }
128 
129     public ComponentStatistics getStatistics()
130     {
131         return statistics;
132     }
133 
134     public void setService(Service service)
135     {
136         this.service = service;
137     }
138 
139     public Service getService()
140     {
141         return service;
142     }
143 
144     public final void initialise() throws InitialisationException
145     {
146         if (!initialised.get())
147         {
148             if (logger.isInfoEnabled())
149             {
150                 logger.info("Initialising: " + this);
151             }
152             if (service == null)
153             {
154                 throw new InitialisationException(
155                         MessageFactory.createStaticMessage("Component has not been initialized properly, no service."),
156                         this);
157             }
158             doInitialise();
159             initialised.set(true);
160         }
161     }
162 
163     protected void doInitialise() throws InitialisationException
164     {
165         // Default implementation is no-op
166     }
167 
168     public void dispose()
169     {
170         disposing.set(true);
171         try
172         {
173             if (started.get())
174             {
175                 stop();
176             }
177         }
178         catch (MuleException e)
179         {
180             logger.error(CoreMessages.failedToStop(toString()));
181         }
182         try
183         {
184             doDispose();
185         }
186         catch (Exception e)
187         {
188             logger.warn(CoreMessages.failedToDispose(toString()), e);
189         }
190         finally
191         {
192             disposed.set(true);
193             disposing.set(false);
194             initialised.set(false);
195         }
196     }
197 
198     protected void doDispose()
199     {
200         // Default implementation is no-op
201     }
202 
203     public void stop() throws MuleException
204     {
205         // If component is already disposed then ignore, don't fails, as stop() might
206         // get called by service after spring has called disposed etc.
207         if (!disposed.get() && started.get() && !stopping.get())
208         {
209             stopping.set(true);
210             if (logger.isInfoEnabled())
211             {
212                 logger.info("Stopping: " + this);
213             }
214             doStop();
215             started.set(false);
216             stopping.set(false);
217         }
218     }
219 
220     protected void doStart() throws MuleException
221     {
222         // Default implementation is no-op
223     }
224 
225     public void start() throws MuleException
226     {
227         checkDisposed();
228         if (!started.get())
229         {
230             if (logger.isInfoEnabled())
231             {
232                 logger.info("Starting: " + this);
233             }
234             notificationHandler = new OptimisedNotificationHandler(service.getMuleContext()
235                 .getNotificationManager(), ComponentMessageNotification.class);
236             doStart();
237             started.set(true);
238         }
239     }
240 
241     protected void doStop() throws MuleException
242     {
243         // Default implementation is no-op
244     }
245 
246     protected void checkDisposed() throws DisposeException
247     {
248         if (disposed.get())
249         {
250             throw new DisposeException(CoreMessages.createStaticMessage("Cannot use a disposed component"), this);
251         }
252     }
253 
254     protected void fireComponentNotification(MuleMessage message, int action)
255     {
256         if (notificationHandler.isNotificationEnabled(ComponentMessageNotification.class))
257         {
258             notificationHandler.fireNotification(new ComponentMessageNotification(message, this, action));
259         }
260     }
261 
262 }