web app support split out to plugin

This commit is contained in:
Mark Harrah 2011-05-07 22:02:05 -04:00
parent 5e9b080fc8
commit 37823e5ffb
38 changed files with 0 additions and 904 deletions

View File

@ -53,8 +53,6 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
val cacheSub = project(cachePath, "Cache", new CacheProject(_), ioSub, collectionSub)
// Builds on cache to provide caching for filesystem-related operations
val trackingSub = baseProject(cachePath / "tracking", "Tracking", cacheSub, ioSub)
// Interface to Jetty
val webappSub = project("web", "Web App", new WebAppProject(_), ioSub, logSub, classpathSub, controlSub)
// Embedded Scala code runner
val runSub = baseProject("run", "Run", ioSub, logSub, classpathSub, processSub)
@ -146,37 +144,6 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
{
val jline = jlineDep
}
class WebAppProject(info: ProjectInfo) extends Base(info)
{
val jetty = "org.mortbay.jetty" % "jetty" % "6.1.14" % "optional"
val jettyplus = "org.mortbay.jetty" % "jetty-plus" % "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 jetty7plus = "org.eclipse.jetty" % "jetty-plus" % "7.0.1.v20091125" % "optional"
val optional = Configurations.Optional
/* 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 = info.projectPath
def jettyTemplate = jettySrcDir / "LazyJettyRun.scala.templ"
lazy val generateJettyRun6 = generateJettyRunN("6")
lazy val generateJettyRun7 = generateJettyRunN("7")
def generateJettyRunN(n: String) =
generateJettyRun(jettyTemplate, jettySrcDir / ("LazyJettyRun" + n + ".scala"), n, jettySrcDir / ("jetty" + n + ".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)
}
trait TestDependencies extends Project
{
val sc = "org.scala-tools.testing" % "scalacheck_2.8.0" % "1.7" % "test"

View File

@ -1,38 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<New id="testEnvEntry" class="org.eclipse.jetty.plus.jndi.EnvEntry">
<Arg></Arg>
<Arg>testValue</Arg>
<Arg type="java.lang.String">It works</Arg>
<Arg type="boolean">true</Arg>
</New>
<!--
<New id="DbNameDataSource" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg>jdbc/DbName</Arg>
<Arg>
<New class="com.mchange.v2.c3p0.ComboPooledDataSource">
<Set name="driverClass">com.mysql.jdbc.Driver</Set>
<Set name="jdbcUrl">jdbc:mysql://localhost/dbName</Set>
<Set name="User">myUsername</Set>
<Set name="Password">myPassword</Set>
<Set name="maxPoolSize">30</Set>
<Set name="checkoutTimeout">1800</Set>
</New>
</Arg>
</New>
<New id="DbNameDataSource" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg>jdbc/DbName</Arg>
<Arg>
<New class="com.mchange.v2.c3p0.ComboPooledDataSource">
<Set name="driverClass">org.h2.Driver</Set>
<Set name="jdbcUrl">jdbc:h2:tcp://localhost/~/dbName</Set>
<Set name="jdbcUrl">jdbc:h2:mem:dbName</Set>
<Set name="User">myUsername</Set>
<Set name="Password">myPassword</Set>
</New>
</Arg>
</New>
-->
</Configure>

View File

@ -1,3 +0,0 @@
project.organization=sbt
project.name=JettyEnvTest
project.version=1.0

View File

@ -1,24 +0,0 @@
import sbt._
import java.io.File
import java.lang.System
import Process._
class JettyEnvTestProject(info: ProjectInfo) extends DefaultWebProject(info){
override def jettyEnvXml = Some( (info.projectPath / "conf" / "jetty" / "jetty-env.xml").asFile)
val jetty7WebApp = "org.eclipse.jetty" % "jetty-webapp" % "7.0.2.RC0" % "test"
val jetty7Plus = "org.eclipse.jetty" % "jetty-plus" % "7.0.2.RC0" % "test"
val servletApiDep = "javax.servlet" % "servlet-api" % "2.5" % "provided"
def indexURL = new java.net.URL("http://localhost:" + jettyPort)
def indexFile = new java.io.File("index.html")
override def jettyPort = 7127
lazy val getPage = execTask { indexURL #> indexFile }
lazy val checkPage = task { args => task { checkHelloWorld(args.mkString(" ")) } dependsOn getPage }
private def checkHelloWorld(checkString: String) =
{
val value = xsbt.FileUtilities.read(indexFile)
if(value.contains(checkString)) None else Some("index.html did not contain '" + checkString + "' :\n" +value)
}
}

View File

@ -1,14 +0,0 @@
import javax.servlet.http.{HttpServlet, HttpServletRequest => HSReq, HttpServletResponse => HSResp}
import javax.naming.{InitialContext => IC};
class HelloJndi extends HttpServlet {
val key = "java:comp/env/testValue"
val testValue = (new IC).lookup(key)
override def doGet(req : HSReq, resp : HSResp) =
resp.getWriter().print("<HTML>" +
"<HEAD><TITLE>Hello JNDI!</TITLE></HEAD>" +
"<BODY>Hello JNDI, <br/>Value of " + key + ": " + testValue + "</BODY>" +
"</HTML>")
}

View File

@ -1,13 +0,0 @@
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>helloJNDI</servlet-name>
<servlet-class>HelloJndi</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloJNDI</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

View File

@ -1,9 +0,0 @@
> ++2.7.7
> update
# verify that it fails without Jetty running
-> check-page It works
> jetty-run
# verify it now works with our servlet running
> check-page It works
> jetty-stop

View File

@ -1,5 +0,0 @@
<html>
<body>
<% out.println(" Hello World 2!"); %>
</body>
</html>

View File

@ -1,2 +0,0 @@
project.name=JSP Test
project.version=a

View File

@ -1,21 +0,0 @@
import sbt._
class JSP(info: ProjectInfo) extends DefaultWebProject(info)
{
val j6 = "org.mortbay.jetty" % "jetty" % "6.1.17" % "test->default"
val j = "org.mortbay.jetty" % "jsp-2.0" % "6.1.17" % "test->default"
def indexURL = new java.net.URL("http://localhost:" + jettyPort)
override def jettyPort = 7126
def indexFile = new java.io.File("index.html")
import Process._
lazy val getPage = execTask { indexURL #> indexFile }
lazy val checkPage = task { args => task { checkHelloWorld(args.mkString(" ")) } dependsOn getPage }
private def checkHelloWorld(checkString: String) =
{
val value = xsbt.FileUtilities.read(indexFile)
if(value.contains(checkString)) None else Some("index.html did not contain '" + checkString + "' :\n" +value)
}
}

View File

@ -1,5 +0,0 @@
<html>
<body>
<% out.println(" Hello World!"); %>
</body>
</html>

View File

@ -1,12 +0,0 @@
> update
> jetty-run
> check-page "Hello World!"
$ copy-file changes/index.jsp src/main/webapp/index.jsp
> prepare-webapp
> jetty-reload
> check-page "Hello World 2!"
> jetty-stop
-> check-page "Hello World 2!"

View File

@ -1,20 +0,0 @@
package test
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class MyServlet extends HttpServlet {
val html = <HTML>
<HEAD><TITLE>Hello, Scala!</TITLE></HEAD>
<BODY>Hello, Scala! This is a servlet.</BODY>
</HTML>
override def doGet(req:HttpServletRequest, resp:HttpServletResponse) {
resp.setContentType("text/html")
resp.getWriter().print(html.toString)
}
def check28(f: Int = 3) = f
}

View File

@ -1,20 +0,0 @@
package test
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class MyServlet extends HttpServlet {
val html = <HTML>
<HEAD><TITLE>Hello, Scala 2!</TITLE></HEAD>
<BODY>Hello, Scala 2! This is a servlet.</BODY>
</HTML>
override def doGet(req:HttpServletRequest, resp:HttpServletResponse) {
resp.setContentType("text/html")
resp.getWriter().print(html.toString)
}
def check28(f: Int = 3) = f
}

View File

@ -1,3 +0,0 @@
project.organization=tester
project.name=sbtweb
project.version=1.0

View File

@ -1,28 +0,0 @@
import sbt._
class WebappBuild(info: ProjectInfo) extends DefaultWebProject(info) {
override def libraryDependencies = if("jetty7".asFile.exists) jetty7Dependencies else jetty6Dependencies
def jetty6Dependencies =
Set("org.mortbay.jetty" % "servlet-api-2.5" % "6.1.14" % "provided->default",
"org.mortbay.jetty" % "jetty" % "6.1.14" % "test->default")
def jetty7Dependencies =
Set("javax.servlet" % "servlet-api" % "2.5" % "provided",
"org.eclipse.jetty" % "jetty-server" % "7.0.1.v20091125" % "test",
"org.eclipse.jetty" % "jetty-webapp" % "7.0.1.v20091125" % "test")
def indexURL = new java.net.URL("http://localhost:" + jettyPort)
override def jettyPort = 7125
def indexFile = new java.io.File("index.html")
import Process._
lazy val getPage = execTask { indexURL #> indexFile }
lazy val checkPage = task { args => task { checkHelloWorld(args.mkString(" ")) } dependsOn getPage }
override def jettyWebappPath = webappPath
private def checkHelloWorld(checkString: String) =
{
val value = xsbt.FileUtilities.read(indexFile)
if(value.contains(checkString)) None else Some("index.html did not contain '" + checkString + "' :\n" +value)
}
}

View File

@ -1,18 +0,0 @@
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Test Web Application</display-name>
<servlet>
<servlet-name>Home</servlet-name>
<servlet-class>test.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Home</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

View File

@ -1,30 +0,0 @@
> ++2.8.0.Beta1
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
> update
> jetty-run
> check-page "Hello, Scala!"
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
> prepare-webapp
> jetty-reload
> check-page "Hello, Scala 2!"
> jetty-stop
-> check-page "Hello World 2!"
$ touch jetty7
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
> update
> jetty-run
> check-page "Hello, Scala!"
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
> prepare-webapp
> jetty-reload
> check-page "Hello, Scala 2!"
> jetty-stop
-> check-page "Hello World 2!"

View File

@ -1,24 +0,0 @@
package test
import java.util.Collections
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class MyServlet extends HttpServlet {
val html = <HTML>
<HEAD><TITLE>Hello, Scala!</TITLE></HEAD>
<BODY>Hello, Scala! This is a servlet.</BODY>
</HTML>
override def doGet(req:HttpServletRequest, resp:HttpServletResponse) {
val found = Collections.list(getClass.getClassLoader.getResources("test/MyServlet.class"))
assert( found.size == 1, "Multiple instances of MyServlet.class on classpath")
resp.setContentType("text/html")
resp.getWriter().print(html.toString)
}
def check28(f: Int = 3) = f
}

View File

@ -1,24 +0,0 @@
package test
import java.util.Collections
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class MyServlet extends HttpServlet {
val html = <HTML>
<HEAD><TITLE>Hello, Scala 2!</TITLE></HEAD>
<BODY>Hello, Scala 2! This is a servlet.</BODY>
</HTML>
override def doGet(req:HttpServletRequest, resp:HttpServletResponse) {
val found = Collections.list(getClass.getClassLoader.getResources("test/MyServlet.class"))
assert( found.size == 1, "Multiple instances of MyServlet.class on classpath")
resp.setContentType("text/html")
resp.getWriter().print(html.toString)
}
def check28(f: Int = 3) = f
}

View File

@ -1,3 +0,0 @@
project.organization=tester
project.name=sbtweb
project.version=1.0

View File

@ -1,26 +0,0 @@
import sbt._
class WebappBuild(info: ProjectInfo) extends DefaultWebProject(info) {
override def libraryDependencies = if("jetty7".asFile.exists) jetty7Dependencies else jetty6Dependencies
def jetty6Dependencies =
Set("org.mortbay.jetty" % "servlet-api-2.5" % "6.1.14" % "provided->default",
"org.mortbay.jetty" % "jetty" % "6.1.14" % "test->default")
def jetty7Dependencies =
Set("javax.servlet" % "servlet-api" % "2.5" % "provided",
"org.eclipse.jetty" % "jetty-server" % "7.0.1.v20091125" % "test",
"org.eclipse.jetty" % "jetty-webapp" % "7.0.1.v20091125" % "test")
def indexURL = new java.net.URL("http://localhost:" + jettyPort)
override def jettyPort = 7124
def indexFile = new java.io.File("index.html")
import Process._
lazy val getPage = execTask { indexURL #> indexFile }
lazy val checkPage = task { args => task { checkHelloWorld(args.mkString(" ")) } dependsOn getPage }
private def checkHelloWorld(checkString: String) =
{
val value = xsbt.FileUtilities.read(indexFile)
if(value.contains(checkString)) None else Some("index.html did not contain '" + checkString + "' :\n" +value)
}
}

View File

@ -1,18 +0,0 @@
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Test Web Application</display-name>
<servlet>
<servlet-name>Home</servlet-name>
<servlet-class>test.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Home</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

View File

@ -1,32 +0,0 @@
> ++2.8.0.Beta1
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
> update
> jetty-run
> check-page "Hello, Scala!"
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
> prepare-webapp
> jetty-reload
> check-page "Hello, Scala 2!"
> jetty-stop
-> check-page "Hello World 2!"
# test that it works with Jetty 7 support
$ touch jetty7
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
> update
> jetty-run
> check-page "Hello, Scala!"
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
> prepare-webapp
> jetty-reload
> check-page "Hello, Scala 2!"
> jetty-stop
-> check-page "Hello World 2!"

View File

@ -1,20 +0,0 @@
package test
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class MyServlet extends HttpServlet {
val html = <HTML>
<HEAD><TITLE>Hello, Scala!</TITLE></HEAD>
<BODY>Hello, Scala! This is a servlet.</BODY>
</HTML>
override def doGet(req:HttpServletRequest, resp:HttpServletResponse) {
resp.setContentType("text/html")
resp.getWriter().print(html.toString)
}
def check28(f: Int = 3) = f
}

View File

@ -1,20 +0,0 @@
package test
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class MyServlet extends HttpServlet {
val html = <HTML>
<HEAD><TITLE>Hello, Scala 2!</TITLE></HEAD>
<BODY>Hello, Scala 2! This is a servlet.</BODY>
</HTML>
override def doGet(req:HttpServletRequest, resp:HttpServletResponse) {
resp.setContentType("text/html")
resp.getWriter().print(html.toString)
}
def check28(f: Int = 3) = f
}

View File

@ -1,3 +0,0 @@
project.organization=tester
project.name=sbtweb
project.version=1.0

View File

@ -1,35 +0,0 @@
import sbt._
class WebappBuild(info: ProjectInfo) extends DefaultWebProject(info) {
override def libraryDependencies =
if("jetty7.0".asFile.exists)
jetty70Dependencies
else if("jetty7.1".asFile.exists)
jetty71Dependencies
else
jetty6Dependencies
def jetty6Dependencies =
Set("org.mortbay.jetty" % "servlet-api-2.5" % "6.1.14" % "provided->default",
"org.mortbay.jetty" % "jetty" % "6.1.14" % "test->default")
def jetty70Dependencies =
Set("javax.servlet" % "servlet-api" % "2.5" % "provided",
"org.eclipse.jetty" % "jetty-webapp" % "7.0.1.v20091125" % "test")
def jetty71Dependencies =
Set("javax.servlet" % "servlet-api" % "2.5" % "provided",
"org.eclipse.jetty" % "jetty-webapp" % "7.1.6.v20100715" % "test")
def indexURL = new java.net.URL("http://localhost:" + jettyPort)
def indexFile = new java.io.File("index.html")
override def jettyPort = 7123
import Process._
lazy val getPage = execTask { indexURL #> indexFile }
lazy val checkPage = task { args => task { checkHelloWorld(args.mkString(" ")) } dependsOn getPage }
private def checkHelloWorld(checkString: String) =
{
val value = xsbt.FileUtilities.read(indexFile)
if(value.contains(checkString)) None else Some("index.html did not contain '" + checkString + "' :\n" +value)
}
}

View File

@ -1,18 +0,0 @@
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Test Web Application</display-name>
<servlet>
<servlet-name>Home</servlet-name>
<servlet-class>test.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Home</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

View File

@ -1,54 +0,0 @@
> set build.scala.versions 2.8.0
> reload
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
> update
> jetty-run
> check-page "Hello, Scala!"
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
> prepare-webapp
> jetty-reload
> check-page "Hello, Scala 2!"
> jetty-stop
-> check-page "Hello World 2!"
# test that it works with Jetty 7 support
$ touch jetty7.0
> reload
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
> update
> jetty-run
> check-page "Hello, Scala!"
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
> prepare-webapp
> jetty-reload
> check-page "Hello, Scala 2!"
> jetty-stop
-> check-page "Hello World 2!"
# test that it works with Jetty 7 support
$ touch jetty7.1
> reload
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
> update
> jetty-run
> check-page "Hello, Scala!"
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
> prepare-webapp
> jetty-reload
> check-page "Hello, Scala 2!"
> jetty-stop
-> check-page "Hello World 2!"

View File

@ -1,2 +0,0 @@
project.name=Webapp Unmanaged
project.version=1.0

View File

@ -1,7 +0,0 @@
import sbt._
class UnmanagedTest(info: ProjectInfo) extends DefaultWebProject(info)
{
override def disableCrossPaths = true
override def webappUnmanaged = temporaryWarPath / "WEB-INF" / "appengine-generated" ***
}

View File

@ -1,6 +0,0 @@
> prepare-webapp
$ touch target/webapp/WEB-INF/appengine-generated/test-keep
$ touch target/webapp/WEB-INF/other/test-remove
> prepare-webapp
$ exists target/webapp/WEB-INF/appengine-generated/test-keep
$ absent target/webapp/WEB-INF/other/test-remove

View File

@ -1,144 +0,0 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009, 2010 Mark Harrah
*/
package sbt
package 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}
// Jetty classes must be loaded on initialization in order for the version detection code in WebApp to work properly
// this forces them to be loaded- otherwise, it is possible they aren't loaded until 'apply' is called
private[this] val forceJettyLoad = classOf[Server]
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)
val webapp = new WebAppContext(war.absolutePath, contextPath)
webDefaultXml.foreach{webDefaultXml:File => webapp.setDefaultsDescriptor(webDefaultXml.toString)}
def createLoader =
{
// Jetty treats WebAppClassLoader subclasses specially and we need this special behavior.
// However, Jetty adds extra classpath components directly using 'addURL'.
// We only want the 'urls' we provide in the constructor, so 'addURL' is overridden to do nothing.
class SbtWebAppLoader(urls: Seq[URL]) extends WebAppClassLoader(jettyLoader, webapp)
{
urls.foreach(super.addURL)
override def addURL(u: URL) = {}
}
new SbtWebAppLoader(classpath.getURLs)
}
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: AbstractLogger) extends JettyLoggerBase(delegate) with JLogger
{
def getLogger(name: String) = this
}
}

View File

@ -1,3 +0,0 @@
Simple Build Tool: Process Component
Copyright 2008, 2009, 2010 Mark Harrah, Vesa Vilhonen
Licensed under BSD-style license (see LICENSE)

View File

@ -1,150 +0,0 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009, 2010 Mark Harrah
*/
package sbt
import java.io.File
import java.net.{URL, URLClassLoader}
import scala.xml.NodeSeq
import classpath.ClasspathUtilities
object JettyRunner
{
val DefaultPort = 8080
val DefaultScanInterval = 3
}
class JettyRunner(configuration: JettyConfiguration) extends ExitHook
{
def name = "jetty-shutdown"
def runBeforeExiting() { stop() }
private var running: Option[Stoppable] = None
private def started(s: Stoppable) { running = Some(s) }
def stop()
{
running.foreach(_.stop())
running = None
}
def reload() = running.foreach(_.reload())
def apply(): Option[String] =
{
import configuration._
def runJetty() =
{
val baseLoader = this.getClass.getClassLoader
val jettyParentLoader = configuration match { case d: DefaultJettyConfiguration => d.parentLoader; case _ => ClassLoader.getSystemClassLoader }
val jettyLoader: ClassLoader = ClasspathUtilities.toLoader(jettyClasspath, jettyParentLoader)
val jettyFilter = (name: String) => name.startsWith("org.mortbay.") || name.startsWith("org.eclipse.jetty.")
val notJettyFilter = (name: String) => !jettyFilter(name)
val dual = new classpath.DualLoader(baseLoader, notJettyFilter, x => true, jettyLoader, jettyFilter, x => false)
def createRunner(implClassName: String) =
{
val lazyLoader = new classpath.LazyFrameworkLoader(implClassName, Array(IO.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)
}
if(running.isDefined)
Some("This instance of Jetty is already running.")
else
{
try
{
started(runJetty())
None
}
catch
{
case e: NoClassDefFoundError => runError(e, "Jetty and its dependencies must be on the " + classpathName + " classpath: ", log)
case e => runError(e, "Error running Jetty: ", log)
}
}
}
private val implClassName6 = "sbt.jetty.LazyJettyRun6"
private val implClassName7 = "sbt.jetty.LazyJettyRun7"
private def runError(e: Throwable, messageBase: String, log: Logger) =
{
log.trace(e)
Some(messageBase + e.toString)
}
}
private trait Stoppable
{
def stop(): Unit
def reload(): Unit
}
private trait JettyRun
{
def apply(configuration: JettyConfiguration, jettyLoader: ClassLoader): Stoppable
}
sealed trait JettyConfiguration extends NotNull
{
/** The classpath to get Jetty from. */
def jettyClasspath: PathFinder
def classpathName: String
def log: AbstractLogger
}
trait DefaultJettyConfiguration extends JettyConfiguration
{
def war: Path
def scanDirectories: Seq[File]
def scanInterval: Int
def contextPath: String
def port: Int
/** The classpath containing the classes, jars, and resources for the web application. */
def classpath: PathFinder
def parentLoader: ClassLoader
def jettyEnv: Option[File]
def webDefaultXml: Option[File]
}
abstract class CustomJettyConfiguration extends JettyConfiguration
{
def jettyConfigurationFiles: Seq[File] = Nil
def jettyConfigurationXML: NodeSeq = NodeSeq.Empty
}
private class JettyLoggerBase(delegate: AbstractLogger)
{
def getName = "JettyLogger"
def isDebugEnabled = delegate.atLevel(Level.Debug)
def setDebugEnabled(enabled: Boolean) = delegate.setLevel(if(enabled) Level.Debug else Level.Info)
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 info(msg: String, args: Array[AnyRef]) { delegate.info(format(msg, args: _*)) }
def debug(msg: String, args: Array[AnyRef]) { delegate.debug(format(msg, args: _*)) }
def warn(msg: String, args: Array[AnyRef]) { delegate.warn(format(msg, args: _*)) }
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, args: AnyRef*) =
{
def toString(arg: AnyRef) = if(arg == null) "" else arg.toString
val pieces = msg.split("""\{\}""", args.length + 1).toList
val argStrs = args.map(toString).toList ::: List("")
pieces.zip(argStrs).foldLeft(new StringBuilder) { (sb, pair) =>
val (piece, argStr) = pair
if (piece.isEmpty) sb
else sb.append(piece).append(argStr)
}.toString
}
}

View File

@ -1,8 +0,0 @@
import org.mortbay.jetty.{Handler, Server}
import org.mortbay.jetty.nio.SelectChannelConnector
import org.mortbay.jetty.webapp.{WebAppClassLoader, WebAppContext, WebInfConfiguration, Configuration, JettyWebXmlConfiguration, TagLibConfiguration, WebXmlConfiguration}
import org.mortbay.log.{Log, Logger => JLogger}
import org.mortbay.util.Scanner
import org.mortbay.xml.XmlConfiguration
import org.mortbay.jetty.plus.webapp.{EnvConfiguration, Configuration=>PlusConfiguration}

View File

@ -1,9 +0,0 @@
import org.eclipse.jetty.server.{Server, Handler}
import org.eclipse.jetty.server.nio.SelectChannelConnector
import org.eclipse.jetty.webapp.{WebAppClassLoader, WebAppContext, WebInfConfiguration, Configuration, FragmentConfiguration, JettyWebXmlConfiguration, TagLibConfiguration, WebXmlConfiguration}
import org.eclipse.jetty.util.log.{Log, Logger => JLogger}
import org.eclipse.jetty.util.Scanner
import org.eclipse.jetty.xml.XmlConfiguration
import org.eclipse.jetty.plus.webapp.{EnvConfiguration, Configuration=>PlusConfiguration}