=act split Props java api implementation in separate files.

This commit is contained in:
Andrea 2015-08-11 14:46:43 +02:00 committed by Konrad Malawski
parent 74ce3bfb1f
commit 0511b07f3e
3 changed files with 182 additions and 144 deletions

View file

@ -0,0 +1,72 @@
/**
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.actor
import java.lang.reflect.{ Modifier, ParameterizedType, TypeVariable }
import akka.dispatch._
import akka.japi.Creator
import akka.routing._
import akka.util.Reflect
import scala.annotation.varargs
import scala.language.existentials
import scala.reflect.ClassTag
import akka.japi.Util.immutableSeq
/**
*
* Java API: Factory for Props instances.
*/
private[akka] trait AbstractProps {
/**
* INTERNAL API
*/
private[akka] def validate(clazz: Class[_]) =
if (Modifier.isAbstract(clazz.getModifiers))
throw new IllegalArgumentException(s"Actor class [${clazz.getName}] must not be abstract")
/**
* Java API: create a Props given a class and its constructor arguments.
*/
@varargs
def create(clazz: Class[_], args: AnyRef*): Props = new Props(deploy = Props.defaultDeploy, clazz = clazz, args = args.toList)
/**
* Create new Props from the given [[akka.japi.Creator]].
*
* You can not use a Java 8 lambda with this method since the generated classes
* don't carry enough type information.
*
* Use the Props.create(actorClass, creator) instead.
*/
def create[T <: Actor](creator: Creator[T]): Props = {
val cc = creator.getClass
if ((cc.getEnclosingClass ne null) && (cc.getModifiers & Modifier.STATIC) == 0)
throw new IllegalArgumentException("cannot use non-static local Creator to create actors; make it static (e.g. local to a static method) or top-level")
val ac = classOf[Actor]
val coc = classOf[Creator[_]]
val actorClass = Reflect.findMarker(cc, coc) match {
case t: ParameterizedType
t.getActualTypeArguments.head match {
case c: Class[_] c // since T <: Actor
case v: TypeVariable[_]
v.getBounds collectFirst { case c: Class[_] if ac.isAssignableFrom(c) && c != ac c } getOrElse ac
case x throw new IllegalArgumentException(s"unsupported type found in Creator argument [$x]")
}
case c: Class[_] if (c == coc)
throw new IllegalArgumentException(s"erased Creator types are unsupported, use Props.create(actorClass, creator) instead")
}
create(classOf[CreatorConsumer], actorClass, creator)
}
/**
* Create new Props from the given [[akka.japi.Creator]] with the type set to the given actorClass.
*/
def create[T <: Actor](actorClass: Class[T], creator: Creator[T]): Props = {
create(classOf[CreatorConsumer], actorClass, creator)
}
}

View file

@ -0,0 +1,108 @@
/**
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.actor
import java.lang.reflect.Constructor
import akka.japi.Creator
import akka.util.Reflect
import scala.collection.immutable
/**
* This interface defines a class of actor creation strategies deviating from
* the usual default of just reflectively instantiating the [[Actor]]
* subclass. It can be used to allow a dependency injection framework to
* determine the actual actor class and how it shall be instantiated.
*/
trait IndirectActorProducer {
/**
* This factory method must produce a fresh actor instance upon each
* invocation. <b>It is not permitted to return the same instance more than
* once.</b>
*/
def produce(): Actor
/**
* This method is used by [[Props]] to determine the type of actor which will
* be created. This means that an instance of this `IndirectActorProducer`
* will be created in order to call this method during any call to
* [[Props#actorClass]]; it should be noted that such calls may
* performed during actor set-up before the actual actors instantiation, and
* that the instance created for calling `actorClass` is not necessarily reused
* later to produce the actor.
*/
def actorClass: Class[_ <: Actor]
}
private[akka] object IndirectActorProducer {
val CreatorFunctionConsumerClass = classOf[CreatorFunctionConsumer]
val CreatorConsumerClass = classOf[CreatorConsumer]
val TypedCreatorFunctionConsumerClass = classOf[TypedCreatorFunctionConsumer]
def apply(clazz: Class[_], args: immutable.Seq[Any]): IndirectActorProducer = {
if (classOf[IndirectActorProducer].isAssignableFrom(clazz)) {
def get1stArg[T]: T = args.head.asInstanceOf[T]
def get2ndArg[T]: T = args.tail.head.asInstanceOf[T]
// The cost of doing reflection to create these for every props
// is rather high, so we match on them and do new instead
clazz match {
case TypedCreatorFunctionConsumerClass
new TypedCreatorFunctionConsumer(get1stArg, get2ndArg)
case CreatorFunctionConsumerClass
new CreatorFunctionConsumer(get1stArg)
case CreatorConsumerClass
new CreatorConsumer(get1stArg, get2ndArg)
case _
Reflect.instantiate(clazz, args).asInstanceOf[IndirectActorProducer]
}
} else if (classOf[Actor].isAssignableFrom(clazz)) {
if (args.isEmpty) new NoArgsReflectConstructor(clazz.asInstanceOf[Class[_ <: Actor]])
else new ArgsReflectConstructor(clazz.asInstanceOf[Class[_ <: Actor]], args)
} else throw new IllegalArgumentException(s"unknown actor creator [$clazz]")
}
}
/**
* INTERNAL API
*/
private[akka] class CreatorFunctionConsumer(creator: () Actor) extends IndirectActorProducer {
override def actorClass = classOf[Actor]
override def produce() = creator()
}
/**
* INTERNAL API
*/
private[akka] class CreatorConsumer(clazz: Class[_ <: Actor], creator: Creator[Actor]) extends IndirectActorProducer {
override def actorClass = clazz
override def produce() = creator.create()
}
/**
* INTERNAL API
*/
private[akka] class TypedCreatorFunctionConsumer(clz: Class[_ <: Actor], creator: () Actor) extends IndirectActorProducer {
override def actorClass = clz
override def produce() = creator()
}
/**
* INTERNAL API
*/
private[akka] class ArgsReflectConstructor(clz: Class[_ <: Actor], args: immutable.Seq[Any]) extends IndirectActorProducer {
private[this] val constructor: Constructor[_] = Reflect.findConstructor(clz, args)
override def actorClass = clz
override def produce() = Reflect.instantiate(constructor, args).asInstanceOf[Actor]
}
/**
* INTERNAL API
*/
private[akka] class NoArgsReflectConstructor(clz: Class[_ <: Actor]) extends IndirectActorProducer {
Reflect.findConstructor(clz, List.empty)
override def actorClass = clz
override def produce() = Reflect.instantiate(clz)
}

View file

