diff --git a/akka-actor-tests/src/test/scala/akka/actor/DeployerSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/DeployerSpec.scala index d8084c0f37..9907e89159 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/DeployerSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/DeployerSpec.scala @@ -64,7 +64,7 @@ class DeployerSpec extends AkkaSpec(DeployerSpec.deployerConf) { service, deployment.get.config, NoRouter, - NoScope))) + NoScopeGiven))) } "use None deployment for undefined service" in { @@ -119,7 +119,7 @@ class DeployerSpec extends AkkaSpec(DeployerSpec.deployerConf) { deployment.get.path must be(service) deployment.get.routerConfig.getClass must be(expected.getClass) deployment.get.routerConfig.resizer must be(expected.resizer) - deployment.get.scope must be(NoScope) + deployment.get.scope must be(NoScopeGiven) } } diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index cdddf71d7b..688c036380 100755 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -96,7 +96,10 @@ trait ActorRefProvider { * Actor factory with create-only semantics: will create an actor as * described by props with the given supervisor and path (may be different * in case of remote supervision). If systemService is true, deployment is - * bypassed (local-only). + * bypassed (local-only). If ``Some(deploy)`` is passed in, it should be + * regarded as taking precedence over the nominally applicable settings, + * but it should be overridable from external configuration; the lookup of + * the latter can be suppressed by setting ``lookupDeploy`` to ``false``. */ def actorOf( system: ActorSystemImpl, @@ -532,8 +535,8 @@ class LocalActorRefProvider( case NoRouter ⇒ new LocalActorRef(system, props, supervisor, path, systemService) // create a local actor case router ⇒ val lookup = if (lookupDeploy) deployer.lookup(path.elements.drop(1).mkString("/", "/", "")) else None - val fromProps = props.deploy.copy(routerConfig = props.deploy.routerConfig withFallback router) :: Nil - val d = lookup.toList ::: deploy.toList ::: fromProps reduceRight (_ withFallback _) + val fromProps = Iterator(props.deploy.copy(routerConfig = props.deploy.routerConfig withFallback router)) + val d = fromProps ++ deploy.iterator ++ lookup.iterator reduce ((a, b) ⇒ b withFallback a) new RoutedActorRef(system, props.withRouter(d.routerConfig), supervisor, path) } } diff --git a/akka-actor/src/main/scala/akka/actor/Deployer.scala b/akka-actor/src/main/scala/akka/actor/Deployer.scala index 85225bda4d..d561c74413 100644 --- a/akka-actor/src/main/scala/akka/actor/Deployer.scala +++ b/akka-actor/src/main/scala/akka/actor/Deployer.scala @@ -29,7 +29,7 @@ final case class Deploy( path: String = "", config: Config = ConfigFactory.empty, routerConfig: RouterConfig = NoRouter, - scope: Scope = NoScope) { + scope: Scope = NoScopeGiven) { def this(routing: RouterConfig) = this("", ConfigFactory.empty, routing) def this(routing: RouterConfig, scope: Scope) = this("", ConfigFactory.empty, routing, scope) @@ -40,11 +40,25 @@ final case class Deploy( * precedence. The “path” of the other Deploy is not taken into account. All * other members are merged using ``.withFallback(other.)``. */ - def withFallback(other: Deploy) = + def withFallback(other: Deploy): Deploy = Deploy(path, config.withFallback(other.config), routerConfig.withFallback(other.routerConfig), scope.withFallback(other.scope)) } +/** + * The scope of a [[akka.actor.Deploy]] serves two purposes: as a marker for + * pattern matching the “scope” (i.e. local/remote/cluster) as well as for + * extending the information carried by the final Deploy class. Scopes can be + * used in conjunction with a custom [[akka.actor.ActorRefProvider]], making + * Akka actors fully extensible. + */ trait Scope { + /** + * When merging [[akka.actor.Deploy]] instances using ``withFallback()`` on + * the left one, this is propagated to “merging” scopes in the same way. + * The setup is biased towards preferring the callee over the argument, i.e. + * ``a.withFallback(b)`` is called expecting that ``a`` should in general take + * precedence. + */ def withFallback(other: Scope): Scope } @@ -52,7 +66,7 @@ case object LocalScope extends Scope { /** * Java API */ - def scope = this + def scope: Scope = this def withFallback(other: Scope): Scope = this } @@ -60,7 +74,7 @@ case object LocalScope extends Scope { /** * This is the default value and as such allows overrides. */ -case object NoScope extends Scope { +case object NoScopeGiven extends Scope { def withFallback(other: Scope): Scope = other } @@ -122,7 +136,7 @@ class Deployer(val settings: ActorSystem.Settings, val classloader: ClassLoader) } } - Some(Deploy(key, deployment, router, NoScope)) + Some(Deploy(key, deployment, router, NoScopeGiven)) } } diff --git a/akka-actor/src/main/scala/akka/actor/Props.scala b/akka-actor/src/main/scala/akka/actor/Props.scala index 70ba50f255..260f882753 100644 --- a/akka-actor/src/main/scala/akka/actor/Props.scala +++ b/akka-actor/src/main/scala/akka/actor/Props.scala @@ -137,34 +137,34 @@ case class Props( * * Scala API. */ - def withCreator(c: ⇒ Actor) = copy(creator = () ⇒ c) + def withCreator(c: ⇒ Actor): Props = copy(creator = () ⇒ c) /** * Returns a new Props with the specified creator set. * * Java API. */ - def withCreator(c: Creator[Actor]) = copy(creator = () ⇒ c.create) + def withCreator(c: Creator[Actor]): Props = copy(creator = () ⇒ c.create) /** * Returns a new Props with the specified creator set. * * Java API. */ - def withCreator(c: Class[_ <: Actor]) = copy(creator = () ⇒ c.newInstance) + def withCreator(c: Class[_ <: Actor]): Props = copy(creator = () ⇒ c.newInstance) /** * Returns a new Props with the specified dispatcher set. */ - def withDispatcher(d: String) = copy(dispatcher = d) + def withDispatcher(d: String): Props = copy(dispatcher = d) /** * Returns a new Props with the specified router config set. */ - def withRouter(r: RouterConfig) = copy(routerConfig = r) + def withRouter(r: RouterConfig): Props = copy(routerConfig = r) /** * Returns a new Props with the specified deployment configuration. */ - def withDeploy(d: Deploy) = copy(deploy = d) + def withDeploy(d: Deploy): Props = copy(deploy = d) } diff --git a/akka-actor/src/main/scala/akka/actor/TypedActor.scala b/akka-actor/src/main/scala/akka/actor/TypedActor.scala index 7e3f965851..881aa665dc 100644 --- a/akka-actor/src/main/scala/akka/actor/TypedActor.scala +++ b/akka-actor/src/main/scala/akka/actor/TypedActor.scala @@ -472,12 +472,12 @@ case class TypedProps[T <: AnyRef] protected[TypedProps] ( /** * Returns a new TypedProps with the specified dispatcher set. */ - def withDispatcher(d: String) = copy(dispatcher = d) + def withDispatcher(d: String): TypedProps[T] = copy(dispatcher = d) /** * Returns a new TypedProps with the specified deployment configuration. */ - def withDeploy(d: Deploy) = copy(deploy = d) + def withDeploy(d: Deploy): TypedProps[T] = copy(deploy = d) /** * @return a new TypedProps that will use the specified ClassLoader to create its proxy class in diff --git a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala index c49c529572..69ccdec572 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala @@ -163,13 +163,13 @@ class RemoteActorRefProvider( else None val deployment = { - lookup.toList ::: deploy.toList ::: Nil match { + deploy.toList ::: lookup.toList match { case Nil ⇒ Nil - case l ⇒ List(l reduceRight (_ withFallback _)) + case l ⇒ List(l reduce ((a, b) ⇒ b withFallback a)) } } - deployment ::: props.deploy :: Nil reduceRight (_ withFallback _) match { + Iterator(props.deploy) ++ deployment.iterator reduce ((a, b) ⇒ b withFallback a) match { case d @ Deploy(_, _, _, RemoteScope(addr)) ⇒ if (addr == rootPath.address || addr == transport.address) { local.actorOf(system, props, supervisor, path, false, deployment.headOption, false) diff --git a/akka-remote/src/main/scala/akka/remote/RemoteDaemon.scala b/akka-remote/src/main/scala/akka/remote/RemoteDaemon.scala index d230c89534..295227081a 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteDaemon.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteDaemon.scala @@ -9,9 +9,9 @@ import scala.annotation.tailrec import akka.actor.{ VirtualPathContainer, Terminated, Deploy, Props, Nobody, LocalActorRef, InternalActorRef, Address, ActorSystemImpl, ActorRef, ActorPathExtractor, ActorPath, Actor } import akka.event.LoggingAdapter -sealed trait DaemonMsg -case class DaemonMsgCreate(props: Props, deploy: Deploy, path: String, supervisor: ActorRef) extends DaemonMsg -case class DaemonMsgWatch(watcher: ActorRef, watched: ActorRef) extends DaemonMsg +private[akka] sealed trait DaemonMsg +private[akka] case class DaemonMsgCreate(props: Props, deploy: Deploy, path: String, supervisor: ActorRef) extends DaemonMsg +private[akka] case class DaemonMsgWatch(watcher: ActorRef, watched: ActorRef) extends DaemonMsg /** * Internal system "daemon" actor for remote internal communication.