From 888580e60423786064e1bf32742af75c66257141 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Mon, 25 May 2020 14:07:58 +0200 Subject: [PATCH] remove reply type parameter from Command in Account example * only makes it look more complex than it is * probably a remaining of the early reply experiments --- ...ccountExampleWithEventHandlersInState.java | 12 +++--- .../typed/AccountExampleWithMutableState.java | 12 +++--- .../typed/AccountExampleWithNullState.java | 12 +++--- .../typed/AccountExampleDocSpec.scala | 2 +- .../sharding/typed/AccountExampleSpec.scala | 8 ++-- ...untExampleWithCommandHandlersInState.scala | 43 ++++++++++--------- ...countExampleWithEventHandlersInState.scala | 38 +++++++++------- .../typed/AccountExampleWithOptionState.scala | 43 ++++++++++--------- 8 files changed, 91 insertions(+), 79 deletions(-) diff --git a/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithEventHandlersInState.java b/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithEventHandlersInState.java index be6e5ba857..ef9f2c586d 100644 --- a/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithEventHandlersInState.java +++ b/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithEventHandlersInState.java @@ -38,10 +38,10 @@ public interface AccountExampleWithEventHandlersInState { // Command // #reply-command - interface Command extends CborSerializable {} + interface Command extends CborSerializable {} // #reply-command - public static class CreateAccount implements Command { + public static class CreateAccount implements Command { public final ActorRef replyTo; @JsonCreator @@ -50,7 +50,7 @@ public interface AccountExampleWithEventHandlersInState { } } - public static class Deposit implements Command { + public static class Deposit implements Command { public final BigDecimal amount; public final ActorRef replyTo; @@ -60,7 +60,7 @@ public interface AccountExampleWithEventHandlersInState { } } - public static class Withdraw implements Command { + public static class Withdraw implements Command { public final BigDecimal amount; public final ActorRef replyTo; @@ -70,7 +70,7 @@ public interface AccountExampleWithEventHandlersInState { } } - public static class GetBalance implements Command { + public static class GetBalance implements Command { public final ActorRef replyTo; @JsonCreator @@ -79,7 +79,7 @@ public interface AccountExampleWithEventHandlersInState { } } - public static class CloseAccount implements Command { + public static class CloseAccount implements Command { public final ActorRef replyTo; @JsonCreator diff --git a/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithMutableState.java b/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithMutableState.java index 70da5c1bf3..2c9b9ac4fc 100644 --- a/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithMutableState.java +++ b/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithMutableState.java @@ -35,9 +35,9 @@ public interface AccountExampleWithMutableState { EntityTypeKey.create(Command.class, "Account"); // Command - interface Command extends CborSerializable {} + interface Command extends CborSerializable {} - public static class CreateAccount implements Command { + public static class CreateAccount implements Command { public final ActorRef replyTo; @JsonCreator @@ -46,7 +46,7 @@ public interface AccountExampleWithMutableState { } } - public static class Deposit implements Command { + public static class Deposit implements Command { public final BigDecimal amount; public final ActorRef replyTo; @@ -56,7 +56,7 @@ public interface AccountExampleWithMutableState { } } - public static class Withdraw implements Command { + public static class Withdraw implements Command { public final BigDecimal amount; public final ActorRef replyTo; @@ -66,7 +66,7 @@ public interface AccountExampleWithMutableState { } } - public static class GetBalance implements Command { + public static class GetBalance implements Command { public final ActorRef replyTo; @JsonCreator @@ -75,7 +75,7 @@ public interface AccountExampleWithMutableState { } } - public static class CloseAccount implements Command { + public static class CloseAccount implements Command { public final ActorRef replyTo; @JsonCreator diff --git a/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithNullState.java b/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithNullState.java index 0402cce01a..0afce2091e 100644 --- a/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithNullState.java +++ b/akka-cluster-sharding-typed/src/test/java/jdocs/akka/cluster/sharding/typed/AccountExampleWithNullState.java @@ -35,9 +35,9 @@ public interface AccountExampleWithNullState { EntityTypeKey.create(Command.class, "Account"); // Command - interface Command extends CborSerializable {} + interface Command extends CborSerializable {} - public static class CreateAccount implements Command { + public static class CreateAccount implements Command { public final ActorRef replyTo; @JsonCreator @@ -46,7 +46,7 @@ public interface AccountExampleWithNullState { } } - public static class Deposit implements Command { + public static class Deposit implements Command { public final BigDecimal amount; public final ActorRef replyTo; @@ -56,7 +56,7 @@ public interface AccountExampleWithNullState { } } - public static class Withdraw implements Command { + public static class Withdraw implements Command { public final BigDecimal amount; public final ActorRef replyTo; @@ -66,7 +66,7 @@ public interface AccountExampleWithNullState { } } - public static class GetBalance implements Command { + public static class GetBalance implements Command { public final ActorRef replyTo; @JsonCreator @@ -75,7 +75,7 @@ public interface AccountExampleWithNullState { } } - public static class CloseAccount implements Command { + public static class CloseAccount implements Command { public final ActorRef replyTo; @JsonCreator diff --git a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleDocSpec.scala b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleDocSpec.scala index a32dfe3e4a..fff3609ea3 100644 --- a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleDocSpec.scala +++ b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleDocSpec.scala @@ -26,7 +26,7 @@ class AccountExampleDocSpec with LogCapturing { private val eventSourcedTestKit = - EventSourcedBehaviorTestKit[AccountEntity.Command[_], AccountEntity.Event, AccountEntity.Account]( + EventSourcedBehaviorTestKit[AccountEntity.Command, AccountEntity.Event, AccountEntity.Account]( system, AccountEntity("1", PersistenceId("Account", "1"))) diff --git a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleSpec.scala b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleSpec.scala index 42a954b749..6574180b95 100644 --- a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleSpec.scala +++ b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleSpec.scala @@ -79,10 +79,8 @@ class AccountExampleSpec } "reject Withdraw overdraft" in { - // AccountCommand[_] is the command type, but it should also be possible to narrow it to - // AccountCommand[OperationResult] val probe = createTestProbe[OperationResult]() - val ref = ClusterSharding(system).entityRefFor[Command[OperationResult]](AccountEntity.TypeKey, "3") + val ref = ClusterSharding(system).entityRefFor[Command](AccountEntity.TypeKey, "3") ref ! CreateAccount(probe.ref) probe.expectMessage(Confirmed) ref ! Deposit(100, probe.ref) @@ -90,10 +88,12 @@ class AccountExampleSpec ref ! Withdraw(110, probe.ref) probe.expectMessageType[Rejected] + // Account.Command is the command type, but it should also be possible to narrow it // ... thus restricting the entity ref from being sent other commands, e.g.: + // val ref2 = ClusterSharding(system).entityRefFor[Deposit](AccountEntity.TypeKey, "3") // val probe2 = createTestProbe[CurrentBalance]() // val msg = GetBalance(probe2.ref) - // ref ! msg // type mismatch: GetBalance NOT =:= AccountCommand[OperationResult] + // ref2 ! msg // type mismatch: GetBalance NOT =:= Deposit } "handle GetBalance" in { diff --git a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithCommandHandlersInState.scala b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithCommandHandlersInState.scala index e41ff492de..c5f3772b16 100644 --- a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithCommandHandlersInState.scala +++ b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithCommandHandlersInState.scala @@ -24,14 +24,12 @@ object AccountExampleWithCommandHandlersInState { //#account-entity object AccountEntity { // Command - sealed trait Command[Reply <: CommandReply] extends CborSerializable { - def replyTo: ActorRef[Reply] - } - final case class CreateAccount(replyTo: ActorRef[OperationResult]) extends Command[OperationResult] - final case class Deposit(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command[OperationResult] - final case class Withdraw(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command[OperationResult] - final case class GetBalance(replyTo: ActorRef[CurrentBalance]) extends Command[CurrentBalance] - final case class CloseAccount(replyTo: ActorRef[OperationResult]) extends Command[OperationResult] + sealed trait Command extends CborSerializable + final case class CreateAccount(replyTo: ActorRef[OperationResult]) extends Command + final case class Deposit(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command + final case class Withdraw(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command + final case class GetBalance(replyTo: ActorRef[CurrentBalance]) extends Command + final case class CloseAccount(replyTo: ActorRef[OperationResult]) extends Command // Reply sealed trait CommandReply extends CborSerializable @@ -54,11 +52,11 @@ object AccountExampleWithCommandHandlersInState { // State sealed trait Account extends CborSerializable { - def applyCommand(cmd: Command[_]): ReplyEffect + def applyCommand(cmd: Command): ReplyEffect def applyEvent(event: Event): Account } case object EmptyAccount extends Account { - override def applyCommand(cmd: Command[_]): ReplyEffect = + override def applyCommand(cmd: Command): ReplyEffect = cmd match { case CreateAccount(replyTo) => Effect.persist(AccountCreated).thenReply(replyTo)(_ => Confirmed) @@ -76,7 +74,7 @@ object AccountExampleWithCommandHandlersInState { case class OpenedAccount(balance: BigDecimal) extends Account { require(balance >= Zero, "Account balance can't be negative") - override def applyCommand(cmd: Command[_]): ReplyEffect = + override def applyCommand(cmd: Command): ReplyEffect = cmd match { case Deposit(amount, replyTo) => Effect.persist(Deposited(amount)).thenReply(replyTo)(_ => Confirmed) @@ -115,28 +113,33 @@ object AccountExampleWithCommandHandlersInState { } case object ClosedAccount extends Account { - override def applyCommand(cmd: Command[_]): ReplyEffect = + override def applyCommand(cmd: Command): ReplyEffect = cmd match { - case c @ (_: Deposit | _: Withdraw) => - Effect.reply(c.replyTo)(Rejected("Account is closed")) + case c: Deposit => + replyClosed(c.replyTo) + case c: Withdraw => + replyClosed(c.replyTo) case GetBalance(replyTo) => Effect.reply(replyTo)(CurrentBalance(Zero)) case CloseAccount(replyTo) => - Effect.reply(replyTo)(Rejected("Account is already closed")) + replyClosed(replyTo) case CreateAccount(replyTo) => - Effect.reply(replyTo)(Rejected("Account is already created")) + replyClosed(replyTo) } + private def replyClosed(replyTo: ActorRef[AccountEntity.OperationResult]): ReplyEffect = + Effect.reply(replyTo)(Rejected(s"Account is closed")) + override def applyEvent(event: Event): Account = throw new IllegalStateException(s"unexpected event [$event] in state [ClosedAccount]") } // when used with sharding, this TypeKey can be used in `sharding.init` and `sharding.entityRefFor`: - val TypeKey: EntityTypeKey[Command[_]] = - EntityTypeKey[Command[_]]("Account") + val TypeKey: EntityTypeKey[Command] = + EntityTypeKey[Command]("Account") - def apply(persistenceId: PersistenceId): Behavior[Command[_]] = { - EventSourcedBehavior.withEnforcedReplies[Command[_], Event, Account]( + def apply(persistenceId: PersistenceId): Behavior[Command] = { + EventSourcedBehavior.withEnforcedReplies[Command, Event, Account]( persistenceId, EmptyAccount, (state, cmd) => state.applyCommand(cmd), diff --git a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithEventHandlersInState.scala b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithEventHandlersInState.scala index 7c4ca1cf46..dc4c888136 100644 --- a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithEventHandlersInState.scala +++ b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithEventHandlersInState.scala @@ -27,17 +27,15 @@ object AccountExampleWithEventHandlersInState { object AccountEntity { // Command //#reply-command - sealed trait Command[Reply <: CommandReply] extends CborSerializable { - def replyTo: ActorRef[Reply] - } + sealed trait Command extends CborSerializable //#reply-command - final case class CreateAccount(replyTo: ActorRef[OperationResult]) extends Command[OperationResult] - final case class Deposit(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command[OperationResult] + final case class CreateAccount(replyTo: ActorRef[OperationResult]) extends Command + final case class Deposit(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command //#reply-command - final case class Withdraw(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command[OperationResult] + final case class Withdraw(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command //#reply-command - final case class GetBalance(replyTo: ActorRef[CurrentBalance]) extends Command[CurrentBalance] - final case class CloseAccount(replyTo: ActorRef[OperationResult]) extends Command[OperationResult] + final case class GetBalance(replyTo: ActorRef[CurrentBalance]) extends Command + final case class CloseAccount(replyTo: ActorRef[OperationResult]) extends Command // Reply //#reply-command @@ -89,20 +87,20 @@ object AccountExampleWithEventHandlersInState { } // when used with sharding, this TypeKey can be used in `sharding.init` and `sharding.entityRefFor`: - val TypeKey: EntityTypeKey[Command[_]] = - EntityTypeKey[Command[_]]("Account") + val TypeKey: EntityTypeKey[Command] = + EntityTypeKey[Command]("Account") // Note that after defining command, event and state classes you would probably start here when writing this. // When filling in the parameters of EventSourcedBehavior.apply you can use IntelliJ alt+Enter > createValue // to generate the stub with types for the command and event handlers. //#withEnforcedReplies - def apply(accountNumber: String, persistenceId: PersistenceId): Behavior[Command[_]] = { + def apply(accountNumber: String, persistenceId: PersistenceId): Behavior[Command] = { EventSourcedBehavior.withEnforcedReplies(persistenceId, EmptyAccount, commandHandler(accountNumber), eventHandler) } //#withEnforcedReplies - private def commandHandler(accountNumber: String): (Account, Command[_]) => ReplyEffect[Event, Account] = { + private def commandHandler(accountNumber: String): (Account, Command) => ReplyEffect[Event, Account] = { (state, cmd) => state match { case EmptyAccount => @@ -122,18 +120,26 @@ object AccountExampleWithEventHandlersInState { case ClosedAccount => cmd match { - case c @ (_: Deposit | _: Withdraw) => - Effect.reply(c.replyTo)(Rejected(s"Account $accountNumber is closed")) + case c: Deposit => + replyClosed(accountNumber, c.replyTo) + case c: Withdraw => + replyClosed(accountNumber, c.replyTo) case GetBalance(replyTo) => Effect.reply(replyTo)(CurrentBalance(Zero)) case CloseAccount(replyTo) => - Effect.reply(replyTo)(Rejected(s"Account $accountNumber is already closed")) + replyClosed(accountNumber, replyTo) case CreateAccount(replyTo) => - Effect.reply(replyTo)(Rejected(s"Account $accountNumber is already closed")) + replyClosed(accountNumber, replyTo) } } } + private def replyClosed( + accountNumber: String, + replyTo: ActorRef[AccountEntity.OperationResult]): ReplyEffect[Event, Account] = { + Effect.reply(replyTo)(Rejected(s"Account $accountNumber is closed")) + } + private val eventHandler: (Account, Event) => Account = { (state, event) => state.applyEvent(event) } diff --git a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithOptionState.scala b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithOptionState.scala index 0061f125ff..16197c6023 100644 --- a/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithOptionState.scala +++ b/akka-cluster-sharding-typed/src/test/scala/docs/akka/cluster/sharding/typed/AccountExampleWithOptionState.scala @@ -24,14 +24,12 @@ object AccountExampleWithOptionState { //#account-entity object AccountEntity { // Command - sealed trait Command[Reply <: CommandReply] extends CborSerializable { - def replyTo: ActorRef[Reply] - } - final case class CreateAccount(replyTo: ActorRef[OperationResult]) extends Command[OperationResult] - final case class Deposit(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command[OperationResult] - final case class Withdraw(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command[OperationResult] - final case class GetBalance(replyTo: ActorRef[CurrentBalance]) extends Command[CurrentBalance] - final case class CloseAccount(replyTo: ActorRef[OperationResult]) extends Command[OperationResult] + sealed trait Command extends CborSerializable + final case class CreateAccount(replyTo: ActorRef[OperationResult]) extends Command + final case class Deposit(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command + final case class Withdraw(amount: BigDecimal, replyTo: ActorRef[OperationResult]) extends Command + final case class GetBalance(replyTo: ActorRef[CurrentBalance]) extends Command + final case class CloseAccount(replyTo: ActorRef[OperationResult]) extends Command // Reply sealed trait CommandReply extends CborSerializable @@ -54,13 +52,13 @@ object AccountExampleWithOptionState { // State sealed trait Account extends CborSerializable { - def applyCommand(cmd: Command[_]): ReplyEffect + def applyCommand(cmd: Command): ReplyEffect def applyEvent(event: Event): Account } case class OpenedAccount(balance: BigDecimal) extends Account { require(balance >= Zero, "Account balance can't be negative") - override def applyCommand(cmd: Command[_]): ReplyEffect = + override def applyCommand(cmd: Command): ReplyEffect = cmd match { case Deposit(amount, replyTo) => Effect.persist(Deposited(amount)).thenReply(replyTo)(_ => Confirmed) @@ -99,28 +97,33 @@ object AccountExampleWithOptionState { } case object ClosedAccount extends Account { - override def applyCommand(cmd: Command[_]): ReplyEffect = + override def applyCommand(cmd: Command): ReplyEffect = cmd match { - case c @ (_: Deposit | _: Withdraw) => - Effect.reply(c.replyTo)(Rejected("Account is closed")) + case c: Deposit => + replyClosed(c.replyTo) + case c: Withdraw => + replyClosed(c.replyTo) case GetBalance(replyTo) => Effect.reply(replyTo)(CurrentBalance(Zero)) case CloseAccount(replyTo) => - Effect.reply(replyTo)(Rejected("Account is already closed")) + replyClosed(replyTo) case CreateAccount(replyTo) => - Effect.reply(replyTo)(Rejected("Account is already created")) + replyClosed(replyTo) } + private def replyClosed(replyTo: ActorRef[AccountEntity.OperationResult]): ReplyEffect = + Effect.reply(replyTo)(Rejected(s"Account is closed")) + override def applyEvent(event: Event): Account = throw new IllegalStateException(s"unexpected event [$event] in state [ClosedAccount]") } // when used with sharding, this TypeKey can be used in `sharding.init` and `sharding.entityRefFor`: - val TypeKey: EntityTypeKey[Command[_]] = - EntityTypeKey[Command[_]]("Account") + val TypeKey: EntityTypeKey[Command] = + EntityTypeKey[Command]("Account") - def apply(persistenceId: PersistenceId): Behavior[Command[_]] = { - EventSourcedBehavior.withEnforcedReplies[Command[_], Event, Option[Account]]( + def apply(persistenceId: PersistenceId): Behavior[Command] = { + EventSourcedBehavior.withEnforcedReplies[Command, Event, Option[Account]]( persistenceId, None, (state, cmd) => @@ -135,7 +138,7 @@ object AccountExampleWithOptionState { }) } - def onFirstCommand(cmd: Command[_]): ReplyEffect = { + def onFirstCommand(cmd: Command): ReplyEffect = { cmd match { case CreateAccount(replyTo) => Effect.persist(AccountCreated).thenReply(replyTo)(_ => Confirmed)