Jetty 7 support (untested)

This commit is contained in:
Mark Harrah 2010-02-01 18:21:51 -05:00
parent 510a708a08
commit aaea9c3407
7 changed files with 477 additions and 178 deletions

View File

@ -28,28 +28,13 @@ class SbtProject(info: ProjectInfo) extends DefaultProject(info) with test.SbtSc
// Configure which versions of Scala to test against for those tests that do cross building
override def scriptedCompatibility = sbt.test.CompatibilityLevel.Full
def scalaVersionString = ScalaVersion.current.getOrElse(scalaVersion.value)
override def mainSources =
{
if(scalaVersionString == Version2_8_0)
Path.lazyPathFinder( super.mainSources.get.filter( !_.asFile.getName.endsWith("TestFrameworkImpl.scala") ))
else
super.mainSources
}
override def useDefaultConfigurations = false
val default = Configurations.Default
val optional = Configurations.Optional
val provided = Configurations.Provided
val testConf = Configurations.Test
/* Versions of Scala to cross-build against. */
private val Version2_7_7 = "2.7.7"
private val Version2_8_0 = "2.8.0-SNAPSHOT"
// the list of all supported versions
private def allVersions = Version2_7_7 :: Version2_8_0 :: Nil
override def crossScalaVersions = Set(Version2_7_7)
override def crossScalaVersions = Set("2.7.7")
//testing
val scalacheck = "org.scala-tools.testing" %% "scalacheck" % "1.6" % "test"
@ -57,6 +42,9 @@ class SbtProject(info: ProjectInfo) extends DefaultProject(info) with test.SbtSc
val ivy = "org.apache.ivy" % "ivy" % "2.1.0" intransitive()
val jsch = "com.jcraft" % "jsch" % "0.1.31" intransitive()
val jetty = "org.mortbay.jetty" % "jetty" % "6.1.14" % "optional"
val jetty7server = "org.eclipse.jetty" % "jetty-server" % "7.0.1.v20091125" % "optional"
val jetty7webapp = "org.eclipse.jetty" % "jetty-webapp" % "7.0.1.v20091125" % "optional"
val testInterface = "org.scala-tools.testing" % "test-interface" % "0.4"
@ -64,8 +52,19 @@ class SbtProject(info: ProjectInfo) extends DefaultProject(info) with test.SbtSc
val xsbti = "org.scala-tools.sbt" % "launcher-interface" % projectVersion.value.toString % "provided"
val compiler = "org.scala-tools.sbt" %% "compile" % projectVersion.value.toString
override def libraryDependencies = super.libraryDependencies ++ getDependencies(scalaVersionString)
def getDependencies(scalaVersion: String) =
if(scalaVersion == Version2_8_0) Seq("jline" % "jline" % "0.9.94" intransitive()) else Nil
/* For generating JettyRun for Jetty 6 and 7. The only difference is the imports, but the file has to be compiled against each set of imports. */
override def compileAction = super.compileAction dependsOn (generateJettyRun6, generateJettyRun7)
def jettySrcDir = mainScalaSourcePath / "sbt" / "jetty"
def jettyTemplate = jettySrcDir / "LazyJettyRun.scala.templ"
lazy val generateJettyRun6 = generateJettyRun(jettyTemplate, jettySrcDir / "LazyJettyRun6.scala", "6", jettySrcDir / "jetty6.imports")
lazy val generateJettyRun7 = generateJettyRun(jettyTemplate, jettySrcDir / "LazyJettyRun7.scala", "7", jettySrcDir / "jetty7.imports")
def generateJettyRun(in: Path, out: Path, version: String, importsPath: Path) =
task
{
(for(template <- FileUtilities.readString(in asFile, log).right; imports <- FileUtilities.readString(importsPath asFile, log).right) yield
FileUtilities.write(out asFile, processJettyTemplate(template, version, imports), log).toLeft(()) ).left.toOption
}
def processJettyTemplate(template: String, version: String, imports: String): String =
template.replaceAll("""\Q${jetty.version}\E""", version).replaceAll("""\Q${jetty.imports}\E""", imports)
}

View File

@ -41,8 +41,12 @@ class JettyRunner(configuration: JettyConfiguration) extends ExitHook
val dual = new xsbt.DualLoader(baseLoader, notJettyFilter, x => true, jettyLoader, jettyFilter, x => false)
val lazyLoader = new LazyFrameworkLoader(implClassName, Array(FileUtilities.classLocation[Stoppable].toURI.toURL), dual, baseLoader)
val runner = ModuleUtilities.getObject(implClassName, lazyLoader).asInstanceOf[JettyRun]
def createRunner(implClassName: String) =
{
val lazyLoader = new LazyFrameworkLoader(implClassName, Array(FileUtilities.classLocation[Stoppable].toURI.toURL), dual, baseLoader)
ModuleUtilities.getObject(implClassName, lazyLoader).asInstanceOf[JettyRun]
}
val runner = try { createRunner(implClassName6) } catch { case e: NoClassDefFoundError => createRunner(implClassName7) }
runner(configuration, jettyLoader)
}
@ -62,7 +66,8 @@ class JettyRunner(configuration: JettyConfiguration) extends ExitHook
}
}
}
private val implClassName = "sbt.LazyJettyRun"
private val implClassName6 = "sbt.jetty.LazyJettyRun6"
private val implClassName7 = "sbt.jetty.LazyJettyRun7"
private def runError(e: Throwable, messageBase: String, log: Logger) =
{
@ -105,165 +110,41 @@ abstract class CustomJettyConfiguration extends JettyConfiguration
def jettyConfigurationXML: NodeSeq = NodeSeq.Empty
}
/* This class starts Jetty.
* NOTE: DO NOT actively use this class. You will see NoClassDefFoundErrors if you fail
* to do so.Only use its name in JettyRun for reflective loading. This allows using
* the Jetty libraries provided on the project classpath instead of requiring them to be
* available on sbt's classpath at startup.
*/
private object LazyJettyRun extends JettyRun
private class JettyLoggerBase(delegate: Logger)
{
import org.mortbay.jetty.{Handler, Server}
import org.mortbay.jetty.nio.SelectChannelConnector
import org.mortbay.jetty.webapp.{WebAppClassLoader, WebAppContext}
import org.mortbay.log.Log
import org.mortbay.util.Scanner
import org.mortbay.xml.XmlConfiguration
def getName = "JettyLogger"
def isDebugEnabled = delegate.atLevel(Level.Debug)
def setDebugEnabled(enabled: Boolean) = delegate.setLevel(if(enabled) Level.Debug else Level.Info)
import java.lang.ref.{Reference, WeakReference}
val DefaultMaxIdleTime = 30000
def apply(configuration: JettyConfiguration, jettyLoader: ClassLoader): Stoppable =
def info(msg: String) { delegate.info(msg) }
def debug(msg: String) { delegate.warn(msg) }
def warn(msg: String) { delegate.warn(msg) }
def info(msg: String, arg0: AnyRef, arg1: AnyRef) { delegate.info(format(msg, arg0, arg1)) }
def debug(msg: String, arg0: AnyRef, arg1: AnyRef) { delegate.debug(format(msg, arg0, arg1)) }
def warn(msg: String, arg0: AnyRef, arg1: AnyRef) { delegate.warn(format(msg, arg0, arg1)) }
def warn(msg: String, th: Throwable)
{
val oldLog = Log.getLog
Log.setLog(new JettyLogger(configuration.log))
val server = new Server
def configureScanner(listener: Scanner.BulkListener, scanDirectories: Seq[File], scanInterval: Int) =
delegate.warn(msg)
delegate.trace(th)
}
def debug(msg: String, th: Throwable)
{
delegate.debug(msg)
delegate.trace(th)
}
private def format(msg: String, arg0: AnyRef, arg1: AnyRef) =
{
def toString(arg: AnyRef) = if(arg == null) "" else arg.toString
val pieces = msg.split("""\{\}""", 3)
if(pieces.length == 1)
pieces(0)
else
{
if(scanDirectories.isEmpty)
None
val base = pieces(0) + toString(arg0) + pieces(1)
if(pieces.length == 2)
base
else
{
configuration.log.debug("Scanning for changes to: " + scanDirectories.mkString(", "))
val scanner = new Scanner
val list = new java.util.ArrayList[File]
scanDirectories.foreach(x => list.add(x))
scanner.setScanDirs(list)
scanner.setRecursive(true)
scanner.setScanInterval(scanInterval)
scanner.setReportExistingFilesOnStartup(false)
scanner.addListener(listener)
scanner.start()
Some(new WeakReference(scanner))
}
}
val (listener, scanner) =
configuration match
{
case c: DefaultJettyConfiguration =>
import c._
configureDefaultConnector(server, port)
def classpathURLs = classpath.get.map(_.asURL).toSeq
val webapp = new WebAppContext(war.absolutePath, contextPath)
def createLoader =
{
class SbtWebAppLoader extends WebAppClassLoader(jettyLoader, webapp) { override def addURL(u: URL) = super.addURL(u) };
val loader = new SbtWebAppLoader
classpathURLs.foreach(loader.addURL)
loader
}
def setLoader() = webapp.setClassLoader(createLoader)
setLoader()
server.setHandler(webapp)
val listener = new Scanner.BulkListener with Reload {
def reloadApp() = reload(server, setLoader(), log)
def filesChanged(files: java.util.List[_]) { reloadApp() }
}
(Some(listener), configureScanner(listener, c.scanDirectories, c.scanInterval))
case c: CustomJettyConfiguration =>
for(x <- c.jettyConfigurationXML)
(new XmlConfiguration(x.toString)).configure(server)
for(file <- c.jettyConfigurationFiles)
(new XmlConfiguration(file.toURI.toURL)).configure(server)
(None, None)
}
try
{
server.start()
new StopServer(new WeakReference(server), listener.map(new WeakReference(_)), scanner, oldLog)
}
catch { case e => server.stop(); throw e }
}
private def configureDefaultConnector(server: Server, port: Int)
{
val defaultConnector = new SelectChannelConnector
defaultConnector.setPort(port)
defaultConnector.setMaxIdleTime(DefaultMaxIdleTime)
server.addConnector(defaultConnector)
}
trait Reload { def reloadApp(): Unit }
private class StopServer(serverReference: Reference[Server], reloadReference: Option[Reference[Reload]], scannerReferenceOpt: Option[Reference[Scanner]], oldLog: org.mortbay.log.Logger) extends Stoppable
{
def reload(): Unit = on(reloadReference)(_.reloadApp())
private def on[T](refOpt: Option[Reference[T]])(f: T => Unit): Unit = refOpt.foreach(ref => onReferenced(ref.get)(f))
private def onReferenced[T](t: T)(f: T => Unit): Unit = if(t == null) () else f(t)
def stop()
{
onReferenced(serverReference.get)(_.stop())
on(scannerReferenceOpt)(_.stop())
Log.setLog(oldLog)
base + toString(arg1) + pieces(2)
}
}
private def reload(server: Server, reconfigure: => Unit, log: Logger)
{
log.info("Reloading web application...")
val handlers = wrapNull(server.getHandlers, server.getHandler)
log.debug("Stopping handlers: " + handlers.mkString(", "))
handlers.foreach(_.stop)
log.debug("Reconfiguring...")
reconfigure
log.debug("Restarting handlers: " + handlers.mkString(", "))
handlers.foreach(_.start)
log.info("Reload complete.")
}
private def wrapNull(a: Array[Handler], b: Handler) =
(a, b) match
{
case (null, null) => Nil
case (null, notB) => notB :: Nil
case (notA, null) => notA.toList
case (notA, notB) => notB :: notA.toList
}
private class JettyLogger(delegate: Logger) extends org.mortbay.log.Logger
{
def isDebugEnabled = delegate.atLevel(Level.Debug)
def setDebugEnabled(enabled: Boolean) = delegate.setLevel(if(enabled) Level.Debug else Level.Info)
def getLogger(name: String) = this
def info(msg: String, arg0: AnyRef, arg1: AnyRef) { delegate.info(format(msg, arg0, arg1)) }
def debug(msg: String, arg0: AnyRef, arg1: AnyRef) { delegate.debug(format(msg, arg0, arg1)) }
def warn(msg: String, arg0: AnyRef, arg1: AnyRef) { delegate.warn(format(msg, arg0, arg1)) }
def warn(msg: String, th: Throwable)
{
delegate.warn(msg)
delegate.trace(th)
}
def debug(msg: String, th: Throwable)
{
delegate.debug(msg)
delegate.trace(th)
}
private def format(msg: String, arg0: AnyRef, arg1: AnyRef) =
{
def toString(arg: AnyRef) = if(arg == null) "" else arg.toString
val pieces = msg.split("""\{\}""", 3)
if(pieces.length == 1)
pieces(0)
else
{
val base = pieces(0) + toString(arg0) + pieces(1)
if(pieces.length == 2)
base
else
base + toString(arg1) + pieces(2)
}
}
}
}
}

View File

@ -0,0 +1,131 @@
package sbt.jetty
import java.io.File
import java.net.URL
/* This class starts Jetty.
* NOTE: DO NOT actively use this class. You will see NoClassDefFoundErrors if you fail
* to do so.Only use its name in JettyRun for reflective loading. This allows using
* the Jetty libraries provided on the project classpath instead of requiring them to be
* available on sbt's classpath at startup.
*/
private object LazyJettyRun${jetty.version} extends JettyRun
{
${jetty.imports}
import java.lang.ref.{Reference, WeakReference}
val DefaultMaxIdleTime = 30000
def apply(configuration: JettyConfiguration, jettyLoader: ClassLoader): Stoppable =
{
val oldLog = Log.getLog
Log.setLog(new JettyLogger(configuration.log))
val server = new Server
def configureScanner(listener: Scanner.BulkListener, scanDirectories: Seq[File], scanInterval: Int) =
{
if(scanDirectories.isEmpty)
None
else
{
configuration.log.debug("Scanning for changes to: " + scanDirectories.mkString(", "))
val scanner = new Scanner
val list = new java.util.ArrayList[File]
scanDirectories.foreach(x => list.add(x))
scanner.setScanDirs(list)
scanner.setRecursive(true)
scanner.setScanInterval(scanInterval)
scanner.setReportExistingFilesOnStartup(false)
scanner.addListener(listener)
scanner.start()
Some(new WeakReference(scanner))
}
}
val (listener, scanner) =
configuration match
{
case c: DefaultJettyConfiguration =>
import c._
configureDefaultConnector(server, port)
def classpathURLs = classpath.get.map(_.asURL).toSeq
val webapp = new WebAppContext(war.absolutePath, contextPath)
def createLoader =
{
class SbtWebAppLoader extends WebAppClassLoader(jettyLoader, webapp) { override def addURL(u: URL) = super.addURL(u) };
val loader = new SbtWebAppLoader
classpathURLs.foreach(loader.addURL)
loader
}
def setLoader() = webapp.setClassLoader(createLoader)
setLoader()
server.setHandler(webapp)
val listener = new Scanner.BulkListener with Reload {
def reloadApp() = reload(server, setLoader(), log)
def filesChanged(files: java.util.List[_]) { reloadApp() }
}
(Some(listener), configureScanner(listener, c.scanDirectories, c.scanInterval))
case c: CustomJettyConfiguration =>
for(x <- c.jettyConfigurationXML)
(new XmlConfiguration(x.toString)).configure(server)
for(file <- c.jettyConfigurationFiles)
(new XmlConfiguration(file.toURI.toURL)).configure(server)
(None, None)
}
try
{
server.start()
new StopServer(new WeakReference(server), listener.map(new WeakReference(_)), scanner, oldLog)
}
catch { case e => server.stop(); throw e }
}
private def configureDefaultConnector(server: Server, port: Int)
{
val defaultConnector = new SelectChannelConnector
defaultConnector.setPort(port)
defaultConnector.setMaxIdleTime(DefaultMaxIdleTime)
server.addConnector(defaultConnector)
}
trait Reload { def reloadApp(): Unit }
private class StopServer(serverReference: Reference[Server], reloadReference: Option[Reference[Reload]], scannerReferenceOpt: Option[Reference[Scanner]], oldLog: JLogger) extends Stoppable
{
def reload(): Unit = on(reloadReference)(_.reloadApp())
private def on[T](refOpt: Option[Reference[T]])(f: T => Unit): Unit = refOpt.foreach(ref => onReferenced(ref.get)(f))
private def onReferenced[T](t: T)(f: T => Unit): Unit = if(t == null) () else f(t)
def stop()
{
onReferenced(serverReference.get)(_.stop())
on(scannerReferenceOpt)(_.stop())
Log.setLog(oldLog)
}
}
private def reload(server: Server, reconfigure: => Unit, log: Logger)
{
log.info("Reloading web application...")
val handlers = wrapNull(server.getHandlers, server.getHandler)
log.debug("Stopping handlers: " + handlers.mkString(", "))
handlers.foreach(_.stop)
log.debug("Reconfiguring...")
reconfigure
log.debug("Restarting handlers: " + handlers.mkString(", "))
handlers.foreach(_.start)
log.info("Reload complete.")
}
private def wrapNull(a: Array[Handler], b: Handler) =
(a, b) match
{
case (null, null) => Nil
case (null, notB) => notB :: Nil
case (notA, null) => notA.toList
case (notA, notB) => notB :: notA.toList
}
private class JettyLogger(delegate: Logger) extends JettyLoggerBase(delegate) with JLogger
{
def getLogger(name: String) = this
}
}

View File

@ -0,0 +1,137 @@
package sbt.jetty
import java.io.File
import java.net.URL
/* This class starts Jetty.
* NOTE: DO NOT actively use this class. You will see NoClassDefFoundErrors if you fail
* to do so.Only use its name in JettyRun for reflective loading. This allows using
* the Jetty libraries provided on the project classpath instead of requiring them to be
* available on sbt's classpath at startup.
*/
private object LazyJettyRun6 extends JettyRun
{
import org.mortbay.jetty.{Handler, Server}
import org.mortbay.jetty.nio.SelectChannelConnector
import org.mortbay.jetty.webapp.{WebAppClassLoader, WebAppContext}
import org.mortbay.log.{Log, Logger => JLogger}
import org.mortbay.util.Scanner
import org.mortbay.xml.XmlConfiguration
import java.lang.ref.{Reference, WeakReference}
val DefaultMaxIdleTime = 30000
def apply(configuration: JettyConfiguration, jettyLoader: ClassLoader): Stoppable =
{
val oldLog = Log.getLog
Log.setLog(new JettyLogger(configuration.log))
val server = new Server
def configureScanner(listener: Scanner.BulkListener, scanDirectories: Seq[File], scanInterval: Int) =
{
if(scanDirectories.isEmpty)
None
else
{
configuration.log.debug("Scanning for changes to: " + scanDirectories.mkString(", "))
val scanner = new Scanner
val list = new java.util.ArrayList[File]
scanDirectories.foreach(x => list.add(x))
scanner.setScanDirs(list)
scanner.setRecursive(true)
scanner.setScanInterval(scanInterval)
scanner.setReportExistingFilesOnStartup(false)
scanner.addListener(listener)
scanner.start()
Some(new WeakReference(scanner))
}
}
val (listener, scanner) =
configuration match
{
case c: DefaultJettyConfiguration =>
import c._
configureDefaultConnector(server, port)
def classpathURLs = classpath.get.map(_.asURL).toSeq
val webapp = new WebAppContext(war.absolutePath, contextPath)
def createLoader =
{
class SbtWebAppLoader extends WebAppClassLoader(jettyLoader, webapp) { override def addURL(u: URL) = super.addURL(u) };
val loader = new SbtWebAppLoader
classpathURLs.foreach(loader.addURL)
loader
}
def setLoader() = webapp.setClassLoader(createLoader)
setLoader()
server.setHandler(webapp)
val listener = new Scanner.BulkListener with Reload {
def reloadApp() = reload(server, setLoader(), log)
def filesChanged(files: java.util.List[_]) { reloadApp() }
}
(Some(listener), configureScanner(listener, c.scanDirectories, c.scanInterval))
case c: CustomJettyConfiguration =>
for(x <- c.jettyConfigurationXML)
(new XmlConfiguration(x.toString)).configure(server)
for(file <- c.jettyConfigurationFiles)
(new XmlConfiguration(file.toURI.toURL)).configure(server)
(None, None)
}
try
{
server.start()
new StopServer(new WeakReference(server), listener.map(new WeakReference(_)), scanner, oldLog)
}
catch { case e => server.stop(); throw e }
}
private def configureDefaultConnector(server: Server, port: Int)
{
val defaultConnector = new SelectChannelConnector
defaultConnector.setPort(port)
defaultConnector.setMaxIdleTime(DefaultMaxIdleTime)
server.addConnector(defaultConnector)
}
trait Reload { def reloadApp(): Unit }
private class StopServer(serverReference: Reference[Server], reloadReference: Option[Reference[Reload]], scannerReferenceOpt: Option[Reference[Scanner]], oldLog: JLogger) extends Stoppable
{
def reload(): Unit = on(reloadReference)(_.reloadApp())
private def on[T](refOpt: Option[Reference[T]])(f: T => Unit): Unit = refOpt.foreach(ref => onReferenced(ref.get)(f))
private def onReferenced[T](t: T)(f: T => Unit): Unit = if(t == null) () else f(t)
def stop()
{
onReferenced(serverReference.get)(_.stop())
on(scannerReferenceOpt)(_.stop())
Log.setLog(oldLog)
}
}
private def reload(server: Server, reconfigure: => Unit, log: Logger)
{
log.info("Reloading web application...")
val handlers = wrapNull(server.getHandlers, server.getHandler)
log.debug("Stopping handlers: " + handlers.mkString(", "))
handlers.foreach(_.stop)
log.debug("Reconfiguring...")
reconfigure
log.debug("Restarting handlers: " + handlers.mkString(", "))
handlers.foreach(_.start)
log.info("Reload complete.")
}
private def wrapNull(a: Array[Handler], b: Handler) =
(a, b) match
{
case (null, null) => Nil
case (null, notB) => notB :: Nil
case (notA, null) => notA.toList
case (notA, notB) => notB :: notA.toList
}
private class JettyLogger(delegate: Logger) extends JettyLoggerBase(delegate) with JLogger
{
def getLogger(name: String) = this
}
}

View File

@ -0,0 +1,137 @@
package sbt.jetty
import java.io.File
import java.net.URL
/* This class starts Jetty.
* NOTE: DO NOT actively use this class. You will see NoClassDefFoundErrors if you fail
* to do so.Only use its name in JettyRun for reflective loading. This allows using
* the Jetty libraries provided on the project classpath instead of requiring them to be
* available on sbt's classpath at startup.
*/
private object LazyJettyRun7 extends JettyRun
{
import org.eclipse.jetty.server.{Server, Handler}
import org.eclipse.jetty.server.nio.SelectChannelConnector
import org.eclipse.jetty.webapp.{WebAppClassLoader, WebAppContext}
import org.eclipse.jetty.util.log.{Log, Logger => JLogger}
import org.eclipse.jetty.util.Scanner
import org.eclipse.jetty.xml.XmlConfiguration
import java.lang.ref.{Reference, WeakReference}
val DefaultMaxIdleTime = 30000
def apply(configuration: JettyConfiguration, jettyLoader: ClassLoader): Stoppable =
{
val oldLog = Log.getLog
Log.setLog(new JettyLogger(configuration.log))
val server = new Server
def configureScanner(listener: Scanner.BulkListener, scanDirectories: Seq[File], scanInterval: Int) =
{
if(scanDirectories.isEmpty)
None
else
{
configuration.log.debug("Scanning for changes to: " + scanDirectories.mkString(", "))
val scanner = new Scanner
val list = new java.util.ArrayList[File]
scanDirectories.foreach(x => list.add(x))
scanner.setScanDirs(list)
scanner.setRecursive(true)
scanner.setScanInterval(scanInterval)
scanner.setReportExistingFilesOnStartup(false)
scanner.addListener(listener)
scanner.start()
Some(new WeakReference(scanner))
}
}
val (listener, scanner) =
configuration match
{
case c: DefaultJettyConfiguration =>
import c._
configureDefaultConnector(server, port)
def classpathURLs = classpath.get.map(_.asURL).toSeq
val webapp = new WebAppContext(war.absolutePath, contextPath)
def createLoader =
{
class SbtWebAppLoader extends WebAppClassLoader(jettyLoader, webapp) { override def addURL(u: URL) = super.addURL(u) };
val loader = new SbtWebAppLoader
classpathURLs.foreach(loader.addURL)
loader
}
def setLoader() = webapp.setClassLoader(createLoader)
setLoader()
server.setHandler(webapp)
val listener = new Scanner.BulkListener with Reload {
def reloadApp() = reload(server, setLoader(), log)
def filesChanged(files: java.util.List[_]) { reloadApp() }
}
(Some(listener), configureScanner(listener, c.scanDirectories, c.scanInterval))
case c: CustomJettyConfiguration =>
for(x <- c.jettyConfigurationXML)
(new XmlConfiguration(x.toString)).configure(server)
for(file <- c.jettyConfigurationFiles)
(new XmlConfiguration(file.toURI.toURL)).configure(server)
(None, None)
}
try
{
server.start()
new StopServer(new WeakReference(server), listener.map(new WeakReference(_)), scanner, oldLog)
}
catch { case e => server.stop(); throw e }
}
private def configureDefaultConnector(server: Server, port: Int)
{
val defaultConnector = new SelectChannelConnector
defaultConnector.setPort(port)
defaultConnector.setMaxIdleTime(DefaultMaxIdleTime)
server.addConnector(defaultConnector)
}
trait Reload { def reloadApp(): Unit }
private class StopServer(serverReference: Reference[Server], reloadReference: Option[Reference[Reload]], scannerReferenceOpt: Option[Reference[Scanner]], oldLog: JLogger) extends Stoppable
{
def reload(): Unit = on(reloadReference)(_.reloadApp())
private def on[T](refOpt: Option[Reference[T]])(f: T => Unit): Unit = refOpt.foreach(ref => onReferenced(ref.get)(f))
private def onReferenced[T](t: T)(f: T => Unit): Unit = if(t == null) () else f(t)
def stop()
{
onReferenced(serverReference.get)(_.stop())
on(scannerReferenceOpt)(_.stop())
Log.setLog(oldLog)
}
}
private def reload(server: Server, reconfigure: => Unit, log: Logger)
{
log.info("Reloading web application...")
val handlers = wrapNull(server.getHandlers, server.getHandler)
log.debug("Stopping handlers: " + handlers.mkString(", "))
handlers.foreach(_.stop)
log.debug("Reconfiguring...")
reconfigure
log.debug("Restarting handlers: " + handlers.mkString(", "))
handlers.foreach(_.start)
log.info("Reload complete.")
}
private def wrapNull(a: Array[Handler], b: Handler) =
(a, b) match
{
case (null, null) => Nil
case (null, notB) => notB :: Nil
case (notA, null) => notA.toList
case (notA, notB) => notB :: notA.toList
}
private class JettyLogger(delegate: Logger) extends JettyLoggerBase(delegate) with JLogger
{
def getLogger(name: String) = this
}
}

View File

@ -0,0 +1,7 @@
import org.mortbay.jetty.{Handler, Server}
import org.mortbay.jetty.nio.SelectChannelConnector
import org.mortbay.jetty.webapp.{WebAppClassLoader, WebAppContext}
import org.mortbay.log.{Log, Logger => JLogger}
import org.mortbay.util.Scanner
import org.mortbay.xml.XmlConfiguration

View File

@ -0,0 +1,7 @@
import org.eclipse.jetty.server.{Server, Handler}
import org.eclipse.jetty.server.nio.SelectChannelConnector
import org.eclipse.jetty.webapp.{WebAppClassLoader, WebAppContext}
import org.eclipse.jetty.util.log.{Log, Logger => JLogger}
import org.eclipse.jetty.util.Scanner
import org.eclipse.jetty.xml.XmlConfiguration