Created
May 28, 2012 18:38
-
-
Save kevinwright/2820571 to your computer and use it in GitHub Desktop.
Building a better ActorSystem (for spray)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.zeebox.starwatch | |
import akka.actor.ActorSystem | |
import akka.util.Reflect | |
import java.net.InetAddress | |
import com.typesafe.config.ConfigFactory | |
import org.slf4j.LoggerFactory | |
object ActorSystemFactory { | |
val log = LoggerFactory.getLogger(this.getClass) | |
def mkActorSystem(): ActorSystem = { | |
val configLoader = findClassLoader() | |
val config = loadConfig(configLoader) | |
val systemName = config.getString("zeebox.actor-system-name") | |
ActorSystem(systemName, config, configLoader) | |
} | |
private[this] def loadConfig(loader: ClassLoader) = { | |
//start by seeding some system props | |
System.setProperty("env.hostname", InetAddress.getLocalHost.getHostName) | |
val default = ConfigFactory.load(loader) | |
val test = ConfigFactory.load(loader, "application-test") | |
val config = test withFallback default | |
config | |
} | |
private[this] 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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.zeebox.starwatch | |
import javax.servlet.{ServletContextEvent, ServletContextListener} | |
import java.net.InetAddress | |
import akka.actor.ActorSystem | |
import cc.spray.SprayServletSettings | |
import akka.config.ConfigurationException | |
import akka.util.Switch | |
class Initializer extends ServletContextListener { | |
private val booted = new Switch(false) | |
private[this] var actorSystem: Option[ActorSystem] = None | |
def contextInitialized(e: ServletContextEvent) { | |
booted switchOn { | |
println("Starting spray application ...") | |
val ctx = e.getServletContext | |
val loader = getClass.getClassLoader | |
Thread.currentThread.setContextClassLoader(loader) | |
val system = ActorSystemFactory.mkActorSystem() | |
actorSystem = Some(system) | |
ctx.setAttribute(Initializer.SystemAttrName, system) | |
SprayServletSettings.BootClasses match { | |
case Nil => | |
val e = new ConfigurationException("No boot classes configured. Please specify at least one boot class " + | |
"in the spray.servlet.boot-classes config setting.") | |
ctx.log(e.getMessage, e) | |
case classes => { | |
for (className <- classes) { | |
try { | |
loader | |
.loadClass(className) | |
.getConstructor(classOf[ActorSystem]) | |
.newInstance(system) | |
} catch { | |
case e: ClassNotFoundException => | |
ctx.log("Configured boot class " + className + " cannot be found", e) | |
case e: NoSuchMethodException => | |
ctx.log("Configured boot class " + className + " does not define required constructor " + | |
"with one parameter of type `akka.actor.ActorSystem`", e) | |
case e: Exception => | |
ctx.log("Could not create instance of boot class " + className, e) | |
} | |
} | |
} | |
} | |
} | |
} | |
def contextDestroyed(e: ServletContextEvent) { | |
booted switchOff { | |
println("Shutting down spray application ...") | |
actorSystem foreach {_.shutdown()} | |
actorSystem = None | |
} | |
} | |
} | |
object Initializer { | |
private[starwatch] val SystemAttrName = "spray.servlet.system" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment