* Remove -linksource as a default option for doc

* First attempt at fixing webapp classloading
 * Additional tests
This commit is contained in:
Mark Harrah 2010-01-13 20:01:06 -05:00
parent e02afb36c8
commit 791c7a2a14
15 changed files with 187 additions and 39 deletions

View File

@ -75,7 +75,6 @@ abstract class BasicScalaProject extends ScalaProject with BasicDependencyProjec
/** The options provided to the 'doc' and 'docTest' actions.*/
def documentOptions: Seq[ScaladocOption] =
LinkSource ::
documentTitle(name + " " + version + " API") ::
windowTitle(name + " " + version + " API") ::
Nil
@ -404,6 +403,7 @@ abstract class BasicWebScalaProject extends BasicScalaProject with WebScalaProje
/** The port that Jetty runs on. */
def jettyPort: Int = JettyRunner.DefaultPort
lazy val jettyReload = task { jettyInstance.reload(); None } describedAs(JettyReloadDescription)
lazy val jettyRestart = jettyStop && jettyRun
lazy val jettyStop = jettyStopAction
protected def jettyStopAction = jettyStopTask(jettyInstance) describedAs(JettyStopDescription)
@ -489,6 +489,8 @@ object BasicWebScalaProject
"Starts the Jetty server and serves this project as a web application."
val JettyDescription =
"Starts the Jetty server and serves this project as a web application. Waits until interrupted, so it is suitable to call this batch-style."
val JettyReloadDescription =
"Forces a reload of a web application running in a Jetty server started by 'jetty-run'. Does nothing if Jetty is not running."
}
/** Analyzes the dependencies of a project after compilation. All methods except `snapshot` return a
* `PathFinder`. The underlying calculations are repeated for each call to PathFinder.get. */

View File

