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;
8   
9   import org.mule.api.MuleContext;
10  import org.mule.api.MuleException;
11  import org.mule.api.lifecycle.Disposable;
12  import org.mule.api.lifecycle.Initialisable;
13  import org.mule.api.lifecycle.LifecycleCallback;
14  import org.mule.api.lifecycle.LifecycleException;
15  import org.mule.api.lifecycle.LifecyclePhase;
16  import org.mule.api.lifecycle.RegistryLifecycleHelpers;
17  import org.mule.api.lifecycle.Startable;
18  import org.mule.api.lifecycle.Stoppable;
19  import org.mule.api.registry.Registry;
20  import org.mule.config.i18n.CoreMessages;
21  import org.mule.lifecycle.phases.ContainerManagedLifecyclePhase;
22  import org.mule.lifecycle.phases.MuleContextDisposePhase;
23  import org.mule.lifecycle.phases.MuleContextInitialisePhase;
24  import org.mule.lifecycle.phases.MuleContextStartPhase;
25  import org.mule.lifecycle.phases.MuleContextStopPhase;
26  import org.mule.lifecycle.phases.NotInLifecyclePhase;
27  import org.mule.registry.AbstractRegistryBroker;
28  
29  import java.util.Collection;
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.Iterator;
33  import java.util.LinkedList;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.Set;
37  import java.util.TreeMap;
38  
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  
42  
43  public class RegistryLifecycleManager extends AbstractLifecycleManager<Registry> implements RegistryLifecycleHelpers
44  {
45      protected Map<String, LifecyclePhase> phases = new HashMap<String, LifecyclePhase>();
46      protected TreeMap<String, LifecycleCallback> callbacks = new TreeMap<String, LifecycleCallback>();
47      protected MuleContext muleContext;
48  
49      public RegistryLifecycleManager(String id, Registry object, MuleContext muleContext)
50      {
51          super(id, object);
52          this.muleContext = muleContext;
53  
54          registerPhases();
55      }
56  
57      protected void registerPhases()
58      {
59          RegistryLifecycleCallback callback = new RegistryLifecycleCallback();
60  
61          registerPhase(NotInLifecyclePhase.PHASE_NAME, NOT_IN_LIFECYCLE_PHASE,
62              new EmptyLifecycleCallback<AbstractRegistryBroker>());
63          registerPhase(Initialisable.PHASE_NAME, new MuleContextInitialisePhase(), callback);
64          registerPhase(Startable.PHASE_NAME, new MuleContextStartPhase(),
65              new EmptyLifecycleCallback<AbstractRegistryBroker>());
66          registerPhase(Stoppable.PHASE_NAME, new MuleContextStopPhase(),
67              new EmptyLifecycleCallback<AbstractRegistryBroker>());
68          registerPhase(Disposable.PHASE_NAME, new MuleContextDisposePhase(), callback);
69      }
70  
71      public RegistryLifecycleManager(String id, Registry object, Map<String, LifecyclePhase> phases )
72      {
73          super(id, object);
74          RegistryLifecycleCallback callback = new RegistryLifecycleCallback();
75  
76          registerPhase(NotInLifecyclePhase.PHASE_NAME, NOT_IN_LIFECYCLE_PHASE, new LifecycleCallback(){
77              public void onTransition(String phaseName, Object object) throws MuleException
78              { }});
79  
80          for (Map.Entry<String, LifecyclePhase> entry : phases.entrySet())
81          {
82              registerPhase(entry.getKey(), entry.getValue(), callback);
83          }
84      }
85  
86      @Override
87      protected void registerTransitions()
88      {
89          addDirectTransition(NotInLifecyclePhase.PHASE_NAME, Initialisable.PHASE_NAME);
90          addDirectTransition(Initialisable.PHASE_NAME, Startable.PHASE_NAME);
91  
92          //start stop
93          addDirectTransition(Startable.PHASE_NAME, Stoppable.PHASE_NAME);
94          addDirectTransition(Stoppable.PHASE_NAME, Startable.PHASE_NAME);
95          //Dispose can be called from init or stopped
96          addDirectTransition(NotInLifecyclePhase.PHASE_NAME, Disposable.PHASE_NAME);
97          addDirectTransition(Initialisable.PHASE_NAME, Disposable.PHASE_NAME);
98          addDirectTransition(Stoppable.PHASE_NAME, Disposable.PHASE_NAME);
99  
100     }
101 
102     protected void registerPhase(String phaseName, LifecyclePhase phase)
103     {
104         phaseNames.add(phaseName);
105         callbacks.put(phaseName, new RegistryLifecycleCallback());
106         phases.put(phaseName, phase);
107     }
108 
109     protected void registerPhase(String phaseName, LifecyclePhase phase, LifecycleCallback callback)
110     {
111         phaseNames.add(phaseName);
112         callbacks.put(phaseName, callback);
113         phases.put(phaseName, phase);
114     }
115 
116     public void fireLifecycle(String destinationPhase) throws LifecycleException
117     {
118         checkPhase(destinationPhase);
119         if (isDirectTransition(destinationPhase))
120         {
121 
122             // transition to phase without going through other phases first
123             invokePhase(destinationPhase, object, callbacks.get(destinationPhase));
124         }
125         else
126         {
127             //Call all phases to including the destination phase
128             boolean start = false;
129             for (String phase : phaseNames)
130             {
131                 if (start)
132                 {
133                     invokePhase(phase, object, callbacks.get(phase));
134                     if (phase.equals(destinationPhase))
135                     {
136                         break;
137                     }
138                 }
139                 if (phase.equals(getCurrentPhase()))
140                 {
141                     start = true;
142                 }
143             }
144         }
145     }
146 
147     protected void invokePhase(String phase, Object object, LifecycleCallback callback) throws LifecycleException
148     {
149         try
150         {
151             setExecutingPhase(phase);
152             callback.onTransition(phase, object);
153             setCurrentPhase(phase);
154         }
155         catch (LifecycleException e)
156         {
157             throw e;
158         }
159         catch (MuleException e)
160         {
161             throw new LifecycleException(CoreMessages.failedToInvokeLifecycle(phase, object), e);
162         }
163         finally
164         {
165             setExecutingPhase(null);
166         }
167     }
168 
169 
170     //-------------------------------------------------------------------------------------------//
171     //-                     LIFECYCLE HELPER METHODS
172     //-------------------------------------------------------------------------------------------//
173 
174 
175     public void applyPhase(Object object, String fromPhase, String toPhase) throws LifecycleException
176     {
177         //TODO i18n
178         if(fromPhase == null || toPhase==null)
179         {
180             throw new IllegalArgumentException("toPhase and fromPhase must be null");
181         }
182         if(!phaseNames.contains(fromPhase))
183         {
184             throw new IllegalArgumentException("fromPhase '" + fromPhase + "' not a valid phase.");
185         }
186         if(!phaseNames.contains(toPhase))
187         {
188             throw new IllegalArgumentException("toPhase '" + fromPhase + "' not a valid phase.");
189         }
190         boolean start = false;
191         for (String phaseName : phaseNames)
192         {
193             if(start)
194             {
195                 phases.get(phaseName).applyLifecycle(object);
196             }
197             if(toPhase.equals(phaseName))
198             {
199                 break;
200             }
201             if(phaseName.equals(fromPhase))
202             {
203                 start = true;
204             }
205 
206         }
207     }
208 
209     public void applyCompletedPhases(Object object) throws LifecycleException
210     {
211         String lastPhase = NotInLifecyclePhase.PHASE_NAME;
212         for (String phase : completedPhases)
213         {
214             if(isDirectTransition(lastPhase, phase))
215             {
216                 LifecyclePhase lp = phases.get(phase);
217                 lp.applyLifecycle(object);
218                 lastPhase = phase;
219             }
220         }
221     }
222 
223     class RegistryLifecycleCallback implements LifecycleCallback<Object>
224     {
225         /**
226          * logger used by this class
227          */
228         protected transient final Log logger = LogFactory.getLog(RegistryLifecycleCallback.class);
229 
230         public void onTransition(String phaseName, Object object) throws MuleException
231         {
232             LifecyclePhase phase = phases.get(phaseName);
233 
234             if (logger.isDebugEnabled())
235             {
236                 logger.debug("Applying lifecycle phase: " + phase + " for registry: " + object.getClass().getSimpleName());
237             }
238 
239             if (phase instanceof ContainerManagedLifecyclePhase)
240             {
241                 phase.applyLifecycle(object);
242                 return;
243             }
244 
245             // overlapping interfaces can cause duplicates
246             Set<Object> duplicates = new HashSet<Object>();
247 
248             for (LifecycleObject lo : phase.getOrderedLifecycleObjects())
249             {
250                 // TODO Collection -> List API refactoring
251                 Collection<?> targetsObj = getLifecycleObject().lookupObjectsForLifecycle(lo.getType());
252                 List<Object> targets = new LinkedList<Object>(targetsObj);
253                 if (targets.size() == 0)
254                 {
255                     continue;
256                 }
257 
258                 lo.firePreNotification(muleContext);
259 
260                 for (Iterator<Object> target = targets.iterator(); target.hasNext();)
261                 {
262                     Object o = target.next();
263                     if (duplicates.contains(o))
264                     {
265                         target.remove();
266                     }
267                     else
268                     {
269                         if (logger.isDebugEnabled())
270                         {
271                             logger.debug("lifecycle phase: " + phase.getName() + " for object: " + o);
272                         }
273                         phase.applyLifecycle(o);
274                         target.remove();
275                         duplicates.add(o);
276                     }
277                 }
278 
279                 lo.firePostNotification(muleContext);
280             }
281         }
282     }
283 }