Merging from releases/1.6@3944:4025

svn merge -r3944:4025 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4032 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/build.xml b/build.xml
index 4efa2f8..6b8bcc9 100755
--- a/build.xml
+++ b/build.xml
@@ -7,9 +7,9 @@
   <property name="target" value="build" />
 
   <property name="gwt.apicheck.config" 
-    location="tools/api-checker/config/gwt14_15userApi.conf"/>
+    location="tools/api-checker/config/gwt15_16userApi.conf"/>
   <property name="gwt.apicheck.oldroot" 
-    location="../gwt-1.4"/>
+    location="../gwt-1.5"/>
 
   <target name="dist" depends="dev, user, servlet, tools, jni, doc, samples" description="Run the distributions">
     <gwt.ant dir="distro-source" />
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JPackage.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JPackage.java
index 23ea00f..5db5a59 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JPackage.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JPackage.java
@@ -28,7 +28,7 @@
 
   private final Annotations annotations = new Annotations();
 
-  private final Map<String, JClassType> types = new HashMap<String, JClassType>();
+  private final Map<String, JRealClassType> types = new HashMap<String, JRealClassType>();
 
   JPackage(String name) {
     this.name = name;
@@ -81,7 +81,7 @@
     return "package " + name;
   }
 
-  void addType(JClassType type) {
+  void addType(JRealClassType type) {
     types.put(type.getSimpleSourceName(), type);
   }
 
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
index 955146f..e326756 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
@@ -87,6 +87,7 @@
       } while (enclosing != null);
       nestedName = nn;
     }
+    oracle.addNewType(this);
   }
 
   public void addAnnotations(
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
index e217ce2..75e8e2e 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
@@ -167,10 +167,14 @@
     }
   }
 
-  private Set<JClassType> allTypes = null;
+  private final Set<JRealClassType> allTypes = new HashSet<JRealClassType>();
 
   private final Map<JType, JArrayType> arrayTypes = new IdentityHashMap<JType, JArrayType>();
 
+  /**
+   * A set of invalidated types queued up to be removed on the next
+   * {@link #reset()}.
+   */
   private final Set<JRealClassType> invalidatedTypes = new HashSet<JRealClassType>();
 
   private JClassType javaLangObject;
@@ -179,6 +183,12 @@
 
   private final Map<String, List<JParameterizedType>> parameterizedTypes = new HashMap<String, List<JParameterizedType>>();
 
+  /**
+   * A list of recently-added types that will be fully initialized on the next
+   * call to {@link #finish(TreeLogger)}.
+   */
+  private final List<JRealClassType> recentTypes = new ArrayList<JRealClassType>();
+
   private int reloadCount = 0;
 
   private final Map<String, List<JWildcardType>> wildcardTypes = new HashMap<String, List<JWildcardType>>();
@@ -248,6 +258,18 @@
   }
 
   /**
+   * Called after a block of new types are added.
+   * 
+   * TODO: make not public?
+   */
+  public void finish(TreeLogger logger) {
+    JClassType[] newTypes = recentTypes.toArray(NO_JCLASSES);
+    computeHierarchyRelationships(newTypes);
+    consumeTypeArgMetaData(logger, newTypes);
+    recentTypes.clear();
+  }
+
+  /**
    * Gets the type object that represents an array of the specified type. The
    * returned type always has a stable identity so as to guarantee that all
    * calls to this method with the same argument return the same object.
@@ -270,7 +292,10 @@
    * <code>java.lang.Object</code>.
    */
   public JClassType getJavaLangObject() {
-    assert javaLangObject != null;
+    if (javaLangObject == null) {
+      javaLangObject = findType("java.lang.Object");
+      assert javaLangObject != null;
+    }
     return javaLangObject;
   }
 
@@ -457,18 +482,6 @@
    * @return an array of types, possibly of zero length
    */
   public JClassType[] getTypes() {
-    if (allTypes == null) {
-      allTypes = new HashSet<JClassType>();
-      JPackage[] pkgs = getPackages();
-      for (int i = 0; i < pkgs.length; i++) {
-        JPackage pkg = pkgs[i];
-        JClassType[] types = pkg.getTypes();
-        for (int j = 0; j < types.length; j++) {
-          JRealClassType type = (JRealClassType) types[j];
-          buildAllTypesImpl(allTypes, type);
-        }
-      }
-    }
     return allTypes.toArray(NO_JCLASSES);
   }
 
@@ -525,35 +538,12 @@
   }
 
   /**
-   * Updates relationships within this type oracle. Should be called after any
-   * changes are made.
-   * 
-   * <p>
-   * Throws <code>TypeOracleException</code> thrown if fundamental baseline
-   * correctness criteria are violated, most notably the absence of
-   * "java.lang.Object"
-   * </p>
+   * Reset this type oracle for rebuild.
    * 
    * TODO: make this not public.
    */
-  public void refresh(TreeLogger logger) throws NotFoundException {
-    allTypes = null;
-    if (javaLangObject == null) {
-      javaLangObject = findType("java.lang.Object");
-      if (javaLangObject == null) {
-        throw new NotFoundException("java.lang.Object");
-      }
-    }
-    computeHierarchyRelationships();
-    consumeTypeArgMetaData(logger);
-  }
-
-  /**
-   * Removes all types that are no longer valid.
-   * 
-   * TODO: make not public?
-   */
-  public void removeInvalidatedTypes() {
+  public void reset() {
+    recentTypes.clear();
     if (!invalidatedTypes.isEmpty()) {
       invalidateTypes(invalidatedTypes);
       invalidatedTypes.clear();
@@ -620,32 +610,25 @@
     });
   }
 
+  void addNewType(JRealClassType newType) {
+    allTypes.add(newType);
+    recentTypes.add(newType);
+  }
+
   void invalidate(JRealClassType realClassType) {
     invalidatedTypes.add(realClassType);
   }
 
