!per #18168 consistency improvements for PersistentFSM
This commit is contained in:
parent
1bbf0731df
commit
488b1f4d6d
9 changed files with 398 additions and 408 deletions
|
|
@ -1,596 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.persistence.fsm;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.japi.Option;
|
||||
import akka.persistence.PersistenceSpec;
|
||||
import akka.testkit.AkkaJUnitActorSystemResource;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import akka.testkit.TestProbe;
|
||||
import org.junit.ClassRule;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import akka.persistence.fsm.FSM.CurrentState;
|
||||
import org.junit.Test;
|
||||
import scala.concurrent.duration.Duration;
|
||||
|
||||
import static akka.persistence.fsm.AbstractPersistentFsmActorTest.WebStoreCustomerFSMActor.UserState;
|
||||
import static akka.persistence.fsm.AbstractPersistentFsmActorTest.WebStoreCustomerFSMActor.ShoppingCart;
|
||||
import static akka.persistence.fsm.AbstractPersistentFsmActorTest.WebStoreCustomerFSMActor.Item;
|
||||
|
||||
import static akka.persistence.fsm.AbstractPersistentFsmActorTest.WebStoreCustomerFSMActor.GetCurrentCart;
|
||||
import static akka.persistence.fsm.AbstractPersistentFsmActorTest.WebStoreCustomerFSMActor.AddItem;
|
||||
import static akka.persistence.fsm.AbstractPersistentFsmActorTest.WebStoreCustomerFSMActor.Buy;
|
||||
import static akka.persistence.fsm.AbstractPersistentFsmActorTest.WebStoreCustomerFSMActor.Leave;
|
||||
|
||||
import static akka.persistence.fsm.AbstractPersistentFsmActorTest.WebStoreCustomerFSMActor.PurchaseWasMade;
|
||||
import static akka.persistence.fsm.AbstractPersistentFsmActorTest.WebStoreCustomerFSMActor.ShoppingCardDiscarded;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.matchers.JUnitMatchers.hasItems;
|
||||
|
||||
public class AbstractPersistentFsmActorTest {
|
||||
private static Option<String> none = Option.none();
|
||||
@ClassRule
|
||||
public static AkkaJUnitActorSystemResource actorSystemResource =
|
||||
new AkkaJUnitActorSystemResource("PersistentFSMJavaTest", PersistenceSpec.config(
|
||||
"leveldb", "AbstractPersistentFsmActorTest", "off", none.asScala()));
|
||||
|
||||
private final ActorSystem system = actorSystemResource.getSystem();
|
||||
|
||||
//Dummy report actor, for tests that don't need it
|
||||
private final ActorRef dummyReportActorRef = new TestProbe(system).ref();
|
||||
|
||||
@Test
|
||||
public void fsmFunctionalTest() throws Exception {
|
||||
new JavaTestKit(system) {{
|
||||
String persistenceId = generateId();
|
||||
ActorRef fsmRef = system.actorOf(WebStoreCustomerFSMActor.props(persistenceId, dummyReportActorRef));
|
||||
|
||||
watch(fsmRef);
|
||||
fsmRef.tell(new FSM.SubscribeTransitionCallBack(getRef()), getRef());
|
||||
|
||||
Item shirt = new Item("1", "Shirt", 59.99F);
|
||||
Item shoes = new Item("2", "Shoes", 89.99F);
|
||||
Item coat = new Item("3", "Coat", 119.99F);
|
||||
|
||||
fsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
fsmRef.tell(new AddItem(shirt), getRef());
|
||||
fsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
fsmRef.tell(new AddItem(shoes), getRef());
|
||||
fsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
fsmRef.tell(new AddItem(coat), getRef());
|
||||
fsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
fsmRef.tell(Buy.INSTANCE, getRef());
|
||||
fsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
fsmRef.tell(Leave.INSTANCE, getRef());
|
||||
|
||||
CurrentState currentState = expectMsgClass(akka.persistence.fsm.FSM.CurrentState.class);
|
||||
assertEquals(currentState.state(), UserState.LOOKING_AROUND);
|
||||
|
||||
ShoppingCart shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertTrue(shoppingCart.getItems().isEmpty());
|
||||
|
||||
FSM.Transition stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, fsmRef, UserState.LOOKING_AROUND, UserState.SHOPPING);
|
||||
|
||||
shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertThat(shoppingCart.getItems(), hasItems(shirt));
|
||||
|
||||
shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertThat(shoppingCart.getItems(), hasItems(shirt, shoes));
|
||||
|
||||
shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertThat(shoppingCart.getItems(), hasItems(shirt, shoes, coat));
|
||||
|
||||
stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, fsmRef, UserState.SHOPPING, UserState.PAID);
|
||||
|
||||
shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertThat(shoppingCart.getItems(), hasItems(shirt, shoes, coat));
|
||||
|
||||
Terminated terminated = expectMsgClass(Terminated.class);
|
||||
assertEquals(fsmRef, terminated.getActor());
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fsmTimeoutTest() throws Exception {
|
||||
new JavaTestKit(system) {{
|
||||
String persistenceId = generateId();
|
||||
ActorRef fsmRef = system.actorOf(WebStoreCustomerFSMActor.props(persistenceId, dummyReportActorRef));
|
||||
|
||||
watch(fsmRef);
|
||||
fsmRef.tell(new FSM.SubscribeTransitionCallBack(getRef()), getRef());
|
||||
|
||||
Item shirt = new Item("1", "Shirt", 59.99F);
|
||||
|
||||
fsmRef.tell(new AddItem(shirt), getRef());
|
||||
|
||||
CurrentState currentState = expectMsgClass(akka.persistence.fsm.FSM.CurrentState.class);
|
||||
assertEquals(currentState.state(), UserState.LOOKING_AROUND);
|
||||
|
||||
FSM.Transition stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, fsmRef, UserState.LOOKING_AROUND, UserState.SHOPPING);
|
||||
|
||||
new Within(duration("0.9 seconds"), duration("1.9 seconds")) {
|
||||
@Override
|
||||
protected void run() {
|
||||
FSM.Transition stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, fsmRef, UserState.SHOPPING, UserState.INACTIVE);
|
||||
}
|
||||
};
|
||||
|
||||
new Within(duration("1.9 seconds"), duration("2.9 seconds")) {
|
||||
@Override
|
||||
protected void run() {
|
||||
expectTerminated(fsmRef);
|
||||
}
|
||||
};
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulRecoveryWithCorrectStateData() {
|
||||
new JavaTestKit(system) {{
|
||||
String persistenceId = generateId();
|
||||
ActorRef fsmRef = system.actorOf(WebStoreCustomerFSMActor.props(persistenceId, dummyReportActorRef));
|
||||
|
||||
watch(fsmRef);
|
||||
fsmRef.tell(new FSM.SubscribeTransitionCallBack(getRef()), getRef());
|
||||
|
||||
Item shirt = new Item("1", "Shirt", 59.99F);
|
||||
Item shoes = new Item("2", "Shoes", 89.99F);
|
||||
Item coat = new Item("3", "Coat", 119.99F);
|
||||
|
||||
fsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
fsmRef.tell(new AddItem(shirt), getRef());
|
||||
fsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
fsmRef.tell(new AddItem(shoes), getRef());
|
||||
fsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
|
||||
CurrentState currentState = expectMsgClass(akka.persistence.fsm.FSM.CurrentState.class);
|
||||
assertEquals(currentState.state(), UserState.LOOKING_AROUND);
|
||||
|
||||
ShoppingCart shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertTrue(shoppingCart.getItems().isEmpty());
|
||||
|
||||
FSM.Transition stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, fsmRef, UserState.LOOKING_AROUND, UserState.SHOPPING);
|
||||
|
||||
shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertThat(shoppingCart.getItems(), hasItems(shirt));
|
||||
|
||||
shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertThat(shoppingCart.getItems(), hasItems(shirt, shoes));
|
||||
|
||||
fsmRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
|
||||
expectTerminated(fsmRef);
|
||||
|
||||
ActorRef recoveredFsmRef = system.actorOf(WebStoreCustomerFSMActor.props(persistenceId, dummyReportActorRef));
|
||||
watch(recoveredFsmRef);
|
||||
recoveredFsmRef.tell(new FSM.SubscribeTransitionCallBack(getRef()), getRef());
|
||||
|
||||
recoveredFsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
|
||||
recoveredFsmRef.tell(new AddItem(coat), getRef());
|
||||
recoveredFsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
|
||||
recoveredFsmRef.tell(Buy.INSTANCE, getRef());
|
||||
recoveredFsmRef.tell(GetCurrentCart.INSTANCE, getRef());
|
||||
recoveredFsmRef.tell(Leave.INSTANCE, getRef());
|
||||
|
||||
currentState = expectMsgClass(akka.persistence.fsm.FSM.CurrentState.class);
|
||||
assertEquals(currentState.state(), UserState.SHOPPING);
|
||||
|
||||
shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertThat(shoppingCart.getItems(), hasItems(shirt, shoes));
|
||||
|
||||
shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertThat(shoppingCart.getItems(), hasItems(shirt, shoes, coat));
|
||||
|
||||
stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, recoveredFsmRef, UserState.SHOPPING, UserState.PAID);
|
||||
|
||||
shoppingCart = expectMsgClass(ShoppingCart.class);
|
||||
assertThat(shoppingCart.getItems(), hasItems(shirt, shoes, coat));
|
||||
|
||||
expectTerminated(recoveredFsmRef);
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecutionOfDefinedActionsFollowingSuccessfulPersistence() {
|
||||
new JavaTestKit(system) {{
|
||||
String persistenceId = generateId();
|
||||
|
||||
TestProbe reportActorProbe = new TestProbe(system);
|
||||
ActorRef fsmRef = system.actorOf(WebStoreCustomerFSMActor.props(persistenceId, reportActorProbe.ref()));
|
||||
|
||||
watch(fsmRef);
|
||||
fsmRef.tell(new FSM.SubscribeTransitionCallBack(getRef()), getRef());
|
||||
|
||||
Item shirt = new Item("1", "Shirt", 59.99F);
|
||||
Item shoes = new Item("2", "Shoes", 89.99F);
|
||||
Item coat = new Item("3", "Coat", 119.99F);
|
||||
|
||||
fsmRef.tell(new AddItem(shirt), getRef());
|
||||
fsmRef.tell(new AddItem(shoes), getRef());
|
||||
fsmRef.tell(new AddItem(coat), getRef());
|
||||
fsmRef.tell(Buy.INSTANCE, getRef());
|
||||
fsmRef.tell(Leave.INSTANCE, getRef());
|
||||
|
||||
CurrentState currentState = expectMsgClass(akka.persistence.fsm.FSM.CurrentState.class);
|
||||
assertEquals(currentState.state(), UserState.LOOKING_AROUND);
|
||||
|
||||
FSM.Transition stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, fsmRef, UserState.LOOKING_AROUND, UserState.SHOPPING);
|
||||
|
||||
stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, fsmRef, UserState.SHOPPING, UserState.PAID);
|
||||
|
||||
PurchaseWasMade purchaseWasMade = reportActorProbe.expectMsgClass(PurchaseWasMade.class);
|
||||
assertThat(purchaseWasMade.getItems(), hasItems(shirt, shoes, coat));
|
||||
|
||||
expectTerminated(fsmRef);
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecutionOfDefinedActionsFollowingSuccessfulPersistenceOfFSMStop() {
|
||||
new JavaTestKit(system) {{
|
||||
String persistenceId = generateId();
|
||||
|
||||
TestProbe reportActorProbe = new TestProbe(system);
|
||||
ActorRef fsmRef = system.actorOf(WebStoreCustomerFSMActor.props(persistenceId, reportActorProbe.ref()));
|
||||
|
||||
watch(fsmRef);
|
||||
fsmRef.tell(new FSM.SubscribeTransitionCallBack(getRef()), getRef());
|
||||
|
||||
Item shirt = new Item("1", "Shirt", 59.99F);
|
||||
Item shoes = new Item("2", "Shoes", 89.99F);
|
||||
Item coat = new Item("3", "Coat", 119.99F);
|
||||
|
||||
fsmRef.tell(new AddItem(shirt), getRef());
|
||||
fsmRef.tell(new AddItem(shoes), getRef());
|
||||
fsmRef.tell(new AddItem(coat), getRef());
|
||||
fsmRef.tell(Leave.INSTANCE, getRef());
|
||||
|
||||
CurrentState currentState = expectMsgClass(akka.persistence.fsm.FSM.CurrentState.class);
|
||||
assertEquals(currentState.state(), UserState.LOOKING_AROUND);
|
||||
|
||||
FSM.Transition stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, fsmRef, UserState.LOOKING_AROUND, UserState.SHOPPING);
|
||||
|
||||
reportActorProbe.expectMsgClass(ShoppingCardDiscarded.class);
|
||||
|
||||
expectTerminated(fsmRef);
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectStateTimeoutFollowingRecovery() {
|
||||
new JavaTestKit(system) {{
|
||||
String persistenceId = generateId();
|
||||
ActorRef fsmRef = system.actorOf(WebStoreCustomerFSMActor.props(persistenceId, dummyReportActorRef));
|
||||
|
||||
watch(fsmRef);
|
||||
fsmRef.tell(new FSM.SubscribeTransitionCallBack(getRef()), getRef());
|
||||
|
||||
Item shirt = new Item("1", "Shirt", 59.99F);
|
||||
|
||||
fsmRef.tell(new AddItem(shirt), getRef());
|
||||
|
||||
CurrentState currentState = expectMsgClass(akka.persistence.fsm.FSM.CurrentState.class);
|
||||
assertEquals(currentState.state(), UserState.LOOKING_AROUND);
|
||||
|
||||
FSM.Transition stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, fsmRef, UserState.LOOKING_AROUND, UserState.SHOPPING);
|
||||
|
||||
expectNoMsg(duration("0.6seconds")); //randomly chosen delay, less than the timeout, before stopping the FSM
|
||||
fsmRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
|
||||
expectTerminated(fsmRef);
|
||||
|
||||
final ActorRef recoveredFsmRef = system.actorOf(WebStoreCustomerFSMActor.props(persistenceId, dummyReportActorRef));
|
||||
watch(recoveredFsmRef);
|
||||
recoveredFsmRef.tell(new FSM.SubscribeTransitionCallBack(getRef()), getRef());
|
||||
|
||||
|
||||
currentState = expectMsgClass(akka.persistence.fsm.FSM.CurrentState.class);
|
||||
assertEquals(currentState.state(), UserState.SHOPPING);
|
||||
|
||||
new Within(duration("0.9 seconds"), duration("1.9 seconds")) {
|
||||
@Override
|
||||
protected void run() {
|
||||
FSM.Transition stateTransition = expectMsgClass(FSM.Transition.class);
|
||||
assertTransition(stateTransition, recoveredFsmRef, UserState.SHOPPING, UserState.INACTIVE);
|
||||
}
|
||||
};
|
||||
|
||||
expectNoMsg(duration("0.9 seconds")); //randomly chosen delay, less than the timeout, before stopping the FSM
|
||||
recoveredFsmRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
|
||||
expectTerminated(recoveredFsmRef);
|
||||
|
||||
final ActorRef recoveredFsmRef2 = system.actorOf(WebStoreCustomerFSMActor.props(persistenceId, dummyReportActorRef));
|
||||
watch(recoveredFsmRef2);
|
||||
recoveredFsmRef2.tell(new FSM.SubscribeTransitionCallBack(getRef()), getRef());
|
||||
|
||||
currentState = expectMsgClass(akka.persistence.fsm.FSM.CurrentState.class);
|
||||
assertEquals(currentState.state(), UserState.INACTIVE);
|
||||
|
||||
new Within(duration("1.9 seconds"), duration("2.9 seconds")) {
|
||||
@Override
|
||||
protected void run() {
|
||||
expectTerminated(recoveredFsmRef2);
|
||||
}
|
||||
};
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
private static <State, From extends State, To extends State> void assertTransition(FSM.Transition transition, ActorRef ref, From from, To to) {
|
||||
assertEquals(ref, transition.fsmRef());
|
||||
assertEquals(from, transition.from());
|
||||
assertEquals(to, transition.to());
|
||||
}
|
||||
|
||||
private static String generateId() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
|
||||
public static class WebStoreCustomerFSMActor extends AbstractPersistentFsmActor<WebStoreCustomerFSMActor.UserState, WebStoreCustomerFSMActor.ShoppingCart, WebStoreCustomerFSMActor.DomainEvent> {
|
||||
|
||||
//State name
|
||||
//#customer-states
|
||||
enum UserState implements PersistentFsmActor.FSMState {
|
||||
LOOKING_AROUND("Looking Around"),
|
||||
SHOPPING("Shopping"),
|
||||
INACTIVE("Inactive"),
|
||||
PAID("Paid");
|
||||
|
||||
private final String stateIdentifier;
|
||||
|
||||
UserState(String stateIdentifier) {
|
||||
this.stateIdentifier = stateIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String identifier() {
|
||||
return stateIdentifier;
|
||||
}
|
||||
}
|
||||
//#customer-states
|
||||
|
||||
//#customer-states-data
|
||||
static class ShoppingCart {
|
||||
private final List<Item> items = new ArrayList<>();
|
||||
|
||||
public List<Item> getItems() {
|
||||
return Collections.unmodifiableList(items);
|
||||
}
|
||||
|
||||
void addItem(Item item) {
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
void empty() {
|
||||
items.clear();
|
||||
}
|
||||
}
|
||||
|
||||
static class Item implements Serializable {
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final float price;
|
||||
|
||||
Item(String id, String name, float price) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public float getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Item{id=%s, name=%s, price=%s}", id, price, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Item item = (Item) o;
|
||||
|
||||
return item.price == price && id.equals(item.id) && name.equals(item.name);
|
||||
}
|
||||
}
|
||||
//#customer-states-data
|
||||
|
||||
public interface Command {
|
||||
}
|
||||
|
||||
//#customer-commands
|
||||
public static final class AddItem implements Command {
|
||||
private final Item item;
|
||||
|
||||
public AddItem(Item item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
public Item getItem() {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Buy implements Command {INSTANCE}
|
||||
|
||||
public enum Leave implements Command {INSTANCE}
|
||||
|
||||
public enum GetCurrentCart implements Command {INSTANCE}
|
||||
//#customer-commands
|
||||
|
||||
interface DomainEvent extends Serializable {
|
||||
}
|
||||
|
||||
//#customer-domain-events
|
||||
public static final class ItemAdded implements DomainEvent {
|
||||
private final Item item;
|
||||
|
||||
public ItemAdded(Item item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
public Item getItem() {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public enum OrderExecuted implements DomainEvent {INSTANCE}
|
||||
|
||||
public enum OrderDiscarded implements DomainEvent {INSTANCE}
|
||||
//#customer-domain-events
|
||||
|
||||
|
||||
//Side effects - report events to be sent to some "Report Actor"
|
||||
public interface ReportEvent {
|
||||
}
|
||||
|
||||
public static final class PurchaseWasMade implements ReportEvent {
|
||||
private final List<Item> items;
|
||||
|
||||
public PurchaseWasMade(List<Item> items) {
|
||||
this.items = Collections.unmodifiableList(items);
|
||||
}
|
||||
|
||||
public List<Item> getItems() {
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ShoppingCardDiscarded implements ReportEvent {INSTANCE}
|
||||
|
||||
final private String persistenceId;
|
||||
|
||||
@Override
|
||||
public Class<DomainEvent> domainEventClass() {
|
||||
return DomainEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String persistenceId() {
|
||||
return persistenceId;
|
||||
}
|
||||
|
||||
public static Props props(String persistenceId, ActorRef reportActor) {
|
||||
return Props.create(WebStoreCustomerFSMActor.class, persistenceId, reportActor);
|
||||
}
|
||||
|
||||
public WebStoreCustomerFSMActor(String persistenceId, ActorRef reportActor) {
|
||||
this.persistenceId = persistenceId;
|
||||
|
||||
//#customer-fsm-body
|
||||
startWith(UserState.LOOKING_AROUND, new ShoppingCart());
|
||||
|
||||
when(UserState.LOOKING_AROUND,
|
||||
matchEvent(AddItem.class,
|
||||
(event, data) ->
|
||||
goTo(UserState.SHOPPING).applying(new ItemAdded(event.getItem()))
|
||||
.forMax(Duration.create(1, TimeUnit.SECONDS))
|
||||
)
|
||||
.event(GetCurrentCart.class, (event, data) -> stay().replying(data))
|
||||
);
|
||||
|
||||
when(UserState.SHOPPING,
|
||||
matchEvent(AddItem.class,
|
||||
(event, data) ->
|
||||
stay().applying(new ItemAdded(event.getItem()))
|
||||
.forMax(Duration.create(1, TimeUnit.SECONDS)))
|
||||
.event(Buy.class,
|
||||
(event, data) ->
|
||||
goTo(UserState.PAID).applying(OrderExecuted.INSTANCE)
|
||||
.andThen(exec(cart ->
|
||||
reportActor.tell(new PurchaseWasMade(cart.getItems()), self()))
|
||||
))
|
||||
.event(Leave.class,
|
||||
(event, data) ->
|
||||
stop().applying(OrderDiscarded.INSTANCE)
|
||||
.andThen(exec(cart ->
|
||||
reportActor.tell(ShoppingCardDiscarded.INSTANCE, self())
|
||||
)))
|
||||
.event(GetCurrentCart.class, (event, data) -> stay().replying(data))
|
||||
.event(StateTimeout$.class,
|
||||
(event, data) ->
|
||||
goTo(UserState.INACTIVE).forMax(Duration.create(2, TimeUnit.SECONDS)))
|
||||
);
|
||||
|
||||
|
||||
when(UserState.INACTIVE,
|
||||
matchEvent(AddItem.class,
|
||||
(event, data) ->
|
||||
goTo(UserState.SHOPPING).applying(new ItemAdded(event.getItem()))
|
||||
.forMax(Duration.create(1, TimeUnit.SECONDS)))
|
||||
.event(GetCurrentCart.class, (event, data) -> stay().replying(data))
|
||||
.event(StateTimeout$.class,
|
||||
(event, data) ->
|
||||
stop().applying(OrderDiscarded.INSTANCE)
|
||||
.andThen(exec(cart ->
|
||||
reportActor.tell(ShoppingCardDiscarded.INSTANCE, self())
|
||||
)))
|
||||
);
|
||||
|
||||
when(UserState.PAID,
|
||||
matchEvent(Leave.class, (event, data) -> stop())
|
||||
.event(GetCurrentCart.class, (event, data) -> stay().replying(data))
|
||||
);
|
||||
|
||||
initialize();
|
||||
//#customer-fsm-body
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this handler to define the action on Domain Event during recovery
|
||||
*
|
||||
* @param event domain event to apply
|
||||
* @param currentData state data of the previous state
|
||||
*/
|
||||
//#customer-apply-event
|
||||
@Override
|
||||
public ShoppingCart applyEvent(DomainEvent event, ShoppingCart currentData) {
|
||||
if (event instanceof ItemAdded) {
|
||||
currentData.addItem(((ItemAdded) event).getItem());
|
||||
return currentData;
|
||||
} else if (event instanceof OrderExecuted) {
|
||||
return currentData;
|
||||
} else if (event instanceof OrderDiscarded) {
|
||||
currentData.empty();
|
||||
return currentData;
|
||||
}
|
||||
throw new RuntimeException("Unhandled");
|
||||
}
|
||||
//#customer-apply-event
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue