KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > gbean > runtime > GBeanInstanceState


1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.geronimo.gbean.runtime;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.apache.geronimo.gbean.AbstractName;
22 import org.apache.geronimo.kernel.DependencyManager;
23 import org.apache.geronimo.kernel.GBeanNotFoundException;
24 import org.apache.geronimo.kernel.Kernel;
25 import org.apache.geronimo.kernel.management.State;
26
27 import java.util.Iterator JavaDoc;
28 import java.util.Set JavaDoc;
29
30 /**
31  * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
32  */

33 public class GBeanInstanceState {
34     private static final Log log = LogFactory.getLog(GBeanInstanceState.class);
35
36     /**
37      * The GBeanInstance in which this server is registered.
38      */

39     private final GBeanInstance gbeanInstance;
40
41     /**
42      * The kernel in which this server is registered.
43      */

44     private final Kernel kernel;
45
46     /**
47      * The unique name of this service.
48      */

49     private final AbstractName abstractName;
50
51     /**
52      * The dependency manager
53      */

54     private final DependencyManager dependencyManager;
55
56     /**
57      * The broadcaster of lifecycle events
58      */

59     private final LifecycleBroadcaster lifecycleBroadcaster;
60
61     // This must be volatile otherwise getState must be synchronized which will result in deadlock as dependent
62
// objects check if each other are in one state or another (i.e., classic A calls B while B calls A)
63
private volatile State state = State.STOPPED;
64
65     GBeanInstanceState(AbstractName abstractName, Kernel kernel, DependencyManager dependencyManager, GBeanInstance gbeanInstance, LifecycleBroadcaster lifecycleBroadcaster) {
66         this.abstractName = abstractName;
67         this.kernel = kernel;
68         this.dependencyManager = dependencyManager;
69         this.gbeanInstance = gbeanInstance;
70         this.lifecycleBroadcaster = lifecycleBroadcaster;
71     }
72
73     /**
74      * Moves this MBean to the {@link org.apache.geronimo.kernel.management.State#STARTING} state and then attempts to move this MBean immediately
75      * to the {@link org.apache.geronimo.kernel.management.State#RUNNING} state.
76      * <p/>
77      * Note: This method cannot be called while the current thread holds a synchronized lock on this MBean,
78      * because this method sends JMX notifications. Sending a general notification from a synchronized block
79      * is a bad idea and therefore not allowed.
80      */

81     public final void start() {
82         assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
83
84         // Move to the starting state
85
State originalState;
86         synchronized (this) {
87             originalState = getStateInstance();
88             if (originalState == State.RUNNING) {
89                 return;
90             }
91             // only try to change states if we are not already starting
92
if (originalState != State.STARTING) {
93                 setStateInstance(State.STARTING);
94             }
95         }
96
97         // only fire a notification if we are not already starting
98
if (originalState != State.STARTING) {
99             lifecycleBroadcaster.fireStartingEvent();
100         }
101
102         attemptFullStart();
103     }
104
105     /**
106      * Starts this MBean and then attempts to start all of its start dependent children.
107      * <p/>
108      * Note: This method cannot be call while the current thread holds a synchronized lock on this MBean,
109      * because this method sends JMX notifications. Sending a general notification from a synchronized block
110      * is a bad idea and therefore not allowed.
111      */

112     public final void startRecursive() {
113         assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
114
115         State state = getStateInstance();
116         if (state != State.STOPPED && state != State.FAILED && state != State.RUNNING) {
117             // Cannot startRecursive while in the stopping state
118
// Dain: I don't think we can throw an exception here because there is no way for the caller
119
// to lock the instance and check the state before calling
120
return;
121         }
122
123         // get myself starting
124
start();
125
126         // startRecursive all of objects that depend on me
127
Set JavaDoc dependents = dependencyManager.getChildren(abstractName);
128         for (Iterator JavaDoc iterator = dependents.iterator(); iterator.hasNext();) {
129             AbstractName dependent = (AbstractName) iterator.next();
130             try {
131                 kernel.startRecursiveGBean(dependent);
132             } catch (GBeanNotFoundException e) {
133                 // this is ok the gbean died before we could start it
134
} catch (Exception JavaDoc e) {
135                 // there is something wrong with this gbean... skip it
136
}
137         }
138     }
139
140     /**
141      * Moves this MBean to the STOPPING state, calls stop on all start dependent children, and then attempt
142      * to move this MBean to the STOPPED state.
143      * <p/>
144      * Note: This method can not be call while the current thread holds a syncronized lock on this MBean,
145      * because this method sends JMX notifications. Sending a general notification from a synchronized block
146      * is a bad idea and therefore not allowed.
147      */

148     public final void stop() {
149         assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
150
151         // move to the stopping state
152
State originalState;
153         synchronized (this) {
154             originalState = getStateInstance();
155             if (originalState == State.STOPPED) {
156                 return;
157             }
158
159             // only try to change states if we are not already stopping
160
if (originalState != State.STOPPING) {
161                 setStateInstance(State.STOPPING);
162             }
163         }
164
165         // only fire a notification if we are not already stopping
166
if (originalState != State.STOPPING) {
167             lifecycleBroadcaster.fireStoppingEvent();
168         }
169
170         // Don't try to stop dependents from within a synchronized block... this should reduce deadlocks
171

172         // stop all of my dependent objects
173
Set JavaDoc dependents = dependencyManager.getChildren(abstractName);
174         for (Iterator JavaDoc iterator = dependents.iterator(); iterator.hasNext();) {
175             AbstractName child = (AbstractName) iterator.next();
176             try {
177                 log.trace("Checking if child is running: child=" + child);
178                 if (kernel.getGBeanState(child) == State.RUNNING_INDEX) {
179                     log.trace("Stopping child: child=" + child);
180                     kernel.stopGBean(child);
181                     log.trace("Stopped child: child=" + child);
182                 }
183             } catch (Exception JavaDoc ignore) {
184                 // not a big deal... did my best
185
}
186         }
187
188         attemptFullStop();
189     }
190
191     /**
192      * Moves this MBean to the FAILED state. There are no calls to dependent children, but they will be notified
193      * using standard J2EE management notification.
194      * <p/>
195      * Note: This method can not be call while the current thread holds a syncronized lock on this MBean,
196      * because this method sends JMX notifications. Sending a general notification from a synchronized block
197      * is a bad idea and therefore not allowed.
198      */

199     final void fail() {
200         assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
201
202         synchronized (this) {
203             State state = getStateInstance();
204             if (state == State.STOPPED || state == State.FAILED) {
205                 return;
206             }
207         }
208
209         try {
210             if (gbeanInstance.destroyInstance(false)) {
211                 // instance is not ready to destroyed... this is because another thread has
212
// already killed the gbean.
213
return;
214             }
215         } catch (Throwable JavaDoc e) {
216             log.warn("Problem in doFail", e);
217         }
218         setStateInstance(State.FAILED);
219         lifecycleBroadcaster.fireFailedEvent();
220     }
221
222     /**
223      * Attempts to bring the component into {@link org.apache.geronimo.kernel.management.State#RUNNING} state. If an Exception occurs while
224      * starting the component, the component will be failed.
225      * <p/>
226      * <p/>
227      * Note: Do not call this from within a synchronized block as it makes may send a JMX notification
228      */

229     void attemptFullStart() {
230         assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
231
232         synchronized (this) {
233             // if we are still trying to start and can start now... start
234
if (getStateInstance() != State.STARTING) {
235                 return;
236             }
237
238             // check if all of the gbeans we depend on are running
239
Set JavaDoc parents = dependencyManager.getParents(abstractName);
240             for (Iterator JavaDoc i = parents.iterator(); i.hasNext();) {
241                 AbstractName parent = (AbstractName) i.next();
242                 if (!kernel.isLoaded(parent)) {
243                     log.trace("Cannot run because parent is not registered: parent=" + parent);
244                     return;
245                 }
246                 try {
247                     log.trace("Checking if parent is running: parent=" + parent);
248                     if (kernel.getGBeanState(parent) != State.RUNNING_INDEX) {
249                         log.trace("Cannot run because parent is not running: parent=" + parent);
250                         return;
251                     }
252                     log.trace("Parent is running: parent=" + parent);
253                 } catch (GBeanNotFoundException e) {
254                     // depended on instance was removed bewteen the register check and the invoke
255
log.trace("Cannot run because parent is not registered: parent=" + parent);
256                     return;
257                 } catch (Exception JavaDoc e) {
258                     // problem getting the attribute, parent has most likely failed
259
log.trace("Cannot run because an error occurred while checking if parent is running: parent=" + parent);
260                     return;
261                 }
262             }
263         }
264
265         try {
266             // try to create the instance
267
if (!gbeanInstance.createInstance()) {
268                 // instance is not ready to start... this is normally caused by references
269
// not being available, but could be because someone already started the gbean.
270
// in another thread. The reference will log a debug message about why
271
// it could not start
272
return;
273             }
274         } catch (Throwable JavaDoc t) {
275             // oops there was a problem and the gbean failed
276
log.error("Error while starting; GBean is now in the FAILED state: abstractName=\"" + abstractName + "\"", t);
277             setStateInstance(State.FAILED);
278             lifecycleBroadcaster.fireFailedEvent();
279
280             if (t instanceof Exception JavaDoc) {
281                 // ignore - we only rethrow errors
282
return;
283             } else if (t instanceof Error JavaDoc) {
284                 throw (Error JavaDoc) t;
285             } else {
286                 throw new Error JavaDoc(t);
287             }
288         }
289
290         // started successfully... notify everyone else
291
setStateInstance(State.RUNNING);
292         lifecycleBroadcaster.fireRunningEvent();
293     }
294
295     /**
296      * Attempt to bring the component into the fully stopped state.
297      * If an exception occurs while stopping the component, the component will be failed.
298      * <p/>
299      * <p/>
300      * Note: Do not call this from within a synchronized block as it may send a JMX notification
301      */

302     void attemptFullStop() {
303         assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
304
305         // check if we are able to stop
306
synchronized (this) {
307             // if we are still trying to stop...
308
if (getStateInstance() != State.STOPPING) {
309                 return;
310             }
311
312             // check if all of the mbeans depending on us are stopped
313
Set JavaDoc children = dependencyManager.getChildren(abstractName);
314             for (Iterator JavaDoc i = children.iterator(); i.hasNext();) {
315                 AbstractName child = (AbstractName) i.next();
316                 if (kernel.isLoaded(child)) {
317                     try {
318                         log.trace("Checking if child is stopped: child=" + child);
319                         int state = kernel.getGBeanState(child);
320                         if (state == State.RUNNING_INDEX) {
321                             log.trace("Cannot stop because child is still running: child=" + child);
322                             return;
323                         }
324                     } catch (GBeanNotFoundException e) {
325                         // depended on instance was removed between the register check and the invoke
326
} catch (Exception JavaDoc e) {
327                         // problem getting the attribute, depended on bean has most likely failed
328
log.trace("Cannot run because an error occurred while checking if child is stopped: child=" + child);
329                         return;
330                     }
331                 }
332             }
333         }
334
335         // all is clear to stop... try to stop
336
try {
337             if (!gbeanInstance.destroyInstance(true)) {
338                 // instance is not ready to stop... this is because another thread has
339
// already stopped the gbean.
340
return;
341             }
342         } catch (Throwable JavaDoc t) {
343             log.error("Error while stopping; GBean is now in the FAILED state: abstractName=\"" + abstractName + "\"", t);
344             setStateInstance(State.FAILED);
345             lifecycleBroadcaster.fireFailedEvent();
346
347             if (t instanceof Exception JavaDoc) {
348                 // ignore - we only rethrow errors
349
return;
350             } else if (t instanceof Error JavaDoc) {
351                 throw (Error JavaDoc) t;
352             } else {
353                 throw new Error JavaDoc(t);
354             }
355         }
356
357         // we successfully stopped, notify everyone else
358
setStateInstance(State.STOPPED);
359         lifecycleBroadcaster.fireStoppedEvent();
360     }
361
362     public int getState() {
363         return state.toInt();
364     }
365
366     public final State getStateInstance() {
367         return state;
368     }
369
370     /**
371      * Set the Component state.
372      *
373      * @param newState the target state to transition
374      * @throws IllegalStateException Thrown if the transition is not supported by the J2EE Management lifecycle.
375      */

376     private synchronized void setStateInstance(State newState) throws IllegalStateException JavaDoc {
377         switch (state.toInt()) {
378             case State.STOPPED_INDEX:
379                 switch (newState.toInt()) {
380                     case State.STARTING_INDEX:
381                         break;
382                     case State.STOPPED_INDEX:
383                     case State.RUNNING_INDEX:
384                     case State.STOPPING_INDEX:
385                     case State.FAILED_INDEX:
386                         throw new IllegalStateException JavaDoc("Cannot transition to " + newState + " state from " + state);
387                 }
388                 break;
389
390             case State.STARTING_INDEX:
391                 switch (newState.toInt()) {
392                     case State.RUNNING_INDEX:
393                     case State.FAILED_INDEX:
394                     case State.STOPPING_INDEX:
395                         break;
396                     case State.STOPPED_INDEX:
397                     case State.STARTING_INDEX:
398                         throw new IllegalStateException JavaDoc("Cannot transition to " + newState + " state from " + state);
399                 }
400                 break;
401
402             case State.RUNNING_INDEX:
403                 switch (newState.toInt()) {
404                     case State.STOPPING_INDEX:
405                     case State.FAILED_INDEX:
406                         break;
407                     case State.STOPPED_INDEX:
408                     case State.STARTING_INDEX:
409                     case State.RUNNING_INDEX:
410                         throw new IllegalStateException JavaDoc("Cannot transition to " + newState + " state from " + state);
411                 }
412                 break;
413
414             case State.STOPPING_INDEX:
415                 switch (newState.toInt()) {
416                     case State.STOPPED_INDEX:
417                     case State.FAILED_INDEX:
418                         break;
419                     case State.STARTING_INDEX:
420                     case State.RUNNING_INDEX:
421                     case State.STOPPING_INDEX:
422                         throw new IllegalStateException JavaDoc("Cannot transition to " + newState + " state from " + state);
423                 }
424                 break;
425
426             case State.FAILED_INDEX:
427                 switch (newState.toInt()) {
428                     case State.STARTING_INDEX:
429                     case State.STOPPING_INDEX:
430                         break;
431                     case State.RUNNING_INDEX:
432                     case State.STOPPED_INDEX:
433                     case State.FAILED_INDEX:
434                         throw new IllegalStateException JavaDoc("Cannot transition to " + newState + " state from " + state);
435                 }
436                 break;
437         }
438         log.debug(toString() + " State changed from " + state + " to " + newState);
439         state = newState;
440     }
441
442     public String JavaDoc toString() {
443         return "GBeanInstanceState for: " + abstractName;
444     }
445
446 }
447
Popular Tags