Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2009-2018 Lightbend Inc.
*/
package akka.actor.typed.internal
import akka.actor.typed
import akka.actor.typed.Behavior.{ SameBehavior, UnhandledBehavior }
import akka.actor.typed.internal.TimerSchedulerImpl.TimerMsg
import akka.actor.typed.{ ActorContext, ActorRef, Behavior, BehaviorInterceptor, ExtensibleBehavior, PreRestart, Signal }
import akka.annotation.InternalApi
import akka.util.LineNumbers
/**
* Provides the impl of any behavior that could nest another behavior
*
* INTERNAL API
*/
@InternalApi
private[akka] object InterceptorImpl {
def apply[O, I](interceptor: BehaviorInterceptor[O, I], nestedBehavior: Behavior[I]): Behavior[O] = {
Behavior.DeferredBehavior[O] { ctx ⇒
val interceptorBehavior = new InterceptorImpl[O, I](interceptor, nestedBehavior)
interceptorBehavior.preStart(ctx)
}
}
}
/**
* Provides the impl of any behavior that could nest another behavior
*
* INTERNAL API
*/
@InternalApi
private[akka] final class InterceptorImpl[O, I](val interceptor: BehaviorInterceptor[O, I], val nestedBehavior: Behavior[I])
extends ExtensibleBehavior[O] with WrappingBehavior[O, I] {
import BehaviorInterceptor._
private val preStartTarget: PreStartTarget[I] = new PreStartTarget[I] {
override def start(ctx: ActorContext[_]): Behavior[I] = {
Behavior.start[I](nestedBehavior, ctx.asInstanceOf[ActorContext[I]])
}
}
private val receiveTarget: ReceiveTarget[I] = new ReceiveTarget[I] {
override def apply(ctx: ActorContext[_], msg: I): Behavior[I] =
Behavior.interpretMessage(nestedBehavior, ctx.asInstanceOf[ActorContext[I]], msg)
override def signalRestart(ctx: ActorContext[_]): Unit =
Behavior.interpretSignal(nestedBehavior, ctx.asInstanceOf[ActorContext[I]], PreRestart)
}
private val signalTarget = new SignalTarget[I] {
override def apply(ctx: ActorContext[_], signal: Signal): Behavior[I] =
Behavior.interpretSignal(nestedBehavior, ctx.asInstanceOf[ActorContext[I]], signal)
}
// invoked pre-start to start/de-duplicate the initial behavior stack
def preStart(ctx: typed.ActorContext[O]): Behavior[O] = {
val started = interceptor.aroundStart(ctx, preStartTarget)
deduplicate(started, ctx)
}
override def replaceNested(newNested: Behavior[I]): Behavior[O] =
new InterceptorImpl(interceptor, newNested)
override def receive(ctx: typed.ActorContext[O], msg: O): Behavior[O] = {
val interceptedResult = interceptor.aroundReceive(ctx, msg, receiveTarget)
deduplicate(interceptedResult, ctx)
}
override def receiveSignal(ctx: typed.ActorContext[O], signal: Signal): Behavior[O] = {
val interceptedResult = interceptor.aroundSignal(ctx, signal, signalTarget)
deduplicate(interceptedResult, ctx)
}
private def deduplicate(interceptedResult: Behavior[I], ctx: ActorContext[O]): Behavior[O] = {
val started = Behavior.start(interceptedResult, ctx.asInstanceOf[ActorContext[I]])
if (started == UnhandledBehavior || started == SameBehavior || !Behavior.isAlive(started)) {
started.asInstanceOf[Behavior[O]]
} else {
// returned behavior could be nested in setups, so we need to start before we deduplicate
val duplicateInterceptExists = Behavior.existsInStack(started) {
case i: InterceptorImpl[O, I] if interceptor.isSame(i.interceptor.asInstanceOf[BehaviorInterceptor[Any, Any]]) ⇒ true
case _ ⇒ false
}
if (duplicateInterceptExists) started.asInstanceOf[Behavior[O]]
else new InterceptorImpl[O, I](interceptor, started)
}
}
override def toString(): String = s"Interceptor($interceptor, $nestedBehavior)"
}
/**
* Fire off any incoming message to another actor before receiving it ourselves.
*
* INTERNAL API
*/
@InternalApi
private[akka] final case class MonitorInterceptor[T](actorRef: ActorRef[T]) extends BehaviorInterceptor[T, T] {
import BehaviorInterceptor._
override def aroundReceive(ctx: ActorContext[T], msg: T, target: ReceiveTarget[T]): Behavior[T] = {
actorRef ! msg
target(ctx, msg)
}
override def aroundSignal(ctx: ActorContext[T], signal: Signal, target: SignalTarget[T]): Behavior[T] = {
target(ctx, signal)
}
// only once to the same actor in the same behavior stack
override def isSame(other: BehaviorInterceptor[Any, Any]): Boolean = other match {
case MonitorInterceptor(`actorRef`) ⇒ true
case _ ⇒ false
}
}
/**
* INTERNAL API
*/
@InternalApi
private[akka] object WidenedInterceptor {
private final val _any2null = (_: Any) ⇒ null
private final def any2null[T] = _any2null.asInstanceOf[Any ⇒ T]
}
/**
* INTERNAL API
*/
@InternalApi
private[akka] final case class WidenedInterceptor[O, I](matcher: PartialFunction[O, I]) extends BehaviorInterceptor[O, I] {
import WidenedInterceptor._
import BehaviorInterceptor._
override def isSame(other: BehaviorInterceptor[Any, Any]): Boolean = other match {
// If they use the same pf instance we can allow it, to have one way to workaround defining
// "recursive" narrowed behaviors.
case WidenedInterceptor(`matcher`) ⇒ true
case WidenedInterceptor(otherMatcher) ⇒
// there is no safe way to allow this
throw new IllegalStateException("Widen can only be used one time in the same behavior stack. " +
s"One defined in ${LineNumbers(matcher)}, and another in ${LineNumbers(otherMatcher)}")
case _ ⇒ false
}
def aroundReceive(ctx: ActorContext[O], msg: O, target: ReceiveTarget[I]): Behavior[I] = {
// widen would wrap the TimerMessage, which would be wrong, see issue #25318
msg match {
case t: TimerMsg ⇒ throw new IllegalArgumentException(
s"Timers and widen can't be used together, [${t.key}]. See issue #25318")
case _ ⇒ ()
}
matcher.applyOrElse(msg, any2null) match {
case null ⇒ Behavior.unhandled
case transformed ⇒ target(ctx, transformed)
}
}
def aroundSignal(ctx: ActorContext[O], signal: Signal, target: SignalTarget[I]): Behavior[I] =
target(ctx, signal)
override def toString: String = s"Widen(${LineNumbers(matcher)})"
}