Merge pull request #361 from jboner/wip-1878-hocon-classloader-√
#1878 - whippin' up some badass ClassLoader magicks
This commit is contained in:
commit
5c3dcb7fdf
5 changed files with 91 additions and 40 deletions
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue