diff --git a/src/main/java/me/bvn13/fsm/Fsm.java b/src/main/java/me/bvn13/fsm/Fsm.java
index 0ad01ef..1253454 100644
--- a/src/main/java/me/bvn13/fsm/Fsm.java
+++ b/src/main/java/me/bvn13/fsm/Fsm.java
@@ -13,6 +13,8 @@ import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
+import static java.lang.String.format;
+
/**
*
* Final State Machine
@@ -239,6 +241,20 @@ public class Fsm {
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) {
if (!transitions.containsKey(currentState.getName())) {
throw new TransitionMissedException(currentState.getName());
diff --git a/src/main/java/me/bvn13/fsm/FsmBuilder.java b/src/main/java/me/bvn13/fsm/FsmBuilder.java
index 42862e1..8bd0631 100644
--- a/src/main/java/me/bvn13/fsm/FsmBuilder.java
+++ b/src/main/java/me/bvn13/fsm/FsmBuilder.java
@@ -31,6 +31,11 @@ public class FsmBuilder {
return fsm;
}
+ public T startingAt(String name) {
+ fsm.setCurrentState(name);
+ return fsm;
+ }
+
T getFsm() {
return fsm;
}
diff --git a/src/main/java/me/bvn13/fsm/exceptions/AmbiguousTransitionException.java b/src/main/java/me/bvn13/fsm/exceptions/AmbiguousTransitionException.java
index ee6e210..c10c909 100644
--- a/src/main/java/me/bvn13/fsm/exceptions/AmbiguousTransitionException.java
+++ b/src/main/java/me/bvn13/fsm/exceptions/AmbiguousTransitionException.java
@@ -2,6 +2,8 @@ package me.bvn13.fsm.exceptions;
import java.util.List;
+import static java.lang.String.format;
+
/**
* is thrown if there are more than 1 appropriate transition from current state
*/
@@ -10,11 +12,14 @@ public class AmbiguousTransitionException extends FsmException {
super(message);
}
public AmbiguousTransitionException(String from, List next) {
- super("");
- String msg = "";
- for (String to : next) {
- msg += (msg.length() > 0 ? ", " : "") + to;
+ super(format("Ambiguous transition from state %s. Candidates are: %s", from, join(next)));
+ }
+
+ private static String join(List 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();
}
}
diff --git a/src/main/java/me/bvn13/fsm/exceptions/FsmException.java b/src/main/java/me/bvn13/fsm/exceptions/FsmException.java
index 5205ae9..8a48568 100644
--- a/src/main/java/me/bvn13/fsm/exceptions/FsmException.java
+++ b/src/main/java/me/bvn13/fsm/exceptions/FsmException.java
@@ -1,23 +1,14 @@
package me.bvn13.fsm.exceptions;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
/**
* Parent FSM exception class
*/
public class FsmException extends RuntimeException {
- protected String message;
public FsmException(String message) {
- this.message = message;
+ super(message);
}
- protected String getStackTraceString() {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- this.printStackTrace(pw);
- return sw.toString();
- }
- public void printStackTrace() {
- System.out.println(String.format("FSMException: %s / %s", message, getStackTraceString()));
+
+ public FsmException(String message, Throwable cause) {
+ super(message, cause);
}
}
diff --git a/src/main/java/me/bvn13/fsm/exceptions/NotInitializedException.java b/src/main/java/me/bvn13/fsm/exceptions/NotInitializedException.java
index a002848..3afad58 100644
--- a/src/main/java/me/bvn13/fsm/exceptions/NotInitializedException.java
+++ b/src/main/java/me/bvn13/fsm/exceptions/NotInitializedException.java
@@ -7,7 +7,12 @@ public class NotInitializedException extends FsmException {
public NotInitializedException(String message) {
super(message);
}
+
+ public NotInitializedException(String message, Exception e) {
+ super(message, e);
+ }
+
public NotInitializedException() {
- super("FSM is not inited");
+ super("FSM is not initialized");
}
}
diff --git a/src/test/java/me/bvn13/fsm/tests/FsmTest.java b/src/test/java/me/bvn13/fsm/tests/FsmTest.java
index ea75140..f79ff1e 100644
--- a/src/test/java/me/bvn13/fsm/tests/FsmTest.java
+++ b/src/test/java/me/bvn13/fsm/tests/FsmTest.java
@@ -109,11 +109,9 @@ public class FsmTest {
.to("finish")
.checking((fsm, event) -> true)
.end()
- .create()
- ;
+ .create();
// @formatter:on
-
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 simpleFsm = Fsm
+ ., 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());
+
+ }
+
}