View Javadoc

1   /*
2    * $Id: AbstractLifecycleManager.java 20321 2010-11-24 15:21:24Z dfeist $
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  package org.mule.lifecycle;
11  
12  import org.mule.api.lifecycle.Disposable;
13  import org.mule.api.lifecycle.Initialisable;
14  import org.mule.api.lifecycle.LifecycleCallback;
15  import org.mule.api.lifecycle.LifecycleException;
16  import org.mule.api.lifecycle.LifecycleManager;
17  import org.mule.api.lifecycle.LifecycleState;
18  import org.mule.api.lifecycle.Startable;
19  import org.mule.api.lifecycle.Stoppable;
20  import org.mule.lifecycle.phases.NotInLifecyclePhase;
21  
22  import java.util.HashSet;
23  import java.util.LinkedHashSet;
24  import java.util.Set;
25  import java.util.TreeMap;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  
30  /**
31   * This is a base implementation of the {@link org.mule.api.lifecycle.LifecycleManager} interface and provides
32   * almost all the plumbing required to write a {@link org.mule.api.lifecycle.LifecycleManager} implementation.  This
33   * class handles the tracking ofg the phases, transition validation and checking state.
34   *
35   * @param <O> The object type being managed by this {@link org.mule.api.lifecycle.LifecycleManager}
36   * @since 3.0
37   */
38  public abstract class AbstractLifecycleManager<O> implements LifecycleManager
39  {
40  
41      /**
42       * logger used by this class
43       */
44      protected transient final Log logger = LogFactory.getLog(AbstractLifecycleManager.class);
45  
46      protected String lifecycleManagerId;
47      protected String currentPhase = NotInLifecyclePhase.PHASE_NAME;
48      protected String executingPhase = null;
49      private Set<String> directTransitions = new HashSet<String>();
50      protected Set<String> phaseNames = new LinkedHashSet<String>(4);
51      protected Set<String> completedPhases = new LinkedHashSet<String>(4);
52      protected O object;
53      protected LifecycleState state;
54  
55      private TreeMap<String, LifecycleCallback> callbacks = new TreeMap<String, LifecycleCallback>();
56  
57  
58      public AbstractLifecycleManager(String id, O object)
59      {
60          lifecycleManagerId = id;
61          this.object = object;
62          state = createLifecycleState();
63  
64          currentPhase = NotInLifecyclePhase.PHASE_NAME;
65          completedPhases.add(currentPhase);
66          registerTransitions();
67      }
68  
69      protected abstract void registerTransitions();
70  
71      public void registerLifecycleCallback(String phaseName, LifecycleCallback<O> callback)
72      {
73          callbacks.put(phaseName, callback);
74      }
75  
76      protected LifecycleState createLifecycleState()
77      {
78          return new DefaultLifecycleState(this);
79      }
80  
81      protected void addDirectTransition(String phase1, String phase2)
82      {
83          directTransitions.add(phase1 + "-" + phase2);
84          phaseNames.add(phase1);
85          phaseNames.add(phase2);
86      }
87  
88      public void checkPhase(String name) throws IllegalStateException
89      {
90          if (executingPhase != null)
91          {
92              if (name.equalsIgnoreCase(executingPhase))
93              {
94                  throw new IllegalStateException("Phase '" + name + "' is already currently being executed");
95              }
96              else
97              {
98                  throw new IllegalStateException("Cannot fire phase '" + name + "', currently executing lifecycle phase: " + executingPhase);
99              }
100         }
101 
102         if (name.equalsIgnoreCase(currentPhase))
103         {
104             throw new IllegalStateException("Already in lifecycle phase '" + name + "', cannot fire the same phase twice");
105         }
106 
107 
108         if (!phaseNames.contains(name))
109         {
110             throw new IllegalStateException("Phase does not exist: " + name);
111         }
112         else
113         {
114             if (isDirectTransition(name))
115             {
116                 return;
117             }
118 
119             throw new IllegalStateException("Lifecycle Manager '" + lifecycleManagerId + "' phase '" + currentPhase + "' does not support phase '" + name + "'");
120         }
121     }
122 
123     public O getLifecycleObject()
124     {
125         return object;
126     }
127 
128     public void fireLifecycle(String phase) throws LifecycleException
129     {
130         checkPhase(phase);
131         invokePhase(phase, object, callbacks.get(phase));
132     }
133 
134     protected void invokePhase(String phase, Object object, LifecycleCallback callback) throws LifecycleException
135     {
136         try
137         {
138             setExecutingPhase(phase);
139             callback.onTransition(phase, object);
140             setCurrentPhase(phase);
141         }
142         catch (LifecycleException e)
143         {
144             throw e;
145         }
146         catch (Exception e)
147         {
148             throw new LifecycleException(e, object);
149         }
150         finally
151         {
152             setExecutingPhase(null);
153         }
154 
155     }
156 
157     public boolean isDirectTransition(String destinationPhase)
158     {
159         return isDirectTransition(getCurrentPhase(), destinationPhase);
160     }
161 
162     protected boolean isDirectTransition(String startPhase, String endPhase)
163     {
164         String key = startPhase + "-" + endPhase;
165         return directTransitions.contains(key);
166     }
167 
168     public String getCurrentPhase()
169     {
170         return currentPhase;
171     }
172 
173     protected void setCurrentPhase(String currentPhase)
174     {
175         this.currentPhase = currentPhase;
176         completedPhases.add(currentPhase);
177         //remove irrelevant phases
178         if (currentPhase.equals(Stoppable.PHASE_NAME))
179         {
180             completedPhases.remove(Startable.PHASE_NAME);
181         }
182         else if (currentPhase.equals(Disposable.PHASE_NAME))
183         {
184             completedPhases.remove(Initialisable.PHASE_NAME);
185         }
186 
187         notifyTransition(currentPhase);
188 
189     }
190 
191     public String getExecutingPhase()
192     {
193         return executingPhase;
194     }
195 
196     protected void setExecutingPhase(String executingPhase)
197     {
198         this.executingPhase = executingPhase;
199     }
200 
201     /**
202      * Allows any for any state adjustments in sub classes.  For example, it may be necessary to remove a
203      * state from the 'completedPhases' collection once a transition occurs. This is only necessary for a Lifecycle
204      * Manager that introduces a new phase pair.
205      *
206      * @param currentPhase the currently completed phase
207      */
208     protected void notifyTransition(String currentPhase)
209     {
210         //do nothing
211     }
212 
213     public void reset()
214     {
215         completedPhases.clear();
216         setExecutingPhase(null);
217         setCurrentPhase(NOT_IN_LIFECYCLE_PHASE.getName());
218         completedPhases.add(getCurrentPhase());
219     }
220 
221     public boolean isPhaseComplete(String phaseName)
222     {
223         return completedPhases.contains(phaseName);
224     }
225 
226     public LifecycleState getState()
227     {
228         return state;
229     }
230 
231 
232 }