diff --git a/akka-actor-migration/src/main/scala/akka/actor/GlobalActorSystem.scala b/akka-actor-migration/src/main/scala/akka/actor/GlobalActorSystem.scala index e08883c6ed..93787d43a6 100644 --- a/akka-actor-migration/src/main/scala/akka/actor/GlobalActorSystem.scala +++ b/akka-actor-migration/src/main/scala/akka/actor/GlobalActorSystem.scala @@ -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() 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 } diff --git a/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala b/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala index 127907412e..a2aed20c6c 100644 --- a/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala @@ -9,9 +9,10 @@ import com.typesafe.config.ConfigFactory import scala.collection.JavaConverters._ import akka.util.duration._ import akka.util.Duration +import akka.actor.ActorSystem @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) -class ConfigSpec extends AkkaSpec(ConfigFactory.defaultReference) { +class ConfigSpec extends AkkaSpec(ConfigFactory.defaultReference(ActorSystem.findClassLoader())) { "The default configuration file (i.e. reference.conf)" must { "contain all configuration properties for akka-actor that are used in code with their correct defaults" in { diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index 255a42d87c..f997c36623 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -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. diff --git a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala index 1daad13963..c10965fd66 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala @@ -37,27 +37,76 @@ 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() + /** + * Creates a new ActorSystem with the name "default", + * obtains the current ClassLoader by first inspecting the current threads' getContextClassLoader, + * then tries to walk the stack to find the callers class loader, then falls back to the ClassLoader + * associated with the ActorSystem class. + * Then it loads the default reference configuration using the ClassLoader. + */ + def create(): ActorSystem = apply() /** - * Uses the standard default Config from ConfigFactory.load(), since none is provided. + * Creates a new ActorSystem with the specified name, + * obtains the current ClassLoader by first inspecting the current threads' getContextClassLoader, + * then tries to walk the stack to find the callers class loader, then falls back to the ClassLoader + * associated with the ActorSystem class. + * Then it loads the default reference configuration using the ClassLoader. */ def create(name: String): ActorSystem = apply(name) /** - * Uses the standard default Config from ConfigFactory.load(), since none is provided. + * Creates a new ActorSystem with the name "default", and the specified Config, then + * obtains the current ClassLoader by first inspecting the current threads' getContextClassLoader, + * then tries to walk the stack to find the callers class loader, then falls back to the ClassLoader + * associated with the ActorSystem class. */ - def apply(name: String): ActorSystem = apply(name, ConfigFactory.load()) + def create(name: String, config: Config): ActorSystem = apply(name, config) - def create(): ActorSystem = apply() + /** + * Creates a new ActorSystem with the name "default", the specified Config, and specified ClassLoader + */ + def create(name: String, config: Config, classLoader: ClassLoader): ActorSystem = apply(name, config, classLoader) + + /** + * Creates a new ActorSystem with the name "default", + * obtains the current ClassLoader by first inspecting the current threads' getContextClassLoader, + * then tries to walk the stack to find the callers class loader, then falls back to the ClassLoader + * associated with the ActorSystem class. + * Then it loads the default reference configuration using the ClassLoader. + */ def apply(): ActorSystem = apply("default") - class Settings(cfg: Config, final val name: String) { + /** + * Creates a new ActorSystem with the specified name, + * obtains the current ClassLoader by first inspecting the current threads' getContextClassLoader, + * then tries to walk the stack to find the callers class loader, then falls back to the ClassLoader + * associated with the ActorSystem class. + * Then it loads the default reference configuration using the ClassLoader. + */ + def apply(name: String): ActorSystem = { + val classLoader = findClassLoader() + apply(name, ConfigFactory.load(classLoader), classLoader) + } + + /** + * Creates a new ActorSystem with the name "default", and the specified Config, then + * obtains the current ClassLoader by first inspecting the current threads' getContextClassLoader, + * then tries to walk the stack to find the callers class loader, then falls back to the ClassLoader + * associated with the ActorSystem class. + */ + def apply(name: String, config: Config): ActorSystem = apply(name, config, findClassLoader()) + + /** + * Creates a new ActorSystem with the name "default", the specified Config, and specified ClassLoader + */ + def apply(name: String, config: Config, classLoader: ClassLoader): ActorSystem = new ActorSystemImpl(name, config, classLoader).start() + + 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 +147,27 @@ object ActorSystem { override def toString: String = config.root.render } + + /** + * INTERNAL + */ + private[akka] def findClassLoader(): ClassLoader = { + def findCaller(get: Int ⇒ Class[_]): ClassLoader = + Iterator.from(2 /*is the magic number, promise*/ ).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 +414,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 +436,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 diff --git a/akka-remote/src/multi-jvm/scala/akka/remote/AkkaRemoteSpec.scala b/akka-remote/src/multi-jvm/scala/akka/remote/AkkaRemoteSpec.scala index 9a6dd08226..c1a2109bc0 100644 --- a/akka-remote/src/multi-jvm/scala/akka/remote/AkkaRemoteSpec.scala +++ b/akka-remote/src/multi-jvm/scala/akka/remote/AkkaRemoteSpec.scala @@ -5,12 +5,12 @@ package akka.remote import akka.testkit._ -import akka.actor.ActorSystemImpl import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigParseOptions import com.typesafe.config.ConfigResolveOptions import java.io.File +import akka.actor.{ActorSystem, ActorSystemImpl} object AkkaRemoteSpec { private def configParseOptions = ConfigParseOptions.defaults.setAllowMissing(false) @@ -21,7 +21,7 @@ object AkkaRemoteSpec { case location ⇒ ConfigFactory.systemProperties .withFallback(ConfigFactory.parseFileAnySyntax(new File(location), configParseOptions)) - .withFallback(ConfigFactory.defaultReference).resolve(ConfigResolveOptions.defaults) + .withFallback(ConfigFactory.defaultReference(ActorSystem.findClassLoader())).resolve(ConfigResolveOptions.defaults) } }