@ -25,6 +25,7 @@ class JettyRunner(configuration: JettyConfiguration) extends ExitHook
running.foreach(_.stop())
running = None
}
def reload() = running.foreach(_.reload())
def apply(): Option[String] =
{
import configuration._
@ -32,10 +33,17 @@ class JettyRunner(configuration: JettyConfiguration) extends ExitHook
{
val baseLoader = this.getClass.getClassLoader
val classpathURLs = jettyClasspath.get.map(_.asURL).toSeq
val loader: ClassLoader = new java.net.URLClassLoader(classpathURLs.toArray, baseLoader)
val lazyLoader = new LazyFrameworkLoader(implClassName, Array(FileUtilities.classLocation[Stoppable].toURI.toURL), loader, baseLoader)
val jettyParentLoader = configuration match { case d: DefaultJettyConfiguration => d.parentLoader; case _ => ClassLoader.getSystemClassLoader }
val jettyLoader: ClassLoader = new java.net.URLClassLoader(classpathURLs.toArray, jettyParentLoader)
val jettyFilter = (name: String) => name.startsWith("org.mortbay.")
val notJettyFilter = (name: String) => !jettyFilter(name)
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]
runner(configuration)
runner(configuration, jettyLoader)
}
if(running.isDefined)
@ -66,10 +74,11 @@ class JettyRunner(configuration: JettyConfiguration) extends ExitHook
private trait Stoppable
{
def stop(): Unit
def reload(): Unit
}
private trait JettyRun
{
def apply(configuration: JettyConfiguration): Stoppable
def apply(configuration: JettyConfiguration, jettyLoader: ClassLoader): Stoppable
}
sealed trait JettyConfiguration extends NotNull
{
@ -105,7 +114,7 @@ private object LazyJettyRun extends JettyRun
{
import org.mortbay.jetty.{Handler, Server}
import org.mortbay.jetty.nio.SelectChannelConnector
import org.mortbay.jetty.webapp.WebAppContext
import org.mortbay.jetty.webapp.{WebAppClassLoader, WebAppContext}
import org.mortbay.log.Log
import org.mortbay.util.Scanner
import org.mortbay.xml.XmlConfiguration
@ -114,7 +123,7 @@ private object LazyJettyRun extends JettyRun
val DefaultMaxIdleTime = 30000
def apply(configuration: JettyConfiguration): Stoppable =
def apply(configuration: JettyConfiguration, jettyLoader: ClassLoader): Stoppable =
{
val oldLog = Log.getLog
Log.setLog(new JettyLogger(configuration.log))
@ -127,15 +136,17 @@ private object LazyJettyRun extends JettyRun
import c._
configureDefaultConnector(server, port)
def classpathURLs = classpath.get.map(_.asURL).toSeq
def createLoader = new URLClassLoader(classpathURLs.toArray, parentLoader)
val webapp = new WebAppContext(war.absolutePath, contextPath)
webapp.setClassLoader(createLoader)
def createLoader = new WebAppClassLoader(jettyLoader, webapp) { override def getURLs = classpathURLs.toArray }
def setLoader() = webapp.setClassLoader(createLoader)
setLoader()
server.setHandler(webapp)
Some(new Scanner.BulkListener {
def filesChanged(files: java.util.List[_]) {
reload(server, webapp.setClassLoader(createLoader), log)
}
Some(new Scanner.BulkListener with Reload {
def reloadApp() = reload(server, setLoader(), log)
def filesChanged(files: java.util.List[_]) { reloadApp() }
})
case c: CustomJettyConfiguration =>
for(x <- c.jettyConfigurationXML)
@ -169,7 +180,7 @@ private object LazyJettyRun extends JettyRun
try
{
server.start()
new StopServer(new WeakReference(server), configureScanner(), oldLog)
new StopServer(new WeakReference(server), listener.map(new WeakReference(_)), configureScanner(), oldLog)
}
catch { case e => server.stop(); throw e }
}
@ -180,19 +191,16 @@ private object LazyJettyRun extends JettyRun
defaultConnector.setMaxIdleTime(DefaultMaxIdleTime)
server.addConnector(defaultConnector)
}
private class StopServer(serverReference: Reference[Server], scannerReferenceOpt: Option[Reference[Scanner]], oldLog: org.mortbay.log.Logger) extends Stoppable
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()
{
val server = serverReference.get
if(server != null)
server.stop()
for(scannerReference <- scannerReferenceOpt)
{
val scanner = scannerReference.get
if(scanner != null)
scanner.stop()
}
onReferenced(serverReference.get)(_.stop())
on(scannerReferenceOpt)(_.stop())
Log.setLog(oldLog)
}
}

View File

@ -0,0 +1,2 @@
project.name=Publish Test
project.version=1.0

View File

@ -0,0 +1,34 @@
import sbt._
class Test(info: ProjectInfo) extends DefaultProject(info)
{
def ivyCacheDirectory = outputPath / "ivy-cache"
override def updateOptions = CacheDirectory(ivyCacheDirectory) :: super.updateOptions.toList
override def managedStyle = ManagedStyle.Maven
def testRepoPath = path("test-repo")
val publishTo = Resolver.file("test repo", testRepoPath asFile)
def srcExt = "-sources.jar"
def srcFilter = extFilter(srcExt)
def docExt = "-javadoc.jar"
def docFilter = extFilter(docExt)
def extFilter(ext: String) = "*" + ext
override def packageDocsJar = defaultJarPath(docExt)
override def packageSrcJar= defaultJarPath(srcExt)
val sourceArtifact = Artifact(artifactID, "src", "jar", "sources")
val docsArtifact = Artifact(artifactID, "docs", "jar", Some("javadoc"), Nil, None)
override def packageToPublishActions = super.packageToPublishActions ++ Seq(packageDocs, packageSrc)
lazy val check = task { check0 }
def check0 = checkPom orElse checkBin orElse checkSource orElse checkDoc
def checkPom = exists("pom", "*.pom")
def checkDoc = exists("javadoc", docFilter)
def checkSource = exists("sources", srcFilter)
def checkBin = exists("binary", "*.jar" - (srcFilter | docFilter))
def exists(label: String, filter: sbt.NameFilter) =
if( (testRepoPath ** filter).get.isEmpty) Some("No " + label + " published") else None
}

View File

@ -0,0 +1 @@
class TestClass

View File

@ -0,0 +1,3 @@
-> check
> publish
> check

View File

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

View File

@ -9,20 +9,12 @@ class JSP(info: ProjectInfo) extends DefaultWebProject(info)
def indexFile = new java.io.File("index.html")
import Process._
lazy val getPage = execTask { indexURL #> indexFile }
lazy val checkPage = task { checkHelloWorld() } dependsOn getPage
private def checkHelloWorld() =
lazy val checkPage = task { args => task { checkHelloWorld(args.mkString(" ")) } dependsOn getPage }
private def checkHelloWorld(checkString: String) =
{
try
{
FileUtilities.readString(indexFile, log) match
{
case Right(value) =>
if(value.contains("Hello World!")) None
else Some("index.html did not contain 'Hello World!' :\n" +value)
case Left(msg) => Some(msg)
}
}
finally { jettyInstance.stop() }
val value = xsbt.FileUtilities.read(indexFile)
if(value.contains(checkString)) None else Some("index.html did not contain '" + checkString + "' :\n" +value)
}
}

View File

@ -1,4 +1,12 @@
> update
> jetty-run
> check-page
> jetty-stop
> 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

@ -0,0 +1,20 @@
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

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

View File

@ -0,0 +1,19 @@
import sbt._
class WebappBuild(info: ProjectInfo) extends DefaultWebProject(info) {
val servlet_api = "org.mortbay.jetty" % "servlet-api-2.5" % "6.1.14" % "provided->default"
val jetty_servlet = "org.mortbay.jetty" % "jetty" % "6.1.14" % "test->default"
def indexURL = new java.net.URL("http://localhost:8080")
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

@ -0,0 +1,20 @@
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

@ -0,0 +1,18 @@
<!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>Archetype Created 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

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