001: /*
002: * $Id: EngineStateMachine.java,v 1.12 2007/03/15 17:08:41 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.server;
008:
009: import org.xins.common.MandatoryArgumentChecker;
010:
011: /**
012: * State machine for the XINS server engine.
013: *
014: * @version $Revision: 1.12 $ $Date: 2007/03/15 17:08:41 $
015: * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
016: */
017: final class EngineStateMachine {
018:
019: /**
020: * Lock for the <code>_state</code> field. This object must be locked on
021: * before _state may be read or changed.
022: */
023: private final Object _stateLock;
024:
025: /**
026: * The current state.
027: */
028: private EngineState _state;
029:
030: /**
031: * Constructs a new <code>EngineStateMachine</code> object. Initially the
032: * state will be {@link EngineState#INITIAL}.
033: */
034: EngineStateMachine() {
035: _stateLock = new Object();
036: _state = EngineState.INITIAL;
037: }
038:
039: /**
040: * Gets the current state.
041: *
042: * @return
043: * the current state, cannot be <code>null</code>.
044: */
045: EngineState getState() {
046: synchronized (_stateLock) {
047: return _state;
048: }
049: }
050:
051: /**
052: * Changes the current state.
053: *
054: * <p>If the state change is considered invalid, then an
055: * {@link IllegalStateException} is thrown.
056: *
057: * @param newState
058: * the new state, cannot be <code>null</code>.
059: *
060: * @throws IllegalArgumentException
061: * if <code>newState == null</code>.
062: *
063: * @throws IllegalStateException
064: * if the state change is considered invalid.
065: */
066: void setState(EngineState newState)
067: throws IllegalArgumentException, IllegalStateException {
068:
069: // Check preconditions
070: MandatoryArgumentChecker.check("newState", newState);
071:
072: synchronized (_stateLock) {
073:
074: // Remember the current state
075: EngineState oldState = _state;
076:
077: // Determine name of current and new state
078: String oldStateName = (oldState == null) ? null : oldState
079: .getName();
080: String newStateName = newState.getName();
081:
082: // Short-circuit if the current equals the new state
083: if (oldState == newState) {
084: return;
085:
086: // Always allow changing state to DISPOSING
087: } else if (oldState != EngineState.DISPOSING
088: && newState == EngineState.DISPOSING) {
089:
090: // The first state change should be to bootstrap the framework
091: } else if (oldState == EngineState.INITIAL
092: && newState == EngineState.BOOTSTRAPPING_FRAMEWORK) {
093:
094: // Bootstrapping the framework may fail
095: } else if (oldState == EngineState.BOOTSTRAPPING_FRAMEWORK
096: && newState == EngineState.FRAMEWORK_BOOTSTRAP_FAILED) {
097:
098: // Bootstrapping the framework can be retried
099: } else if (oldState == EngineState.FRAMEWORK_BOOTSTRAP_FAILED
100: && newState == EngineState.BOOTSTRAPPING_FRAMEWORK) {
101:
102: // Bootstrapping the framework may succeed, in which case the API
103: // will be constructed
104: } else if (oldState == EngineState.BOOTSTRAPPING_FRAMEWORK
105: && newState == EngineState.CONSTRUCTING_API) {
106:
107: // Construction of API may fail
108: } else if (oldState == EngineState.CONSTRUCTING_API
109: && newState == EngineState.API_CONSTRUCTION_FAILED) {
110:
111: // API construction can be retried
112: } else if (oldState == EngineState.API_CONSTRUCTION_FAILED
113: && newState == EngineState.CONSTRUCTING_API) {
114:
115: // Construction of API may succeed, in which case the API is
116: // bootstrapped
117: } else if (oldState == EngineState.CONSTRUCTING_API
118: && newState == EngineState.BOOTSTRAPPING_API) {
119:
120: // Bootstrapping the API may fail
121: } else if (oldState == EngineState.BOOTSTRAPPING_API
122: && newState == EngineState.API_BOOTSTRAP_FAILED) {
123:
124: // Bootstrapping the API can be retried
125: } else if (oldState == EngineState.API_BOOTSTRAP_FAILED
126: && newState == EngineState.BOOTSTRAPPING_API) {
127:
128: // If bootstrapping the API succeeds, then the next step is either to
129: // determine the watch interval...
130: } else if (oldState == EngineState.BOOTSTRAPPING_API
131: && newState == EngineState.INITIALIZING_API) {
132:
133: // ...or to skip that and start initializing the API
134: } else if (oldState == EngineState.BOOTSTRAPPING_API
135: && newState == EngineState.INITIALIZING_API) {
136:
137: // API initialization may fail
138: } else if (oldState == EngineState.INITIALIZING_API
139: && newState == EngineState.API_INITIALIZATION_FAILED) {
140:
141: // API initialization may be retried, but then the interval is
142: // determined first
143: } else if (oldState == EngineState.API_INITIALIZATION_FAILED
144: && newState == EngineState.INITIALIZING_API) {
145:
146: // API initialization may succeed, in which case the engine is ready
147: } else if (oldState == EngineState.INITIALIZING_API
148: && newState == EngineState.READY) {
149:
150: // While the servet is ready, the watch interval may be redetermined,
151: // which is the first step in reinitialization
152: } else if (oldState == EngineState.READY
153: && newState == EngineState.INITIALIZING_API) {
154:
155: // After disposal the state changes to the final disposed state
156: } else if (oldState == EngineState.DISPOSING
157: && newState == EngineState.DISPOSED) {
158:
159: // Otherwise the state change is not allowed, fail!
160: } else {
161:
162: // Log error
163: Log.log_3101(oldStateName, newStateName);
164:
165: // Throw exception
166: String error = "The state " + oldStateName
167: + " cannot be followed by the state "
168: + newStateName + '.';
169: throw new IllegalStateException(error);
170: }
171:
172: // Perform the state change
173: _state = newState;
174: Log.log_3100(oldStateName, newStateName);
175: }
176: }
177: }
|