added possibility to start state machine from custom state
This commit is contained in:
parent
192fb69677
commit
bb085efa88
@ -13,6 +13,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Final State Machine</b>
|
* <b>Final State Machine</b>
|
||||||
@ -239,6 +241,20 @@ public class Fsm<T extends Fsm, E> {
|
|||||||
addTransition(fromState, toState.getName(), condition);
|
addTransition(fromState, toState.getName(), condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a possibility to initialize FSM in custom State
|
||||||
|
* @param name State name (must be added before)
|
||||||
|
*/
|
||||||
|
protected void setCurrentState(String name) {
|
||||||
|
try {
|
||||||
|
this.currentState = this.states.get(name);
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
throw new NotInitializedException(format("Unable to find state '%s'", name), e);
|
||||||
|
}
|
||||||
|
this.done = currentState.isFinish();
|
||||||
|
this.currentState.beforeEvent();
|
||||||
|
}
|
||||||
|
|
||||||
private void switchToNextState(E event) {
|
private void switchToNextState(E event) {
|
||||||
if (!transitions.containsKey(currentState.getName())) {
|
if (!transitions.containsKey(currentState.getName())) {
|
||||||
throw new TransitionMissedException(currentState.getName());
|
throw new TransitionMissedException(currentState.getName());
|
||||||
|
@ -31,6 +31,11 @@ public class FsmBuilder<T extends Fsm, E> {
|
|||||||
return fsm;
|
return fsm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T startingAt(String name) {
|
||||||
|
fsm.setCurrentState(name);
|
||||||
|
return fsm;
|
||||||
|
}
|
||||||
|
|
||||||
T getFsm() {
|
T getFsm() {
|
||||||
return fsm;
|
return fsm;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package me.bvn13.fsm.exceptions;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* is thrown if there are more than 1 appropriate transition from current state
|
* is thrown if there are more than 1 appropriate transition from current state
|
||||||
*/
|
*/
|
||||||
@ -10,11 +12,14 @@ public class AmbiguousTransitionException extends FsmException {
|
|||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
public AmbiguousTransitionException(String from, List<String> next) {
|
public AmbiguousTransitionException(String from, List<String> next) {
|
||||||
super("");
|
super(format("Ambiguous transition from state %s. Candidates are: %s", from, join(next)));
|
||||||
String msg = "";
|
}
|
||||||
for (String to : next) {
|
|
||||||
msg += (msg.length() > 0 ? ", " : "") + to;
|
private static String join(List<String> list) {
|
||||||
|
StringBuilder msg = new StringBuilder();
|
||||||
|
for (String to : list) {
|
||||||
|
msg.append(msg.length() > 0 ? ", " : "").append(to);
|
||||||
}
|
}
|
||||||
this.message = String.format("Ambiguous transition from state %s. Candidates are: %s", from, msg);
|
return msg.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,14 @@
|
|||||||
package me.bvn13.fsm.exceptions;
|
package me.bvn13.fsm.exceptions;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parent FSM exception class
|
* Parent FSM exception class
|
||||||
*/
|
*/
|
||||||
public class FsmException extends RuntimeException {
|
public class FsmException extends RuntimeException {
|
||||||
protected String message;
|
|
||||||
public FsmException(String message) {
|
public FsmException(String message) {
|
||||||
this.message = message;
|
super(message);
|
||||||
}
|
}
|
||||||
protected String getStackTraceString() {
|
|
||||||
StringWriter sw = new StringWriter();
|
public FsmException(String message, Throwable cause) {
|
||||||
PrintWriter pw = new PrintWriter(sw);
|
super(message, cause);
|
||||||
this.printStackTrace(pw);
|
|
||||||
return sw.toString();
|
|
||||||
}
|
|
||||||
public void printStackTrace() {
|
|
||||||
System.out.println(String.format("FSMException: %s / %s", message, getStackTraceString()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,12 @@ public class NotInitializedException extends FsmException {
|
|||||||
public NotInitializedException(String message) {
|
public NotInitializedException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NotInitializedException(String message, Exception e) {
|
||||||
|
super(message, e);
|
||||||
|
}
|
||||||
|
|
||||||
public NotInitializedException() {
|
public NotInitializedException() {
|
||||||
super("FSM is not inited");
|
super("FSM is not initialized");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,11 +109,9 @@ public class FsmTest {
|
|||||||
.to("finish")
|
.to("finish")
|
||||||
.checking((fsm, event) -> true)
|
.checking((fsm, event) -> true)
|
||||||
.end()
|
.end()
|
||||||
.create()
|
.create();
|
||||||
;
|
|
||||||
|
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
simpleFsm.process("");
|
simpleFsm.process("");
|
||||||
simpleFsm.process("");
|
simpleFsm.process("");
|
||||||
|
|
||||||
@ -127,4 +125,67 @@ public class FsmTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void newSyntaxCustomState() {
|
||||||
|
|
||||||
|
AtomicBoolean initBefore = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean initAfter = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean initProcess = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean intermediateBefore = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean intermediateAfter = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean intermediateProcess = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean finishBefore = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean finishAfter = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean finishProcess = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
|
||||||
|
SimpleFsm<String> simpleFsm = Fsm
|
||||||
|
.<SimpleFsm<String>, String>from(SimpleFsm::new)
|
||||||
|
.withStates()
|
||||||
|
.from("init")
|
||||||
|
.withBeforeHandler(fsm -> initBefore.set(true))
|
||||||
|
.withAfterHandler(fsm -> initAfter.set(true))
|
||||||
|
.withProcessor((fsm, event) -> initProcess.set(true))
|
||||||
|
.end()
|
||||||
|
.state("intermediate")
|
||||||
|
.withBeforeHandler(fsm -> intermediateBefore.set(true))
|
||||||
|
.withAfterHandler(fsm -> intermediateAfter.set(true))
|
||||||
|
.withProcessor((fsm, event) -> intermediateProcess.set(true))
|
||||||
|
.end()
|
||||||
|
.finish("finish")
|
||||||
|
.withBeforeHandler(fsm -> finishBefore.set(true))
|
||||||
|
.withAfterHandler(fsm -> finishAfter.set(true))
|
||||||
|
.withProcessor((fsm, event) -> finishProcess.set(true))
|
||||||
|
.end()
|
||||||
|
.withTransition()
|
||||||
|
.from("init")
|
||||||
|
.to("intermediate")
|
||||||
|
.checking((fsm, event) -> true)
|
||||||
|
.end()
|
||||||
|
.withTransition()
|
||||||
|
.from("intermediate")
|
||||||
|
.to("finish")
|
||||||
|
.checking((fsm, event) -> true)
|
||||||
|
.end()
|
||||||
|
.startingAt("intermediate")
|
||||||
|
;
|
||||||
|
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
simpleFsm.process("");
|
||||||
|
|
||||||
|
Assert.assertEquals("finish", simpleFsm.getCurrentState().getName());
|
||||||
|
Assert.assertFalse(initBefore.get());
|
||||||
|
Assert.assertFalse(initProcess.get());
|
||||||
|
Assert.assertFalse(initAfter.get());
|
||||||
|
Assert.assertTrue(intermediateBefore.get());
|
||||||
|
Assert.assertTrue(intermediateAfter.get());
|
||||||
|
Assert.assertTrue(intermediateProcess.get());
|
||||||
|
Assert.assertTrue(finishBefore.get());
|
||||||
|
Assert.assertFalse(finishProcess.get());
|
||||||
|
Assert.assertFalse(finishAfter.get());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user