All Downloads are FREE. Search and download functionalities are using the official Maven repository.

akka.actor.DynamicAccess.scala Maven / Gradle / Ivy

There is a newer version: 2.0.5-protobuf-2.5-java-1.5
Show newest version
/**
 *  Copyright (C) 2009-2012 Typesafe Inc. 
 */
package akka.actor

import akka.util.NonFatal
import java.lang.reflect.InvocationTargetException

/**
 * The DynamicAccess implementation is the class which is used for
 * loading all configurable parts of an actor system (the
 * [[akka.actor.ReflectiveDynamicAccess]] is the default implementation).
 *
 * This is an internal facility and users are not expected to encounter it
 * unless they are extending Akka in ways which go beyond simple Extensions.
 */
trait DynamicAccess {

  /**
   * Convenience method which given a `Class[_]` object and a constructor description
   * will create a new instance of that class.
   *
   * {{{
   * val obj = DynamicAccess.createInstanceFor(clazz, Seq(classOf[Config] -> config, classOf[String] -> name))
   * }}}
   */
  def createInstanceFor[T: ClassManifest](clazz: Class[_], args: Seq[(Class[_], AnyRef)]): Either[Throwable, T] = {
    val types = args.map(_._1).toArray
    val values = args.map(_._2).toArray
    withErrorHandling {
      val constructor = clazz.getDeclaredConstructor(types: _*)
      constructor.setAccessible(true)
      val obj = constructor.newInstance(values: _*).asInstanceOf[T]
      val t = classManifest[T].erasure
      if (t.isInstance(obj)) Right(obj) else Left(new ClassCastException(clazz + " is not a subtype of " + t))
    }
  }

  /**
   * Obtain a `Class[_]` object loaded with the right class loader (i.e. the one
   * returned by `classLoader`).
   */
  def getClassFor[T: ClassManifest](fqcn: String): Either[Throwable, Class[_ <: T]]

  /**
   * Obtain an object conforming to the type T, which is expected to be
   * instantiated from a class designated by the fully-qualified class name
   * given, where the constructor is selected and invoked according to the
   * `args` argument. The exact usage of args depends on which type is requested,
   * see the relevant requesting code for details.
   */
  def createInstanceFor[T: ClassManifest](fqcn: String, args: Seq[(Class[_], AnyRef)]): Either[Throwable, T]

  /**
   * Obtain the Scala “object” instance for the given fully-qualified class name, if there is one.
   */
  def getObjectFor[T: ClassManifest](fqcn: String): Either[Throwable, T]

  /**
   * This is the class loader to be used in those special cases where the
   * other factory method are not applicable (e.g. when constructing a ClassLoaderBinaryInputStream).
   */
  def classLoader: ClassLoader

  /**
   * Caught exception is returned as Left(exception).
   * Unwraps `InvocationTargetException` if its getTargetException is an `Exception`.
   * Other `Throwable`, such as `Error` is thrown.
   */
  @inline
  final def withErrorHandling[T](body: ⇒ Either[Throwable, T]): Either[Throwable, T] =
    try body catch {
      case e: InvocationTargetException ⇒
        e.getTargetException match {
          case NonFatal(t) ⇒ Left(t)
          case t           ⇒ throw t
        }
      case NonFatal(e) ⇒ Left(e)
    }

}

/**
 * This is the default [[akka.actor.DynamicAccess]] implementation used by [[akka.actor.ActorSystemImpl]]
 * unless overridden. It uses reflection to turn fully-qualified class names into `Class[_]` objects
 * and creates instances from there using `getDeclaredConstructor()` and invoking that. The class loader
 * to be used for all this is determined by the [[akka.actor.ActorSystemImpl]]’s `findClassLoader` method
 * by default.
 */
class ReflectiveDynamicAccess(val classLoader: ClassLoader) extends DynamicAccess {

  override def getClassFor[T: ClassManifest](fqcn: String): Either[Throwable, Class[_ <: T]] =
    try {
      val c = classLoader.loadClass(fqcn).asInstanceOf[Class[_ <: T]]
      val t = classManifest[T].erasure
      if (t.isAssignableFrom(c)) Right(c) else Left(new ClassCastException(t + " is not assignable from " + c))
    } catch {
      case NonFatal(e) ⇒ Left(e)
    }

  override def createInstanceFor[T: ClassManifest](fqcn: String, args: Seq[(Class[_], AnyRef)]): Either[Throwable, T] =
    getClassFor(fqcn).fold(Left(_), { c ⇒
      val types = args.map(_._1).toArray
      val values = args.map(_._2).toArray
      withErrorHandling {
        val constructor = c.getDeclaredConstructor(types: _*)
        constructor.setAccessible(true)
        val obj = constructor.newInstance(values: _*)
        val t = classManifest[T].erasure
        if (t.isInstance(obj)) Right(obj) else Left(new ClassCastException(fqcn + " is not a subtype of " + t))
      }
    })

  override def getObjectFor[T: ClassManifest](fqcn: String): Either[Throwable, T] = {
    getClassFor(fqcn).fold(Left(_), { c ⇒
      withErrorHandling {
        val module = c.getDeclaredField("MODULE$")
        module.setAccessible(true)
        val t = classManifest[T].erasure
        module.get(null) match {
          case null                  ⇒ Left(new NullPointerException)
          case x if !t.isInstance(x) ⇒ Left(new ClassCastException(fqcn + " is not a subtype of " + t))
          case x                     ⇒ Right(x.asInstanceOf[T])
        }
      }
    })
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy