View Javadoc

1   /*
2    * $Id: DefaultLifecyclePhase.java 11530 2008-04-08 12:49:14Z 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  package org.mule.lifecycle;
11  
12  import org.mule.RegistryContext;
13  import org.mule.api.MuleContext;
14  import org.mule.api.MuleException;
15  import org.mule.api.lifecycle.LifecycleException;
16  import org.mule.api.lifecycle.LifecyclePhase;
17  import org.mule.api.registry.Registry;
18  import org.mule.config.i18n.CoreMessages;
19  import org.mule.util.ClassUtils;
20  import org.mule.util.StringMessageUtils;
21  
22  import java.lang.reflect.Method;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.HashSet;
26  import java.util.Iterator;
27  import java.util.LinkedHashSet;
28  import java.util.List;
29  import java.util.Set;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  /**
35   * Represents a configurable lifecycle phase. This is a default implementation of a 'generic phase' in that is
36   * can be configured to represnt any phase. Instances of this phase can then be registered with a
37   * {@link org.mule.api.lifecycle.LifecycleManager} and by used to enforce a lifecycle phase on an object.
38   * Usually, Lifecycle phases have a fixed configuration in which case a specialisation of this class should be
39   * created that initialises its configuration internally.
40   *
41   * <p>Note that this class and {@link org.mule.api.lifecycle.LifecycleTransitionResult} both make assumptions about
42   * the interfaces used - the return values and exceptions.  These are, currently, that the return value is either
43   * void or {@link org.mule.api.lifecycle.LifecycleTransitionResult} and either 0 or 1 exceptions can be
44   * thrown which are either {@link InstantiationException} or {@link org.mule.api.lifecycle.LifecycleException}.
45   *
46   * @see org.mule.api.lifecycle.LifecyclePhase
47   */
48  public class DefaultLifecyclePhase implements LifecyclePhase
49  {
50      protected transient final Log logger = LogFactory.getLog(DefaultLifecyclePhase.class);
51      private Class lifecycleClass;
52      private Method lifecycleMethod;
53      private Set orderedLifecycleObjects = new LinkedHashSet(6);
54      private Class[] ignorredObjectTypes;
55      private String name;
56      private String oppositeLifecyclePhase;
57      private Set supportedPhases;
58      private int registryScope = Registry.SCOPE_REMOTE;
59  
60      public DefaultLifecyclePhase(String name, Class lifecycleClass, String oppositeLifecyclePhase)
61      {
62          this.name = name;
63          this.lifecycleClass = lifecycleClass;
64          //DefaultLifecyclePhase interface only has one method
65          lifecycleMethod = lifecycleClass.getMethods()[0];
66          this.oppositeLifecyclePhase = oppositeLifecyclePhase;
67      }
68  
69      public void fireLifecycle(MuleContext muleContext, String currentPhase) throws MuleException
70      {
71          if (logger.isDebugEnabled())
72          {
73              logger.debug("Attempting to fire lifecycle phase: " + getName());
74          }
75          if (currentPhase.equals(name))
76          {
77              if (logger.isDebugEnabled())
78              {
79                  logger.debug("Not firing, already in lifecycle phase: " + getName());
80              }
81              return;
82          }
83          if (!isPhaseSupported(currentPhase))
84          {
85              throw new IllegalStateException("Lifecycle phase: " + name + " does not support current phase: "
86                                              + currentPhase + ". Phases supported are: " + StringMessageUtils.toString(supportedPhases));
87          }
88  
89          // overlapping interfaces can cause duplicates
90          Set duplicates = new HashSet();
91  
92          for (Iterator iterator = orderedLifecycleObjects.iterator(); iterator.hasNext();)
93          {
94              LifecycleObject lo = (LifecycleObject) iterator.next();
95  
96              Collection lifecycleInstances = RegistryContext.getRegistry().lookupObjects(lo.getType(), getRegistryScope());
97              if (lifecycleInstances.size() == 0)
98              {
99                  continue;
100             }
101             List targets = this.sortLifecycleInstances(lifecycleInstances, lo);
102                         
103             lo.firePreNotification(muleContext);
104 
105             for (Iterator target = targets.iterator(); target.hasNext();)
106             {
107                 Object o = target.next();
108                 
109                 if (duplicates.contains(o))
110                 {
111                     target.remove();
112                 }
113                 else
114                 {
115                     if (logger.isDebugEnabled())
116                     {
117                         logger.debug("lifecycle phase: " + getName() + " for object: " + o);
118                     }
119                     this.applyLifecycle(o);
120                     target.remove();
121                     duplicates.add(o);
122                 }
123             }
124 
125             lo.firePostNotification(muleContext);
126         }
127     }
128 
129     /**
130      * Subclasses can override this method to order <code>objects</code> before
131      * the lifecycle method is applied to them.
132      * 
133      * This method does not apply any special ordering to <code>objects</code>.
134      * 
135      * @param objects
136      * @param lo
137      * @return List with ordered objects
138      */
139     protected List sortLifecycleInstances(Collection objects, LifecycleObject lo)
140     {
141         return new ArrayList(objects);
142     }
143 
144     public void addOrderedLifecycleObject(LifecycleObject lco)
145     {
146         orderedLifecycleObjects.add(lco);
147     }
148 
149     public void removeOrderedLifecycleObject(LifecycleObject lco)
150     {
151         orderedLifecycleObjects.remove(lco);
152     }
153 
154     protected boolean ignoreType(Class type)
155     {
156         if (ignorredObjectTypes == null)
157         {
158             return false;
159         }
160         else
161         {
162             for (int i = 0; i < ignorredObjectTypes.length; i++)
163             {
164                 Class ignorredObjectType = ignorredObjectTypes[i];
165                 if (ignorredObjectType.isAssignableFrom(type))
166                 {
167                     return true;
168                 }
169             }
170         }
171         return false;
172     }
173 
174     public Set getOrderedLifecycleObjects()
175     {
176         return orderedLifecycleObjects;
177     }
178 
179     public void setOrderedLifecycleObjects(Set orderedLifecycleObjects)
180     {
181         this.orderedLifecycleObjects = orderedLifecycleObjects;
182     }
183 
184     public Class[] getIgnoredObjectTypes()
185     {
186         return ignorredObjectTypes;
187     }
188 
189     public void setIgnoredObjectTypes(Class[] ignorredObjectTypes)
190     {
191         this.ignorredObjectTypes = ignorredObjectTypes;
192     }
193 
194     public Class getLifecycleClass()
195     {
196         return lifecycleClass;
197     }
198 
199     public void setLifecycleClass(Class lifecycleClass)
200     {
201         this.lifecycleClass = lifecycleClass;
202     }
203 
204     public String getName()
205     {
206         return name;
207     }
208 
209     public Set getSupportedPhases()
210     {
211         return supportedPhases;
212     }
213 
214     public void setSupportedPhases(Set supportedPhases)
215     {
216         this.supportedPhases = supportedPhases;
217     }
218 
219     public void registerSupportedPhase(String phase)
220     {
221         if (supportedPhases == null)
222         {
223             supportedPhases = new HashSet();
224         }
225         supportedPhases.add(phase);
226     }
227 
228     public boolean isPhaseSupported(String phase)
229     {
230         if (getSupportedPhases() == null)
231         {
232             return true;
233         }
234         else
235         {
236             if (getSupportedPhases().contains(ALL_PHASES))
237             {
238                 return true;
239             }
240             else
241             {
242                 return getSupportedPhases().contains(phase);
243             }
244         }
245     }
246 
247     public void applyLifecycle(Object o) throws LifecycleException
248     {
249         if (o == null)
250         {
251             return;
252         }
253         if (ignoreType(o.getClass()))
254         {
255             return;
256         }
257         if (!getLifecycleClass().isAssignableFrom(o.getClass()))
258         {
259             return;
260         }
261         try
262         {
263             lifecycleMethod.invoke(o, ClassUtils.NO_ARGS);
264         }
265         catch (Exception e)
266         {
267             throw new LifecycleException(CoreMessages.failedToInvokeLifecycle(lifecycleMethod.getName(), o), e, this);
268         }
269     }
270 
271     public int getRegistryScope()
272     {
273         return registryScope;
274     }
275 
276     public void setRegistryScope(int registryScope)
277     {
278         this.registryScope = registryScope;
279     }
280 
281     public String getOppositeLifecyclePhase()
282     {
283         return oppositeLifecyclePhase;
284     }
285 }
286 
287 
288 
289