#1878 - whippin' up some badass ClassLoader magicks

This commit is contained in:
Viktor Klang 2012-03-01 16:09:46 +01:00
parent 4876eb037f
commit 8b02a20d75
3 changed files with 41 additions and 37 deletions

View file

@ -11,7 +11,7 @@ import akka.util.Timeout
import akka.util.duration._
@deprecated("use ActorSystem instead", "2.0")
object GlobalActorSystem extends ActorSystemImpl("GlobalSystem", OldConfigurationLoader.defaultConfig) {
object GlobalActorSystem extends ActorSystemImpl("GlobalSystem", OldConfigurationLoader.defaultConfig, OldConfigurationLoader.oldClassLoader) {
start()
/**
@ -26,11 +26,12 @@ object GlobalActorSystem extends ActorSystemImpl("GlobalSystem", OldConfiguratio
*/
@deprecated("use default config location or write your own configuration loader", "2.0")
object OldConfigurationLoader {
val oldClassLoader: ClassLoader = ActorSystem.findClassLoader(1)
val defaultConfig: Config = {
val cfg = fromProperties orElse fromClasspath orElse fromHome getOrElse emptyConfig
val config = cfg.withFallback(ConfigFactory.defaultReference)
config.checkValid(ConfigFactory.defaultReference, "akka")
val config = cfg.withFallback(ConfigFactory.defaultReference(oldClassLoader))
config.checkValid(ConfigFactory.defaultReference(oldClassLoader), "akka")
config
}

View file

@ -10,7 +10,6 @@ import akka.routing._
import akka.AkkaException
import akka.util.{ Switch, Helpers }
import akka.event._
import com.typesafe.config.ConfigFactory
/**
* Interface for all ActorRef providers to implement.

View file

@ -37,27 +37,30 @@ object ActorSystem {
val GlobalHome = SystemHome orElse EnvHome
def create(name: String, config: Config): ActorSystem = apply(name, config)
def apply(name: String, config: Config): ActorSystem = new ActorSystemImpl(name, config).start()
def create(): ActorSystem = apply()
/**
* Uses the standard default Config from ConfigFactory.load(), since none is provided.
*/
def create(name: String): ActorSystem = apply(name)
def create(name: String, config: Config): ActorSystem = apply(name, config)
def create(name: String, config: Config, classLoader: ClassLoader): ActorSystem = apply(name, config, classLoader)
/**
* Uses the standard default Config from ConfigFactory.load(), since none is provided.
*/
def apply(name: String): ActorSystem = apply(name, ConfigFactory.load())
def create(): ActorSystem = apply()
def apply(): ActorSystem = apply("default")
def apply(name: String): ActorSystem = {
val classLoader = findClassLoader(1)
apply(name, ConfigFactory.load(classLoader), classLoader)
}
def apply(name: String, config: Config): ActorSystem = apply(name, config, findClassLoader(1))
def apply(name: String, config: Config, classLoader: ClassLoader): ActorSystem = new ActorSystemImpl(name, config, classLoader).start()
class Settings(cfg: Config, final val name: String) {
class Settings(classLoader: ClassLoader, cfg: Config, final val name: String) {
final val config: Config = {
val config = cfg.withFallback(ConfigFactory.defaultReference)
config.checkValid(ConfigFactory.defaultReference, "akka")
val config = cfg.withFallback(ConfigFactory.defaultReference(classLoader))
config.checkValid(ConfigFactory.defaultReference(classLoader), "akka")
config
}
@ -98,6 +101,27 @@ object ActorSystem {
override def toString: String = config.root.render
}
/**
* INTERNAL
*/
private[akka] def findClassLoader(depth: Int): ClassLoader = {
def findCaller(get: Int Class[_]): ClassLoader =
Iterator.from(depth).map(get) dropWhile { c
c != null &&
(c.getName.startsWith("akka.actor.ActorSystem") ||
c.getName.startsWith("scala.Option") ||
c.getName.startsWith("scala.collection.Iterator") ||
c.getName.startsWith("akka.util.Reflect"))
} next () match {
case null getClass.getClassLoader
case c c.getClassLoader
}
Option(Thread.currentThread.getContextClassLoader) orElse
(Reflect.getCallerClass map findCaller) getOrElse
getClass.getClassLoader
}
}
/**
@ -344,14 +368,14 @@ abstract class ExtendedActorSystem extends ActorSystem {
def dynamicAccess: DynamicAccess
}
class ActorSystemImpl protected[akka] (val name: String, applicationConfig: Config) extends ExtendedActorSystem {
class ActorSystemImpl protected[akka] (val name: String, applicationConfig: Config, classLoader: ClassLoader) extends ExtendedActorSystem {
if (!name.matches("""^\w+$"""))
throw new IllegalArgumentException("invalid ActorSystem name [" + name + "], must contain only word characters (i.e. [a-zA-Z_0-9])")
import ActorSystem._
final val settings: Settings = new Settings(applicationConfig, name)
final val settings: Settings = new Settings(classLoader, applicationConfig, name)
protected def uncaughtExceptionHandler: Thread.UncaughtExceptionHandler =
new Thread.UncaughtExceptionHandler() {
@ -366,33 +390,13 @@ class ActorSystemImpl protected[akka] (val name: String, applicationConfig: Conf
}
final val threadFactory: MonitorableThreadFactory =
MonitorableThreadFactory(name, settings.Daemonicity, Option(Thread.currentThread.getContextClassLoader), uncaughtExceptionHandler)
MonitorableThreadFactory(name, settings.Daemonicity, Option(classLoader), uncaughtExceptionHandler)
/**
* This is an extension point: by overriding this method, subclasses can
* control all reflection activities of an actor system.
*/
protected def createDynamicAccess(): DynamicAccess = new ReflectiveDynamicAccess(findClassLoader)
protected def findClassLoader: ClassLoader = {
def findCaller(get: Int Class[_]): ClassLoader = {
val frames = Iterator.from(2).map(get)
frames dropWhile { c
c != null &&
(c.getName.startsWith("akka.actor.ActorSystem") ||
c.getName.startsWith("scala.Option") ||
c.getName.startsWith("scala.collection.Iterator") ||
c.getName.startsWith("akka.util.Reflect"))
} next () match {
case null getClass.getClassLoader
case c c.getClassLoader
}
}
Option(Thread.currentThread.getContextClassLoader) orElse
(Reflect.getCallerClass map findCaller) getOrElse
getClass.getClassLoader
}
protected def createDynamicAccess(): DynamicAccess = new ReflectiveDynamicAccess(classLoader)
private val _pm: DynamicAccess = createDynamicAccess()
def dynamicAccess: DynamicAccess = _pm