@ -4,13 +4,9 @@
package akka.actor
import java.lang.reflect.{ Constructor, Modifier, ParameterizedType, TypeVariable }
import akka.actor.Deploy.{ NoDispatcherGiven, NoMailboxGiven }
import akka.dispatch._
import akka.japi.Creator
import akka.routing._
import akka.util.Reflect
import scala.annotation.varargs
import scala.collection.immutable
@ -24,7 +20,7 @@ import scala.reflect.ClassTag
*
* Used when creating new actors through <code>ActorSystem.actorOf</code> and <code>ActorContext.actorOf</code>.
*/
object Props {
object Props extends AbstractProps {
/**
* The defaultCreator, simply throws an UnsupportedOperationException when applied, which is used when creating a Props
@ -90,46 +86,6 @@ object Props {
*/
def apply(clazz: Class[_], args: Any*): Props = apply(defaultDeploy, clazz, args.toList)
/**
* Java API: create a Props given a class and its constructor arguments.
*/
@varargs
def create(clazz: Class[_], args: AnyRef*): Props = apply(defaultDeploy, clazz, args.toList)
/**
* Create new Props from the given [[akka.japi.Creator]].
*
* You can not use a Java 8 lambda with this method since the generated classes
* don't carry enough type information.
*
* Use the Props.create(actorClass, creator) instead.
*/
def create[T <: Actor](creator: Creator[T]): Props = {
val cc = creator.getClass
if ((cc.getEnclosingClass ne null) && (cc.getModifiers & Modifier.STATIC) == 0)
throw new IllegalArgumentException("cannot use non-static local Creator to create actors; make it static (e.g. local to a static method) or top-level")
val ac = classOf[Actor]
val coc = classOf[Creator[_]]
val actorClass = Reflect.findMarker(cc, coc) match {
case t: ParameterizedType
t.getActualTypeArguments.head match {
case c: Class[_] c // since T <: Actor
case v: TypeVariable[_]
v.getBounds collectFirst { case c: Class[_] if ac.isAssignableFrom(c) && c != ac c } getOrElse ac
case x throw new IllegalArgumentException(s"unsupported type found in Creator argument [$x]")
}
case c: Class[_] if (c == coc)
throw new IllegalArgumentException(s"erased Creator types are unsupported, use Props.create(actorClass, creator) instead")
}
apply(defaultDeploy, classOf[CreatorConsumer], actorClass :: creator :: Nil)
}
/**
* Create new Props from the given [[akka.japi.Creator]] with the type set to the given actorClass.
*/
def create[T <: Actor](actorClass: Class[T], creator: Creator[T]): Props = {
apply(defaultDeploy, classOf[CreatorConsumer], actorClass :: creator :: Nil)
}
}
/**
@ -158,8 +114,7 @@ object Props {
@SerialVersionUID(2L)
final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]) {
if (Modifier.isAbstract(clazz.getModifiers))
throw new IllegalArgumentException(s"Actor class [${clazz.getName}] must not be abstract")
Props.validate(clazz)
// derived property, does not need to be serialized
@transient
@ -259,100 +214,3 @@ final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]
producer.produce()
}
}
/**
* This interface defines a class of actor creation strategies deviating from
* the usual default of just reflectively instantiating the [[Actor]]
* subclass. It can be used to allow a dependency injection framework to
* determine the actual actor class and how it shall be instantiated.
*/
trait IndirectActorProducer {
/**
* This factory method must produce a fresh actor instance upon each
* invocation. <b>It is not permitted to return the same instance more than
* once.</b>
*/
def produce(): Actor
/**
* This method is used by [[Props]] to determine the type of actor which will
* be created. This means that an instance of this `IndirectActorProducer`
* will be created in order to call this method during any call to
* [[Props#actorClass]]; it should be noted that such calls may
* performed during actor set-up before the actual actors instantiation, and
* that the instance created for calling `actorClass` is not necessarily reused
* later to produce the actor.
*/
def actorClass: Class[_ <: Actor]
}
private[akka] object IndirectActorProducer {
val CreatorFunctionConsumerClass = classOf[CreatorFunctionConsumer]
val CreatorConsumerClass = classOf[CreatorConsumer]
val TypedCreatorFunctionConsumerClass = classOf[TypedCreatorFunctionConsumer]
def apply(clazz: Class[_], args: immutable.Seq[Any]): IndirectActorProducer = {
if (classOf[IndirectActorProducer].isAssignableFrom(clazz)) {
def get1stArg[T]: T = args.head.asInstanceOf[T]
def get2ndArg[T]: T = args.tail.head.asInstanceOf[T]
// The cost of doing reflection to create these for every props
// is rather high, so we match on them and do new instead
clazz match {
case TypedCreatorFunctionConsumerClass
new TypedCreatorFunctionConsumer(get1stArg, get2ndArg)
case CreatorFunctionConsumerClass
new CreatorFunctionConsumer(get1stArg)
case CreatorConsumerClass
new CreatorConsumer(get1stArg, get2ndArg)
case _
Reflect.instantiate(clazz, args).asInstanceOf[IndirectActorProducer]
}
} else if (classOf[Actor].isAssignableFrom(clazz)) {
if (args.isEmpty) new NoArgsReflectConstructor(clazz.asInstanceOf[Class[_ <: Actor]])
else new ArgsReflectConstructor(clazz.asInstanceOf[Class[_ <: Actor]], args)
} else throw new IllegalArgumentException(s"unknown actor creator [$clazz]")
}
}
/**
* INTERNAL API
*/
private[akka] class CreatorFunctionConsumer(creator: () Actor) extends IndirectActorProducer {
override def actorClass = classOf[Actor]
override def produce() = creator()
}
/**
* INTERNAL API
*/
private[akka] class CreatorConsumer(clazz: Class[_ <: Actor], creator: Creator[Actor]) extends IndirectActorProducer {
override def actorClass = clazz
override def produce() = creator.create()
}
/**
* INTERNAL API
*/
private[akka] class TypedCreatorFunctionConsumer(clz: Class[_ <: Actor], creator: () Actor) extends IndirectActorProducer {
override def actorClass = clz
override def produce() = creator()
}
/**
* INTERNAL API
*/
private[akka] class ArgsReflectConstructor(clz: Class[_ <: Actor], args: immutable.Seq[Any]) extends IndirectActorProducer {
private[this] val constructor: Constructor[_] = Reflect.findConstructor(clz, args)
override def actorClass = clz
override def produce() = Reflect.instantiate(constructor, args).asInstanceOf[Actor]
}
/**
* INTERNAL API
*/
private[akka] class NoArgsReflectConstructor(clz: Class[_ <: Actor]) extends IndirectActorProducer {
Reflect.findConstructor(clz, List.empty)
override def actorClass = clz
override def produce() = Reflect.instantiate(clz)
}