Adds modified copy of GWT compile plugin.
diff --git a/.gitignore b/.gitignore
index bc2e910..b60f4de 100755
--- a/.gitignore
+++ b/.gitignore
@@ -34,5 +34,5 @@
 *.iml
 *.eml
 .settings/
-project/
+project/target
 target/
diff --git a/build.sbt b/build.sbt
index 80f20f0..e7b3a5f 100644
--- a/build.sbt
+++ b/build.sbt
@@ -41,3 +41,15 @@
 fork in run := true
 
 //parallelExecution in Test := false
+
+//import net.thunderklaus.GwtPlugin._
+
+seq(gwtSettings :_*)
+
+//seq(ScriptedPlugin.scriptedSettings: _*)
+
+libraryDependencies += "org.mortbay.jetty" % "jetty" % "6.1.22" % "container"
+
+gwtVersion := "2.7.0"
+
+gwtModules := List("org.waveprotocol.box.webclient.WebClientProd")
\ No newline at end of file
diff --git a/project/GwtPlugin.scala b/project/GwtPlugin.scala
new file mode 100644
index 0000000..ed32bfa
--- /dev/null
+++ b/project/GwtPlugin.scala
@@ -0,0 +1,157 @@
+package net.thunderklaus
+
+import sbt._
+import sbt.Keys._
+import java.io.File
+import com.earldouglas.xsbtwebplugin.WebPlugin._
+import com.earldouglas.xsbtwebplugin.PluginKeys._
+
+object GwtPlugin extends Plugin {
+
+  lazy val Gwt = config("gwt") extend (Compile)
+
+  val gwtModules = TaskKey[Seq[String]]("gwt-modules")
+  val gwtCompile = TaskKey[Unit]("gwt-compile", "Runs the GWT compiler")
+  val gwtForceCompile = TaskKey[Boolean]("gwt-force-compile", "Always recompile gwt modules")
+  val gwtDevMode = TaskKey[Unit]("gwt-devmode", "Runs the GWT devmode shell")
+  val gwtVersion = SettingKey[String]("gwt-version")
+  val gwtTemporaryPath = SettingKey[File]("gwt-temporary-path")
+  val gwtWebappPath = SettingKey[File]("gwt-webapp-path")
+  val gaeSdkPath = SettingKey[Option[String]]("gae-sdk-path")
+
+  var gwtModule: Option[String] = None
+  val gwtSetModule = Command.single("gwt-set-module") { (state, arg) =>
+    Project.evaluateTask(gwtModules, state) match {
+      case Some(Value(mods)) => {
+        gwtModule = mods.find(_.toLowerCase.contains(arg.toLowerCase))
+        gwtModule match {
+          case Some(m) => println("gwt-devmode will run: " + m)
+          case None => println("No match for '" + arg + "' in " + mods.mkString(", "))
+        }
+      }
+      case _ => None
+    }
+    state
+  }
+
+  lazy val gwtSettings: Seq[Setting[_]] = webSettings ++ gwtOnlySettings
+
+  lazy val gwtOnlySettings: Seq[Setting[_]] = inConfig(Gwt)(Defaults.configSettings) ++ Seq(
+    managedClasspath in Gwt <<= (managedClasspath in Compile, update) map {
+      (cp, up) => cp ++ Classpaths.managedJars(Provided, Set("src"), up)
+    },
+    unmanagedClasspath in Gwt <<= (unmanagedClasspath in Compile),
+    gwtTemporaryPath <<= (target) { (target) => target / "gwt" },
+    gwtWebappPath <<= (target) { (target) => target / "webapp" },
+    gwtVersion := "2.3.0",
+    gwtForceCompile := false,
+    gaeSdkPath := None,
+    libraryDependencies <++= gwtVersion(gwtVersion => Seq(
+      "com.google.gwt" % "gwt-user" % gwtVersion % "provided",
+      "com.google.gwt" % "gwt-dev" % gwtVersion % "provided",
+      "javax.validation" % "validation-api" % "1.0.0.GA" % "provided" withSources (),
+      "com.google.gwt" % "gwt-servlet" % gwtVersion)),
+    gwtModules <<= (javaSource in Compile, resourceDirectory in Compile) map {
+      (javaSource, resources) => findGwtModules(javaSource) ++ findGwtModules(resources)
+    },
+    gwtDevMode <<= (dependencyClasspath in Gwt, thisProject in Gwt,  state in Gwt, javaSource in Compile, javaOptions in Gwt,
+      gwtModules, gaeSdkPath, gwtWebappPath, streams) map {
+      (dependencyClasspath, thisProject, pstate, javaSource, javaOpts, gwtModules, gaeSdkPath, warPath, s) => {
+        def gaeFile (path :String*) = gaeSdkPath.map(_ +: path mkString(File.separator))
+        val module = gwtModule.getOrElse(gwtModules.headOption.getOrElse(error("Found no .gwt.xml files.")))
+        val cp = dependencyClasspath.map(_.data.absolutePath) ++ getDepSources(thisProject.dependencies, pstate) ++
+          gaeFile("lib", "appengine-tools-api.jar").toList :+ javaSource.absolutePath
+        val javaArgs = javaOpts ++ (gaeFile("lib", "agent", "appengine-agent.jar") match {
+          case None => Nil
+          case Some(path) => List("-javaagent:" + path)
+        })
+        val gwtArgs = gaeSdkPath match {
+          case None => Nil
+          case Some(path) => List(
+            "-server", "com.google.appengine.tools.development.gwt.AppEngineLauncher")
+        }
+        val command = mkGwtCommand(
+          cp, javaArgs, "com.google.gwt.dev.DevMode", warPath, gwtArgs, module)
+        s.log.info("Running GWT devmode on: " + module)
+        s.log.debug("Running GWT devmode command: " + command)
+        command !
+      }
+    },
+
+    gwtCompile <<= (classDirectory in Compile, dependencyClasspath in Gwt, thisProject in Gwt, state in Gwt, javaSource in Compile, unmanagedSourceDirectories in Compile, javaOptions in Gwt,
+      gwtModules, gwtTemporaryPath, streams, gwtForceCompile) map {
+      (classDirectory, dependencyClasspath, thisProject, pstate, javaSource, unmanagedSource, javaOpts, gwtModules, warPath, s, force) => {
+
+        val srcDirs = Seq(javaSource.absolutePath) ++  unmanagedSource.map(_.absolutePath) ++ getDepSources(thisProject.dependencies, pstate)
+        val cp = Seq(classDirectory.absolutePath) ++
+          dependencyClasspath.map(_.data.absolutePath) ++
+          srcDirs
+
+        val needToCompile : Boolean = {
+          s.log.info("Checking GWT module updates: " + gwtModules.mkString(", "))
+          val gwtFiles : Seq[File] = (warPath ** "*.nocache.js").get
+          if(gwtFiles.isEmpty) {
+            s.log.info("No GWT output is found in " + warPath)
+            true
+          }
+          else {
+            val lastCompiled = gwtFiles.map(_.lastModified).max
+            val moduleDirs = for(d <- srcDirs; m <- (new File(d) ** "*.gwt.xml").get) yield { m.getParentFile }
+            val gwtSrcs = for(m <- moduleDirs; f <- (m ** "*").get) yield f
+            gwtSrcs.find(lastCompiled < _.lastModified).isDefined
+          }
+        }
+
+        if(force || needToCompile) {
+          val command = mkGwtCommand(
+            cp, javaOpts, "com.google.gwt.dev.Compiler", warPath, Nil, gwtModules.mkString(" "))
+          s.log.info("Compiling GWT modules: " + gwtModules.mkString(","))
+          s.log.debug("Running GWT compiler command: " + command)
+          command !
+        }
+        else
+          s.log.info("GWT modules are up to date")
+      }
+    },
+    webappResources in Compile <+= (gwtTemporaryPath) { (t: File) => t },
+
+    packageWar in Compile <<= (packageWar in Compile).dependsOn(gwtCompile),
+
+    commands ++= Seq(gwtSetModule)
+  )
+
+
+
+
+  def getDepSources(deps : Seq[ClasspathDep[ProjectRef]], state : State) : Set[String] = {
+    var sources = Set.empty[String]
+    val structure = Project.extract(state).structure
+    def get[A] = setting[A](structure)_
+    deps.foreach{
+      dep=>
+        sources +=  (get(dep.project, Keys.sourceDirectory, Compile).get.toString + "/java")
+        sources ++= getDepSources(Project.getProject(dep.project, structure).get.dependencies, state)
+    }
+    sources
+  }
+
+  def setting[T](structure: Load.BuildStructure)(ref: ProjectRef, key: SettingKey[T], configuration: Configuration): Option[T] = key in (ref, configuration) get structure.data
+
+  private def mkGwtCommand(cp: Seq[String], javaArgs: Seq[String], clazz: String, warPath: File,
+                           gwtArgs: Seq[String], modules: String) = {
+    println("classpath: " + cp.mkString("\n"))
+    (List("java", "-cp", cp.mkString(File.pathSeparator)) ++ javaArgs ++
+      List(clazz, "-war", warPath.absolutePath) ++ gwtArgs :+ modules).mkString(" ")
+  }
+
+
+  private def findGwtModules(srcRoot: File): Seq[String] = {
+    import Path.relativeTo
+    val files = (srcRoot ** "*.gwt.xml").get
+    val relativeStrings = files.flatMap(_ x relativeTo(srcRoot)).map(_._2)
+    relativeStrings.map(_.dropRight(".gwt.xml".length).replace(File.separator, "."))
+  }
+
+
+
+}
\ No newline at end of file
diff --git a/project/plugins.sbt b/project/plugins.sbt
new file mode 100644
index 0000000..c5082fc
--- /dev/null
+++ b/project/plugins.sbt
@@ -0,0 +1,4 @@
+//addSbtPlugin("net.thunderklaus" % "sbt-gwt-plugin" % "1.1-105a30073000a6c09d19c1745c49dc58799e68f8")
+
+addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "0.4.0")
+
diff --git a/test/org/waveprotocol/box/server/robots/dataapi/DataApiOAuthServletTest.java b/test/org/waveprotocol/box/server/robots/dataapi/DataApiOAuthServletTest.java
index 4016ab9..67d120b 100644
--- a/test/org/waveprotocol/box/server/robots/dataapi/DataApiOAuthServletTest.java
+++ b/test/org/waveprotocol/box/server/robots/dataapi/DataApiOAuthServletTest.java
@@ -98,15 +98,6 @@
       stringWriter.close();
       closed = true;
     }
-
-    @Override
-    public boolean isReady() {
-      return true;
-    }
-
-    @Override
-    public void setWriteListener(WriteListener wl) {
-    }
   }
 
   private static final String FAKE_TOKEN = "fake_token";