object typed
Contains the com.thoughtworks.dsl.Dsl instances in a typed actor.
Installation
This typed object supports !-notation for keywords.akka.actor.ReceiveMessage in the typed actor domains,
which requires BangNotation and ResetEverywhere compiler plugins along with this typed
library.
For sbt, add the following settings to your build.sbt
:
addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" % "latest.release") addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-reseteverywhere" % "latest.release") libraryDependencies += "com.yang-bo.dsl.domains.akka.actor" %% "typed" % "latest.release"
Imports
Then, add the following import statement to enable 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)
- Source
- typed.scala
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 simplewhile
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 anOpen
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
andClosed
according toOpen
andClose
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 beBehavior[?] !! Throwable
, as shown in the followingcreateDecoderActor
method. It will open an java.io.InputStream, read String from the stream, and close the stream in afinally
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 class DecoderException(cause: Throwable) extends Exception(cause) 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] } catch { case e: IOException => throw new DecoderException(e) } finally { inputStream.close() } } throw new AssertionError("Unreachable code!") }
Since
createDecoderActor
returnsBehavior[Command] !! Throwable
, it receives message of typeCommand
, and accepts an additional callback function to handle exceptions that are not handled increateDecoderActor
.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()) decoderActor.run(Open(() => inputStream))
when the
decoderActor
try to read a String from the stream, it should close the stream due tofinally
block triggered by the exception.val inbox = TestInbox[String]() errorHandler.expects(where[Throwable](_.isInstanceOf[DecoderException])).returns(Behaviors.stopped) toMockFunction0(inputStream.close _).expects().returns(()).once() decoderActor.run(ReadObject(inbox.ref)) inbox.receiveAll() should be(empty)
- Alphabetic
- By Inheritance
- typed
- AnyRef
- Any
- Hide All
- Show All
- Public
- Protected
Value Members
- final def !=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def ##: Int
- Definition Classes
- AnyRef → Any
- final def ==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def asInstanceOf[T0]: T0
- Definition Classes
- Any
- def clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.CloneNotSupportedException]) @native() @HotSpotIntrinsicCandidate()
- final def eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def equals(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef → Any
- final def getClass(): Class[_ <: AnyRef]
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @HotSpotIntrinsicCandidate()
- def hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @HotSpotIntrinsicCandidate()
- final def isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- final def ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- final def notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @HotSpotIntrinsicCandidate()
- final def notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @HotSpotIntrinsicCandidate()
- final def synchronized[T0](arg0: => T0): T0
- Definition Classes
- AnyRef
- def toString(): String
- Definition Classes
- AnyRef → Any
- implicit def typedReceiveMessageDsl[Message, Domain >: Receive[Message] <: Behavior[Message]]: Dsl[ReceiveMessage[Message], Domain, Message]
Returns an com.thoughtworks.dsl.Dsl instance for keywords.akka.actor.ReceiveMessage in the akka.actor.typed.Behavior domain.
Returns an com.thoughtworks.dsl.Dsl instance for keywords.akka.actor.ReceiveMessage in the akka.actor.typed.Behavior domain.
Given an
echoActor
that receivesPing
messages and replies correspondingPong
messagesimport akka.actor.typed._ case class Ping(message: String, response: ActorRef[Pong]) case class Pong(message: String) def echoActor: Behavior[Ping] = { while (true) { val Ping(m, replyTo) = !ReceiveMessage[Ping] replyTo ! Pong(m) } throw new Exception("Unreachable code!") }
When pinging it with "hello", then it should reply a
Pong
with the same message "hello".import akka.actor.testkit.typed.scaladsl._ val pinger = BehaviorTestKit(echoActor) val probe = TestInbox[Pong]() pinger.run(Ping("hello", probe.ref)) probe.expectMessage(Pong("hello"))
Example: - implicit def typedReceiveMessagePartialDsl[PartialMessage <: Message, Message, Domain[T] >: Receive[T] <: Behavior[T]](implicit classTag: ClassTag[PartialMessage]): Dsl[Partial[PartialMessage], Domain[Message], PartialMessage]
Returns an com.thoughtworks.dsl.Dsl instance for keywords.akka.actor.ReceiveMessage.Partial in the akka.actor.typed.Behavior domain.
Returns an com.thoughtworks.dsl.Dsl instance for keywords.akka.actor.ReceiveMessage.Partial in the akka.actor.typed.Behavior domain.
Given an
echoActor
that receivesPing
messages and replies correspondingPong
messagesimport akka.actor.typed._ case class Ping(message: String, response: ActorRef[Pong]) case class Pong(message: String) def echoActor: Behavior[AnyRef] = { while (true) { val Ping(m, replyTo) = !(ReceiveMessage.Partial[Ping]) replyTo ! Pong(m) } throw new Exception("Unreachable code!") }
When pinging it with "hello", then it should reply a
Pong
with the same message "message", and other types of messages should not be handled.import akka.actor.testkit.typed.scaladsl._ val pinger = BehaviorTestKit(echoActor) object UnhandledMessage pinger.run(UnhandledMessage) val probe = TestInbox[Pong]() pinger.run(Ping("hello", probe.ref)) probe.expectMessage(Pong("hello"))
Example: - final def wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException]) @native()
- final def wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])