Add ref docs for error handling

- Base docs for error handling and some tests
  to verify added doc samples.
- Relates to #88
This commit is contained in:
Janne Valkealahti
2015-07-31 16:57:05 +01:00
parent d5257c64e7
commit 5ab1cb3fcb
4 changed files with 142 additions and 7 deletions

View File

@@ -310,5 +310,8 @@ in a state machine.
This appendix provides more detailed technical documentation about
using a Zookeeper with a Spring State Machine.
tbd.
[NOTE]
====
This article is not complete as it requires jepsen tests which are
planned for next release.
====

View File

@@ -609,6 +609,52 @@ exposed directly via `StateMachine` interface.
include::samples/DocsConfigurationSampleTests.java[tags=snippetZH]
----
[NOTE]
====
More about error handling shown in above example, see section
<<sm-error-handling>>.
====
[[sm-error-handling]]
== State Machine Error Handling
If state machine detects an internal error during a state transition
logic it may throw an exception. Before this exception is processed
internally, user is given a change to intercept.
Normal `StateMachineInterceptor` can be used to intercept errors and
example of it is shown above.
[source,java,indent=0]
----
include::samples/DocsConfigurationSampleTests.java[tags=snippet1]
----
When errors are detected, normal event notify mechanism is executed.
This allows to use either `StateMachineListener` or Spring Application
context event listener, more about these read section
<<sm-listeners>>.
Having said that, a simple listener would look like:
[source,java,indent=0]
----
include::samples/DocsConfigurationSampleTests.java[tags=snippet2]
----
Generic `ApplicationListener` checking `StateMachineEvent` would look
like.
[source,java,indent=0]
----
include::samples/DocsConfigurationSampleTests.java[tags=snippet3]
----
It's also possible to define `ApplicationListener` directly to
recognize only `StateMachineEvent` instances.
[source,java,indent=0]
----
include::samples/DocsConfigurationSampleTests.java[tags=snippet4]
----
[[sm-persist]]
== Persisting State Machine

View File

@@ -56,7 +56,8 @@ public class StateMachineErrorTests extends AbstractStateMachineTests {
context.register(Config.class, Config1.class);
context.refresh();
TestApplicationEventListener listener1 = context.getBean(TestApplicationEventListener.class);
TestApplicationEventListener1 listener1 = context.getBean(TestApplicationEventListener1.class);
TestApplicationEventListener2 listener3 = context.getBean(TestApplicationEventListener2.class);
@SuppressWarnings("unchecked")
ObjectStateMachine<TestStates,TestEvents> machine =
@@ -72,6 +73,8 @@ public class StateMachineErrorTests extends AbstractStateMachineTests {
assertThat(listener1.latch.await(1, TimeUnit.SECONDS), is(true));
assertThat(listener1.count, is(1));
assertThat(listener3.latch.await(1, TimeUnit.SECONDS), is(true));
assertThat(listener3.count, is(1));
assertThat(listener2.latch.await(1, TimeUnit.SECONDS), is(true));
assertThat(listener2.count, is(1));
assertThat(machine.hasStateMachineError(), is(true));
@@ -82,7 +85,7 @@ public class StateMachineErrorTests extends AbstractStateMachineTests {
context.register(Config.class, Config1.class);
context.refresh();
TestApplicationEventListener listener1 = context.getBean(TestApplicationEventListener.class);
TestApplicationEventListener1 listener1 = context.getBean(TestApplicationEventListener1.class);
@SuppressWarnings("unchecked")
ObjectStateMachine<TestStates,TestEvents> machine =
@@ -180,8 +183,13 @@ public class StateMachineErrorTests extends AbstractStateMachineTests {
static class Config {
@Bean
public TestApplicationEventListener testApplicationEventListener() {
return new TestApplicationEventListener();
public TestApplicationEventListener1 testApplicationEventListener1() {
return new TestApplicationEventListener1();
}
@Bean
public TestApplicationEventListener2 testApplicationEventListener2() {
return new TestApplicationEventListener2();
}
}
@@ -197,7 +205,7 @@ public class StateMachineErrorTests extends AbstractStateMachineTests {
}
}
static class TestApplicationEventListener implements ApplicationListener<StateMachineEvent> {
static class TestApplicationEventListener1 implements ApplicationListener<StateMachineEvent> {
CountDownLatch latch = new CountDownLatch(1);
int count = 0;
@@ -211,4 +219,17 @@ public class StateMachineErrorTests extends AbstractStateMachineTests {
}
}
static class TestApplicationEventListener2 implements ApplicationListener<OnStateMachineError> {
CountDownLatch latch = new CountDownLatch(1);
int count = 0;
@Override
public void onApplicationEvent(OnStateMachineError event) {
count++;
latch.countDown();
}
}
}

View File

@@ -56,11 +56,13 @@ import org.springframework.statemachine.config.builders.StateMachineStateConfigu
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.config.configurers.StateConfigurer.History;
import org.springframework.statemachine.ensemble.StateMachineEnsemble;
import org.springframework.statemachine.event.OnStateMachineError;
import org.springframework.statemachine.event.StateMachineEvent;
import org.springframework.statemachine.guard.Guard;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;
import org.springframework.statemachine.support.StateMachineInterceptor;
import org.springframework.statemachine.support.StateMachineInterceptorAdapter;
import org.springframework.statemachine.transition.Transition;
/**
@@ -878,4 +880,67 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests {
}
@SuppressWarnings("unused")
private static class InterceptorAddExample {
// tag::snippet1[]
StateMachine<String, String> stateMachine;
void addInterceptor() {
stateMachine.getStateMachineAccessor()
.doWithRegion(new StateMachineFunction<StateMachineAccess<String, String>>() {
@Override
public void apply(StateMachineAccess<String, String> function) {
function.addStateMachineInterceptor(
new StateMachineInterceptorAdapter<String, String>() {
@Override
public Exception stateMachineError(StateMachine<String, String> stateMachine,
Exception exception) {
// return null indicating handled error
return exception;
}
});
}
});
}
// end::snippet1[]
}
// tag::snippet2[]
public static class ErrorStateMachineListener
extends StateMachineListenerAdapter<String, String> {
@Override
public void stateMachineError(StateMachine<String, String> stateMachine, Exception exception) {
// do something with error
}
}
// end::snippet2[]
// tag::snippet3[]
public static class GenericApplicationEventListener
implements ApplicationListener<StateMachineEvent> {
@Override
public void onApplicationEvent(StateMachineEvent event) {
if (event instanceof OnStateMachineError) {
// do something with error
}
}
}
// end::snippet3[]
// tag::snippet4[]
public static class ErrorApplicationEventListener
implements ApplicationListener<OnStateMachineError> {
@Override
public void onApplicationEvent(OnStateMachineError event) {
// do something with error
}
}
// end::snippet4[]
}