@SuppressWarnings("unchecked") @Test public void testSimpleFSM() throws TooBusyException, RetryException { final Foo stateful = new Foo(); Action<Foo> actionA = mock(Action.class); Action<Foo> actionB = mock(Action.class); String eventA = "eventA"; String eventB = "eventB"; State<Foo> stateA = new StateImpl<Foo>("stateA"); State<Foo> stateB = new StateImpl<Foo>("stateB"); State<Foo> stateC = new StateImpl<Foo>("stateC", true); stateA.addTransition(eventA, stateB, actionA); stateB.addTransition(eventB, stateC, actionB); List<State<Foo>> states = new LinkedList<State<Foo>>(); states.add(stateA); states.add(stateB); states.add(stateC); Persister<Foo> persister = new MemoryPersisterImpl<Foo>(stateful, states, stateA); FSM<Foo> fsm = new FSM<Foo>("SimpleFSM", persister); Foo arg = new Foo(); State<Foo> current = fsm.onEvent(stateful, eventA, arg); assertEquals(stateB, current); assertFalse(current.isEndState()); verify(actionA).execute(stateful, eventA, arg); verify(actionB, never()).execute(stateful, eventA, arg); reset(actionA); current = fsm.onEvent(stateful, eventA, arg); assertEquals(stateB, current); assertFalse(current.isEndState()); verify(actionA, never()).execute(stateful, eventA, arg); verify(actionB, never()).execute(stateful, eventA, arg); current = fsm.onEvent(stateful, eventB, arg); assertEquals(stateC, current); assertTrue(current.isEndState()); verify(actionA, never()).execute(stateful, eventB, arg); verify(actionB).execute(stateful, eventB, arg); }
public State<T> onEvent(T stateful, String event, Object ... args) throws TooBusyException { int attempts = 0; while(this.retryAttempts == -1 || attempts < this.retryAttempts) { try { State<T> current = this.getCurrentState(stateful); Transition<T> transition = this.getTransition(event, current); if (transition != null) { current = this.transition(stateful, current, event, transition, args); } else { if (logger.isDebugEnabled()) logger.debug("{}({})::{}({})->{}/noop", this.name, stateful.getClass().getSimpleName(), current.getName(), event, current.getName()); if (current.isBlocking()) { this.setCurrent(stateful, current, current); throw new WaitAndRetryException(this.retryInterval); } } return current; } catch(RetryException re) { logger.warn("{}({})::Retrying event", this.name, stateful); if (WaitAndRetryException.class.isInstance(re)) { try { Thread.sleep(((WaitAndRetryException)re).getWait()); } catch(InterruptedException ie) { throw new RuntimeException(ie); } } attempts++; } } logger.error("{}({})::Unable to process event", this.name, stateful); throw new TooBusyException(); }
FSM { public State<T> onEvent(T stateful, String event, Object ... args) throws TooBusyException { int attempts = 0; while(this.retryAttempts == -1 || attempts < this.retryAttempts) { try { State<T> current = this.getCurrentState(stateful); Transition<T> transition = this.getTransition(event, current); if (transition != null) { current = this.transition(stateful, current, event, transition, args); } else { if (logger.isDebugEnabled()) logger.debug("{}({})::{}({})->{}/noop", this.name, stateful.getClass().getSimpleName(), current.getName(), event, current.getName()); if (current.isBlocking()) { this.setCurrent(stateful, current, current); throw new WaitAndRetryException(this.retryInterval); } } return current; } catch(RetryException re) { logger.warn("{}({})::Retrying event", this.name, stateful); if (WaitAndRetryException.class.isInstance(re)) { try { Thread.sleep(((WaitAndRetryException)re).getWait()); } catch(InterruptedException ie) { throw new RuntimeException(ie); } } attempts++; } } logger.error("{}({})::Unable to process event", this.name, stateful); throw new TooBusyException(); } }
FSM { public State<T> onEvent(T stateful, String event, Object ... args) throws TooBusyException { int attempts = 0; while(this.retryAttempts == -1 || attempts < this.retryAttempts) { try { State<T> current = this.getCurrentState(stateful); Transition<T> transition = this.getTransition(event, current); if (transition != null) { current = this.transition(stateful, current, event, transition, args); } else { if (logger.isDebugEnabled()) logger.debug("{}({})::{}({})->{}/noop", this.name, stateful.getClass().getSimpleName(), current.getName(), event, current.getName()); if (current.isBlocking()) { this.setCurrent(stateful, current, current); throw new WaitAndRetryException(this.retryInterval); } } return current; } catch(RetryException re) { logger.warn("{}({})::Retrying event", this.name, stateful); if (WaitAndRetryException.class.isInstance(re)) { try { Thread.sleep(((WaitAndRetryException)re).getWait()); } catch(InterruptedException ie) { throw new RuntimeException(ie); } } attempts++; } } logger.error("{}({})::Unable to process event", this.name, stateful); throw new TooBusyException(); } FSM(String name);  FSM(Persister<T> persister);  FSM(String name, Persister<T> persister);  FSM(String name, Persister<T> persister, int retryAttempts, int retryInterval); }
FSM { public State<T> onEvent(T stateful, String event, Object ... args) throws TooBusyException { int attempts = 0; while(this.retryAttempts == -1 || attempts < this.retryAttempts) { try { State<T> current = this.getCurrentState(stateful); Transition<T> transition = this.getTransition(event, current); if (transition != null) { current = this.transition(stateful, current, event, transition, args); } else { if (logger.isDebugEnabled()) logger.debug("{}({})::{}({})->{}/noop", this.name, stateful.getClass().getSimpleName(), current.getName(), event, current.getName()); if (current.isBlocking()) { this.setCurrent(stateful, current, current); throw new WaitAndRetryException(this.retryInterval); } } return current; } catch(RetryException re) { logger.warn("{}({})::Retrying event", this.name, stateful); if (WaitAndRetryException.class.isInstance(re)) { try { Thread.sleep(((WaitAndRetryException)re).getWait()); } catch(InterruptedException ie) { throw new RuntimeException(ie); } } attempts++; } } logger.error("{}({})::Unable to process event", this.name, stateful); throw new TooBusyException(); } FSM(String name);  FSM(Persister<T> persister);  FSM(String name, Persister<T> persister);  FSM(String name, Persister<T> persister, int retryAttempts, int retryInterval); State<T> onEvent(T stateful, String event, Object ... args); int getRetryAttempts(); void setRetryAttempts(int retries); int getRetryInterval(); void setRetryInterval(int retryInterval); Persister<T> getPersister(); void setPersister(Persister<T> persister); String getName(); void setName(String name); State<T> getCurrentState(T obj); }
FSM { public State<T> onEvent(T stateful, String event, Object ... args) throws TooBusyException { int attempts = 0; while(this.retryAttempts == -1 || attempts < this.retryAttempts) { try { State<T> current = this.getCurrentState(stateful); Transition<T> transition = this.getTransition(event, current); if (transition != null) { current = this.transition(stateful, current, event, transition, args); } else { if (logger.isDebugEnabled()) logger.debug("{}({})::{}({})->{}/noop", this.name, stateful.getClass().getSimpleName(), current.getName(), event, current.getName()); if (current.isBlocking()) { this.setCurrent(stateful, current, current); throw new WaitAndRetryException(this.retryInterval); } } return current; } catch(RetryException re) { logger.warn("{}({})::Retrying event", this.name, stateful); if (WaitAndRetryException.class.isInstance(re)) { try { Thread.sleep(((WaitAndRetryException)re).getWait()); } catch(InterruptedException ie) { throw new RuntimeException(ie); } } attempts++; } } logger.error("{}({})::Unable to process event", this.name, stateful); throw new TooBusyException(); } FSM(String name);  FSM(Persister<T> persister);  FSM(String name, Persister<T> persister);  FSM(String name, Persister<T> persister, int retryAttempts, int retryInterval); State<T> onEvent(T stateful, String event, Object ... args); int getRetryAttempts(); void setRetryAttempts(int retries); int getRetryInterval(); void setRetryInterval(int retryInterval); Persister<T> getPersister(); void setPersister(Persister<T> persister); String getName(); void setName(String name); State<T> getCurrentState(T obj);  }