View Javadoc

1   /*
2    * $Id: AbstractModel.java 10415 2008-01-21 10:46:37Z dirk.olmes $
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.impl.model;
12  
13  import org.mule.MuleManager;
14  import org.mule.config.i18n.CoreMessages;
15  import org.mule.impl.DefaultComponentExceptionStrategy;
16  import org.mule.impl.DefaultLifecycleAdapterFactory;
17  import org.mule.impl.ImmutableMuleDescriptor;
18  import org.mule.impl.MuleSession;
19  import org.mule.impl.internal.notifications.ModelNotification;
20  import org.mule.impl.model.resolvers.DynamicEntryPointResolver;
21  import org.mule.umo.UMOComponent;
22  import org.mule.umo.UMODescriptor;
23  import org.mule.umo.UMOException;
24  import org.mule.umo.UMOSession;
25  import org.mule.umo.lifecycle.Initialisable;
26  import org.mule.umo.lifecycle.InitialisationException;
27  import org.mule.umo.lifecycle.UMOLifecycleAdapterFactory;
28  import org.mule.umo.manager.UMOServerNotification;
29  import org.mule.umo.model.ModelException;
30  import org.mule.umo.model.UMOEntryPointResolver;
31  import org.mule.umo.model.UMOModel;
32  
33  import java.beans.ExceptionListener;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Map;
37  
38  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
39  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentSkipListMap;
40  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
41  
42  import org.apache.commons.logging.Log;
43  import org.apache.commons.logging.LogFactory;
44  
45  /**
46   * <code>MuleModel</code> is the default implementation of the UMOModel. The model
47   * encapsulates and manages the runtime behaviour of a Mule Server instance. It is
48   * responsible for maintaining the UMOs instances and their configuration.
49   */
50  public abstract class AbstractModel implements UMOModel
51  {
52      /**
53       * logger used by this class
54       */
55      protected transient Log logger = LogFactory.getLog(getClass());
56  
57      private String name;
58      private UMOEntryPointResolver entryPointResolver = new DynamicEntryPointResolver();
59      private UMOLifecycleAdapterFactory lifecycleAdapterFactory = new DefaultLifecycleAdapterFactory();
60  
61      private Map components = new ConcurrentSkipListMap();
62  
63      /**
64       * Collection for mule descriptors registered in this Manager
65       */
66      protected Map descriptors = new ConcurrentHashMap();
67  
68      private AtomicBoolean initialised = new AtomicBoolean(false);
69  
70      private AtomicBoolean started = new AtomicBoolean(false);
71  
72      private ExceptionListener exceptionListener = new DefaultComponentExceptionStrategy();
73  
74      /**
75       * Default constructor
76       */
77      public AbstractModel()
78      {
79          // Always set default entrypoint resolver, lifecycle and compoenent
80          // resolver and exceptionstrategy.
81          entryPointResolver = new DynamicEntryPointResolver();
82          lifecycleAdapterFactory = new DefaultLifecycleAdapterFactory();
83          components = new ConcurrentSkipListMap();
84          descriptors = new ConcurrentHashMap();
85          exceptionListener = new DefaultComponentExceptionStrategy();
86          name = "mule";
87      }
88  
89      /*
90       * (non-Javadoc)
91       * 
92       * @see org.mule.umo.UMOModel#getName()
93       */
94      public String getName()
95      {
96          return name;
97      }
98  
99      /*
100      * (non-Javadoc)
101      * 
102      * @see org.mule.umo.UMOModel#setName(java.lang.String)
103      */
104     public void setName(String name)
105     {
106         this.name = name;
107     }
108 
109     /*
110      * (non-Javadoc)
111      * 
112      * @see org.mule.umo.model.UMOModel#getEntryPointResolver()
113      */
114     public UMOEntryPointResolver getEntryPointResolver()
115     {
116         return entryPointResolver;
117     }
118 
119     /*
120      * (non-Javadoc)
121      * 
122      * @see org.mule.umo.model.UMOModel#setEntryPointResolver(org.mule.umo.model.UMOEntryPointResolver)
123      */
124     public void setEntryPointResolver(UMOEntryPointResolver entryPointResolver)
125     {
126         this.entryPointResolver = entryPointResolver;
127     }
128 
129     /*
130      * (non-Javadoc)
131      * 
132      * @see org.mule.umo.UMOModel#isUMORegistered(java.lang.String)
133      */
134     public boolean isComponentRegistered(String name)
135     {
136         return (components.get(name) != null);
137     }
138 
139     /*
140      * (non-Javadoc)
141      * 
142      * @see org.mule.umo.UMOModel#registerUMO(org.mule.umo.UMODescriptor)
143      */
144     public UMOComponent registerComponent(UMODescriptor descriptor) throws UMOException
145     {
146         if (descriptor == null)
147         {
148             throw new ModelException(CoreMessages.objectIsNull("UMO Descriptor"));
149         }
150 
151         // Set the es if one wasn't set in the configuration
152         if (descriptor.getExceptionListener() == null)
153         {
154             descriptor.setExceptionListener(exceptionListener);
155         }
156 
157         if (initialised.get())
158         {
159             descriptor.initialise();
160         }
161 
162         // detect duplicate descriptor declarations
163         if (descriptors.get(descriptor.getName()) != null)
164         {
165             throw new ModelException(CoreMessages.descriptorAlreadyExists(descriptor.getName()));
166         }
167 
168         UMOComponent component = (UMOComponent) components.get(descriptor.getName());
169 
170         if (component == null)
171         {
172             component = createComponent(descriptor);
173             descriptors.put(descriptor.getName(), descriptor);
174             components.put(descriptor.getName(), component);
175         }
176 
177         logger.debug("Added Mule UMO: " + descriptor.getName());
178 
179         if (initialised.get())
180         {
181             logger.info("Initialising component: " + descriptor.getName());
182             component.initialise();
183         }
184         if (started.get())
185         {
186             logger.info("Starting component: " + descriptor.getName());
187             component.start();
188         }
189         return component;
190     }
191 
192     public void unregisterComponent(UMODescriptor descriptor) throws UMOException
193     {
194         if (descriptor == null)
195         {
196             throw new ModelException(CoreMessages.objectIsNull("UMO Descriptor"));
197         }
198 
199         if (!isComponentRegistered(descriptor.getName()))
200         {
201             throw new ModelException(CoreMessages.componentNotRegistered(descriptor.getName()));
202         }
203         UMOComponent component = (UMOComponent) components.remove(descriptor.getName());
204 
205         if (component != null)
206         {
207             component.stop();
208             descriptors.remove(descriptor.getName());
209             component.dispose();
210             logger.info("The component: " + descriptor.getName() + " has been unregistered and disposing");
211         }
212     }
213 
214     /*
215      * (non-Javadoc)
216      * 
217      * @see org.mule.umo.model.UMOModel#getLifecycleAdapterFactory()
218      */
219     public UMOLifecycleAdapterFactory getLifecycleAdapterFactory()
220     {
221         return lifecycleAdapterFactory;
222     }
223 
224     /*
225      * (non-Javadoc)
226      * 
227      * @see org.mule.umo.model.UMOModel#setLifecycleAdapterFactory(org.mule.umo.lifecycle.UMOLifecycleAdapterFactory)
228      */
229     public void setLifecycleAdapterFactory(UMOLifecycleAdapterFactory lifecycleAdapterFactory)
230     {
231         this.lifecycleAdapterFactory = lifecycleAdapterFactory;
232     }
233 
234     /**
235      * Destroys any current components
236      */
237     public void dispose()
238     {
239         fireNotification(new ModelNotification(this, ModelNotification.MODEL_DISPOSING));
240 
241         for (Iterator i = components.values().iterator(); i.hasNext();)
242         {
243             UMOComponent component = (UMOComponent) i.next();
244             try
245             {
246                 component.dispose();
247                 logger.info(component + " has been destroyed successfully");
248             }
249             catch (Exception e1)
250             {
251                 // The component could not be disposed. Since we're in progress of shutting
252                 // down anyway, just log the error and continue
253                 logger.warn("Failed to dispose component: " + e1.getMessage());
254             }
255         }
256 
257         components.clear();
258         descriptors.clear();
259 
260         fireNotification(new ModelNotification(this, ModelNotification.MODEL_DISPOSED));
261     }
262 
263     /**
264      * Returns a valid component for the given Mule name
265      * 
266      * @param muleName the Name of the Mule for which the component is required
267      * @return a component for the specified name
268      */
269     public UMOSession getComponentSession(String muleName)
270     {
271         UMOComponent component = (UMOComponent) components.get(muleName);
272         if (component == null)
273         {
274             logger.warn("Component: " + muleName + " not found returning null session");
275             return null;
276         }
277         else
278         {
279             return new MuleSession(component);
280         }
281     }
282 
283     /**
284      * Stops any registered components
285      * 
286      * @throws UMOException if a Component fails tcomponent
287      */
288     public void stop() throws UMOException
289     {
290         fireNotification(new ModelNotification(this, ModelNotification.MODEL_STOPPING));
291         for (Iterator i = components.values().iterator(); i.hasNext();)
292         {
293             UMOComponent component = (UMOComponent) i.next();
294             component.stop();
295             logger.info("Component " + component + " has been stopped successfully");
296         }
297         started.set(false);
298         initialised.set(false);
299         fireNotification(new ModelNotification(this, ModelNotification.MODEL_STOPPED));
300     }
301 
302     /**
303      * Starts all registered components
304      * 
305      * @throws UMOException if any of the components fail to start
306      */
307     public void start() throws UMOException
308     {
309         if (!initialised.get())
310         {
311             initialise();
312         }
313 
314         if (!started.get())
315         {
316             fireNotification(new ModelNotification(this, ModelNotification.MODEL_STARTING));
317 
318             for (Iterator i = components.values().iterator(); i.hasNext();)
319             {
320                 AbstractComponent component = (AbstractComponent) i.next();
321 
322                 if (component.getDescriptor().getInitialState().equals(
323                     ImmutableMuleDescriptor.INITIAL_STATE_STARTED))
324                 {
325                     component.start();
326                     logger.info("Component " + component + " has been started successfully");
327                 }
328                 else if (component.getDescriptor().getInitialState().equals(
329                     ImmutableMuleDescriptor.INITIAL_STATE_PAUSED))
330                 {
331                     component.start(true);
332                     logger.info("Component " + component
333                                 + " has been started and paused (initial state = 'paused')");
334                 }
335                 else
336                 {
337                     logger.info("Component " + component
338                                 + " has not been started (initial state = 'stopped')");
339                 }
340             }
341             started.set(true);
342             fireNotification(new ModelNotification(this, ModelNotification.MODEL_STARTED));
343         }
344         else
345         {
346             logger.debug("Model already started");
347         }
348     }
349 
350     /**
351      * Starts a single Mule Component. This can be useful when stopping and starting
352      * some Mule UMOs while letting others continue
353      * 
354      * @param name the name of the Mule UMO to start
355      * @throws UMOException if the MuleUMO is not registered or the component failed
356      *             to start
357      */
358     public void startComponent(String name) throws UMOException
359     {
360         UMOComponent component = (UMOComponent) components.get(name);
361         if (component == null)
362         {
363             throw new ModelException(CoreMessages.componentNotRegistered(name));
364         }
365         else
366         {
367             component.start();
368             logger.info("Mule " + component.toString() + " has been started successfully");
369         }
370     }
371 
372     /**
373      * Stops a single Mule Component. This can be useful when stopping and starting
374      * some Mule UMOs while letting others continue.
375      * 
376      * @param name the name of the Mule UMO to stop
377      * @throws UMOException if the MuleUMO is not registered
378      */
379     public void stopComponent(String name) throws UMOException
380     {
381         UMOComponent component = (UMOComponent) components.get(name);
382         if (component == null)
383         {
384             throw new ModelException(CoreMessages.componentNotRegistered(name));
385         }
386         else
387         {
388             component.stop();
389             logger.info("mule " + name + " has been stopped successfully");
390         }
391     }
392 
393     /**
394      * Pauses event processing for a single Mule Component. Unlike stopComponent(), a
395      * paused component will still consume messages from the underlying transport,
396      * but those messages will be queued until the component is resumed. <p/> In
397      * order to persist these queued messages you can set the 'recoverableMode'
398      * property on the Muleconfiguration to true. this causes all internal queues to
399      * store their state.
400      * 
401      * @param name the name of the Mule UMO to stop
402      * @throws org.mule.umo.UMOException if the MuleUMO is not registered or the
403      *             component failed to pause.
404      * @see org.mule.config.MuleConfiguration
405      */
406     public void pauseComponent(String name) throws UMOException
407     {
408         UMOComponent component = (UMOComponent) components.get(name);
409 
410         if (component != null)
411         {
412             component.pause();
413             logger.info("Mule Component " + name + " has been paused successfully");
414         }
415         else
416         {
417             throw new ModelException(CoreMessages.componentNotRegistered(name));
418         }
419     }
420 
421     /**
422      * Resumes a single Mule Component that has been paused. If the component is not
423      * paused nothing is executed.
424      * 
425      * @param name the name of the Mule UMO to resume
426      * @throws org.mule.umo.UMOException if the MuleUMO is not registered or the
427      *             component failed to resume
428      */
429     public void resumeComponent(String name) throws UMOException
430     {
431         UMOComponent component = (UMOComponent) components.get(name);
432 
433         if (component != null)
434         {
435             component.resume();
436             logger.info("Mule Component " + name + " has been resumed successfully");
437         }
438         else
439         {
440             throw new ModelException(CoreMessages.componentNotRegistered(name));
441         }
442     }
443 
444     public void setComponents(List descriptors) throws UMOException
445     {
446         for (Iterator iterator = descriptors.iterator(); iterator.hasNext();)
447         {
448             registerComponent((UMODescriptor) iterator.next());
449         }
450     }
451 
452     public void initialise() throws InitialisationException
453     {
454         if (!initialised.get())
455         {
456             fireNotification(new ModelNotification(this, ModelNotification.MODEL_INITIALISING));
457 
458             if (exceptionListener instanceof Initialisable)
459             {
460                 ((Initialisable) exceptionListener).initialise();
461             }
462             UMOComponent component = null;
463             for (Iterator i = components.values().iterator(); i.hasNext();)
464             {
465                 component = (UMOComponent) i.next();
466                 component.initialise();
467 
468                 logger.info("Component " + component.getDescriptor().getName()
469                             + " has been started successfully");
470             }
471             initialised.set(true);
472             fireNotification(new ModelNotification(this, ModelNotification.MODEL_INITIALISED));
473         }
474         else
475         {
476             logger.debug("Model already initialised");
477         }
478     }
479 
480     public ExceptionListener getExceptionListener()
481     {
482         return exceptionListener;
483     }
484 
485     public void setExceptionListener(ExceptionListener exceptionListener)
486     {
487         this.exceptionListener = exceptionListener;
488     }
489 
490     public UMODescriptor getDescriptor(String name)
491     {
492         return (UMODescriptor) descriptors.get(name);
493     }
494 
495     public UMOComponent getComponent(String name)
496     {
497         return (UMOComponent) components.get(name);
498     }
499 
500     /**
501      * Gets an iterator of all component names registered in the model
502      * 
503      * @return an iterator of all component names
504      */
505     public Iterator getComponentNames()
506     {
507         return components.keySet().iterator();
508     }
509 
510     void fireNotification(UMOServerNotification notification)
511     {
512         MuleManager.getInstance().fireNotification(notification);
513     }
514 
515     protected abstract UMOComponent createComponent(UMODescriptor descriptor);
516 }