StateMachine { public void execute(final Callable<Void> process, final StateT success, final StateT fail) { lock.writeLock().lock(); try { process.call(); logger.trace("Success to execute {}", process); if (null != success) { changeState(success); } } catch (Throwable th) { if (null != fail) { logger.trace("Fail to execute {}", process); changeState(fail); } } finally { lock.writeLock().unlock(); } } StateMachine(final StateT initialState); ReadWriteLock getLock(); void addListener(final StateChangeListener<StateT> listener); void removeListener(final StateChangeListener<StateT> listener); @SuppressWarnings("unchecked") boolean isState(final StateT... states); @SuppressWarnings("unchecked") void waitState(final StateT... states); StateT getState(); Object[] getArguments(); void changeState(final StateT state, final Object... args); boolean changeState(final StateT state, final StateCondition<StateT> condition,
      final Object... args); void execute(final Callable<Void> process, final StateT success, final StateT fail); @Override String toString();  }
@Test @SuppressWarnings("unchecked") public void testExecute() { final String s1 = randomUUID().toString(); final String success = randomUUID().toString(); final String failure = randomUUID().toString(); final Callable<Void> callable1 = new Callable<Void>() { @Override public Void call() throws Exception { logger.trace("Success"); return null; } }; final Callable<Void> callable2 = new Callable<Void>() { @Override public Void call() throws Exception { throw new IllegalArgumentException(); } }; final StateChangeListener<String> listener = mock(StateChangeListener.class); final StateMachine<String> stateMachine = new StateMachine<String>(s1); stateMachine.addListener(listener); stateMachine.execute(callable1, success, failure); assertEquals(success, stateMachine.getState()); stateMachine.execute(callable2, success, failure); assertEquals(failure, stateMachine.getState()); stateMachine.removeListener(listener); }