-  private void buildAllTypesImpl(Set<JClassType> allTypes, JRealClassType type) {
-    boolean didAdd = allTypes.add(type);
-    assert (didAdd);
-    JClassType[] nestedTypes = type.getNestedTypes();
-    for (int i = 0; i < nestedTypes.length; i++) {
-      JRealClassType nestedType = (JRealClassType) nestedTypes[i];
-      buildAllTypesImpl(allTypes, nestedType);
-    }
-  }
-
-  private void computeHierarchyRelationships() {
+  private void computeHierarchyRelationships(JClassType[] types) {
     // For each type, walk up its hierarchy chain and tell each supertype
     // about its subtype.
-    //
-    JClassType[] types = getTypes();
     for (int i = 0; i < types.length; i++) {
       JClassType type = types[i];
       type.notifySuperTypes();
     }
   }
 
-  private void consumeTypeArgMetaData(TreeLogger logger) {
+  private void consumeTypeArgMetaData(TreeLogger logger, JClassType[] types) {
     if (GenUtil.warnAboutMetadata()) {
       logger = logger.branch(
           TreeLogger.DEBUG,
@@ -654,10 +637,6 @@
               + " javadoc annotation; please use Java parameterized types instead",
           null);
     }
-    consumeTypeArgMetaData(logger, getTypes());
-  }
-
-  private void consumeTypeArgMetaData(TreeLogger logger, JClassType[] types) {
     for (int i = 0; i < types.length; i++) {
       JClassType type = types[i];
       // CTORS not supported yet
@@ -1012,12 +991,16 @@
   private void removeTypes(Set<JRealClassType> invalidTypes) {
     for (Iterator<JRealClassType> iter = invalidTypes.iterator(); iter.hasNext();) {
       JClassType classType = iter.next();
+
+      allTypes.remove(classType);
+
       JPackage pkg = classType.getPackage();
       if (pkg != null) {
         pkg.remove(classType);
       }
 
       classType.removeFromSupertypes();
+
       iter.remove();
     }
   }
diff --git a/dev/core/src/com/google/gwt/dev/CompileArgProcessor.java b/dev/core/src/com/google/gwt/dev/CompileArgProcessor.java
index d19ae45..14047e5 100644
--- a/dev/core/src/com/google/gwt/dev/CompileArgProcessor.java
+++ b/dev/core/src/com/google/gwt/dev/CompileArgProcessor.java
@@ -17,15 +17,15 @@
 
 import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
 import com.google.gwt.dev.util.arg.ArgHandlerModuleName;
-import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
 import com.google.gwt.dev.util.arg.ArgHandlerTreeLoggerFlag;
+import com.google.gwt.dev.util.arg.ArgHandlerWorkDir;
 import com.google.gwt.util.tools.ToolBase;
 
 abstract class CompileArgProcessor extends ToolBase {
   public CompileArgProcessor(CompileTaskOptions options) {
     registerHandler(new ArgHandlerLogLevel(options));
     registerHandler(new ArgHandlerTreeLoggerFlag(options));
-    registerHandler(new ArgHandlerOutDir(options));
+    registerHandler(new ArgHandlerWorkDir(options));
     registerHandler(new ArgHandlerModuleName(options));
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/CompileTaskOptions.java b/dev/core/src/com/google/gwt/dev/CompileTaskOptions.java
index dd345fc..82965c9 100644
--- a/dev/core/src/com/google/gwt/dev/CompileTaskOptions.java
+++ b/dev/core/src/com/google/gwt/dev/CompileTaskOptions.java
@@ -18,11 +18,11 @@
 import com.google.gwt.dev.util.arg.OptionGuiLogger;
 import com.google.gwt.dev.util.arg.OptionLogLevel;
 import com.google.gwt.dev.util.arg.OptionModuleName;
-import com.google.gwt.dev.util.arg.OptionOutDir;
+import com.google.gwt.dev.util.arg.OptionWorkDir;
 
 /**
  * A common set of options for all compile tasks.
  */
 public interface CompileTaskOptions extends OptionGuiLogger, OptionModuleName,
-    OptionLogLevel, OptionOutDir {
+    OptionLogLevel, OptionWorkDir {
 }
diff --git a/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java b/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java
index 9c093c0..e0b7ead 100644
--- a/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java
+++ b/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java
@@ -28,7 +28,6 @@
 
   private Type logLevel;
   private String moduleName;
-  private File outDir;
   private boolean useGuiLogger;
   private File workDir;
 
@@ -42,8 +41,8 @@
   public void copyFrom(CompileTaskOptions other) {
     setLogLevel(other.getLogLevel());
     setModuleName(other.getModuleName());
-    setOutDir(other.getOutDir());
     setUseGuiLogger(other.isUseGuiLogger());
+    setWorkDir(other.getWorkDir());
   }
 
   public File getCompilerWorkDir() {
@@ -58,8 +57,8 @@
     return moduleName;
   }
 
-  public File getOutDir() {
-    return outDir;
+  public File getWorkDir() {
+    return workDir;
   }
 
   public boolean isUseGuiLogger() {
@@ -74,22 +73,11 @@
     this.moduleName = moduleName;
   }
 
-  public void setOutDir(File outDir) {
-    this.outDir = outDir;
-  }
-
   public void setUseGuiLogger(boolean useGuiLogger) {
     this.useGuiLogger = useGuiLogger;
   }
 
-  /**
-   * TODO: add a command line option to pass files between compile phases?
-   */
-  protected File getWorkDir() {
-    if (workDir == null) {
-      workDir = new File(System.getProperty("java.io.tmpdir"), GWT_TMP_DIR);
-      workDir.mkdirs();
-    }
-    return workDir;
+  public void setWorkDir(File workDir) {
+    this.workDir = workDir;
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index fd4786a..9a85324 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -19,9 +19,11 @@
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.dev.CompilePerms.CompilePermsOptionsImpl;
 import com.google.gwt.dev.CompileTaskRunner.CompileTask;
+import com.google.gwt.dev.Link.LinkOptionsImpl;
 import com.google.gwt.dev.Precompile.PrecompileOptionsImpl;
 import com.google.gwt.dev.util.PerfLogger;
 import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
+import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
 
 import java.io.File;
 
@@ -34,6 +36,7 @@
     public ArgProcessor(CompilerOptions options) {
       super(options);
       registerHandler(new ArgHandlerExtraDir(options));
+      registerHandler(new ArgHandlerOutDir(options));
     }
 
     @Override
@@ -45,7 +48,7 @@
   static class GWTCompilerOptionsImpl extends PrecompileOptionsImpl implements
       CompilerOptions {
 
-    private File extraDir;
+    private LinkOptionsImpl linkOptions = new LinkOptionsImpl();
 
     public GWTCompilerOptionsImpl() {
     }
@@ -56,15 +59,23 @@
 
     public void copyFrom(CompilerOptions other) {
       super.copyFrom(other);
-      setExtraDir(other.getExtraDir());
+      linkOptions.copyFrom(other);
     }
 
     public File getExtraDir() {
-      return extraDir;
+      return linkOptions.getExtraDir();
+    }
+
+    public File getOutDir() {
+      return linkOptions.getOutDir();
     }
 
     public void setExtraDir(File extraDir) {
-      this.extraDir = extraDir;
+      linkOptions.setExtraDir(extraDir);
+    }
+
+    public void setOutDir(File outDir) {
+      linkOptions.setOutDir(outDir);
     }
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/GWTHosted.java b/dev/core/src/com/google/gwt/dev/GWTHosted.java
index f81cb76..87bd0d4 100644
--- a/dev/core/src/com/google/gwt/dev/GWTHosted.java
+++ b/dev/core/src/com/google/gwt/dev/GWTHosted.java
@@ -23,6 +23,7 @@
 import com.google.gwt.dev.shell.ArtifactAcceptor;
 import com.google.gwt.dev.shell.GWTShellServletFilter;
 import com.google.gwt.dev.shell.ServletContainer;
+import com.google.gwt.dev.shell.ServletContainerLauncher;
 import com.google.gwt.dev.shell.jetty.JettyLauncher;
 import com.google.gwt.dev.util.PerfLogger;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
@@ -30,6 +31,7 @@
 import com.google.gwt.util.tools.ArgHandlerString;
 
 import java.io.PrintWriter;
+import java.net.BindException;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -44,12 +46,6 @@
    */
   protected class ArgHandlerModulesExtra extends ArgHandlerExtra {
 
-    private final PrintWriterTreeLogger console = new PrintWriterTreeLogger(
-        new PrintWriter(System.err));
-    {
-      console.setMaxDetail(TreeLogger.WARN);
-    }
-
     @Override
     public boolean addExtraArg(String arg) {
       return addModule(console, arg);
@@ -65,6 +61,32 @@
       return new String[] {"module"};
     }
   }
+  /**
+   * Handles the -server command line flag.
+   */
+  protected class ArgHandlerServer extends ArgHandlerString {
+    @Override
+    public String getPurpose() {
+      return "Prevents the embedded Tomcat server from running, even if a port is specified";
+    }
+
+    @Override
+    public String getTag() {
+      return "-server";
+    }
+
+    @Override
+    public String[] getTagArgs() {
+      return new String[] {"serverLauncherClass"};
+    }
+
+    @Override
+    public boolean setString(String arg) {
+      // Supercedes -noserver.
+      setRunTomcat(true);
+      return setServer(console, arg);
+    }
+  }
 
   /**
    * Handles a startup url that can be passed on the command line.
@@ -100,7 +122,6 @@
      * shutdown AWT related threads, since the contract for their termination is
      * still implementation-dependent.
      */
-    BootStrapPlatform.init();
     GWTHosted shellMain = new GWTHosted();
     if (shellMain.processArgs(args)) {
       shellMain.run();
@@ -108,14 +129,37 @@
     System.exit(0);
   }
 
+  protected final PrintWriterTreeLogger console = new PrintWriterTreeLogger(
+      new PrintWriter(System.err, true));
+
+  /**
+   * The servlet launcher to use (defaults to embedded Jetty).
+   */
+  private ServletContainerLauncher launcher = new JettyLauncher();
+
+  /**
+   * The set of modules this hosted mode instance can run.
+   */
   private Set<ModuleDef> modules = new HashSet<ModuleDef>();
 
+  /**
+   * The server that was started.
+   */
   private ServletContainer server;
 
+  /**
+   * Our servlet filter, embedded into the server, which autogenerates GWT
+   * modules when the selection script is requested.
+   */
   private GWTShellServletFilter servletFilter;
 
+  {
+    console.setMaxDetail(TreeLogger.WARN);
+  }
+
   public GWTHosted() {
     super(false, true);
+    registerHandler(new ArgHandlerServer());
     registerHandler(new ArgHandlerStartupURLs());
     registerHandler(new ArgHandlerModulesExtra());
   }
@@ -127,11 +171,33 @@
       modules.add(moduleDef);
       return true;
     } catch (UnableToCompleteException e) {
-      System.err.println("Unable to load module '" + moduleName + "'");
+      logger.log(TreeLogger.ERROR, "Unable to load module '" + moduleName + "'");
       return false;
     }
   }
 
+  public boolean setServer(TreeLogger logger, String serverClassName) {
+    Throwable t;
+    try {
+      Class<?> clazz = Class.forName(serverClassName, true,
+          Thread.currentThread().getContextClassLoader());
+      Class<? extends ServletContainerLauncher> sclClass = clazz.asSubclass(ServletContainerLauncher.class);
+      launcher = sclClass.newInstance();
+      return true;
+    } catch (ClassCastException e) {
+      t = e;
+    } catch (ClassNotFoundException e) {
+      t = e;
+    } catch (InstantiationException e) {
+      t = e;
+    } catch (IllegalAccessException e) {
+      t = e;
+    }
+    logger.log(TreeLogger.ERROR, "Unable to load server class '"
+        + serverClassName + "'", t);
+    return false;
+  }
+
   @Override
   protected ArtifactAcceptor doCreateArtifactAcceptor(final ModuleDef module) {
     return new ArtifactAcceptor() {
@@ -156,8 +222,7 @@
 
   @Override
   protected int startUpServer() {
-    PerfLogger.start("GWTShell.startup (Jetty launch)");
-    JettyLauncher launcher = new JettyLauncher();
+    PerfLogger.start("GWTHosted.startUpServer");
     try {
       TreeLogger serverLogger = getTopLogger().branch(TreeLogger.INFO,
           "Starting HTTP on port " + getPort(), null);
@@ -175,14 +240,18 @@
           moduleArray);
       server = launcher.start(serverLogger, getPort(), options.getOutDir(),
           servletFilter);
-    } catch (UnableToCompleteException e) {
+      assert (server != null);
+      return server.getPort();
+    } catch (BindException e) {
+      System.err.println("Port "
+          + getPort()
+          + " is already is use; you probably still have another session active");
+    } catch (Exception e) {
+      System.err.println("Unable to start embedded HTTP server");
+      e.printStackTrace();
+    } finally {
       PerfLogger.end();
-      return -1;
     }
-    assert (server != null);
-
-    PerfLogger.end();
-    return server.getPort();
+    return -1;
   }
-
 }
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 2da8519..460ec3f 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -43,6 +43,7 @@
 import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
 import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
 import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
+import com.google.gwt.dev.util.arg.ArgHandlerWorkDir;
 import com.google.gwt.dev.util.log.AbstractTreeLogger;
 import com.google.gwt.util.tools.ArgHandlerExtra;
 import com.google.gwt.util.tools.ArgHandlerFlag;
@@ -103,7 +104,7 @@
   }
 
   /**
-   * handles the -noserver command line flag.
+   * Handles the -noserver command line flag.
    */
   protected class ArgHandlerNoServerFlag extends ArgHandlerFlag {
     @Override
@@ -378,7 +379,6 @@
      * shutdown AWT related threads, since the contract for their termination is
      * still implementation-dependent.
      */
-    BootStrapPlatform.init();
     GWTShell shellMain = new GWTShell();
     if (shellMain.processArgs(args)) {
       shellMain.run();
@@ -423,6 +423,10 @@
   }
 
   protected GWTShell(boolean forceServer, boolean noURLs) {
+    // Set any platform specific system properties.
+    BootStrapPlatform.init();
+    BootStrapPlatform.applyPlatformHacks();
+
     registerHandler(getArgHandlerPort());
 
     if (!forceServer) {
@@ -435,12 +439,13 @@
     registerHandler(new ArgHandlerLogLevel(options));
 
     registerHandler(new ArgHandlerGenDir(options));
-    registerHandler(new ArgHandlerExtraDir(options));
+    registerHandler(new ArgHandlerWorkDir(options));
 
     if (!noURLs) {
       registerHandler(new ArgHandlerStartupURLsExtra());
     }
 
+    registerHandler(new ArgHandlerExtraDir(options));
     registerHandler(new ArgHandlerOutDir(options));
 
     registerHandler(new ArgHandlerScriptStyle(options));
@@ -562,9 +567,6 @@
    */
   public void run() {
     try {
-      // Set any platform specific system properties.
-      BootStrapPlatform.applyPlatformHacks();
-
       if (!startUp()) {
         // Failed to initalize.
         return;
diff --git a/dev/core/src/com/google/gwt/dev/Link.java b/dev/core/src/com/google/gwt/dev/Link.java
index d458108..97968b0 100644
--- a/dev/core/src/com/google/gwt/dev/Link.java
+++ b/dev/core/src/com/google/gwt/dev/Link.java
@@ -28,7 +28,9 @@
 import com.google.gwt.dev.cfg.StaticPropertyOracle;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
+import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
 import com.google.gwt.dev.util.arg.OptionExtraDir;
+import com.google.gwt.dev.util.arg.OptionOutDir;
 
 import java.io.File;
 import java.util.HashMap;
@@ -42,13 +44,15 @@
   /**
    * Options for Link.
    */
-  public interface LinkOptions extends CompileTaskOptions, OptionExtraDir {
+  public interface LinkOptions extends CompileTaskOptions, OptionExtraDir,
+      OptionOutDir {
   }
 
   static class ArgProcessor extends CompileArgProcessor {
     public ArgProcessor(LinkOptions options) {
       super(options);
       registerHandler(new ArgHandlerExtraDir(options));
+      registerHandler(new ArgHandlerOutDir(options));
     }
 
     @Override
@@ -64,6 +68,7 @@
       LinkOptions {
 
     private File extraDir;
+    private File outDir;
 
     public LinkOptionsImpl() {
     }
@@ -75,15 +80,24 @@
     public void copyFrom(LinkOptions other) {
       super.copyFrom(other);
       setExtraDir(other.getExtraDir());
+      setOutDir(other.getOutDir());
     }
 
     public File getExtraDir() {
       return extraDir;
     }
 
+    public File getOutDir() {
+      return outDir;
+    }
+
     public void setExtraDir(File extraDir) {
       this.extraDir = extraDir;
     }
+
+    public void setOutDir(File outDir) {
+      this.outDir = outDir;
+    }
   }
 
   public static ArtifactSet link(TreeLogger logger, ModuleDef module,
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index 627ef1e..a7e8bf0 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -26,6 +26,7 @@
 import com.google.gwt.dev.cfg.PropertyPermutations;
 import com.google.gwt.dev.cfg.Rules;
 import com.google.gwt.dev.cfg.StaticPropertyOracle;
+import com.google.gwt.dev.javac.CompilationState;
 import com.google.gwt.dev.javac.CompilationUnit;
 import com.google.gwt.dev.jdt.RebindOracle;
 import com.google.gwt.dev.jdt.RebindPermutationOracle;
@@ -37,6 +38,7 @@
 import com.google.gwt.dev.jjs.UnifiedAst;
 import com.google.gwt.dev.jjs.impl.FragmentLoaderCreator;
 import com.google.gwt.dev.shell.StandardRebindOracle;
+import com.google.gwt.dev.util.PerfLogger;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
 import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
@@ -153,8 +155,8 @@
     private RebindOracle[] rebindOracles;
 
     public DistillerRebindPermutationOracle(ModuleDef module,
-        ArtifactSet generatorArtifacts, PropertyPermutations perms,
-        File genDir, File generatorResourcesDir) {
+        CompilationState compilationState, ArtifactSet generatorArtifacts,
+        PropertyPermutations perms, File genDir, File generatorResourcesDir) {
       permutations = new Permutation[perms.size()];
       propertyOracles = new StaticPropertyOracle[perms.size()];
       rebindOracles = new RebindOracle[perms.size()];
@@ -166,9 +168,9 @@
         String[] orderedPropValues = perms.getOrderedPropertyValues(i);
         propertyOracles[i] = new StaticPropertyOracle(orderedProps,
             orderedPropValues, configProps);
-        rebindOracles[i] = new StandardRebindOracle(
-            module.getCompilationState(), propertyOracles[i], module, rules,
-            genDir, generatorResourcesDir, generatorArtifacts);
+        rebindOracles[i] = new StandardRebindOracle(compilationState,
+            propertyOracles[i], module, rules, genDir, generatorResourcesDir,
+            generatorArtifacts);
         permutations[i] = new Permutation(propertyOracles[i]);
       }
     }
@@ -253,6 +255,8 @@
       JJSOptions jjsOptions, ModuleDef module, File genDir,
       File generatorResourcesDir) {
     try {
+      CompilationState compilationState = module.getCompilationState(logger);
+
       String[] declEntryPts = module.getEntryPointTypeNames();
       if (declEntryPts.length == 0) {
         logger.log(TreeLogger.ERROR, "Module has no entry points defined", null);
@@ -261,14 +265,18 @@
 
       ArtifactSet generatedArtifacts = new ArtifactSet();
       DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
-          module, generatedArtifacts, new PropertyPermutations(
-              module.getProperties()), genDir, generatorResourcesDir);
+          module, compilationState, generatedArtifacts,
+          new PropertyPermutations(module.getProperties()), genDir,
+          generatorResourcesDir);
       FragmentLoaderCreator fragmentLoaderCreator = new FragmentLoaderCreator(
-          module.getCompilationState(), module, genDir, generatorResourcesDir, generatedArtifacts);
+          compilationState, module, genDir, generatorResourcesDir,
+          generatedArtifacts);
       WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
-          module.getCompilationState(), rpo, fragmentLoaderCreator);
+          compilationState, rpo, fragmentLoaderCreator);
+      PerfLogger.start("Precompile");
       UnifiedAst unifiedAst = JavaToJavaScriptCompiler.precompile(logger,
           frontEnd, declEntryPts, jjsOptions, rpo.getPermuationCount() == 1);
+      PerfLogger.end();
 
       // Merge all identical permutations together.
       Permutation[] permutations = rpo.getPermutations();
@@ -307,10 +315,12 @@
   public static boolean validate(TreeLogger logger, JJSOptions jjsOptions,
       ModuleDef module, File genDir, File generatorResourcesDir) {
     try {
+      CompilationState compilationState = module.getCompilationState(logger);
+
       String[] declEntryPts = module.getEntryPointTypeNames();
       if (declEntryPts.length == 0) {
         // Pretend that every single compilation unit is an entry point.
-        Set<CompilationUnit> compilationUnits = module.getCompilationState().getCompilationUnits();
+        Set<CompilationUnit> compilationUnits = compilationState.getCompilationUnits();
         declEntryPts = new String[compilationUnits.size()];
         int i = 0;
         for (CompilationUnit unit : compilationUnits) {
@@ -320,12 +330,14 @@
 
       ArtifactSet generatorArtifacts = new ArtifactSet();
       DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
-          module, generatorArtifacts, new PropertyPermutations(
-              module.getProperties()), genDir, generatorResourcesDir);
+          module, compilationState, generatorArtifacts,
+          new PropertyPermutations(module.getProperties()), genDir,
+          generatorResourcesDir);
       FragmentLoaderCreator fragmentLoaderCreator = new FragmentLoaderCreator(
-          module.getCompilationState(), module, genDir, generatorResourcesDir, generatorArtifacts);
+          compilationState, module, genDir, generatorResourcesDir,
+          generatorArtifacts);
       WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
-          module.getCompilationState(), rpo, fragmentLoaderCreator);
+          compilationState, rpo, fragmentLoaderCreator);
       JavaToJavaScriptCompiler.precompile(logger, frontEnd, declEntryPts,
           jjsOptions, true);
       return true;
@@ -388,6 +400,6 @@
         options.getModuleName());
 
     // TODO: All JDT checks now before even building TypeOracle?
-    module.getCompilationState().compile(logger);
+    module.getCompilationState(logger);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
index b4e4b1e..cbc3e39 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -85,14 +85,14 @@
 
   private Class<? extends Linker> activePrimaryLinker;
 
-  private CompilationState compilationState;
-
   private String deployTo;
 
   private final List<String> entryPointTypeNames = new ArrayList<String>();
 
   private final Set<File> gwtXmlFiles = new HashSet<File>();
 
+  private CompilationState lazyCompilationState;
+
   private JavaSourceOracle lazyJavaSourceOracle;
 
   private ResourceOracleImpl lazyPublicOracle;
@@ -262,8 +262,11 @@
     return name;
   }
 
-  public CompilationState getCompilationState() {
-    return compilationState;
+  public CompilationState getCompilationState(TreeLogger logger) {
+    if (lazyCompilationState == null) {
+      lazyCompilationState = new CompilationState(logger, lazyJavaSourceOracle);
+    }
+    return lazyCompilationState;
   }
 
   /**
@@ -333,8 +336,29 @@
   public synchronized TypeOracle getTypeOracle(TreeLogger logger)
       throws UnableToCompleteException {
     if (lazyTypeOracle == null) {
-      lazyTypeOracle = compilationState.getTypeOracle();
-      updateTypeOracle(logger);
+      lazyTypeOracle = getCompilationState(logger).getTypeOracle();
+
+      // Sanity check the seed types and don't even start it they're missing.
+      boolean seedTypesMissing = false;
+      if (lazyTypeOracle.findType("java.lang.Object") == null) {
+        Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
+        seedTypesMissing = true;
+      } else {
+        TreeLogger branch = logger.branch(TreeLogger.TRACE,
+            "Finding entry point classes", null);
+        String[] typeNames = getEntryPointTypeNames();
+        for (int i = 0; i < typeNames.length; i++) {
+          String typeName = typeNames[i];
+          if (lazyTypeOracle.findType(typeName) == null) {
+            Util.logMissingTypeErrorWithHints(branch, typeName);
+            seedTypesMissing = true;
+          }
+        }
+      }
+
+      if (seedTypesMissing) {
+        throw new UnableToCompleteException();
+      }
     }
     return lazyTypeOracle;
   }
@@ -371,11 +395,13 @@
     lazySourceOracle.refresh(logger);
 
     // Update the compilation state to reflect the resource oracle changes.
-    compilationState.refresh();
+    if (lazyCompilationState != null) {
+      lazyCompilationState.refresh(logger);
+    }
 
     // Refresh type oracle if needed.
     if (lazyTypeOracle != null) {
-      updateTypeOracle(logger);
+      getTypeOracle(logger);
     }
     PerfLogger.end();
   }
@@ -470,9 +496,6 @@
     }
     lazyJavaSourceOracle = new JavaSourceOracleImpl(lazySourceOracle);
 
-    // Create the compilation state.
-    compilationState = new CompilationState(lazyJavaSourceOracle);
-
     PerfLogger.end();
   }
 
@@ -499,37 +522,4 @@
     return scanner;
   }
 
-  private void updateTypeOracle(TreeLogger logger)
-      throws UnableToCompleteException {
-    PerfLogger.start("ModuleDef.updateTypeOracle");
-    TreeLogger branch = logger.branch(TreeLogger.TRACE,
-        "Compiling Java source files in module '" + getName() + "'");
-    compilationState.compile(branch);
-    PerfLogger.end();
-
-    TypeOracle typeOracle = compilationState.getTypeOracle();
-
-    // Sanity check the seed types and don't even start it they're missing.
-    boolean seedTypesMissing = false;
-    if (typeOracle.findType("java.lang.Object") == null) {
-      Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
-      seedTypesMissing = true;
-    } else {
-      branch = logger.branch(TreeLogger.TRACE, "Finding entry point classes",
-          null);
-      String[] typeNames = getEntryPointTypeNames();
-      for (int i = 0; i < typeNames.length; i++) {
-        String typeName = typeNames[i];
-        if (typeOracle.findType(typeName) == null) {
-          Util.logMissingTypeErrorWithHints(branch, typeName);
-          seedTypesMissing = true;
-        }
-      }
-    }
-
-    if (seedTypesMissing) {
-      throw new UnableToCompleteException();
-    }
-  }
-
 }
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationState.java b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
index 1af9a10..a63ae7b 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.dev.javac.CompilationUnit.State;
 import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
@@ -40,34 +39,17 @@
  */
 public class CompilationState {
 
-  /**
-   * Compute the set of all valid binary type names (for
-   * {@link BinaryTypeReferenceRestrictionsChecker}.
-   */
-  private static Set<String> getValidBinaryTypeNames(Set<CompilationUnit> units) {
-    Set<String> validBinaryTypeNames = new HashSet<String>();
+  private static void markSurvivorsChecked(Set<CompilationUnit> units) {
     for (CompilationUnit unit : units) {
-      switch (unit.getState()) {
-        case COMPILED:
-          for (ClassFile classFile : unit.getJdtCud().compilationResult().getClassFiles()) {
-            char[] binaryName = CharOperation.concatWith(
-                classFile.getCompoundName(), '/');
-            validBinaryTypeNames.add(String.valueOf(binaryName));
-          }
-          break;
-        case CHECKED:
-          for (CompiledClass compiledClass : unit.getCompiledClasses()) {
-            validBinaryTypeNames.add(compiledClass.getBinaryName());
-          }
-          break;
+      if (unit.getState() == State.COMPILED) {
+        unit.setState(State.CHECKED);
       }
     }
-    return validBinaryTypeNames;
   }
 
   protected final Map<String, CompilationUnit> unitMap = new HashMap<String, CompilationUnit>();
-  private Set<JavaSourceFile> cachedSourceFiles = Collections.emptySet();
 
+  private Set<JavaSourceFile> cachedSourceFiles = Collections.emptySet();
   /**
    * Classes mapped by binary name.
    */
@@ -83,68 +65,55 @@
    */
   private final Map<String, CompilationUnit> exposedUnitMap = Collections.unmodifiableMap(unitMap);
 
+  /**
+   * Unmodifiable view of all units.
+   */
   private Set<CompilationUnit> exposedUnits = Collections.emptySet();
+
+  /**
+   * Recreated on refresh, allows incremental compiles.
+   */
+  private JdtCompiler jdtCompiler;
+
+  /**
+   * Controls our type oracle.
+   */
   private final TypeOracleMediator mediator = new TypeOracleMediator();
+
+  /**
+   * Our source file inputs.
+   */
   private final JavaSourceOracle sourceOracle;
 
   /**
+   * Tracks the set of valid binary type names for
+   * {@link BinaryTypeReferenceRestrictionsChecker}.
+   */
+  private final Set<String> validBinaryTypeNames = new HashSet<String>();
+
+  /**
    * Construct a new {@link CompilationState}.
    * 
    * @param sourceOracle an oracle used to retrieve source code and check for
    *          changes in the underlying source code base
    */
-  public CompilationState(JavaSourceOracle sourceOracle) {
+  public CompilationState(TreeLogger logger, JavaSourceOracle sourceOracle) {
     this.sourceOracle = sourceOracle;
-    refresh();
+    refresh(logger);
   }
 
-  public void addGeneratedCompilationUnit(CompilationUnit unit) {
-    String typeName = unit.getTypeName();
-    assert (!unitMap.containsKey(typeName));
-    unitMap.put(typeName, unit);
-    updateExposedUnits();
-  }
-
-  /**
-   * Compile all units and updates all internal state. Invalidate any units with
-   * compile errors.
-   */
-  public void compile(TreeLogger logger) throws UnableToCompleteException {
-    PerfLogger.start("CompilationState.compile");
-    Set<CompilationUnit> units = getCompilationUnits();
-    if (JdtCompiler.compile(units)) {
-      Set<String> validBinaryTypeNames = getValidBinaryTypeNames(units);
-
-      // Dump all units with direct errors; we cannot safely check them.
-      boolean anyErrors = CompilationUnitInvalidator.invalidateUnitsWithErrors(
-          logger, units);
-
-      // Check all units using our custom checks.
-      CompilationUnitInvalidator.validateCompilationUnits(units,
-          validBinaryTypeNames);
-
-      // More units may have errors now.
-      anyErrors |= CompilationUnitInvalidator.invalidateUnitsWithErrors(logger,
-          units);
-
-      if (anyErrors) {
-        CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(logger, units);
-      }
-
-      JsniCollector.collectJsniMethods(logger, units, new JsProgram());
+  @SuppressWarnings("unchecked")
+  public void addGeneratedCompilationUnits(TreeLogger logger,
+      Set<? extends CompilationUnit> generatedCups) {
+    for (CompilationUnit unit : generatedCups) {
+      String typeName = unit.getTypeName();
+      assert (!unitMap.containsKey(typeName));
+      unitMap.put(typeName, unit);
     }
-
-    mediator.refresh(logger, units);
-
-    // Any surviving units are now considered CHECKED.
-    for (CompilationUnit unit : units) {
-      if (unit.getState() == State.COMPILED) {
-        unit.setState(State.CHECKED);
-      }
-    }
-
     updateExposedUnits();
-    PerfLogger.end();
+    compile(logger, (Set<CompilationUnit>) generatedCups);
+    mediator.addNewUnits(logger, (Set<CompilationUnit>) generatedCups);
+    markSurvivorsChecked((Set<CompilationUnit>) generatedCups);
   }
 
   /**
@@ -193,7 +162,7 @@
    * 
    * TODO: something more optimal with generated files?
    */
-  public void refresh() {
+  public void refresh(TreeLogger logger) {
     // Always remove all generated compilation units.
     for (Iterator<CompilationUnit> it = unitMap.values().iterator(); it.hasNext();) {
       CompilationUnit unit = it.next();
@@ -204,10 +173,49 @@
     }
 
     refreshFromSourceOracle();
+    updateExposedUnits();
+
     // Don't log about invalidated units via refresh.
     CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(TreeLogger.NULL,
         getCompilationUnits());
-    updateExposedUnits();
+
+    jdtCompiler = new JdtCompiler();
+    validBinaryTypeNames.clear();
+    compile(logger, getCompilationUnits());
+    mediator.refresh(logger, getCompilationUnits());
+    markSurvivorsChecked(getCompilationUnits());
+  }
+
+  /**
+   * Compile units and update their internal state. Invalidate any units with
+   * compile errors.
+   */
+  private void compile(TreeLogger logger, Set<CompilationUnit> newUnits) {
+    PerfLogger.start("CompilationState.compile");
+    if (jdtCompiler.doCompile(newUnits)) {
+      // Dump all units with direct errors; we cannot safely check them.
+      boolean anyErrors = CompilationUnitInvalidator.invalidateUnitsWithErrors(
+          logger, newUnits);
+
+      // Check all units using our custom checks.
+      CompilationUnitInvalidator.validateCompilationUnits(newUnits,
+          validBinaryTypeNames);
+
+      // More units may have errors now.
+      anyErrors |= CompilationUnitInvalidator.invalidateUnitsWithErrors(logger,
+          newUnits);
+
+      if (anyErrors) {
+        CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(logger,
+            newUnits);
+      }
+
+      recordValidBinaryTypeNames(newUnits);
+
+      JsniCollector.collectJsniMethods(logger, newUnits, new JsProgram());
+    }
+
+    PerfLogger.end();
   }
 
   private void rebuildClassMaps() {
@@ -225,6 +233,18 @@
     exposedClassFileMapBySource = Collections.unmodifiableMap(classFileMapBySource);
   }
 
+  private void recordValidBinaryTypeNames(Set<CompilationUnit> units) {
+    for (CompilationUnit unit : units) {
+      if (unit.getState() == State.COMPILED) {
+        for (ClassFile classFile : unit.getJdtCud().compilationResult().getClassFiles()) {
+          char[] binaryName = CharOperation.concatWith(
+              classFile.getCompoundName(), '/');
+          validBinaryTypeNames.add(String.valueOf(binaryName));
+        }
+      }
+    }
+  }
+
   private void refreshFromSourceOracle() {
     // See if the source oracle has changed.
     Set<JavaSourceFile> newSourceFiles = sourceOracle.getSourceFiles();
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
index f9e19a7..b02a342 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
@@ -98,11 +98,12 @@
 
     @Override
     public void process(CompilationUnitDeclaration cud, int i) {
-      // TODO: not always generate bytecode eagerly?
       super.process(cud, i);
       ICompilationUnit icu = cud.compilationResult().compilationUnit;
       CompilationUnitAdapter adapter = (CompilationUnitAdapter) icu;
-      adapter.getUnit().setJdtCud(cud);
+      CompilationUnit unit = adapter.getUnit();
+      unit.setJdtCud(cud);
+      recordBinaryTypes(unit.getCompiledClasses());
     }
   }
 
@@ -228,8 +229,6 @@
     return new CompilerOptions(settings);
   }
 
-  private final List<CompilationUnit> activeUnits = new ArrayList<CompilationUnit>();
-
   /**
    * Maps dotted binary names to compiled classes.
    */
@@ -244,7 +243,29 @@
   /**
    * Not externally instantiable.
    */
-  private JdtCompiler() {
+  public JdtCompiler() {
+  }
+
+  public boolean doCompile(Collection<CompilationUnit> units) {
+    List<ICompilationUnit> icus = new ArrayList<ICompilationUnit>();
+    for (CompilationUnit unit : units) {
+      String packageName = Shared.getPackageName(unit.getTypeName());
+      addPackages(packageName);
+      Set<CompiledClass> compiledClasses = unit.getCompiledClasses();
+      if (compiledClasses == null) {
+        icus.add(new CompilationUnitAdapter(unit));
+      } else {
+        recordBinaryTypes(compiledClasses);
+      }
+    }
+    if (icus.isEmpty()) {
+      return false;
+    }
+
+    PerfLogger.start("JdtCompiler.compile");
+    compiler.compile(icus.toArray(new ICompilationUnit[icus.size()]));
+    PerfLogger.end();
+    return true;
   }
 
   private void addPackages(String packageName) {
@@ -260,30 +281,11 @@
     }
   }
 
-  private boolean doCompile(Collection<CompilationUnit> units) {
-    List<ICompilationUnit> icus = new ArrayList<ICompilationUnit>();
-    for (CompilationUnit unit : units) {
-      String packageName = Shared.getPackageName(unit.getTypeName());
-      addPackages(packageName);
-      Set<CompiledClass> compiledClasses = unit.getCompiledClasses();
-      if (compiledClasses == null) {
-        icus.add(new CompilationUnitAdapter(unit));
-        activeUnits.add(unit);
-      } else {
-        for (CompiledClass compiledClass : compiledClasses) {
-          binaryTypes.put(compiledClass.getBinaryName().replace('/', '.'),
-              compiledClass);
-        }
-      }
+  private void recordBinaryTypes(Set<CompiledClass> compiledClasses) {
+    for (CompiledClass compiledClass : compiledClasses) {
+      binaryTypes.put(compiledClass.getBinaryName().replace('/', '.'),
+          compiledClass);
     }
-    if (icus.isEmpty()) {
-      return false;
-    }
-
-    PerfLogger.start("JdtCompiler.compile");
-    compiler.compile(icus.toArray(new ICompilationUnit[icus.size()]));
-    PerfLogger.end();
-    return true;
   }
 
 }
diff --git a/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
index 885f0d4..63e4a4e 100644
--- a/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
+++ b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.HasMetaData;
 import com.google.gwt.core.ext.typeinfo.HasTypeParameters;
 import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
@@ -37,12 +36,10 @@
 import com.google.gwt.core.ext.typeinfo.JRealClassType;
 import com.google.gwt.core.ext.typeinfo.JType;
 import com.google.gwt.core.ext.typeinfo.JTypeParameter;
-import com.google.gwt.core.ext.typeinfo.NotFoundException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.core.ext.typeinfo.JWildcardType.BoundType;
 import com.google.gwt.dev.javac.impl.Shared;
 import com.google.gwt.dev.util.Empty;
-import com.google.gwt.dev.util.PerfLogger;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
@@ -336,22 +333,28 @@
 
   private final Map<String, JRealClassType> binaryMapper = new HashMap<String, JRealClassType>();
   private final Map<SourceTypeBinding, JRealClassType> sourceMapper = new IdentityHashMap<SourceTypeBinding, JRealClassType>();
-  private final Map<TypeVariableBinding, JTypeParameter> tvMapper = new IdentityHashMap<TypeVariableBinding, JTypeParameter>();
+
+  /**
+   * Mapping of type variable bindings; transient because compilation units are
+   * processed monolithically, and a tv binding is only valid within a single
+   * unit.
+   */
+  private final transient Map<TypeVariableBinding, JTypeParameter> tvMapper = new IdentityHashMap<TypeVariableBinding, JTypeParameter>();
+
   private final TypeOracle typeOracle = new TypeOracle();
-  private final Set<JRealClassType> unresolvedTypes = new HashSet<JRealClassType>();
 
-  public TypeOracle getTypeOracle() {
-    return typeOracle;
-  }
+  /**
+   * Set of unresolved types to process, generated from the first phase of type
+   * oracle resolution. Transient because they all get resolved in the second
+   * phase.
+   */
+  private final transient Set<JRealClassType> unresolvedTypes = new HashSet<JRealClassType>();
 
-  public void refresh(TreeLogger logger, Set<CompilationUnit> units)
-      throws UnableToCompleteException {
-    PerfLogger.start("TypeOracleMediator.refresh");
-    typeOracle.removeInvalidatedTypes();
-    clear();
-
+  /**
+   * Adds new units to an existing TypeOracle.
+   */
+  public void addNewUnits(TreeLogger logger, Set<CompilationUnit> units) {
     // Perform a shallow pass to establish identity for new and old types.
-    PerfLogger.start("TypeOracleMediator.refresh (shallow)");
     for (CompilationUnit unit : units) {
       if (!unit.isCompiled()) {
         continue;
@@ -365,10 +368,8 @@
         binaryMapper.put(compiledClass.getBinaryName(), type);
       }
     }
-    PerfLogger.end();
 
     // Perform a deep pass to resolve all new types in terms of our types.
-    PerfLogger.start("TypeOracleMediator.refresh (deep)");
     for (CompilationUnit unit : units) {
       if (!unit.isCompiled()) {
         continue;
@@ -377,9 +378,10 @@
           "Processing types in compilation unit: " + unit.getDisplayLocation());
       Set<CompiledClass> compiledClasses = unit.getCompiledClasses();
       for (CompiledClass compiledClass : compiledClasses) {
-        if (unresolvedTypes.contains(compiledClass.getRealClassType())) {
+        if (unresolvedTypes.remove(compiledClass.getRealClassType())) {
           TypeDeclaration typeDeclaration = compiledClass.getTypeDeclaration();
-          if (!resolveTypeDeclaration(cudLogger, unit.getSource(), typeDeclaration)) {
+          if (!resolveTypeDeclaration(cudLogger, unit.getSource(),
+              typeDeclaration)) {
             logger.log(TreeLogger.WARN,
                 "Unexpectedly unable to fully resolve type "
                     + compiledClass.getSourceName());
@@ -387,24 +389,25 @@
         }
       }
     }
-    clear();
-    PerfLogger.end();
+    // Clean transient state.
+    assert unresolvedTypes.size() == 0;
+    tvMapper.clear();
 
-    try {
-      typeOracle.refresh(logger);
-    } catch (NotFoundException e) {
-      // TODO
-      e.printStackTrace();
-    }
-
-    PerfLogger.end();
+    typeOracle.finish(logger);
   }
 
-  private void clear() {
+  public TypeOracle getTypeOracle() {
+    return typeOracle;
+  }
+
+  /**
+   * Full refresh based on new units.
+   */
+  public void refresh(TreeLogger logger, Set<CompilationUnit> units) {
     binaryMapper.clear();
     sourceMapper.clear();
-    tvMapper.clear();
-    unresolvedTypes.clear();
+    typeOracle.reset();
+    addNewUnits(logger, units);
   }
 
   private Object createAnnotationInstance(TreeLogger logger,
diff --git a/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java b/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java
index e3896e2..d9ef731 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java
@@ -16,9 +16,9 @@
 package com.google.gwt.dev.shell;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 
 import java.io.File;
+import java.net.BindException;
 
 import javax.servlet.Filter;
 
@@ -28,6 +28,18 @@
  */
 public interface ServletContainerLauncher {
 
-  ServletContainer start(TreeLogger topLogger, int port, File appRootDir,
-      Filter shellServletFilter) throws UnableToCompleteException;
+  /**
+   * Start an embedded HTTP server.
+   * 
+   * @param logger the server logger
+   * @param port the TCP port to serve on
+   * @param appRootDir the base WAR directory
+   * @param filter a servlet filter that must be installed on the root path to
+   *          serve generated files
+   * @return the launch servlet contained
+   * @throws BindException if the requested port is already in use
+   * @throws Exception if the server fails to start for any other reason
+   */
+  ServletContainer start(TreeLogger logger, int port, File appRootDir,
+      Filter filter) throws BindException, Exception;
 }
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
index 38f106f..0a526c3 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
@@ -90,7 +90,7 @@
     // It has to wait until now because we need to inject javascript.
     //
     Rules rules = module.getRules();
-    rebindOracle = new StandardRebindOracle(module.getCompilationState(),
+    rebindOracle = new StandardRebindOracle(module.getCompilationState(logger),
         propOracle, module, rules, genDir, shellDir, new ArtifactSet());
 
     // Create a completely isolated class loader which owns all classes
@@ -105,7 +105,7 @@
     // class loader (the one that loaded the shell itself).
     //
     classLoader = new CompilingClassLoader(logger,
-        module.getCompilationState(), readySpace);
+        module.getCompilationState(logger), readySpace);
   }
 
   public String rebind(TreeLogger logger, String sourceTypeName)
diff --git a/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java b/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
index 64687f5..06ba50e 100644
--- a/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
+++ b/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
@@ -308,14 +308,14 @@
           String qualifiedTypeName = gcup.getTypeName();
           genTypeNames.add(qualifiedTypeName);
           maybeWriteSource(gcup, qualifiedTypeName);
-          compilationState.addGeneratedCompilationUnit(gcup);
 
           if (subBranch != null) {
             subBranch.log(TreeLogger.DEBUG, gcup.getDisplayLocation(), null);
           }
         }
 
-        compilationState.compile(logger);
+        compilationState.addGeneratedCompilationUnits(logger,
+            committedGeneratedCups);
       }
 
       // Make sure all generated types can be found in TypeOracle.
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
index 9a6b12b..832311d 100644
--- a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
@@ -191,7 +191,7 @@
 
   @SuppressWarnings("unchecked")
   public ServletContainer start(TreeLogger logger, int port, File appRootDir,
-      Filter shellServletFilter) throws UnableToCompleteException {
+      Filter shellServletFilter) throws Exception {
     checkStartParams(logger, port, appRootDir);
 
     // The dance we do with Jetty's logging system.
@@ -210,6 +210,9 @@
     SelectChannelConnector connector = new SelectChannelConnector();
     connector.setPort(port);
     connector.setHost("127.0.0.1");
+    // Don't steal ports from an existing proc.
+    connector.setReuseAddress(false);
+
     server.addConnector(connector);
 
     // Create a new web app in the war directory.
@@ -227,15 +230,10 @@
 
     server.setHandler(wac);
     server.setStopAtShutdown(true);
+    server.start();
 
-    try {
-      server.start();
-      int actualPort = connector.getPort();
-      return new JettyServletContainer(logger, wac, actualPort, appRootDir);
-    } catch (Exception e) {
-      logger.log(TreeLogger.ERROR, "Unable to start embedded Jetty server", e);
-      throw new UnableToCompleteException();
-    }
+    return new JettyServletContainer(logger, wac, connector.getLocalPort(),
+        appRootDir);
   }
 
   private void checkStartParams(TreeLogger logger, int port, File appRootDir) {
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDir.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDir.java
new file mode 100644
index 0000000..c08130f
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDir.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2006 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.util.arg;
+
+import com.google.gwt.util.tools.ArgHandlerDir;
+
+import java.io.File;
+
+/**
+ * Argument handler for processing the output directory flag.
+ */
+public final class ArgHandlerWorkDir extends ArgHandlerDir {
+
+  public static final String GWT_TMP_DIR = "gwt-tmp";
+
+  private final OptionWorkDir option;
+
+  public ArgHandlerWorkDir(OptionWorkDir option) {
+    this.option = option;
+  }
+
+  public String[] getDefaultArgs() {
+    return new String[] {
+        "-workDir",
+        new File(System.getProperty("java.io.tmpdir"), GWT_TMP_DIR).getAbsolutePath()};
+  }
+
+  public String getPurpose() {
+    return "The compiler work directory (must be writeable; defaults to system temp dir)";
+  }
+
+  public String getTag() {
+    return "-workDir";
+  }
+
+  @Override
+  public void setDir(File dir) {
+    option.setWorkDir(dir);
+  }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionWorkDir.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionWorkDir.java
new file mode 100644
index 0000000..acd8539
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionWorkDir.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.util.arg;
+
+import java.io.File;
+
+/**
+ * Option to set the compiler working directory.
+ */
+public interface OptionWorkDir {
+
+  /**
+   * Returns the compiler work directory.
+   */
+  File getWorkDir();
+
+  /**
+   * Sets the compiler work directory.
+   */
+  void setWorkDir(File dir);
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java b/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
index 23cdb49..6c1a9ad 100644
--- a/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.dev.javac.CompilationUnit.State;
 import com.google.gwt.dev.javac.impl.MockJavaSourceFile;
 import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
@@ -38,23 +37,6 @@
  */
 public class CompilationStateTest extends TestCase {
 
-  private MockJavaSourceOracle oracle = new MockJavaSourceOracle(
-      JavaSourceCodeBase.getStandardResources());
-
-  private CompilationState state = new CompilationState(oracle);
-
-  public void testAddGeneratedCompilationUnit() {
-    validateCompilationState();
-
-    // Add a unit and ensure it shows up.
-    addGeneratedUnit(JavaSourceCodeBase.FOO);
-    validateCompilationState(JavaSourceCodeBase.FOO.getTypeName());
-
-    // Ensure it disappears after a refresh.
-    state.refresh();
-    validateCompilationState();
-  }
-
   static void assertUnitsChecked(Collection<CompilationUnit> units) {
     for (CompilationUnit unit : units) {
       assertSame(State.CHECKED, unit.getState());
@@ -63,17 +45,41 @@
     }
   }
 
-  public void testCompile() throws UnableToCompleteException {
-    validateUncompiled();
-    state.compile(createTreeLogger());
-    assertUnitsChecked(state.getCompilationUnits());
+  /**
+   * Tweak this if you want to see the log output.
+   */
+  private static TreeLogger createTreeLogger() {
+    boolean reallyLog = false;
+    if (reallyLog) {
+      AbstractTreeLogger logger = new PrintWriterTreeLogger();
+      logger.setMaxDetail(TreeLogger.ALL);
+      return logger;
+    } else {
+      return TreeLogger.NULL;
+    }
   }
 
-  public void testCompileError() throws UnableToCompleteException {
+  private MockJavaSourceOracle oracle = new MockJavaSourceOracle(
+      JavaSourceCodeBase.getStandardResources());
+
+  private CompilationState state = new CompilationState(createTreeLogger(),
+      oracle);
+
+  public void testAddGeneratedCompilationUnit() {
+    validateCompilationState();
+
+    // Add a unit and ensure it shows up.
+    addGeneratedUnits(JavaSourceCodeBase.FOO);
+    validateCompilationState(JavaSourceCodeBase.FOO.getTypeName());
+
+    // Ensure it disappears after a refresh.
+    state.refresh(createTreeLogger());
+    validateCompilationState();
+  }
+
+  public void testCompileError() {
     oracle.add(JavaSourceCodeBase.BAR);
-    state.refresh();
-    validateUncompiled();
-    state.compile(createTreeLogger());
+    state.refresh(createTreeLogger());
 
     CompilationUnit badUnit = state.getCompilationUnitMap().get(
         JavaSourceCodeBase.BAR.getTypeName());
@@ -85,22 +91,15 @@
     assertUnitsChecked(goodUnits);
   }
 
-  public void testCompileWithGeneratedUnits() throws UnableToCompleteException {
-    validateUncompiled();
-    state.compile(createTreeLogger());
+  public void testCompileWithGeneratedUnits() {
     assertUnitsChecked(state.getCompilationUnits());
-    addGeneratedUnit(JavaSourceCodeBase.FOO);
-    state.compile(createTreeLogger());
+    addGeneratedUnits(JavaSourceCodeBase.FOO);
     assertUnitsChecked(state.getCompilationUnits());
   }
 
-  public void testCompileWithGeneratedUnitsError()
-      throws UnableToCompleteException {
-    validateUncompiled();
-    state.compile(createTreeLogger());
+  public void testCompileWithGeneratedUnitsError() {
     assertUnitsChecked(state.getCompilationUnits());
-    addGeneratedUnit(JavaSourceCodeBase.BAR);
-    state.compile(createTreeLogger());
+    addGeneratedUnits(JavaSourceCodeBase.BAR);
 
     CompilationUnit badUnit = state.getCompilationUnitMap().get(
         JavaSourceCodeBase.BAR.getTypeName());
@@ -112,12 +111,16 @@
     assertUnitsChecked(goodUnits);
   }
 
+  public void testInitialization() {
+    assertUnitsChecked(state.getCompilationUnits());
+  }
+
   public void testSourceOracleAdd() {
     validateCompilationState();
 
     int size = state.getCompilationUnits().size();
     oracle.add(JavaSourceCodeBase.FOO);
-    state.refresh();
+    state.refresh(createTreeLogger());
     assertEquals(size + 1, state.getCompilationUnits().size());
     validateCompilationState();
   }
@@ -128,7 +131,7 @@
 
   public void testSourceOracleEmpty() {
     oracle = new MockJavaSourceOracle();
-    state = new CompilationState(oracle);
+    state = new CompilationState(createTreeLogger(), oracle);
     validateCompilationState();
   }
 
@@ -137,7 +140,7 @@
 
     int size = state.getCompilationUnits().size();
     oracle.remove(JavaSourceCodeBase.OBJECT.getTypeName());
-    state.refresh();
+    state.refresh(createTreeLogger());
     assertEquals(size - 1, state.getCompilationUnits().size());
     validateCompilationState();
   }
@@ -147,7 +150,7 @@
 
     int size = state.getCompilationUnits().size();
     oracle.replace(new MockJavaSourceFile(JavaSourceCodeBase.OBJECT));
-    state.refresh();
+    state.refresh(createTreeLogger());
     assertEquals(size, state.getCompilationUnits().size());
     validateCompilationState();
   }
@@ -157,18 +160,22 @@
 
     int size = state.getCompilationUnits().size();
     oracle.replace(JavaSourceCodeBase.OBJECT);
-    state.refresh();
+    state.refresh(createTreeLogger());
     assertEquals(size, state.getCompilationUnits().size());
     validateCompilationState();
   }
 
-  private void addGeneratedUnit(JavaSourceFile sourceFile) {
-    state.addGeneratedCompilationUnit(new SourceFileCompilationUnit(sourceFile) {
-      @Override
-      public boolean isGenerated() {
-        return true;
-      }
-    });
+  private void addGeneratedUnits(JavaSourceFile... sourceFiles) {
+    Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+    for (JavaSourceFile sourceFile : sourceFiles) {
+      units.add(new SourceFileCompilationUnit(sourceFile) {
+        @Override
+        public boolean isGenerated() {
+          return true;
+        }
+      });
+    }
+    state.addGeneratedCompilationUnits(createTreeLogger(), units);
   }
 
   private void validateCompilationState(String... generatedTypeNames) {
@@ -205,24 +212,4 @@
     assertEquals(0, sourceMap.size());
     assertEquals(0, generatedTypes.size());
   }
-
-  private void validateUncompiled() {
-    for (CompilationUnit unit : state.getCompilationUnits()) {
-      assertNull(unit.getJdtCud());
-    }
-  }
-
-  /**
-   * Tweak this if you want to see the log output.
-   */
-  private TreeLogger createTreeLogger() {
-    boolean reallyLog = false;
-    if (reallyLog) {
-      AbstractTreeLogger logger = new PrintWriterTreeLogger();
-      logger.setMaxDetail(TreeLogger.ALL);
-      return logger;
-    } else {
-      return TreeLogger.NULL;
-    }
-  }
 }
diff --git a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
index ce0305d..b8eb521 100644
--- a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
@@ -16,14 +16,13 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.dev.util.UnitTestTreeLogger;
 
 import junit.framework.TestCase;
 
 public class JSORestrictionsTest extends TestCase {
 
-  public void testFinalClass() throws UnableToCompleteException {
+  public void testFinalClass() {
     StringBuffer code = new StringBuffer();
     code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     code.append("final public class Buggy extends JavaScriptObject {\n");
@@ -34,7 +33,7 @@
     shouldGenerateNoError(code);
   }
 
-  public void testInstanceField() throws UnableToCompleteException {
+  public void testInstanceField() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -46,7 +45,7 @@
         + JSORestrictionsChecker.ERR_INSTANCE_FIELD);
   }
 
-  public void testMultiArgConstructor() throws UnableToCompleteException {
+  public void testMultiArgConstructor() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public final class Buggy extends JavaScriptObject {\n");
@@ -57,7 +56,7 @@
         + JSORestrictionsChecker.ERR_CONSTRUCTOR_WITH_PARAMETERS);
   }
 
-  public void testNew() throws UnableToCompleteException {
+  public void testNew() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy {\n");
@@ -71,7 +70,7 @@
         + JSORestrictionsChecker.ERR_NEW_JSO);
   }
 
-  public void testNoConstructor() throws UnableToCompleteException {
+  public void testNoConstructor() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -82,7 +81,7 @@
         + JSORestrictionsChecker.ERR_NONPROTECTED_CONSTRUCTOR);
   }
 
-  public void testNoInterfaces() throws UnableToCompleteException {
+  public void testNoInterfaces() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy {\n");
@@ -99,7 +98,7 @@
         + JSORestrictionsChecker.errInterfaceWithMethods("Buggy.Squeaks"));
   }
 
-  public void testNonEmptyConstructor() throws UnableToCompleteException {
+  public void testNonEmptyConstructor() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -110,7 +109,7 @@
         + JSORestrictionsChecker.ERR_NONEMPTY_CONSTRUCTOR);
   }
 
-  public void testNonFinalMethod() throws UnableToCompleteException {
+  public void testNonFinalMethod() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -122,7 +121,7 @@
         + JSORestrictionsChecker.ERR_INSTANCE_METHOD_NONFINAL);
   }
 
-  public void testNonProtectedConstructor() throws UnableToCompleteException {
+  public void testNonProtectedConstructor() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -133,7 +132,7 @@
         + JSORestrictionsChecker.ERR_NONPROTECTED_CONSTRUCTOR);
   }
 
-  public void testNonStaticInner() throws UnableToCompleteException {
+  public void testNonStaticInner() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy {\n");
@@ -146,7 +145,7 @@
         + JSORestrictionsChecker.ERR_IS_NONSTATIC_NESTED);
   }
 
-  public void testNoOverride() throws UnableToCompleteException {
+  public void testNoOverride() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -158,7 +157,7 @@
         + JSORestrictionsChecker.ERR_OVERRIDDEN_METHOD);
   }
 
-  public void testPrivateMethod() throws UnableToCompleteException {
+  public void testPrivateMethod() {
     StringBuffer code = new StringBuffer();
     code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     code.append("public class Buggy extends JavaScriptObject {\n");
@@ -175,7 +174,7 @@
    * Buggy.
    */
   private void shouldGenerateError(CharSequence buggyCode,
-      final String expectedError) throws UnableToCompleteException {
+      final String expectedError) {
     UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
     builder.setLowestLogLevel(TreeLogger.ERROR);
     if (expectedError != null) {
@@ -189,8 +188,7 @@
     logger.assertCorrectLogEntries();
   }
 
-  private void shouldGenerateNoError(StringBuffer buggyCode)
-      throws UnableToCompleteException {
+  private void shouldGenerateNoError(StringBuffer buggyCode) {
     shouldGenerateError(buggyCode, null);
   }
 }
diff --git a/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java b/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java
index 0269e7b..7528d2a 100644
--- a/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java
@@ -16,9 +16,7 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.javac.CompilationUnit;
 import com.google.gwt.dev.util.UnitTestTreeLogger;
 
 import junit.framework.TestCase;
@@ -30,7 +28,7 @@
  * Test access to longs from JSNI.
  */
 public class LongFromJSNITest extends TestCase {
-  public void testCyclicReferences() throws UnableToCompleteException {
+  public void testCyclicReferences() {
     {
       StringBuffer buggy = new StringBuffer();
       buggy.append("class Buggy {\n");
@@ -76,7 +74,7 @@
     }
   }
 
-  public void testFieldAccess() throws UnableToCompleteException {
+  public void testFieldAccess() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("volatile long x = -1;\n");
@@ -88,7 +86,7 @@
         "Referencing field 'Buggy.x': type 'long' is not safe to access in JSNI code");
   }
 
-  public void testInnerClass() throws UnableToCompleteException {
+  public void testInnerClass() {
     StringBuffer code = new StringBuffer();
     code.append("public class Buggy {\n");
     code.append("  static class Inner {\n");
@@ -108,7 +106,7 @@
    * completely unusable in JavaScript, so the current reasoning is to allow
    * them.
    */
-  public void testLongArray() throws UnableToCompleteException {
+  public void testLongArray() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  long[] m() { return new long[] { -1 }; }\n");
@@ -119,7 +117,7 @@
     shouldGenerateNoError(code);
   }
 
-  public void testLongParameter() throws UnableToCompleteException {
+  public void testLongParameter() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  native void jsniMeth(long x) /*-{ return; }-*/;\n");
@@ -129,7 +127,7 @@
         "Parameter 'x': type 'long' is not safe to access in JSNI code");
   }
 
-  public void testLongReturn() throws UnableToCompleteException {
+  public void testLongReturn() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  native long jsniMeth() /*-{ return 0; }-*/;\n");
@@ -139,7 +137,7 @@
         "Type 'long' may not be returned from a JSNI method");
   }
 
-  public void testMethodArgument() throws UnableToCompleteException {
+  public void testMethodArgument() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  void print(long x) { }\n");
@@ -152,7 +150,7 @@
         "Parameter 1 of method \'Buggy.print\': type 'long' may not be passed out of JSNI code");
   }
 
-  public void testMethodReturn() throws UnableToCompleteException {
+  public void testMethodReturn() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  long m() { return -1; }\n");
@@ -166,8 +164,7 @@
         "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code");
   }
 
-  public void testOverloadedMethodWithNoWarning()
-      throws UnableToCompleteException {
+  public void testOverloadedMethodWithNoWarning() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  long m(int x) { return -1; }\n");
@@ -179,8 +176,7 @@
     shouldGenerateNoError(code);
   }
 
-  public void testOverloadedMethodWithWarning()
-      throws UnableToCompleteException {
+  public void testOverloadedMethodWithWarning() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  long m(int x) { return -1; }\n");
@@ -195,7 +191,20 @@
         "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code");
   }
 
-  public void testUnsafeAnnotation() throws UnableToCompleteException {
+  public void testRefInString() {
+    {
+      StringBuffer code = new StringBuffer();
+      code.append("import com.google.gwt.core.client.UnsafeNativeLong;");
+      code.append("class Buggy {\n");
+      code.append("  void print(long x) { }\n");
+      code.append("  native void jsniMeth() /*-{ 'this.@Buggy::print(J)(0)'; }-*/;\n");
+      code.append("}\n");
+
+      shouldGenerateNoError(code);
+    }
+  }
+
+  public void testUnsafeAnnotation() {
     {
       StringBuffer code = new StringBuffer();
       code.append("import com.google.gwt.core.client.UnsafeNativeLong;");
@@ -209,20 +218,7 @@
     }
   }
 
-  public void testRefInString() throws UnableToCompleteException {
-    {
-      StringBuffer code = new StringBuffer();
-      code.append("import com.google.gwt.core.client.UnsafeNativeLong;");
-      code.append("class Buggy {\n");
-      code.append("  void print(long x) { }\n");
-      code.append("  native void jsniMeth() /*-{ 'this.@Buggy::print(J)(0)'; }-*/;\n");
-      code.append("}\n");
-
-      shouldGenerateNoError(code);
-    }
-  }
-
-  public void testViolator() throws UnableToCompleteException {
+  public void testViolator() {
     {
       StringBuffer okay = new StringBuffer();
       okay.append("class Buggy {\n");
@@ -274,8 +270,7 @@
   }
 
   private TypeOracle buildOracle(CharSequence buggyCode,
-      CharSequence extraCode, UnitTestTreeLogger logger)
-      throws UnableToCompleteException {
+      CharSequence extraCode, UnitTestTreeLogger logger) {
     Set<CompilationUnit> units = new HashSet<CompilationUnit>();
     addLongCheckingCups(units);
     units.add(new MockCompilationUnit("Buggy", buggyCode.toString()));
@@ -287,8 +282,7 @@
   }
 
   private void shouldGenerateError(CharSequence buggyCode,
-      CharSequence extraCode, int line, String message)
-      throws UnableToCompleteException {
+      CharSequence extraCode, int line, String message) {
     UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder();
     b.setLowestLogLevel(TreeLogger.ERROR);
     if (message != null) {
@@ -306,17 +300,15 @@
   }
 
   private void shouldGenerateError(CharSequence buggyCode, int line,
-      String message) throws UnableToCompleteException {
+      String message) {
     shouldGenerateError(buggyCode, null, line, message);
   }
 
-  private void shouldGenerateNoError(CharSequence code)
-      throws UnableToCompleteException {
+  private void shouldGenerateNoError(CharSequence code) {
     shouldGenerateNoError(code, null);
   }
 
-  private void shouldGenerateNoError(CharSequence code, CharSequence extraCode)
-      throws UnableToCompleteException {
+  private void shouldGenerateNoError(CharSequence code, CharSequence extraCode) {
     shouldGenerateError(code, extraCode, -1, null);
   }
 }
diff --git a/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java b/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
index 2516e15..fee4d53 100644
--- a/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JArrayType;
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.JField;
@@ -59,10 +58,10 @@
   private static void assertEqualArraysUnordered(Object[] expected,
       Object[] actual) {
     assertEquals(expected.length, actual.length);
-    for (int i = 0; i < expected.length; i++) {
+    for (Object element : expected) {
       boolean matched = false;
-      for (int j = 0; j < actual.length; j++) {
-        if (expected[i].equals(actual[j])) {
+      for (Object element2 : actual) {
+        if (element.equals(element2)) {
           matched = true;
           break;
         }
@@ -79,8 +78,10 @@
   }
 
   private static void assertIsNotAssignable(JClassType from, JClassType to) {
-    assertFalse(from.isAssignableTo(to));
-    assertFalse(to.isAssignableFrom(from));
+    assertFalse(from + " should not be assignable to " + to,
+        from.isAssignableTo(to));
+    assertFalse(to + " should not be assignable to " + from,
+        to.isAssignableFrom(from));
   }
 
   private static void recordAssignability(
@@ -101,11 +102,13 @@
 
   protected CheckedMockCompilationUnit CU_AfterAssimilate = new CheckedMockCompilationUnit(
       "test.assim", "AfterAssimilate") {
+    @Override
     public void check(JClassType type) {
       assertEquals("test.assim.BeforeAssimilate",
           type.getSuperclass().getQualifiedSourceName());
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test.assim;\n");
@@ -117,13 +120,16 @@
   protected CheckedMockCompilationUnit CU_Assignable = new CheckedMockCompilationUnit(
       "test.sub", "Derived", "BaseInterface", "DerivedInterface",
       "Derived.Nested") {
+    @Override
     public void check(JClassType type) {
-      if ("Derived".equals(type.getSimpleSourceName()))
+      if ("Derived".equals(type.getSimpleSourceName())) {
         checkDerived(type);
-      else if ("Nested".equals(type.getSimpleSourceName()))
+      } else if ("Nested".equals(type.getSimpleSourceName())) {
         checkNested(type);
+      }
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test.sub;\n");
@@ -148,10 +154,12 @@
 
   protected CheckedMockCompilationUnit CU_BeforeAssimilate = new CheckedMockCompilationUnit(
       "test.assim", "BeforeAssimilate") {
+    @Override
     public void check(JClassType type) {
       assertEquals("test.assim.BeforeAssimilate", type.getQualifiedSourceName());
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test.assim;\n");
@@ -164,13 +172,15 @@
       "test", "BindToTypeScope", "BindToTypeScope.Object",
       "BindToTypeScope.DerivedObject") {
 
+    @Override
     public void check(JClassType type) throws NotFoundException {
-      if ("BindToTypeScope".equals(type.getSimpleSourceName()))
+      if ("BindToTypeScope".equals(type.getSimpleSourceName())) {
         checkBindToTypeScope(type);
-      else if ("Object".equals(type.getSimpleSourceName()))
+      } else if ("Object".equals(type.getSimpleSourceName())) {
         checkObject(type);
-      else
+      } else {
         checkDerivedObject(type);
+      }
     }
 
     public void checkBindToTypeScope(JClassType type) throws NotFoundException {
@@ -187,6 +197,7 @@
       assertEquals("test.BindToTypeScope.Object", type.getQualifiedSourceName());
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test;\n");
@@ -218,6 +229,7 @@
       assertNotNull(type.isGenericType());
     }
 
+    @Override
     public String getSource() {
       StringBuilder sb = new StringBuilder();
       sb.append("package parameterized.type.build.dependency;\n");
@@ -230,6 +242,7 @@
 
   protected CheckedMockCompilationUnit CU_DefaultClass = new CheckedMockCompilationUnit(
       "test", "DefaultClass") {
+    @Override
     public void check(JClassType type) {
       assertEquals("DefaultClass", type.getSimpleSourceName());
       assertEquals("test.DefaultClass", type.getQualifiedSourceName());
@@ -241,6 +254,7 @@
       assertEquals(0, type.getFields().length);
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test;\n");
@@ -257,6 +271,7 @@
       assertNotNull(type.getSuperclass().isParameterized());
     }
 
+    @Override
     public String getSource() {
       StringBuilder sb = new StringBuilder();
       sb.append("package test.refresh;\n");
@@ -272,6 +287,7 @@
       assertNotNull(type.getSuperclass().isParameterized());
     }
 
+    @Override
     public String getSource() {
       StringBuilder sb = new StringBuilder();
       sb.append("package parameterized.type.build.dependency;\n");
@@ -282,6 +298,7 @@
 
   protected CheckedMockCompilationUnit CU_FieldsAndTypes = new CheckedMockCompilationUnit(
       "test", "Fields", "SomeType") {
+    @Override
     public void check(JClassType type) throws NotFoundException {
       if ("Fields".equals(type.getSimpleSourceName())) {
         assertEquals("test.Fields", type.getQualifiedSourceName());
@@ -445,10 +462,11 @@
 
     public void check(JClassType type) {
       final String name = type.getSimpleSourceName();
-      if ("Enclosing".equals(name))
+      if ("Enclosing".equals(name)) {
         checkEnclosing(type);
-      else
+      } else {
         checkLocal(type);
+      }
     }
 
     public void checkEnclosing(JClassType type) {
@@ -603,8 +621,9 @@
 
       methods = type.getOverloads("overloaded");
       assertEquals(2, methods.length);
-      for (int i = 0; i < methods.length; i++)
-        assertEquals("overloaded", methods[i].getName());
+      for (JMethod element : methods) {
+        assertEquals("overloaded", element.getName());
+      }
 
       method = type.getMethod("overloaded", new JType[] {
           JPrimitiveType.INT, javaLangObject});
@@ -655,10 +674,11 @@
 
     public void check(JClassType type) {
       final String name = type.getSimpleSourceName();
-      if ("Outer".equals(name))
+      if ("Outer".equals(name)) {
         checkOuter(type);
-      else
+      } else {
         checkInner(type);
+      }
     }
 
     public void checkInner(JClassType type) {
@@ -759,8 +779,7 @@
   private final Set<CompilationUnit> units = new HashSet<CompilationUnit>();
 
   public void checkTypes(JClassType[] types) throws NotFoundException {
-    for (int i = 0; i < types.length; i++) {
-      JClassType type = types[i];
+    for (JClassType type : types) {
       check(type);
 
       JClassType[] nestedTypes = type.getNestedTypes();
@@ -768,8 +787,7 @@
     }
   }
 
-  public void testAssignable() throws UnableToCompleteException,
-      TypeOracleException {
+  public void testAssignable() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_Assignable);
     units.add(CU_OuterInner);
@@ -806,8 +824,7 @@
     }
   }
 
-  public void testAssimilation() throws UnableToCompleteException,
-      TypeOracleException {
+  public void testAssimilation() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_BeforeAssimilate);
     compileAndRefresh();
@@ -824,8 +841,7 @@
     assertSame(before, after.getSuperclass());
   }
 
-  public void testBindToTypeScope() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testBindToTypeScope() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_BindToTypeScope);
     compileAndRefresh();
@@ -833,8 +849,7 @@
     assertEquals(4, types.length);
   }
 
-  public void testDefaultClass() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testDefaultClass() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_DefaultClass);
     compileAndRefresh();
@@ -842,8 +857,7 @@
     assertEquals(2, types.length);
   }
 
-  public void testFieldsAndTypes() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testFieldsAndTypes() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_FieldsAndTypes);
     compileAndRefresh();
@@ -851,7 +865,7 @@
     assertEquals(3, types.length);
   }
 
-  public void testLocal() throws TypeOracleException, UnableToCompleteException {
+  public void testLocal() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_LocalClass);
     compileAndRefresh();
@@ -859,8 +873,7 @@
     assertEquals(3, types.length);
   }
 
-  public void testMetaData() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testMetaData() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_MetaData);
     compileAndRefresh();
@@ -868,8 +881,7 @@
     assertEquals(2, types.length);
   }
 
-  public void testMethodsAndParams() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testMethodsAndParams() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_Throwable);
     units.add(CU_MethodsAndParams);
@@ -878,8 +890,7 @@
     assertEquals(3, types.length);
   }
 
-  public void testOuterInner() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testOuterInner() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_OuterInner);
     compileAndRefresh();
@@ -896,7 +907,7 @@
    * CU_DeclaresInnerGenericType.
    */
   public void testParameterizedTypeBuildDependencies()
-      throws UnableToCompleteException, TypeOracleException {
+      throws TypeOracleException {
     units.add(CU_ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed);
     units.add(CU_ExtendsParameterizedType);
     units.add(CU_DeclaresInnerGenericType);
@@ -914,8 +925,7 @@
    * @throws NotFoundException
    * @throws IOException
    */
-  public void testRefresh() throws UnableToCompleteException,
-      TypeOracleException {
+  public void testRefresh() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_ExtendsGenericList);
     units.add(CU_GenericList);
@@ -965,8 +975,7 @@
    * @throws UnableToCompleteException
    * @throws IOException
    */
-  public void testRefreshWithErrors() throws UnableToCompleteException,
-      TypeOracleException {
+  public void testRefreshWithErrors() throws TypeOracleException {
     // Add Object
     StringBuffer sb = new StringBuffer();
     sb.append("package java.lang;");
@@ -1042,8 +1051,7 @@
     assertNull(typeOracle.findType("test.refresh.with.errors.GoodClass"));
   }
 
-  public void testSyntaxErrors() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testSyntaxErrors() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_HasSyntaxErrors);
     compileAndRefresh();
@@ -1054,8 +1062,7 @@
     assertEquals("java.lang.Object", types[0].getQualifiedSourceName());
   }
 
-  public void testUnresolvedSymbls() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testUnresolvedSymbls() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_HasUnresolvedSymbols);
     units.add(CU_RefsInfectedCompilationUnit);
@@ -1084,8 +1091,7 @@
     }
   }
 
-  private void compileAndRefresh() throws UnableToCompleteException,
-      TypeOracleException {
+  private void compileAndRefresh() throws TypeOracleException {
     TreeLogger logger = createTreeLogger();
     CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(logger, units);
     JdtCompiler.compile(units);
diff --git a/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
index d657d36..48c34b3 100644
--- a/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
+++ b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
 
@@ -31,14 +30,14 @@
 public class TypeOracleTestingUtils {
 
   public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
-      CompilationUnit... extraUnits) throws UnableToCompleteException {
+      CompilationUnit... extraUnits) {
     Set<CompilationUnit> extraUnitSet = new HashSet<CompilationUnit>();
     Collections.addAll(extraUnitSet, extraUnits);
     return buildStandardTypeOracleWith(logger, extraUnitSet);
   }
 
   public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
-      Set<CompilationUnit> extraUnits) throws UnableToCompleteException {
+      Set<CompilationUnit> extraUnits) {
     Set<CompilationUnit> unitSet = new HashSet<CompilationUnit>();
     addStandardCups(unitSet);
     for (CompilationUnit extraUnit : extraUnits) {
@@ -48,7 +47,7 @@
   }
 
   public static TypeOracle buildTypeOracle(TreeLogger logger,
-      Set<CompilationUnit> units) throws UnableToCompleteException {
+      Set<CompilationUnit> units) {
     JdtCompiler.compile(units);
     Set<String> validBinaryTypeNames = new HashSet<String>();
     for (CompilationUnit unit : units) {
diff --git a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
index ea2625c..ede0be2 100644
--- a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
@@ -56,7 +56,7 @@
   public static class MockCompilationState extends CompilationState {
 
     public MockCompilationState() {
-      super(new JavaSourceOracle() {
+      super(TreeLogger.NULL, new JavaSourceOracle() {
         public Set<String> getClassNames() {
           return Collections.emptySet();
         }
diff --git a/distro-source/core/src/release_notes.html b/distro-source/core/src/release_notes.html
index 37c804b..445a6d4 100644
--- a/distro-source/core/src/release_notes.html
+++ b/distro-source/core/src/release_notes.html
@@ -29,6 +29,7 @@
       <h1>Google Web Toolkit Release Notes</h1>
       <ul>
 		    <li><a href="#Release_Notes_Current">@GWT_VERSION@</a></li>
+		    <li><a href="#Release_Notes_1_5_3">1.5.3</a></li>
 		    <li><a href="#Release_Notes_1_5_2">1.5.2</a></li>
 		    <li><a href="#Release_Notes_1_5_1">1.5.1 (RC2)</a></li>
 		    <li><a href="#Release_Notes_1_5_0">1.5.0 (RC)</a></li>
@@ -49,6 +50,18 @@
       <h2>Release Notes for @GWT_VERSION@</h2>
       <h3>Fixed Issues</h3>
       <ul>
+        <li><code>ConstantMap</code> is really immutable now (it always should
+        have been); it also no longer generates serialization warnings when
+        attempting to serialize <code>Map&lt;String,String&gt;</code></li>
+        <li><code>TreeMap</code> and <code>TreeSet</code> are now
+        serializable</li>
+      </ul>
+      <hr/>
+
+      <a name="Release_Notes_1_5_3"></a>
+      <h2>Release Notes for 1.5.3</h2>
+      <h3>Fixed Issues</h3>
+      <ul>
         <li>RPC requests no longer fail on the embedded Android web browser</li>
         <li>Leaf <code>TreeItems</code> now line up with their non-leaf siblings</li>
         <li>Removing the last child node from a <code>TreeItem</code> no longer creates extra margins on the left</li>
diff --git a/eclipse/samples/DynaTable2/build.xml b/eclipse/samples/DynaTable2/build.xml
index c003fe4..b49d710 100644
--- a/eclipse/samples/DynaTable2/build.xml
+++ b/eclipse/samples/DynaTable2/build.xml
@@ -20,7 +20,7 @@
     </javac>
   </target>
 
-  <target name="deploy" description="Copy output to the war folder">
+  <target name="deploy" depends="gwtc" description="Copy output to the war folder">
     <mkdir dir="${outdir}/WEB-INF/lib" />
     <copy todir="${outdir}/WEB-INF/lib" file="${gwt.install}/gwt-servlet.jar" />
   </target>
@@ -55,14 +55,16 @@
   </target>
 
   <target name="shell" depends="javac" description="Run the deployed app in GWT hosted mode">
-    <java classname="com.google.gwt.dev.GWTShell" fork="yes" failonerror="true">
+    <java classname="com.google.gwt.dev.GWTHosted" fork="yes" failonerror="true">
       <jvmarg value="-Xmx256M"/>
       <jvmarg value="-Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
       <arg value="-out" />
       <arg file="${outdir}" />
       <arg value="-extra" />
       <arg file="${extradir}" />
-      <arg value="http://localhost:8888/DynaTable2.html" />
+      <arg value="-startupUrl" />
+      <arg value="DynaTable2.html" />
+      <arg value="com.google.gwt.sample.dynatable.DynaTable2" />
       <classpath>
         <pathelement location="../../../samples/dynatable/src" />
         <pathelement location="${outdir}/WEB-INF/classes" />
diff --git a/tools/api-checker/config/gwt15_16userApi.conf b/tools/api-checker/config/gwt15_16userApi.conf
new file mode 100644
index 0000000..3ccdb27
--- /dev/null
+++ b/tools/api-checker/config/gwt15_16userApi.conf
@@ -0,0 +1,29 @@
+#existing API
+
+name_old gwt15userApi
+#sourceFiles and excludedFiles are specified as colon-separated list of files
+sourceFiles_old @OLDROOT@/dev/core/super:@OLDROOT@/user/super:@OLDROOT@/user/src
+excludedFiles_old @OLDROOT@/user/src/com/google/gwt/benchmarks:@OLDROOT@/user/src/com/google/gwt/junit:@OLDROOT@/user/src/com/google/gwt/i18n/rebind:@OLDROOT@/user/src/com/google/gwt/i18n/tools:@OLDROOT@/user/src/com/google/gwt/json:@OLDROOT@/user/src/com/google/gwt/user/rebind:@OLDROOT@/user/src/com/google/gwt/user/server:@OLDROOT@/user/src/com/google/gwt/user/tools:@OLDROOT@/user/super/com/google/gwt/benchmarks:@OLDROOT@/user/super/com/google/gwt/junit
+
+##############################################
+#new Api
+
+name_new gwt16userApi
+#sourceFiles and excludedFiles are specified as colon-separated list of files
+sourceFiles_new ./dev/core/super:./user/super:./user/src
+#:dev/core/src
+excludedFiles_new ./user/src/com/google/gwt/benchmarks:./user/src/com/google/gwt/junit:./user/src/com/google/gwt/i18n/rebind:./user/src/com/google/gwt/i18n/tools:./user/src/com/google/gwt/json:./user/src/com/google/gwt/user/rebind:./user/src/com/google/gwt/user/server:./user/src/com/google/gwt/user/tools:./user/super/com/google/gwt/benchmarks:./user/super/com/google/gwt/junit
+
+##############################################
+#excluded packages
+excludedPackages com.google.gwt.core.client.impl:com.google.gwt.i18n.client.impl:com.google.gwt.user.client.impl:com.google.gwt.user.client.rpc.impl:com.google.gwt.user.client.ui.impl:com.google.gwt.xml.client.impl
+
+##############################################
+#Api  whitelist
+# when adding to the white-list, include comments as to why the addition is
+# being made. This needs to be done for this initial white-list below
+
+# the api-checker is currently regarding overloadeded methods that can be
+# overriden. TODO(amitmanjhi): Solving this issue correctly in all cases seems
+# to be hard. Come back and fix this issue, if more such cases come up. 
+java.lang.StringBuilder::append(Ljava/lang/StringBuffer;) OVERRIDABLE_METHOD_ARGUMENT_TYPE_CHANGE
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java
index 516b3ce..71bd2e2 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java
@@ -106,7 +106,7 @@
   public static final boolean DEBUG_DUPLICATE_REMOVAL = false;
 
   // Tweak for log output.
-  public static final TreeLogger.Type type = TreeLogger.ERROR;
+  public static final TreeLogger.Type type = TreeLogger.WARN;
 
   // remove duplicates by default
   public static Collection<ApiChange> getApiDiff(ApiContainer newApi,
@@ -208,12 +208,14 @@
     if (removeDuplicates) {
       collection = apiDiff.removeDuplicates(collection);
     }
+    Set<String> matchedWhiteList = new HashSet<String>();
 
     Collection<ApiChange> prunedCollection = new ArrayList<ApiChange>();
     for (ApiChange apiChange : collection) {
       String apiChangeAsString = apiChange.getStringRepresentationWithoutMessage();
       apiChangeAsString = apiChangeAsString.trim();
-      if (whiteList.remove(apiChangeAsString)) {
+      if (whiteList.contains(apiChangeAsString)) {
+        matchedWhiteList.add(apiChangeAsString);
         continue;
       }
       // check for Status.Compatible and Status.Compatible_with
@@ -227,6 +229,7 @@
       }
       prunedCollection.add(apiChange);
     }
+    whiteList.removeAll(matchedWhiteList);
     if (whiteList.size() > 0) {
       List<String> al = new ArrayList<String>(whiteList);
       Collections.sort(al);
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiContainer.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiContainer.java
index 7cffb0c..84a5235 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiContainer.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiContainer.java
@@ -201,6 +201,10 @@
     return logger;
   }
 
+  String getName() {
+    return name;
+  }
+  
   boolean isApiClass(JClassType classType) {
     Boolean ret = apiClassCache.get(classType);
     if (ret != null) {
@@ -264,8 +268,13 @@
         String pkgName = null;
         if (file.getName().endsWith("java")) {
           pkgName = extractPackageNameFromFile(file);
-          logger.log(TreeLogger.DEBUG, "adding pkgName = " + pkgName
-              + ", file = " + file.toString(), null);
+          if (pkgName == null) {
+            logger.log(TreeLogger.WARN, "Not adding file = "
+                + file.toString() + ", because packageName = null", null);
+          } else {
+            logger.log(TreeLogger.DEBUG, "adding pkgName = " + pkgName
+                + ", file = " + file.toString(), null);
+          }
         }
         if (isValidPackage(pkgName, sourcePathEntry.toURL().toString())) {
           // Add if it's a source file and the package and fileNames are okay
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiPackage.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiPackage.java
index 58ea221..b67dbc5 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiPackage.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiPackage.java
@@ -124,7 +124,7 @@
       }
     }
     if (notAddedClassNames.size() > 0) {
-      logger.log(TreeLogger.SPAM, "API " + name + ", package: " + name
+      logger.log(TreeLogger.SPAM, "API " + apiContainer.getName() + ", package: " + name
           + ", not adding " + notAddedClassNames.size() + " nonApi classes: "
           + notAddedClassNames, null);
     }
diff --git a/user/build.xml b/user/build.xml
index 0539253..6bc6113 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -78,7 +78,7 @@
 
   <target name="remoteweb-test" description="Run a remoteweb test at the given host and path" if="gwt.remote.browsers">
     <echo message="Performing remote browser testing at ${gwt.remote.browsers}" />
-    <gwt.junit test.args="${test.args} -out www -remoteweb ${gwt.remote.browsers}" test.out="${junit.out}/remoteweb" test.cases="default.web.tests" >
+    <gwt.junit test.args="${test.args} -out www -workDir ${junit.out}/remoteweb/workdir -remoteweb ${gwt.remote.browsers}" test.out="${junit.out}/remoteweb" test.cases="default.web.tests" >
       <extraclasspaths>
         <pathelement location="${gwt.build}/out/dev/core/bin-test" />
       </extraclasspaths>
@@ -87,7 +87,7 @@
 
   <target name="selenium-test" description="Run a remote test using Selenium RC test at the given host and path" if="gwt.selenium.hosts">
     <echo message="Performing remote browser testing using Selenium RC at ${gwt.selenium.hosts}" />
-    <gwt.junit test.args="${test.args} -out www -selenium ${gwt.selenium.hosts}" test.out="${junit.out}/selenium" test.cases="default.web.tests" >
+    <gwt.junit test.args="${test.args} -out www -workDir ${junit.out}/selenium/workdir -selenium ${gwt.selenium.hosts}" test.out="${junit.out}/selenium" test.cases="default.web.tests" >
       <extraclasspaths>
         <pathelement location="${gwt.build}/out/dev/core/bin-test" />
       </extraclasspaths>
@@ -95,7 +95,7 @@
   </target>
 
   <target name="test.hosted" depends="compile, compile.tests" description="Run only hosted-mode tests for this project.">
-    <gwt.junit test.args="${test.args}" test.out="${junit.out}/${build.host.platform}-hosted-mode" test.cases="default.hosted.tests" >
+    <gwt.junit test.args="${test.args} -workDir ${junit.out}/${build.host.platform}-hosted-mode/workdir" test.out="${junit.out}/${build.host.platform}-hosted-mode" test.cases="default.hosted.tests" >
       <extraclasspaths>
         <pathelement location="${gwt.build}/out/dev/core/bin-test" />
       </extraclasspaths>
@@ -103,7 +103,7 @@
   </target>
 
   <target name="test.web" depends="compile, compile.tests" description="Run only web-mode tests for this project.">
-    <gwt.junit test.args="${test.args} -out www -web" test.out="${junit.out}/${build.host.platform}-web-mode" test.cases="default.web.tests" >
+    <gwt.junit test.args="${test.args} -out www -workDir ${junit.out}/${build.host.platform}-web-mode/workdir -web" test.out="${junit.out}/${build.host.platform}-web-mode" test.cases="default.web.tests" >
       <extraclasspaths>
         <pathelement location="${gwt.build}/out/dev/core/bin-test" />
       </extraclasspaths>
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index b2ed7605..cd21132 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -20,7 +20,6 @@
 import com.google.gwt.core.ext.TreeLogger.Type;
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.BootStrapPlatform;
 import com.google.gwt.dev.GWTShell;
 import com.google.gwt.dev.cfg.BindingProperty;
 import com.google.gwt.dev.cfg.ConfigurationProperty;
@@ -174,7 +173,8 @@
     if (foundType != null) {
       return null;
     }
-    Map<String, CompilationUnit> unitMap = currentModule.getCompilationState().getCompilationUnitMap();
+    Map<String, CompilationUnit> unitMap = currentModule.getCompilationState(
+        logger).getCompilationUnitMap();
     CompilationUnit unit = unitMap.get(typeName);
     String errMsg;
     if (unit == null) {
@@ -201,8 +201,6 @@
    */
   private static JUnitShell getUnitTestShell() {
     if (unitTestShell == null) {
-      BootStrapPlatform.init();
-      BootStrapPlatform.applyPlatformHacks();
       unitTestShell = new JUnitShell();
       unitTestShell.lastLaunchFailed = true;
       String[] args = unitTestShell.synthesizeArgs();
diff --git a/user/src/com/google/gwt/user/tools/.classpathsrc b/user/src/com/google/gwt/user/tools/.classpathsrc
index 336a085..19b3e77 100644
--- a/user/src/com/google/gwt/user/tools/.classpathsrc
+++ b/user/src/com/google/gwt/user/tools/.classpathsrc
@@ -5,6 +5,6 @@
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
    <classpathentry kind="lib" path="@gwtUserPath"/>
    <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
-   <classpathentry kind="output" path="bin"/>
+   <classpathentry kind="output" path="war/WEB-INF/classes"/>
 @eclipseClassPathEntries
 </classpath>
diff --git a/user/src/com/google/gwt/user/tools/App.launchsrc b/user/src/com/google/gwt/user/tools/App.launchsrc
index b35bd08..1f9e95c 100644
--- a/user/src/com/google/gwt/user/tools/App.launchsrc
+++ b/user/src/com/google/gwt/user/tools/App.launchsrc
@@ -10,7 +10,8 @@
 @eclipseExtraLaunchPaths
 </listAttribute>
 <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="@vmargs -Xmx256M"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out www @startupUrl"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out
+  war -startupUrl @startupUrl @moduleName"/>
 <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="@projectName"/>
 <booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
 </launchConfiguration>
diff --git a/user/src/com/google/gwt/user/tools/AppClassTemplate.javasrc b/user/src/com/google/gwt/user/tools/AppClassTemplate.javasrc
index eae6bd1..f2cd244 100644
--- a/user/src/com/google/gwt/user/tools/AppClassTemplate.javasrc
+++ b/user/src/com/google/gwt/user/tools/AppClassTemplate.javasrc
@@ -1,6 +1,10 @@
 package @clientPackage;
 
 import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.rpc.ServiceDefTarget;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.ClickListener;
 import com.google.gwt.user.client.ui.DialogBox;
@@ -37,7 +41,6 @@
 
     // Create the dialog box
     final DialogBox dialogBox = new DialogBox();
-    dialogBox.setText("Welcome to GWT!");
     dialogBox.setAnimationEnabled(true);
     Button closeButton = new Button("close");
     VerticalPanel dialogVPanel = new VerticalPanel();
@@ -50,14 +53,36 @@
         dialogBox.hide();
       }
     });
-
+    
     // Set the contents of the Widget
     dialogBox.setWidget(dialogVPanel);
+ 
+    final EchoServiceAsync echoService = GWT.create(EchoService.class);
+    ServiceDefTarget target = (ServiceDefTarget) echoService;
+
+    // Use a module-relative URLs to ensure that this client code can find
+    // its way home, even when the URL changes (as might happen when you
+    // deploy this as a webapp under an external servlet container).
+    String moduleRelativeURL = GWT.getModuleBaseURL() + "echo";
+    target.setServiceEntryPoint(moduleRelativeURL);
+    
+    final String textToServer = "Hello GWT World!";
     
     button.addClickListener(new ClickListener() {
       public void onClick(Widget sender) {
+        final String dialogBoxText = "Sending to the server: " + textToServer;
+        dialogBox.setText(dialogBoxText);
         dialogBox.center();
         dialogBox.show();
+        echoService.echo(textToServer, new AsyncCallback<String>() {
+          public void onFailure(Throwable caught) {
+            Window.alert("Rpc failure");
+          }
+
+          public void onSuccess(String result) {
+            dialogBox.setText(dialogBoxText + "\n " + result);
+          }
+        });
       }
     });
   }
diff --git a/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc b/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc
index 5a23afa..9f9c72f 100644
--- a/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc
+++ b/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc
@@ -9,6 +9,10 @@
 <html>
   <head>
     <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+    <!--                                                               -->
+    <!-- Consider inlining CSS to reduce the number of requested files -->
+    <!--                                                               -->
+    <link type="text/css" rel="stylesheet" href="@className.css">
     <!--                                           -->
     <!-- Any title is fine                         -->
     <!--                                           -->
@@ -19,7 +23,7 @@
     <!-- If you add any GWT meta tags, they must   -->
     <!-- be added before this line.                -->
     <!--                                           -->
-    <script type="text/javascript" language="javascript" src="@moduleName.nocache.js"></script>
+    <script type="text/javascript" language="javascript" src="@deployDir/@newModuleName.nocache.js"></script>
   </head>
 
   <!--                                           -->
diff --git a/user/src/com/google/gwt/user/tools/ApplicationCreator.java b/user/src/com/google/gwt/user/tools/ApplicationCreator.java
index 99948f9..9126cd5 100644
--- a/user/src/com/google/gwt/user/tools/ApplicationCreator.java
+++ b/user/src/com/google/gwt/user/tools/ApplicationCreator.java
@@ -21,6 +21,7 @@
 import com.google.gwt.user.tools.util.ArgHandlerIgnore;
 import com.google.gwt.user.tools.util.ArgHandlerOverwrite;
 import com.google.gwt.user.tools.util.CreatorUtilities;
+import com.google.gwt.util.tools.ArgHandlerDir;
 import com.google.gwt.util.tools.ArgHandlerExtra;
 import com.google.gwt.util.tools.ArgHandlerOutDir;
 import com.google.gwt.util.tools.ArgHandlerString;
@@ -28,6 +29,7 @@
 import com.google.gwt.util.tools.Utility;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -144,6 +146,18 @@
     }
   }
 
+  static class FileCreator {
+    private final File dir;
+    private final String sourceName;
+    private final String className;
+
+    FileCreator(File dir, String sourceName, String className) {
+      this.dir = dir;
+      this.sourceName = sourceName;
+      this.className = className;
+    }
+  }
+
   private static final String PACKAGE_PATH;
 
   static {
@@ -172,11 +186,11 @@
    * @throws IOException
    */
   static void createApplication(String fullClassName, File outDir,
-      String eclipse, boolean overwrite, boolean ignore)
-      throws IOException {
-    createApplication(fullClassName, outDir, eclipse, overwrite, ignore, null, null);
+      String eclipse, boolean overwrite, boolean ignore) throws IOException {
+    createApplication(fullClassName, outDir, eclipse, overwrite, ignore, null,
+        null);
   }
-  
+
   /**
    * @param fullClassName Name of the fully-qualified Java class to create as an
    *          Application.
@@ -193,11 +207,35 @@
       String eclipse, boolean overwrite, boolean ignore,
       List<String> extraClassPaths, List<String> extraModules)
       throws IOException {
+    createApplication(fullClassName, outDir, eclipse, overwrite, ignore,
+        extraClassPaths, extraModules, null, null);
+  }
+
+  /**
+   * @param fullClassName Name of the fully-qualified Java class to create as an
+   *          Application.
+   * @param outDir Where to put the output files
+   * @param eclipse The name of a project to attach a .launch config to
+   * @param overwrite Overwrite an existing files if they exist.
+   * @param ignore Ignore existing files if they exist.
+   * @param extraClassPaths A list of paths to append to the class path for
+   *          launch configs.
+   * @param extraModules A list of GWT modules to add 'inherits' tags for.
+   * @param newModuleName The new module name
+   * @param deployDir The deploy directory
+   * @throws IOException
+   */
+  static void createApplication(String fullClassName, File outDir,
+      String eclipse, boolean overwrite, boolean ignore,
+      List<String> extraClassPaths, List<String> extraModules,
+      String newModuleName, File deployDir) throws IOException {
 
     // Figure out the installation directory
+
     String installPath = Utility.getInstallPath();
     String gwtUserPath = installPath + '/' + "gwt-user.jar";
     String gwtDevPath = installPath + '/' + Utility.getDevJarName();
+    String gwtServletPath = installPath + '/' + "gwt-servlet.jar";
 
     // Validate the arguments for extra class path entries and modules.
     if (!CreatorUtilities.validatePathsAndModules(gwtUserPath, extraClassPaths,
@@ -236,19 +274,26 @@
     pos = clientPackageName.lastIndexOf('.');
     File basePackageDir;
     String moduleName;
+    String serverPackageName = null;
     File javaDir = Utility.getDirectory(outDir, "src", true);
+    Utility.getDirectory(outDir, "test", true);
+    File warDir = Utility.getDirectory(outDir, "war", true);
+    File webInfDir = Utility.getDirectory(warDir, "WEB-INF", true);
     if (pos >= 0) {
       String basePackage = clientPackageName.substring(0, pos);
       moduleName = basePackage + "." + className;
+      serverPackageName = basePackage + ".server";
       basePackage = basePackage.replace('.', '/');
       basePackageDir = Utility.getDirectory(javaDir, basePackage, true);
     } else {
       moduleName = className;
       basePackageDir = javaDir;
+      serverPackageName = "server";
     }
     File clientDir = Utility.getDirectory(basePackageDir, "client", true);
     File publicDir = Utility.getDirectory(basePackageDir, "public", true);
-    String startupUrl = moduleName + "/" + className + ".html";
+    File serverDir = Utility.getDirectory(basePackageDir, "server", true);
+    String startupUrl = className + ".html";
 
     // Create a map of replacements
     //
@@ -256,103 +301,125 @@
     replacements.put("@className", className);
     replacements.put("@moduleName", moduleName);
     replacements.put("@clientPackage", clientPackageName);
+    replacements.put("@serverPackage", serverPackageName);
     replacements.put("@gwtUserPath", basePathEnv + gwtUserPath);
     replacements.put("@gwtDevPath", basePathEnv + gwtDevPath);
-    replacements.put("@shellClass", "com.google.gwt.dev.GWTShell");
+    replacements.put("@shellClass", "com.google.gwt.dev.GWTHosted");
     replacements.put("@compileClass", "com.google.gwt.dev.GWTCompiler");
     replacements.put("@startupUrl", startupUrl);
-    replacements.put("@vmargs", isMacOsX ? "-XstartOnFirstThread" : "");
+    replacements.put("@vmargs", isMacOsX
+        ? "<jvmarg value=\"-XstartOnFirstThread\"/>" : "");
     replacements.put("@eclipseExtraLaunchPaths",
         CreatorUtilities.createEclipseExtraLaunchPaths(extraClassPaths));
     replacements.put("@extraModuleInherits",
         createExtraModuleInherits(extraModules));
     replacements.put("@extraClassPathsColon", CreatorUtilities.appendPaths(":",
         extraClassPaths));
-    replacements.put("@extraClassPathsSemicolon", CreatorUtilities.appendPaths(";", extraClassPaths));
+    replacements.put("@extraClassPathsSemicolon", CreatorUtilities.appendPaths(
+        ";", extraClassPaths));
+    replacements.put("@newModuleName", (newModuleName != null) ? newModuleName
+        : moduleName);
+    replacements.put("@deployDir", deployDir.getName());
 
     {
-      // Create the module
-      File moduleXML = Utility.createNormalFile(basePackageDir, className
-          + ModuleDefLoader.GWT_MODULE_XML_SUFFIX, overwrite, ignore);
-      if (moduleXML != null) {
-        String out = Utility.getFileFromClassPath(PACKAGE_PATH
-            + "Module.gwt.xmlsrc");
-        Utility.writeTemplateFile(moduleXML, out, replacements);
+      // create the module xml file, skeleton html file, skeleton css file,
+      // web.xml file
+      FileCreator fileCreators[] = new FileCreator[] {
+          new FileCreator(basePackageDir, "Module.gwt.xml", className
+              + ModuleDefLoader.GWT_MODULE_XML_SUFFIX),
+          new FileCreator(warDir, "AppHtml.html", className + ".html"),
+          new FileCreator(warDir, "AppCss.css", className + ".css"),
+          new FileCreator(webInfDir, "web.xml", "web.xml"),};
+      for (FileCreator fileCreator : fileCreators) {
+        File file = Utility.createNormalFile(fileCreator.dir,
+            fileCreator.className, overwrite, ignore);
+        if (file != null) {
+          String out = Utility.getFileFromClassPath(PACKAGE_PATH
+              + fileCreator.sourceName + "src");
+          Utility.writeTemplateFile(file, out, replacements);
+        }
       }
     }
 
     {
-      // Create a skeleton html file
-      File publicHTML = Utility.createNormalFile(publicDir,
-          className + ".html", overwrite, ignore);
-      if (publicHTML != null) {
-        String out = Utility.getFileFromClassPath(PACKAGE_PATH
-            + "AppHtml.htmlsrc");
-        Utility.writeTemplateFile(publicHTML, out, replacements);
-      }
-    }
-
-    {
-      // Create a skeleton css file
-      File publicCSS = Utility.createNormalFile(publicDir, className + ".css",
-          overwrite, ignore);
-      if (publicCSS != null) {
-        String out = Utility.getFileFromClassPath(PACKAGE_PATH
-            + "AppCss.csssrc");
-        Utility.writeTemplateFile(publicCSS, out, replacements);
-      }
-    }
-
-    {
-      // Create a skeleton Application class
-      File javaClass = Utility.createNormalFile(clientDir, className + ".java",
-          overwrite, ignore);
-      if (javaClass != null) {
-        String out = Utility.getFileFromClassPath(PACKAGE_PATH
-            + "AppClassTemplate.javasrc");
-        Utility.writeTemplateFile(javaClass, out, replacements);
+      /*
+       * Create a skeleton Application: main client class, rpc stub for the
+       * client, async counterpart of the rpc stub, rpc implementation on the
+       * server.
+       */
+      FileCreator fileCreators[] = new FileCreator[] {
+          new FileCreator(clientDir, "AppClass", className),
+          new FileCreator(clientDir, "RpcClient", "EchoService"),
+          new FileCreator(clientDir, "RpcAsyncClient", "EchoServiceAsync"),
+          new FileCreator(serverDir, "RpcServer", "EchoServiceImpl"),};
+      for (FileCreator fileCreator : fileCreators) {
+        File javaClass = Utility.createNormalFile(fileCreator.dir,
+            fileCreator.className + ".java", overwrite, ignore);
+        if (javaClass != null) {
+          String out = Utility.getFileFromClassPath(PACKAGE_PATH
+              + fileCreator.sourceName + "Template.javasrc");
+          Utility.writeTemplateFile(javaClass, out, replacements);
+        }
       }
     }
 
     if (eclipse != null) {
-      // Create an eclipse launch config
       replacements.put("@projectName", eclipse);
-      File launchConfig = Utility.createNormalFile(outDir, className
-          + ".launch", overwrite, ignore);
-      if (launchConfig != null) {
-        String out = Utility.getFileFromClassPath(PACKAGE_PATH
-            + "App.launchsrc");
-        Utility.writeTemplateFile(launchConfig, out, replacements);
+      // Build the list of extra paths
+      replacements.put("@gwtServletPath", basePathEnv + gwtServletPath);
+      StringBuilder buf = new StringBuilder();
+      if (extraClassPaths != null) {
+        for (String path : extraClassPaths) {
+          buf.append("    <pathelement path=\"" + path + "\"/>");
+        }
       }
-    }
+      replacements.put("@extraAntPathElements", buf.toString());
 
-    // create startup files
-    String extension;
-    if (isWindows) {
-      extension = ".cmd";
-    } else {
-      extension = "";
-    }
+      StringBuilder classpathEntries = new StringBuilder();
+      if (extraClassPaths != null) {
+        for (String path : extraClassPaths) {
+          File f = new File(path);
 
-    File gwtshell = Utility.createNormalFile(outDir, className + "-shell"
-        + extension, overwrite, ignore);
-    if (gwtshell != null) {
-      String out = Utility.getFileFromClassPath(PACKAGE_PATH + "gwtshell"
-          + extension + "src");
-      Utility.writeTemplateFile(gwtshell, out, replacements);
-      if (extension.length() == 0) {
-        chmodExecutable(gwtshell);
+          if (!f.exists()) {
+            throw new FileNotFoundException("extraClassPath: " + path
+                + " must be present before .launch file can be created.");
+          }
+          // Handle both .jar files and paths
+          String kindString;
+          if (f.isDirectory()) {
+            kindString = "output";
+          } else if (path.endsWith(".jar")) {
+            kindString = "lib";
+          } else {
+            throw new RuntimeException("Don't know how to handle path: " + path
+                + ". It doesn't appear to be a directory or a .jar file");
+          }
+          classpathEntries.append("   <classpathentry kind=\"");
+          classpathEntries.append(kindString);
+          classpathEntries.append("\" path=\"");
+          classpathEntries.append(path);
+          classpathEntries.append("\"/>\n");
+        }
       }
-    }
+      replacements.put("@eclipseClassPathEntries", classpathEntries.toString());
 
-    File gwtcompile = Utility.createNormalFile(outDir, className + "-compile"
-        + extension, overwrite, ignore);
-    if (gwtcompile != null) {
-      String out = Utility.getFileFromClassPath(PACKAGE_PATH + "gwtcompile"
-          + extension + "src");
-      Utility.writeTemplateFile(gwtcompile, out, replacements);
-      if (extension.length() == 0) {
-        chmodExecutable(gwtcompile);
+      /*
+       * create an ant file, an eclipse .project, an eclipse .classpath, and an
+       * eclipse launch-config
+       */
+      FileCreator fileCreators[] = new FileCreator[] {
+          new FileCreator(outDir, "project.ant.xml", "build.xml"),
+          new FileCreator(outDir, ".project", ".project"),
+          new FileCreator(outDir, ".classpath", ".classpath"),
+          new FileCreator(outDir, "App.launch", className + ".launch"),};
+      for (FileCreator fileCreator : fileCreators) {
+        File file = Utility.createNormalFile(fileCreator.dir,
+            fileCreator.className, overwrite, ignore);
+        if (file != null) {
+          String out = Utility.getFileFromClassPath(PACKAGE_PATH
+              + fileCreator.sourceName + "src");
+          Utility.writeTemplateFile(file, out, replacements);
+        }
       }
     }
   }
@@ -393,13 +460,15 @@
   private ArgHandlerAddModule moduleHandler = new ArgHandlerAddModule();
   private File outDir;
   private boolean overwrite = false;
+  private String newModuleName = null;
+  private File deployDir;
 
   protected ApplicationCreator() {
 
     registerHandler(new ArgHandlerEclipse() {
       @Override
       public String getPurpose() {
-        return "Creates a debug launch config for the named eclipse project";
+        return "Creates an ant file, an eclipse project, and a launch config";
       }
 
       @Override
@@ -440,6 +509,64 @@
       }
     });
 
+    // handler to process newModuleName argument
+    registerHandler(new ArgHandlerString() {
+      @Override
+      public String[] getDefaultArgs() {
+        return null; // later reset to moduleName
+      }
+
+      @Override
+      public String getPurpose() {
+        return "Specifies the new name of the module";
+      }
+
+      @Override
+      public String getTag() {
+        return "-moduleName";
+      }
+
+      @Override
+      public String[] getTagArgs() {
+        return new String[] {"moduleName"};
+      }
+
+      @Override
+      public boolean setString(String str) {
+        newModuleName = str;
+        return true;
+      }
+
+    });
+
+    // handler to create the deployDir
+    registerHandler(new ArgHandlerDir() {
+
+      @Override
+      public String[] getDefaultArgs() {
+        return new String[] {"-deployDir", "deployDir"};
+      }
+
+      @Override
+      public String getPurpose() {
+        return "Specifies the deploy directory (defaults to deployDir)";
+      }
+
+      @Override
+      public String getTag() {
+        return "-deployDir";
+      }
+
+      @Override
+      public void setDir(File dir) {
+        if (dir.getName().length() == 0) {
+          throw new IllegalArgumentException("deployDir may not be empty");
+        }
+        deployDir = dir;
+      }
+
+    });
+
     registerHandler(new ArgHandlerAppClass());
     registerHandler(classPathHandler);
     registerHandler(moduleHandler);
@@ -449,7 +576,7 @@
     try {
       createApplication(fullClassName, outDir, eclipse, overwrite, ignore,
           classPathHandler.getExtraClassPathList(),
-          moduleHandler.getExtraModuleList());
+          moduleHandler.getExtraModuleList(), newModuleName, deployDir);
       return true;
     } catch (IOException e) {
       System.err.println(e.getClass().getName() + ": " + e.getMessage());
diff --git a/user/src/com/google/gwt/user/tools/Module.gwt.xmlsrc b/user/src/com/google/gwt/user/tools/Module.gwt.xmlsrc
index 4228170..79536b4 100644
--- a/user/src/com/google/gwt/user/tools/Module.gwt.xmlsrc
+++ b/user/src/com/google/gwt/user/tools/Module.gwt.xmlsrc
@@ -1,4 +1,4 @@
-<module>
+<module rename-to='@newModuleName' deploy-to='/@deployDir'>
 
       <!-- Inherit the core Web Toolkit stuff.                        -->
       <inherits name='com.google.gwt.user.User'/>
@@ -15,8 +15,5 @@
 
       <!-- Specify the app entry point class.                         -->
       <entry-point class='@clientPackage.@className'/>
-    
-      <!-- Specify the application specific style sheet.              -->
-      <stylesheet src='@className.css' />
-	
+
 </module>
diff --git a/user/src/com/google/gwt/user/tools/ProjectCreator.java b/user/src/com/google/gwt/user/tools/ProjectCreator.java
deleted file mode 100644
index 0ea5d2b..0000000
--- a/user/src/com/google/gwt/user/tools/ProjectCreator.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright 2007 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.tools;
-
-import com.google.gwt.user.tools.util.ArgHandlerAddToClassPath;
-import com.google.gwt.user.tools.util.ArgHandlerEclipse;
-import com.google.gwt.user.tools.util.ArgHandlerIgnore;
-import com.google.gwt.user.tools.util.ArgHandlerOverwrite;
-import com.google.gwt.user.tools.util.CreatorUtilities;
-import com.google.gwt.util.tools.ArgHandlerOutDir;
-import com.google.gwt.util.tools.ArgHandlerString;
-import com.google.gwt.util.tools.ToolBase;
-import com.google.gwt.util.tools.Utility;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Creates a new GWT project.
- */
-public final class ProjectCreator extends ToolBase {
-
-  private static final String PACKAGE_PATH;
-
-  static {
-    String path = ProjectCreator.class.getName();
-    path = path.substring(0, path.lastIndexOf('.') + 1);
-    PACKAGE_PATH = path.replace('.', '/');
-  }
-
-  public static void main(String[] args) {
-    ProjectCreator creator = new ProjectCreator();
-    if (creator.processArgs(args)) {
-      if (creator.run()) {
-        return;
-      }
-    }
-
-    System.exit(1);
-  }
-
-  /**
-   * Create a set of project files.
-   * 
-   * @param eclipse The name of project to create.
-   * @param ant The name of an ant file to create.
-   * @param outDir The directory to write into.
-   * @param overwrite Overwrite an existing files if they exist.
-   * @param ignore Ignore existing files if they exist.
-   * @throws IOException
-   */
-  static void createProject(String eclipse, String ant, File outDir,
-      boolean overwrite, boolean ignore) throws IOException {
-    createProject(eclipse, ant, outDir, overwrite, ignore, null);
-  }
-
-  /**
-   * Create a set of project files.
-   * 
-   * @param eclipse The name of project to create.
-   * @param ant The name of an ant file to create.
-   * @param outDir The directory to write into.
-   * @param overwrite Overwrite an existing files if they exist.
-   * @param ignore Ignore existing files if they exist.
-   * @param extraClassPaths class path entries passed on the command line
-   * @throws IOException
-   */
-  static void createProject(String eclipse, String ant, File outDir,
-      boolean overwrite, boolean ignore, List<String> extraClassPaths)
-      throws IOException {
-
-    // Figure out the installation directory
-    String installPath = Utility.getInstallPath();
-
-    // Create a map of replacements.
-    Map<String, String> replacements = new HashMap<String, String>();
-    String userJarPath = installPath + '/' + "gwt-user.jar";
-    replacements.put("@gwtUserPath", userJarPath);
-
-    // Check to see that the passed extra path/module arguments are valid.
-    if (!CreatorUtilities.validatePathsAndModules(userJarPath, extraClassPaths,
-        null)) {
-      return;
-    }
-
-    Utility.getDirectory(outDir, "src", true);
-    Utility.getDirectory(outDir, "test", true);
-
-    if (ant != null) {
-      // Create an ant build file
-      replacements.put("@projectName", ant);
-
-      // Build the list of extra paths
-      StringBuilder buf = new StringBuilder();
-      if (extraClassPaths != null) {
-        for (String path : extraClassPaths) {
-          buf.append("    <pathelement path=\"" + path + "\"/>");
-        }
-      }
-      replacements.put("@extraAntPathElements", buf.toString());
-
-      File antXML = Utility.createNormalFile(outDir, ant + ".ant.xml",
-          overwrite, ignore);
-      if (antXML != null) {
-        String out = Utility.getFileFromClassPath(PACKAGE_PATH
-            + "project.ant.xmlsrc");
-        Utility.writeTemplateFile(antXML, out, replacements);
-      }
-    }
-
-    if (eclipse != null) {
-      // Create an eclipse project file
-      replacements.put("@projectName", eclipse);
-      File dotProject = Utility.createNormalFile(outDir, ".project", overwrite,
-          ignore);
-      if (dotProject != null) {
-        String out = Utility.getFileFromClassPath(PACKAGE_PATH + ".projectsrc");
-        Utility.writeTemplateFile(dotProject, out, replacements);
-      }
-
-      StringBuilder classpathEntries = new StringBuilder();
-      if (extraClassPaths != null) {
-        for (String path : extraClassPaths) {
-          File f = new File(path);
-
-          if (!f.exists()) {
-            throw new FileNotFoundException("extraClassPath: " + path
-                + " must be present before .launch file can be created.");
-          }
-          // Handle both .jar files and paths
-        String kindString;
-          if (f.isDirectory()) {
-            kindString = "output";
-          } else if (path.endsWith(".jar")) {
-            kindString = "lib";
-          } else {
-            throw new RuntimeException("Don't know how to handle path: " + path
-                + ". It doesn't appear to be a directory or a .jar file");
-          }
-          classpathEntries.append("   <classpathentry kind=\"");
-          classpathEntries.append(kindString);
-          classpathEntries.append("\" path=\"");
-          classpathEntries.append(path);
-          classpathEntries.append("\"/>\n");
-        }
-      }
-
-      replacements.put("@eclipseClassPathEntries", classpathEntries.toString());
-
-      // Create an eclipse classpath file
-      File dotClasspath = Utility.createNormalFile(outDir, ".classpath",
-          overwrite, ignore);
-      if (dotClasspath != null) {
-        String out = Utility.getFileFromClassPath(PACKAGE_PATH
-            + ".classpathsrc");
-        Utility.writeTemplateFile(dotClasspath, out, replacements);
-      }
-    }
-  }
-
-  private String ant = null;
-  private String eclipse = null;
-  private boolean ignore = false;
-  private File outDir = null;
-  private boolean overwrite = false;
-  private ArgHandlerAddToClassPath classPathHandler = new ArgHandlerAddToClassPath();
-
-  protected ProjectCreator() {
-
-    registerHandler(new ArgHandlerString() {
-
-      @Override
-      public String getPurpose() {
-        return "Generate an Ant buildfile to compile source (.ant.xml will be appended)";
-      }
-
-      @Override
-      public String getTag() {
-        return "-ant";
-      }
-
-      @Override
-      public String[] getTagArgs() {
-        return new String[] {"projectName"};
-      }
-
-      @Override
-      public boolean setString(String str) {
-        ant = str;
-        return true;
-      }
-
-    });
-
-    registerHandler(new ArgHandlerEclipse() {
-      @Override
-      public String getPurpose() {
-        return "Generate an eclipse project";
-      }
-
-      @Override
-      public boolean setString(String str) {
-        eclipse = str;
-        return true;
-      }
-    });
-
-    registerHandler(new ArgHandlerOutDir() {
-      @Override
-      public void setDir(File dir) {
-        outDir = dir;
-      }
-    });
-
-    registerHandler(new ArgHandlerOverwrite() {
-      @Override
-      public boolean setFlag() {
-        if (ignore) {
-          System.err.println("-overwrite cannot be used with -ignore.");
-          return false;
-        }
-        overwrite = true;
-        return true;
-      }
-    });
-
-    registerHandler(new ArgHandlerIgnore() {
-      @Override
-      public boolean setFlag() {
-        if (overwrite) {
-          System.err.println("-ignore cannot be used with -overwrite.");
-          return false;
-        }
-        ignore = true;
-        return true;
-      }
-    });
-
-    registerHandler(classPathHandler);
-  }
-
-  protected boolean run() {
-    try {
-      if (ant == null && eclipse == null) {
-        System.err.println("Please specify either -ant or -eclipse.");
-        printHelp();
-        return false;
-      }
-      createProject(eclipse, ant, outDir, overwrite, ignore,
-          classPathHandler.getExtraClassPathList());
-      return true;
-    } catch (IOException e) {
-      System.err.println(e.getClass().getName() + ": " + e.getMessage());
-      return false;
-    }
-  }
-}
diff --git a/user/src/com/google/gwt/user/tools/RpcAsyncClientTemplate.javasrc b/user/src/com/google/gwt/user/tools/RpcAsyncClientTemplate.javasrc
new file mode 100644
index 0000000..52eef3e
--- /dev/null
+++ b/user/src/com/google/gwt/user/tools/RpcAsyncClientTemplate.javasrc
@@ -0,0 +1,10 @@
+package @clientPackage;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+/**
+ * The async counterpart of <code>EchoService</code>. 
+ */
+public interface EchoServiceAsync {
+  void echo (String input, AsyncCallback<String> callback);
+}
diff --git a/user/src/com/google/gwt/user/tools/RpcClientTemplate.javasrc b/user/src/com/google/gwt/user/tools/RpcClientTemplate.javasrc
new file mode 100644
index 0000000..419660c
--- /dev/null
+++ b/user/src/com/google/gwt/user/tools/RpcClientTemplate.javasrc
@@ -0,0 +1,10 @@
+package @clientPackage;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+
+/**
+ * The client side stub for the Rpc service.
+ */
+public interface EchoService extends RemoteService {
+  String echo (String input);
+}
diff --git a/user/src/com/google/gwt/user/tools/RpcServerTemplate.javasrc b/user/src/com/google/gwt/user/tools/RpcServerTemplate.javasrc
new file mode 100644
index 0000000..3f4ae7e
--- /dev/null
+++ b/user/src/com/google/gwt/user/tools/RpcServerTemplate.javasrc
@@ -0,0 +1,16 @@
+package @serverPackage;
+
+import @clientPackage.EchoService;
+import com.google.gwt.user.server.rpc.RemoteServiceServlet;
+
+/**
+ * The server side implementation of the Rpc service.
+ */
+public class EchoServiceImpl extends RemoteServiceServlet implements
+    EchoService {
+
+  public String echo(String input) {
+    return "Server says: " + input;
+  }
+
+}
diff --git a/user/src/com/google/gwt/user/tools/gwtcompile.cmdsrc b/user/src/com/google/gwt/user/tools/gwtcompile.cmdsrc
deleted file mode 100644
index 80f6e97..0000000
--- a/user/src/com/google/gwt/user/tools/gwtcompile.cmdsrc
+++ /dev/null
@@ -1 +0,0 @@
-@java -Xmx256M -cp "%~dp0\src;%~dp0\bin;@gwtUserPath;@gwtDevPath@extraClassPathsSemicolon" @compileClass -out "%~dp0\www" %* @moduleName
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/tools/gwtcompilesrc b/user/src/com/google/gwt/user/tools/gwtcompilesrc
deleted file mode 100644
index 75064a8..0000000
--- a/user/src/com/google/gwt/user/tools/gwtcompilesrc
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-APPDIR=`dirname $0`;
-java @vmargs -Xmx256M -cp "$APPDIR/src:$APPDIR/bin:@gwtUserPath:@gwtDevPath@extraClassPathsColon" @compileClass -out "$APPDIR/www" "$@" @moduleName;
diff --git a/user/src/com/google/gwt/user/tools/gwtshell.cmdsrc b/user/src/com/google/gwt/user/tools/gwtshell.cmdsrc
deleted file mode 100644
index dd14324..0000000
--- a/user/src/com/google/gwt/user/tools/gwtshell.cmdsrc
+++ /dev/null
@@ -1 +0,0 @@
-@java -Xmx256M -cp "%~dp0\src;%~dp0\bin;@gwtUserPath;@gwtDevPath@extraClassPathsSemicolon" @shellClass -out "%~dp0\www" %* @startupUrl
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/tools/gwtshellsrc b/user/src/com/google/gwt/user/tools/gwtshellsrc
deleted file mode 100644
index 195b443..0000000
--- a/user/src/com/google/gwt/user/tools/gwtshellsrc
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-APPDIR=`dirname $0`;
-java @vmargs -Xmx256M -cp "$APPDIR/src:$APPDIR/bin:@gwtUserPath:@gwtDevPath@extraClassPathsColon" @shellClass -out "$APPDIR/www" "$@" @startupUrl;
diff --git a/user/src/com/google/gwt/user/tools/project.ant.xmlsrc b/user/src/com/google/gwt/user/tools/project.ant.xmlsrc
index 942140d..de75dc9 100644
--- a/user/src/com/google/gwt/user/tools/project.ant.xmlsrc
+++ b/user/src/com/google/gwt/user/tools/project.ant.xmlsrc
@@ -1,9 +1,11 @@
 <?xml version="1.0" encoding="utf-8" ?>
-<project name="@projectName" default="compile" basedir=".">
+<project name="@projectName" default="build" basedir=".">
   <description>
     @projectName build file.  This is used to package up your project as a jar,
     if you want to distribute it.  This isn't needed for normal operation.
   </description>
+  <property name="outdir" location="war" />
+  <property name="extradir" location="extra" />
 
   <!-- set classpath -->
   <path id="project.class.path">
@@ -13,36 +15,78 @@
     <!-- Additional dependencies (such as junit) go here -->
   </path>
 
-  <target name="compile" description="Compile src to bin">
-    <mkdir dir="bin"/>
-    <javac srcdir="src:test" destdir="bin" includes="**" debug="on" debuglevel="lines,vars,source" source="1.4">
+  <!-- TODO:  
+   1. revisit this once GWT supports shared dir as a first-clas citizen
+   2. For a 1.4 server, split this so that the server side code is compiled
+   with a target=1.4 build rule -->
+  <target name="javac" description="Compile project to WEB-INF/classes">
+    <mkdir dir="${outdir}/WEB-INF/classes"/>
+    <javac srcdir="src:test"
+      destdir="${outdir}/WEB-INF/classes"
+      includes="**"
+      debug="true"
+      debuglevel="lines,vars,source"
+      source="1.5"
+      target="1.5"
+      nowarn="true"
+      encoding="utf-8">
       <classpath refid="project.class.path"/>
     </javac>
   </target>
 
-  <target name="package" depends="compile" description="Package up the project as a jar">
-    <jar destfile="@projectName.jar">
-      <fileset dir="bin">
-        <include name="**/*.class"/>
-      </fileset>
-      <!-- Get everything; source, modules, html files -->
-      <fileset dir="src">
-        <include name="**"/>
-      </fileset>
-      <fileset dir="test">
-        <include name="**"/>
-      </fileset>
-    </jar>
+  <target name="deploy" depends="gwtc" description="Copy output to the war folder">
+    <mkdir dir="${outdir}/WEB-INF/lib" />
+    <copy todir="${outdir}/WEB-INF/lib" file="@gwtServletPath" />
   </target>
 
-  <target name="clean">
-    <!-- Delete the bin directory tree -->
-    <delete file="@projectName.jar"/>
-    <delete>
-      <fileset dir="bin" includes="**/*.class"/>
-    </delete>
+  <!-- can add additional arguments like -logLevel INFO or -style PRETTY -->
+  <target name="gwtc" depends="javac" description="Compile to JavaScript">
+    <java failonerror="true" fork="true"
+          classname="@compileClass">
+      <classpath>
+        <pathelement location="src"/>
+        <pathelement location="@gwtDevPath"/>
+        <pathelement location="${outdir}/WEB-INF/classes"/>
+        <pathelement path="${java.class.path}/"/>
+        <pathelement path="@gwtUserPath"/>
+      </classpath>
+      @vmargs
+      <arg value="-out"/>
+      <arg file="${outdir}"/>
+      <arg value="-extra"/>
+      <arg file="${extradir}"/>
+      <arg value="@moduleName"/>
+    </java>
   </target>
 
-  <target name="all" depends="package"/>
+  <!-- can add additional arguments like -logLevel INFO -->
+  <target name="shell" depends="javac" description="Run the deployed app in GWT hosted mode">
+    <java failonerror="true" fork="true"
+          classname="@shellClass">
+      <jvmarg value="-Xmx256M"/>
+      <classpath>
+        <pathelement location="src"/>
+        <pathelement location="@gwtDevPath"/>
+        <pathelement path="${java.class.path}/"/>
+        <pathelement path="@gwtUserPath"/>
+      </classpath>
+      @vmargs
+      <arg value="-out"/>
+      <arg file="${outdir}"/>
+      <arg value="-startupUrl"/>
+      <arg value="@startupUrl"/>
+      <arg value="@moduleName"/>
+    </java>
+  </target>
+
+  <target name="build" depends="javac, gwtc, deploy" description="Build this project" />
+
+  <target name="clean" description="Cleans this project's intermediate and
+    output files">
+    <!-- uncomment if the WEB-INF/classes dir only contains GWT output --> 
+    <!-- <delete dir="${outdir}/WEB-INF/classes" failonerror="false" /> -->
+    <delete dir="${outdir}/@deployDir" failonerror="false" />
+    <delete dir="${extradir}" failonerror="false" />
+  </target>
 
 </project>
diff --git a/user/src/com/google/gwt/user/tools/web.xmlsrc b/user/src/com/google/gwt/user/tools/web.xmlsrc
new file mode 100644
index 0000000..1d33d1e
--- /dev/null
+++ b/user/src/com/google/gwt/user/tools/web.xmlsrc
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app>
+
+  <servlet>
+    <servlet-name>echoServlet</servlet-name>
+    <servlet-class>@serverPackage.EchoServiceImpl</servlet-class>
+  </servlet>
+  
+  <servlet-mapping>
+    <servlet-name>echoServlet</servlet-name>
+    <url-pattern>/@deployDir/echo</url-pattern>
+  </servlet-mapping>
+
+</web-app>