parent
9aa0e593b0
commit
9a4674f42f
2 changed files with 77 additions and 3 deletions
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Lightbend Inc. <https://www.lightbend.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package akka.actor.typed
|
||||||
|
|
||||||
|
import akka.actor.ActorPath
|
||||||
|
import akka.actor.ActorRefProvider
|
||||||
|
import akka.actor.ActorSystemImpl
|
||||||
|
import akka.actor.MinimalActorRef
|
||||||
|
import akka.actor.RootActorPath
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import org.scalatest.Matchers
|
||||||
|
import org.scalatest.WordSpec
|
||||||
|
import org.scalatest.concurrent.ScalaFutures
|
||||||
|
|
||||||
|
class ActorRefResolverSpec extends WordSpec with ScalaFutures with Matchers {
|
||||||
|
"ActorRefResolver" should {
|
||||||
|
"not allow serialization of ref originating from other system" in {
|
||||||
|
val system1 = ActorSystem(Behaviors.empty[String], "sys1")
|
||||||
|
val system2 = ActorSystem(Behaviors.empty[String], "sys2")
|
||||||
|
try {
|
||||||
|
val ref1 = system1.systemActorOf(Behaviors.empty, "ref1")
|
||||||
|
val serialized = ActorRefResolver(system1).toSerializationFormat(ref1)
|
||||||
|
serialized should startWith("akka://sys1/")
|
||||||
|
|
||||||
|
intercept[IllegalArgumentException] {
|
||||||
|
// wrong system
|
||||||
|
ActorRefResolver(system2).toSerializationFormat(ref1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can't detect that for MinimalActorRef
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
|
||||||
|
val minRef1: akka.actor.ActorRef = new MinimalActorRef {
|
||||||
|
override def provider: ActorRefProvider = system1.toClassic.asInstanceOf[ActorSystemImpl].provider
|
||||||
|
override def path: ActorPath = RootActorPath(provider.getDefaultAddress) / "minRef1"
|
||||||
|
}
|
||||||
|
|
||||||
|
val minRef1Serialized = ActorRefResolver(system2).toSerializationFormat(minRef1)
|
||||||
|
minRef1Serialized should startWith("akka://sys2/")
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
system1.terminate()
|
||||||
|
system2.terminate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package akka.actor.typed
|
package akka.actor.typed
|
||||||
|
|
||||||
|
import akka.actor.ActorRefWithCell
|
||||||
import akka.actor.ExtendedActorSystem
|
import akka.actor.ExtendedActorSystem
|
||||||
import akka.annotation.DoNotInherit
|
import akka.annotation.DoNotInherit
|
||||||
import akka.annotation.InternalApi
|
import akka.annotation.InternalApi
|
||||||
|
|
@ -35,7 +36,7 @@ abstract class ActorRefResolver extends Extension {
|
||||||
def toSerializationFormat[T](ref: ActorRef[T]): String
|
def toSerializationFormat[T](ref: ActorRef[T]): String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize an `ActorRef` in the [[#toSerializationFormat]].
|
* Deserialize an `ActorRef` in the [[ActorRefResolver#toSerializationFormat]].
|
||||||
*/
|
*/
|
||||||
def resolveActorRef[T](serializedActorRef: String): ActorRef[T]
|
def resolveActorRef[T](serializedActorRef: String): ActorRef[T]
|
||||||
|
|
||||||
|
|
@ -49,8 +50,30 @@ abstract class ActorRefResolver extends Extension {
|
||||||
|
|
||||||
private val classicSystem = system.toClassic.asInstanceOf[ExtendedActorSystem]
|
private val classicSystem = system.toClassic.asInstanceOf[ExtendedActorSystem]
|
||||||
|
|
||||||
override def toSerializationFormat[T](ref: ActorRef[T]): String =
|
override def toSerializationFormat[T](ref: ActorRef[T]): String = {
|
||||||
ref.path.toSerializationFormatWithAddress(classicSystem.provider.getDefaultAddress)
|
|
||||||
|
def toSerializationFormatWithAddress =
|
||||||
|
ref.path.toSerializationFormatWithAddress(classicSystem.provider.getDefaultAddress)
|
||||||
|
|
||||||
|
ref.toClassic match {
|
||||||
|
case a: ActorRefWithCell =>
|
||||||
|
val originSystem = a.underlying.system.asInstanceOf[ExtendedActorSystem]
|
||||||
|
if (originSystem eq classicSystem)
|
||||||
|
toSerializationFormatWithAddress
|
||||||
|
else
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
s"ActorRefResolver for ActorSystem [${classicSystem.provider.getDefaultAddress}] shouldn't be used for " +
|
||||||
|
"serialization of ActorRef that originates from another ActorSystem " +
|
||||||
|
s"[${originSystem.provider.getDefaultAddress}]. Use the ActorRefResolver for that system instead.")
|
||||||
|
|
||||||
|
case _ =>
|
||||||
|
// no origin system information for RemoteActorRef or MinimalActorRef, so just use the
|
||||||
|
// one for this extension. That is correct for RemoteActorRef, but MinimalActorRef
|
||||||
|
// could be wrong. However, since we don't allow usage of "wrong" ActorSystem for
|
||||||
|
// ordinary ActorRef the users will learn not to make that mistake.
|
||||||
|
toSerializationFormatWithAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override def resolveActorRef[T](serializedActorRef: String): ActorRef[T] =
|
override def resolveActorRef[T](serializedActorRef: String): ActorRef[T] =
|
||||||
classicSystem.provider.resolveActorRef(serializedActorRef)
|
classicSystem.provider.resolveActorRef(serializedActorRef)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue