1 package org.sapia.soto.state; 2 3 import org.sapia.soto.Debug; 4 import org.sapia.soto.state.config.Globals; 5 6 import org.sapia.util.xml.confix.ConfigurationException; 7 import org.sapia.util.xml.confix.ObjectHandlerIF; 8 9 import java.util.Iterator ; 10 11 12 23 public class StateMachine implements ObjectHandlerIF { 24 private static final int TYPE_PRE = 0; 25 private static final int TYPE_POST = 1; 26 private static final int TYPE_ERR = 2; 27 private StaticContext _stmContext = new StaticContext(); 28 private boolean _init; 29 30 public StateMachine() { 31 } 32 33 40 public State getState(String id) { 41 StateHolder sh = (StateHolder) _stmContext.getStates().get(id); 42 43 if (sh == null) { 44 return null; 45 } 46 47 return sh.getState(); 48 } 49 50 56 public void addState(State state) throws ConfigurationException { 57 addStateHolder(new StateHolder(state)); 58 } 59 60 66 public void addModule(Module mod) throws ConfigurationException { 67 if (_init) { 68 throw new IllegalStateException ( 69 "Modules must be added prior to initialization"); 70 } 71 72 if (mod.getName() != null) { 73 if (_stmContext.getModules().get(mod.getName()) != null) { 74 throw new ConfigurationException("Module already exists for: " + 75 mod.getName()); 76 } 77 78 if (mod.getStateMachine(false) != null) { 79 mod.getStateMachine(false)._stmContext.setParent(this); 80 } 81 82 _stmContext.getModules().put(mod.getName(), mod); 83 } else { 84 if (mod.getStateMachine(false) != null) { 85 mod.getStateMachine(false)._stmContext.setParent(this); 86 } 87 88 _stmContext.getAnonymousModules().add(mod); 89 } 90 } 91 92 95 public void addGlobals(Globals gb) { 96 _stmContext._globals.merge(gb); 97 } 98 99 104 public void addStateExecListener(StateExecListener listener) { 105 _stmContext._listeners.add(listener); 106 } 107 108 117 public void merge(StateMachine machine) throws ConfigurationException { 118 Iterator itr = machine._stmContext._states.values().iterator(); 119 120 while (itr.hasNext()) { 121 addStateHolder((StateHolder) itr.next()); 122 } 123 124 itr = machine._stmContext._modules.values().iterator(); 125 126 while (itr.hasNext()) { 127 addModule((Module) itr.next()); 128 } 129 130 _stmContext._globals.merge(machine._stmContext._globals); 131 } 132 133 136 public void init() { 137 String id; 138 Iterator itr = _stmContext._states.keySet().iterator(); 139 StateHolder sh; 140 State st; 141 142 while (itr.hasNext()) { 143 id = (String ) itr.next(); 144 sh = (StateHolder) _stmContext._states.get(id); 145 st = sh.getState(); 146 st = _stmContext._globals.applySteps(st); 147 sh.setState(st); 148 sh.setVisible(_stmContext._globals.applyRestriction(st)); 149 } 150 151 itr = _stmContext._modules.values().iterator(); 152 153 Module mod; 154 155 while (itr.hasNext()) { 156 mod = (Module) itr.next(); 157 158 if (mod.getStateMachine(false) == null) { 159 throw new IllegalStateException ( 160 "State machine instance not specified for module: " + mod.getName()); 161 } 162 163 if (mod.isInheritGlobals() && 164 (mod.getStateMachine(false)._stmContext._globals != null)) { 165 mod.getStateMachine(false)._stmContext._globals.setParent(_stmContext._globals); 166 } 167 168 if (mod.isInheritModules()) { 169 mod.getStateMachine(false)._stmContext._inheritModules = true; 170 } 171 172 mod.getStateMachine(false).init(); 173 } 174 _stmContext.init(); 175 176 _init = true; 177 } 178 179 191 public Result execute(String stateId, Context ctx) 192 throws UnknownStateException, StateExecException { 193 return doExecute(stateId, null, ctx, true); 194 } 195 196 209 public Result execute(String stateId, String module, Context ctx) 210 throws UnknownStateException, StateExecException { 211 return doExecute(stateId, module, ctx, true); 212 } 213 214 StaticContext getStmContext() { 215 return _stmContext; 216 } 217 218 protected void addStateHolder(StateHolder sh) throws ConfigurationException { 219 if (sh.getState().getId() != null) { 220 if (_stmContext._states.get(sh.getState().getId()) != null) { 221 throw new ConfigurationException("State already exists for: " + 222 sh.getState().getId()); 223 } 224 225 _stmContext._states.put(sh.getState().getId(), sh); 226 } else { 227 throw new ConfigurationException("'id' attribute not specified on state"); 228 } 229 } 230 231 private Module getModule(String name) { 232 Module mod = (Module) _stmContext._modules.get(name); 233 234 if (_stmContext._inheritModules && (_stmContext._parent != null)) { 235 mod = _stmContext._parent.getModule(name); 236 } 237 238 return mod; 239 } 240 241 private Result doExecute(String stateId, String module, Context ctx, 242 boolean fromOutside) throws UnknownStateException, StateExecException { 243 if (!_init) { 244 throw new IllegalStateException ( 245 "State machine not initialized; call init() prior to using it."); 246 } 247 248 if (stateId == null) { 249 throw new IllegalArgumentException ("State id cannot be null"); 250 } 251 252 if (module != null) { 253 if (Debug.DEBUG) { 254 Debug.debug("Executing state in module: " + module); 255 } 256 257 Module mod = getModule(module); 258 259 if (mod == null) { 260 throw new IllegalArgumentException ("Module does not exist: " + module); 261 } 262 263 StateMachine stm = mod.getStateMachine(true); 264 265 return stm.doExecute(stateId, null, ctx, fromOutside); 266 } 267 268 Result rs = new Result(this, ctx); 269 rs.setNextStateId(stateId); 270 271 StateHolder sh; 272 State st; 273 int count = 0; 274 275 while ((rs.getNextStateId() != null) && !rs.isError() && !rs.isAborted()) { 276 sh = (StateHolder) _stmContext.getStateFor(rs.getNextStateId()); 277 278 if (sh == null) { 279 throw new UnknownStateException(rs.getNextStateId()); 280 } 281 282 st = sh.getState(); 283 284 if ((count == 0) && fromOutside && !sh.isVisible()) { 285 throw new StateAccessException("State '" + st.getId() + 286 "' cannot be executed by client application"); 287 } 288 289 rs.setCurrentStateId(rs.getNextStateId()); 290 rs.reset(); 291 notifyListeners(st, rs, TYPE_PRE); 292 293 if (Debug.DEBUG) { 294 Debug.debug("Executing: " + st.getId() + " (" + 295 st.getClass().getName() + ")"); 296 } 297 298 st.execute(rs); 299 300 if (rs.isError()) { 301 notifyListeners(st, rs, TYPE_ERR); 302 } else { 303 notifyListeners(st, rs, TYPE_POST); 304 } 305 306 count++; 307 } 308 309 if (rs.isError() && !rs.isErrorHandled()) { 310 if ((rs.getError().getThrowable() != null) && 311 rs.getError().getThrowable() instanceof StateExecException) { 312 throw (StateExecException) rs.getError().getThrowable(); 313 } 314 315 throw new StateExecException(rs.getError()); 316 } 317 318 return rs; 319 } 320 321 void execute(String stateId, String module, Result rs) 322 throws StateExecException { 323 doExecute(stateId, module, rs.getContext(), false); 324 } 325 326 private void notifyListeners(State f, Result st, int type) { 327 StateExecListener listener; 328 329 for (int i = 0; i < _stmContext._listeners.size(); i++) { 330 listener = (StateExecListener) _stmContext._listeners.get(i); 331 332 if (type == TYPE_PRE) { 333 listener.onPreExec(st, f.getId()); 334 } else if (type == TYPE_POST) { 335 listener.onPostExec(st, f.getId()); 336 } else { 337 listener.onError(st, f.getId(), st.getError()); 338 } 339 } 340 } 341 342 345 public void handleObject(String name, Object obj) 346 throws ConfigurationException { 347 if (obj instanceof State) { 348 State state = (State) obj; 349 addState(state); 350 } else if (obj instanceof Globals) { 351 _stmContext._globals.merge((Globals) obj); 352 } else if (obj instanceof Module) { 353 addModule((Module) obj); 354 } 355 } 356 } 357 | Popular Tags |