* the functionality they support) in order to provide a consistent mechanism
* to start and stop the component.
* <br>
- * The valid state transitions for components that support Lifecycle are:
+ * The valid state transitions for components that support {@link Lifecycle}
+ * are:
* <pre>
* init()
* NEW ->-- INITIALIZING
* | | | |
* | | \|/ auto auto start() |
* | | STOPPING_PREP ------>----- STOPPING ------>----- STOPPED ---->------
- * | | ^ | | ^
+ * | | ^ | | ^
+ * | | stop() | | | |
+ * | | -------------------------- | | |
* | | | auto | | |
- * | | |stop() MUST_DESTROY------<------- | |
+ * | | | MUST_DESTROY------<------- | |
* | | | | | |
* | | | |auto | |
* | | | destroy() \|/ destroy() | |
/**
- * Get the lifecycle listeners associated with this lifecycle. If this
- * Lifecycle has no listeners registered, a zero-length array is returned.
+ * Get the life cycle listeners associated with this life cycle. If this
+ * component has no listeners registered, a zero-length array is returned.
*/
public LifecycleListener[] findLifecycleListeners();
public void init() throws LifecycleException;
/**
- * Prepare for the beginning of active use of the public methods of this
- * component. This method should be called before any of the public
- * methods of this component are utilized. The following
- * {@link LifecycleEvent}s will be fired in the following order:
+ * Prepare for the beginning of active use of the public methods other than
+ * property getters/setters and life cycle methods of this component. This
+ * method should be called before any of the public methods other than
+ * property getters/setters and life cycle methods of this component are
+ * utilized. The following {@link LifecycleEvent}s will be fired in the
+ * following order:
* <ol>
* <li>BEFORE_START_EVENT: At the beginning of the method. It is as this
* point the state transitions to
* <li>START_EVENT: During the method once it is safe to call start() for
* any child components. It is at this point that the
* state transitions to {@link LifecycleState#STARTING}
- * and that the public methods may be used.</li>
+ * and that the public methods other than property
+ * getters/setters and life cycle methods may be
+ * used.</li>
* <li>AFTER_START_EVENT: At the end of the method, immediately before it
* returns. It is at this point that the state
* transitions to {@link LifecycleState#STARTED}.
/**
- * Gracefully terminate the active use of the public methods of this
- * component. Once the STOP_EVENT is fired, the public methods should not
- * be used. The following {@link LifecycleEvent}s will be fired in the
- * following order:
+ * Gracefully terminate the active use of the public methods other than
+ * property getters/setters and life cycle methods of this component. Once
+ * the STOP_EVENT is fired, the public methods other than property
+ * getters/setters and life cycle methods should not be used. The following
+ * {@link LifecycleEvent}s will be fired in the following order:
* <ol>
* <li>BEFORE_STOP_EVENT: At the beginning of the method. It is at this
* point that the state transitions to
* <li>STOP_EVENT: During the method once it is safe to call stop() for
* any child components. It is at this point that the
* state transitions to {@link LifecycleState#STOPPING}
- * and that the public methods may no longer be used.</li>
+ * and that the public methods other than property
+ * getters/setters and life cycle methods may no longer be
+ * used.</li>
* <li>AFTER_STOP_EVENT: At the end of the method, immediately before it
* returns. It is at this point that the state
* transitions to {@link LifecycleState#STOPPED}.
* </li>
* </ol>
*
+ * Note that if transitioning from {@link LifecycleState#FAILED} then the
+ * three events above will be fired but the component will transition
+ * directly from {@link LifecycleState#FAILED} to
+ * {@link LifecycleState#STOPPING}, bypassing
+ * {@link LifecycleState#STOPPING_PREP}
+ *
* @exception LifecycleException if this component detects a fatal error
* that needs to be reported
*/
DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
FAILED(false, null),
MUST_STOP(true, null),
- MUST_DESTROY(true, null);
+ MUST_DESTROY(false, null);
private final boolean available;
private final String lifecycleEvent;
}
/**
- * Is a component in this state available for use?
+ * May the public methods other than property getters/setters and lifecycle
+ * methods be called for a component in this state? It returns
+ * <code>true</code> for any component in any of the following states:
+ * <ul>
+ * <li>{@link #STARTING}</li>
+ * <li>{@link #STARTED}</li>
+ * <li>{@link #STOPPING_PREP}</li>
+ * <li>{@link #MUST_STOP}</li>
+ * </ul>
*/
public boolean isAvailable() {
return available;
invalidTransition(Lifecycle.BEFORE_STOP_EVENT);
}
- setStateInternal(LifecycleState.STOPPING_PREP, null, false);
+ if (state.equals(LifecycleState.FAILED)) {
+ // Don't transition to STOPPING_PREP as that would briefly mark the
+ // component as available but do ensure the BEFORE_STOP_EVENT is
+ // fired
+ fireLifecycleEvent(BEFORE_STOP_EVENT, null);
+ } else {
+ setStateInternal(LifecycleState.STOPPING_PREP, null, false);
+ }
try {
stopInternal();
// Any method can transition to failed
// startInternal() permits STARTING_PREP to STARTING
- // stopInternal() permits STOPPING_PREP to STOPPING
+ // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
+ // STOPPING
if (!(state == LifecycleState.FAILED ||
(this.state == LifecycleState.STARTING_PREP &&
state == LifecycleState.STARTING) ||
(this.state == LifecycleState.STOPPING_PREP &&
+ state == LifecycleState.STOPPING) ||
+ (this.state == LifecycleState.FAILED &&
state == LifecycleState.STOPPING))) {
// No other transition permitted
invalidTransition(state.name());