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.lifecycle.phases;
8   
9   import java.lang.reflect.Method;
10  import java.util.ArrayList;
11  import java.util.Collection;
12  import java.util.HashSet;
13  import java.util.LinkedHashSet;
14  import java.util.List;
15  import java.util.Set;
16  
17  import org.apache.commons.logging.Log;
18  import org.apache.commons.logging.LogFactory;
19  import org.mule.api.MuleContext;
20  import org.mule.api.context.MuleContextAware;
21  import org.mule.api.lifecycle.LifecycleException;
22  import org.mule.api.lifecycle.LifecyclePhase;
23  import org.mule.api.lifecycle.LifecycleStateEnabled;
24  import org.mule.config.ExceptionHelper;
25  import org.mule.config.i18n.CoreMessages;
26  import org.mule.lifecycle.LifecycleObject;
27  
28  /**
29   * Represents a configurable lifecycle phase. This is a default implementation of a
30   * 'generic phase' in that is can be configured to represnt any phase. Instances of
31   * this phase can then be registered with a
32   * {@link org.mule.api.lifecycle.LifecycleManager} and by used to enforce a lifecycle
33   * phase on an object. Usually, Lifecycle phases have a fixed configuration in which
34   * case a specialisation of this class should be created that initialises its
35   * configuration internally.
36   * <p>
37   * Note that this class and {@link org.mule.api.lifecycle.LifecycleTransitionResult}
38   * both make assumptions about the interfaces used - the return values and
39   * exceptions. These are, currently, that the return value is either void or
40   * {@link org.mule.api.lifecycle.LifecycleTransitionResult} and either 0 or 1
41   * exceptions can be thrown which are either {@link InstantiationException} or
42   * {@link org.mule.api.lifecycle.LifecycleException}.
43   * 
44   * @see org.mule.api.lifecycle.LifecyclePhase
45   */
46  public class DefaultLifecyclePhase implements LifecyclePhase, MuleContextAware
47  {
48      protected transient final Log logger = LogFactory.getLog(DefaultLifecyclePhase.class);
49      private Class<?> lifecycleClass;
50      private final Method lifecycleMethod;
51      private Set<LifecycleObject> orderedLifecycleObjects = new LinkedHashSet<LifecycleObject>(6);
52      private Class<?>[] ignorredObjectTypes;
53      private final String name;
54      private final String oppositeLifecyclePhase;
55      private Set<String> supportedPhases;
56      private MuleContext muleContext;
57  
58      public DefaultLifecyclePhase(String name, Class<?> lifecycleClass, String oppositeLifecyclePhase)
59      {
60          this.name = name;
61          this.lifecycleClass = lifecycleClass;
62          // DefaultLifecyclePhase interface only has one method
63          lifecycleMethod = lifecycleClass.getMethods()[0];
64          this.oppositeLifecyclePhase = oppositeLifecyclePhase;
65      }
66  
67      public void setMuleContext(MuleContext context)
68      {
69          this.muleContext = context;
70      }
71  
72      /**
73       * Subclasses can override this method to order <code>objects</code> before the
74       * lifecycle method is applied to them. This method does not apply any special
75       * ordering to <code>objects</code>.
76       * 
77       * @param objects
78       * @param lo
79       * @return List with ordered objects
80       */
81      protected List sortLifecycleInstances(Collection objects, LifecycleObject lo)
82      {
83          return new ArrayList(objects);
84      }
85  
86      public void addOrderedLifecycleObject(LifecycleObject lco)
87      {
88          orderedLifecycleObjects.add(lco);
89      }
90  
91      public void removeOrderedLifecycleObject(LifecycleObject lco)
92      {
93          orderedLifecycleObjects.remove(lco);
94      }
95  
96      protected boolean ignoreType(Class<?> type)
97      {
98          if (ignorredObjectTypes == null)
99          {
100             return false;
101         }
102         else
103         {
104             for (int i = 0; i < ignorredObjectTypes.length; i++)
105             {
106                 Class<?> ignorredObjectType = ignorredObjectTypes[i];
107                 if (ignorredObjectType.isAssignableFrom(type))
108                 {
109                     return true;
110                 }
111             }
112         }
113         return false;
114     }
115 
116     public Set<LifecycleObject> getOrderedLifecycleObjects()
117     {
118         return orderedLifecycleObjects;
119     }
120 
121     public void setOrderedLifecycleObjects(Set<LifecycleObject> orderedLifecycleObjects)
122     {
123         this.orderedLifecycleObjects = orderedLifecycleObjects;
124     }
125 
126     public Class<?>[] getIgnoredObjectTypes()
127     {
128         return ignorredObjectTypes;
129     }
130 
131     public void setIgnoredObjectTypes(Class<?>[] ignorredObjectTypes)
132     {
133         this.ignorredObjectTypes = ignorredObjectTypes;
134     }
135 
136     public Class<?> getLifecycleClass()
137     {
138         return lifecycleClass;
139     }
140 
141     public void setLifecycleClass(Class<?> lifecycleClass)
142     {
143         this.lifecycleClass = lifecycleClass;
144     }
145 
146     public String getName()
147     {
148         return name;
149     }
150 
151     public Set<String> getSupportedPhases()
152     {
153         return supportedPhases;
154     }
155 
156     public void setSupportedPhases(Set<String> supportedPhases)
157     {
158         this.supportedPhases = supportedPhases;
159     }
160 
161     public void registerSupportedPhase(String phase)
162     {
163         if (supportedPhases == null)
164         {
165             supportedPhases = new HashSet<String>();
166         }
167         supportedPhases.add(phase);
168     }
169 
170     public boolean isPhaseSupported(String phase)
171     {
172         if (getSupportedPhases() == null)
173         {
174             return false;
175         }
176         else
177         {
178             if (getSupportedPhases().contains(ALL_PHASES))
179             {
180                 return true;
181             }
182             else
183             {
184                 return getSupportedPhases().contains(phase);
185             }
186         }
187     }
188 
189     public void applyLifecycle(Object o) throws LifecycleException
190     {
191         if (o == null)
192         {
193             return;
194         }
195         if (ignoreType(o.getClass()))
196         {
197             return;
198         }
199         if (!getLifecycleClass().isAssignableFrom(o.getClass()))
200         {
201             return;
202         }
203         if (o instanceof LifecycleStateEnabled)
204         {
205             // If an object has its own lifecycle manager "LifecycleStateEnabled" it
206             // is possible that
207             // its state can be controlled outside the registry i.e. via JMX, double
208             // check here that we are
209             // not calling the same lifecycle twice
210             if (((LifecycleStateEnabled) o).getLifecycleState().isPhaseComplete(this.getName()))
211             {
212                 return;
213             }
214             else if (!((LifecycleStateEnabled) o).getLifecycleState().isValidTransition(this.getName()))
215             {
216                 return;
217             }
218         }
219         try
220         {
221             lifecycleMethod.invoke(o);
222         }
223         catch (final Exception e)
224         {
225             Throwable t = ExceptionHelper.unwrap(e);
226 
227             if (t instanceof LifecycleException)
228             {
229                 throw (LifecycleException) t;
230             }
231 
232             throw new LifecycleException(CoreMessages.failedToInvokeLifecycle(lifecycleMethod.getName(), o),
233                 t, this);
234         }
235     }
236 
237     public String getOppositeLifecyclePhase()
238     {
239         return oppositeLifecyclePhase;
240     }
241 }