Package

com.yang_bo.dsl.domains.akka

actor

Permalink

package actor

Visibility
  1. Public
  2. All

Value Members

  1. object typed

    Permalink

    Contains the com.thoughtworks.dsl.Dsl instances in a typed actor.

    Contains the com.thoughtworks.dsl.Dsl instances in a typed actor.

    Add the following import statement to enable keywords.akka.actor.ReceiveMessage in the akka.actor.typed.Behavior domain..

    import com.yang_bo.dsl.domains.akka.actor.typed._
    import com.yang_bo.dsl.keywords.akka.actor.ReceiveMessage

    Author:

    杨博 (Yang Bo)

    Example:
    1. This library can be used as an alternative to akka.actor.FSM, for creating state machines in simple Scala control flow. The following state machine contains two states and two transitions between them. It can be created as a simple while loop with the help of keywords.akka.actor.ReceiveMessage.Partial:

      import akka.actor.typed._
      sealed trait State
      case object Opened extends State
      case object Closed extends State
      sealed trait Transition
      case class Open(response: ActorRef[State]) extends Transition
      case class Close(response: ActorRef[State]) extends Transition
      def doorActor: Behavior[Transition] = {
        while (true) {
          val open = !ReceiveMessage.Partial[Open]
          open.response ! Opened
          val close = !ReceiveMessage.Partial[Close]
          close.response ! Closed
        }
        throw new Exception("Unreachable code!")
      }

      The door should reply an Opened state after performing an Open transition,

      import akka.actor.testkit.typed.scaladsl._
      val door = BehaviorTestKit(doorActor)
      val state = TestInbox[State]()
      door.run(Open(state.ref))
      state.expectMessage(Opened)

      and the state of the door can be switched between Opend and Closed according to Open and Close transition.

      door.run(Close(state.ref))
      state.expectMessage(Closed)
      door.run(Open(state.ref))
      state.expectMessage(Opened)
      door.run(Close(state.ref))
      state.expectMessage(Closed)
    Note

    To use try / catch / finally expressions with !-notation, the return type of enclosing function should be Behavior[?] !! Throwable, as shown in the following createDecoderActor method. It will open an java.io.InputStream, read String from the stream, and close the stream in a finally block.

    import akka.actor.typed._
    import akka.actor.typed.scaladsl._
    import com.thoughtworks.dsl.Dsl.!!
    import java.io._
    import java.net._
    sealed trait Command
    case class Open(open: () => InputStream) extends Command
    case class ReadObject(response: ActorRef[String]) extends Command
    case object Close extends Command
    def createDecoderActor: Behavior[Command] !! Throwable = {
      while (true) {
        val inputStream = (!ReceiveMessage.Partial[Open]).open()
        try {
          val ReadObject(replyTo) = !ReceiveMessage.Partial[ReadObject]
          replyTo ! new java.io.DataInputStream(inputStream).readUTF()
          !ReceiveMessage.Partial[Close.type]
        } finally {
          inputStream.close()
        }
      }
      throw new AssertionError("Unreachable code!")
    }

    Since createDecoderActor returns Behavior[Command] !! Throwable, it receives message of type Command, and accepts an additional callback function to handle exceptions that are not handled in createDecoderActor.

    import akka.actor.testkit.typed.scaladsl._
    val errorHandler = mockFunction[Throwable, Behavior[Command]]
    val decoderActor = BehaviorTestKit(createDecoderActor(errorHandler))

    Given an InputStream that throws an java.io.IOException when read from it,

    val inputStream: InputStream = mock[InputStream]
    toMockFunction0(inputStream.read _).expects().throws(new IOException())
    errorHandler.expects(where[Throwable](_.isInstanceOf[IOException])).returns(Behaviors.stopped)
    decoderActor.run(Open(() => inputStream))

    when the decoderActor try to read a String from the stream, it should close the stream due to finally block triggered by the exception.

    toMockFunction0(inputStream.close _).expects().returns(()).once()
    val inbox = TestInbox[String]()
    decoderActor.run(ReadObject(inbox.ref))
    inbox.receiveAll() should be(empty)

Ungrouped