Super Dev Mode: clean up module names and show bindings

External changes in the progress API. (Not used in JavaScript.)
  - renamed the "module" field to "inputModule" and made it
    consistently store the input module. 
  - added the "bindings" field.

More refactoring in preparation for fast browser switching:

- Introduce Outbox id's. The OutboxTable uses them as its primary
key but they're not being used much externally yet.
- Clarify input versus output module names everywhere internally.
(Fixing this in JSON will wait for another patch.)
- Slightly clean up precompiling since setting the module name is no
longer a special case.

Change-Id: I80473f8f1744b43f06b2602fa34060f57c221f47
Review-Link: https://gwt-review.googlesource.com/#/c/9003/
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
index 6c9d808..d2b41a6 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
@@ -138,12 +138,19 @@
     File workDir = ensureWorkDir(options);
     logger.log(Type.INFO, "workDir: " + workDir);
 
+    int nextOutboxId = 1;
     OutboxTable outboxes = new OutboxTable(options);
     for (String moduleName : options.getModuleNames()) {
       AppSpace appSpace = AppSpace.create(new File(workDir, moduleName));
 
       Recompiler recompiler = new Recompiler(appSpace, moduleName, options);
-      outboxes.addOutbox(new Outbox(recompiler, options.getNoPrecompile(), logger));
+
+      // The id should be treated as an opaque string since we will change it again.
+      // TODO: change outbox id to include binding properties.
+      String outboxId = moduleName + "_" + nextOutboxId;
+      nextOutboxId++;
+
+      outboxes.addOutbox(new Outbox(outboxId, recompiler, options.getNoPrecompile(), logger));
     }
     return outboxes;
   }
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Job.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Job.java
index 4da9f3f..cc913b9 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Job.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Job.java
@@ -18,7 +18,7 @@
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.TreeLogger.Type;
 import com.google.gwt.dev.codeserver.Progress.Status;
-import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableSortedMap;
 import com.google.gwt.thirdparty.guava.common.util.concurrent.Futures;
 import com.google.gwt.thirdparty.guava.common.util.concurrent.ListenableFuture;
 import com.google.gwt.thirdparty.guava.common.util.concurrent.SettableFuture;
@@ -37,16 +37,16 @@
  * <p>Jobs are thread-safe.
  */
 class Job {
-  private static final ConcurrentMap<String, AtomicInteger> moduleToNextId =
+  private static final ConcurrentMap<String, AtomicInteger> prefixToNextId =
       new ConcurrentHashMap<String, AtomicInteger>();
 
   private final String id;
 
   // Input
 
-  private final String moduleName;
+  private final String inputModuleName;
 
-  private final ImmutableMap<String, String> bindingProperties;
+  private final ImmutableSortedMap<String, String> bindingProperties;
 
   // Output
 
@@ -54,27 +54,32 @@
 
   // Listeners
 
+  private final Outbox outbox;
+
   private final LogSupplier logSupplier;
 
   private ProgressTable table; // non-null when submitted
 
   /**
-   * Creates a job to recompile a module.
-   * @param moduleName The client-side name of the module to recompile (after renaming).
+   * Creates a job to update an outbox.
    * @param bindingProperties  Properties that uniquely identify a permutation.
    *     (Otherwise, more than one permutation will be compiled.)
    * @param parentLogger  The parent of the logger that will be used for this job.
    */
-  Job(String moduleName, Map<String, String> bindingProperties, TreeLogger parentLogger) {
-    this.id = chooseNextId(moduleName);
-    this.moduleName = moduleName;
-    this.bindingProperties = ImmutableMap.copyOf(bindingProperties);
+  Job(Outbox box, Map<String, String> bindingProperties, TreeLogger parentLogger) {
+    this.id = chooseNextId(box);
+    this.outbox = box;
+    this.inputModuleName = box.getInputModuleName();
+    // TODO: we will use the binding properties to find or create the outbox,
+    // then take binding properties from the outbox here.
+    this.bindingProperties = ImmutableSortedMap.copyOf(bindingProperties);
     this.logSupplier = new LogSupplier(parentLogger, id);
   }
 
-  private static String chooseNextId(String moduleName) {
-    moduleToNextId.putIfAbsent(moduleName, new AtomicInteger(0));
-    return moduleName + "-" + moduleToNextId.get(moduleName).getAndIncrement();
+  private static String chooseNextId(Outbox box) {
+    String prefix = box.getId();
+    prefixToNextId.putIfAbsent(prefix, new AtomicInteger(0));
+    return prefix + "-" + prefixToNextId.get(prefix).getAndIncrement();
   }
 
   /**
@@ -88,20 +93,27 @@
   }
 
   /**
-   * The module to compile.
+   * The module name that will be sent to the compiler.
    */
-  String getModuleName() {
-    return moduleName;
+  String getInputModuleName() {
+    return inputModuleName;
   }
 
   /**
    * The binding properties to use for this recompile.
    */
-  ImmutableMap<String, String> getBindingProperties() {
+  ImmutableSortedMap<String, String> getBindingProperties() {
     return bindingProperties;
   }
 
   /**
+   * The outbox that will serve the job's result (if successful).
+   */
+  Outbox getOutbox() {
+    return outbox;
+  }
+
+  /**
    * Returns the logger for this job. (Creates it on first use.)
    */
   TreeLogger getLogger() {
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/JobRunner.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/JobRunner.java
index abdf13c..923b528 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/JobRunner.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/JobRunner.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.codeserver;
 
 import com.google.gwt.core.ext.TreeLogger.Type;
-import com.google.gwt.dev.codeserver.Job.Result;
 
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -58,14 +57,6 @@
 
   private static void recompile(Job job, OutboxTable outboxes) {
     job.getLogger().log(Type.INFO, "starting job: " + job.getId());
-    Outbox box = outboxes.findOutbox(job);
-    if (box == null) {
-      String msg = "skipped a compile job with an unknown module: " + job.getModuleName();
-      job.getLogger().log(Type.WARN, msg);
-      job.onFinished(new Result(job, null,  new RuntimeException(msg)));
-      return;
-    }
-
-    box.recompile(job);
+    job.getOutbox().recompile(job);
   }
 }
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Outbox.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Outbox.java
index 289e8d5..5f0bb9f 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Outbox.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Outbox.java
@@ -30,6 +30,8 @@
 import java.io.InputStream;
 import java.net.URL;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -43,24 +45,45 @@
    */
   private static final String SOURCEMAP_FILE_SUFFIX = "_sourceMap0.json";
 
-  private final AtomicReference<Job.Result> published = new AtomicReference<Job.Result>();
+  private final String id;
   private final Recompiler recompiler;
 
-  Outbox(Recompiler recompiler, boolean noPrecompile, TreeLogger logger)
+  private final AtomicReference<Job.Result> published = new AtomicReference<Job.Result>();
+
+  Outbox(String id, Recompiler recompiler, boolean noPrecompile, TreeLogger logger)
       throws UnableToCompleteException {
+    this.id = id;
     this.recompiler = recompiler;
     maybePrecompile(noPrecompile, logger);
   }
 
   /**
+   * A unique id for this outbox. (This should be treated as an opaque string.)
+   */
+  String getId() {
+    return id;
+  }
+
+  /**
    * Loads the module and maybe compiles it. Sets up the output directory.
    * Throws an exception if unable. (In this case, Super Dev Mode fails to start.)
    */
   void maybePrecompile(boolean noPrecompile, TreeLogger logger) throws UnableToCompleteException {
+    // TODO: each box will have its own binding properties.
+    Map<String, String> defaultProps = new HashMap<String, String>();
+    defaultProps.put("user.agent", "safari");
+    defaultProps.put("locale", "en");
+
+    // Create a dummy job for the first compile.
+    // Its progress is not visible externally but will still be logged.
+    ProgressTable dummy = new ProgressTable();
+    Job job = new Job(this, defaultProps, logger);
+    job.onSubmitted(dummy);
+
     if (noPrecompile) {
-      publish(recompiler.initWithoutPrecompile(logger));
+      publish(recompiler.initWithoutPrecompile(job));
     } else {
-      publish(recompiler.precompile(logger));
+      publish(recompiler.precompile(job));
     }
   }
 
@@ -98,10 +121,17 @@
   }
 
   /**
-   * Returns the name of this module (after renaming).
+   * Returns the module name that will be sent to the compiler (before renaming).
    */
-  String getModuleName() {
-    return recompiler.getModuleName();
+  String getInputModuleName() {
+    return recompiler.getInputModuleName();
+  }
+
+  /**
+   * Returns the module name last received from the compiler (after renaming).
+   */
+  String getOutputModuleName() {
+    return recompiler.getOutputModuleName();
   }
 
   /**
@@ -140,7 +170,7 @@
    *
    * @throws RuntimeException if unable
    */
-  public File findSourceMap(String strongName) {
+  File findSourceMap(String strongName) {
     File dir = findSymbolMapDir();
     File file = new File(dir, strongName + SOURCEMAP_FILE_SUFFIX);
     if (!file.isFile()) {
@@ -154,7 +184,7 @@
    * @throws RuntimeException if unable
    */
   private File findSymbolMapDir() {
-    String moduleName = recompiler.getModuleName();
+    String moduleName = recompiler.getOutputModuleName();
     File symbolMapsDir = getOutputDir().findSymbolMapDir(moduleName);
     if (symbolMapsDir == null) {
       throw new RuntimeException("Can't find symbol map directory for " + moduleName);
@@ -223,19 +253,19 @@
    * @return The location of the file, which might not actually exist.
    */
   File getExtraFile(String path) {
-    File prefix = new File(getOutputDir().getExtraDir(), getModuleName());
+    File prefix = new File(getOutputDir().getExtraDir(), getOutputModuleName());
     return new File(prefix, path);
   }
 
   JsonObject getTemplateVariables() {
     JsonObject result = new JsonObject();
-    result.put("moduleName", getModuleName());
+    result.put("moduleName", getOutputModuleName());
     result.put("files", listModuleFiles());
     return result;
   }
 
   private JsonArray listModuleFiles() {
-    File[] files = new File(getWarDir(), getModuleName()).listFiles();
+    File[] files = new File(getWarDir(), getOutputModuleName()).listFiles();
     if (files == null) {
       return new JsonArray();
     }
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/OutboxTable.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/OutboxTable.java
index 9f3e718..f7d7f92 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/OutboxTable.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/OutboxTable.java
@@ -20,9 +20,11 @@
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.dev.json.JsonArray;
 import com.google.gwt.dev.json.JsonObject;
+import com.google.gwt.thirdparty.guava.common.collect.Lists;
 import com.google.gwt.thirdparty.guava.common.collect.Maps;
 
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -34,7 +36,7 @@
   private final Options options;
 
   /**
-   * A map from client-side module names (after renaming) to its outbox.
+   * A map from outbox id (an opaque string) to its outbox.
    */
   private final Map<String, Outbox> outboxes = Maps.newHashMap();
 
@@ -46,31 +48,32 @@
    * Adds a {@link Outbox} to the table.
    */
   void addOutbox(Outbox outbox) {
-    outboxes.put(outbox.getModuleName(), outbox);
+    outboxes.put(outbox.getId(), outbox);
   }
 
   /**
-   * Returns the outbox where the output of a compile job will be published,
-   * or null if it can't be found.
-   */
-  Outbox findOutbox(Job job) {
-    return findByModuleName(job.getModuleName());
-  }
-
-  /**
-   * Retrieves a {@link Outbox} corresponding to a given module name.
+   * Retrieves an {@link Outbox} corresponding to a given module name.
    * This should be the module name after renaming.
-   * TODO: remove and use an Outbox id instead.
+   * TODO: callers should use an Outbox id instead.
    */
-  Outbox findByModuleName(String moduleName) {
-    return outboxes.get(moduleName);
+  Outbox findByOutputModuleName(String moduleName) {
+    for (Outbox box : outboxes.values()) {
+      if (box.getOutputModuleName().equals(moduleName)) {
+        return box;
+      }
+    }
+    return null;
   }
 
   /**
    * Returns the list of known module names (after renaming).
    */
-  Collection<String> getModuleNames() {
-    return outboxes.keySet();
+  Collection<String> getOutputModuleNames() {
+    List<String> result = Lists.newArrayList();
+    for (Outbox box : outboxes.values()) {
+      result.add(box.getOutputModuleName());
+    }
+    return result;
   }
 
   void defaultCompileAll(boolean noPrecompile, TreeLogger logger) throws UnableToCompleteException {
@@ -86,7 +89,7 @@
   JsonObject getConfig() {
     JsonObject config = JsonObject.create();
     JsonArray moduleNames = new JsonArray();
-    for (String module : getModuleNames()) {
+    for (String module : getOutputModuleNames()) {
       moduleNames.add(module);
     }
     config.put("moduleNames", moduleNames);
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Progress.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Progress.java
index 59eb4a9..9cbeb45 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Progress.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Progress.java
@@ -16,6 +16,7 @@
 package com.google.gwt.dev.codeserver;
 
 import com.google.gwt.dev.json.JsonObject;
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableSortedMap;
 
 /**
  * A snapshot of a {@link Job}'s current state, for progress dialogs.
@@ -27,12 +28,14 @@
    */
   final String jobId;
 
-  final String module;
+  final String inputModuleName;
+  final ImmutableSortedMap<String, String> bindings;
   final Status status;
 
   Progress(Job job, Status status) {
     this.jobId = job.getId();
-    this.module = job.getModuleName();
+    this.inputModuleName = job.getInputModuleName();
+    this.bindings = job.getBindingProperties();
     this.status = status;
   }
 
@@ -47,11 +50,20 @@
   JsonObject toJsonObject() {
     JsonObject out = new JsonObject();
     out.put("jobId", jobId);
-    out.put("module", module);
+    out.put("inputModule", inputModuleName);
+    out.put("bindings", getBindingsJson());
     out.put("status", status.jsonName);
     return out;
   }
 
+  private JsonObject getBindingsJson() {
+    JsonObject out = new JsonObject();
+    for (String name : bindings.keySet()) {
+      out.put(name, bindings.get(name));
+    }
+    return out;
+  }
+
   /**
    * Defines the lifecycle of a job.
    */
@@ -97,10 +109,7 @@
 
     @Override
     JsonObject toJsonObject() {
-      JsonObject out = new JsonObject();
-      out.put("jobId", jobId);
-      out.put("module", module);
-      out.put("status", "compiling");
+      JsonObject out = super.toJsonObject();
       out.put("finishedSteps", finishedSteps);
       out.put("totalSteps", totalSteps);
       out.put("stepMessage", stepMessage);
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
index 07230f1..df034ff 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
@@ -47,7 +47,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
@@ -58,7 +57,8 @@
 class Recompiler {
 
   private final AppSpace appSpace;
-  private final String originalModuleName;
+  private final String inputModuleName;
+
   private IncrementalBuilder incrementalBuilder;
   private String serverPrefix;
   private int compilesDone = 0;
@@ -66,7 +66,7 @@
       Maps.newHashMap();
 
   // after renaming
-  private AtomicReference<String> moduleName = new AtomicReference<String>(null);
+  private AtomicReference<String> outputModuleName = new AtomicReference<String>(null);
 
   private final AtomicReference<CompileDir> lastBuild = new AtomicReference<CompileDir>();
 
@@ -79,9 +79,9 @@
   private CompilerContext compilerContext;
   private Options options;
 
-  Recompiler(AppSpace appSpace, String moduleName, Options options) {
+  Recompiler(AppSpace appSpace, String inputModuleName, Options options) {
     this.appSpace = appSpace;
-    this.originalModuleName = moduleName;
+    this.inputModuleName = inputModuleName;
     this.options = options;
     this.serverPrefix = options.getPreferredHost() + ":" + options.getPort();
     compilerContext = compilerContextBuilder.build();
@@ -91,23 +91,9 @@
    * Compiles the first time, while Super Dev Mode is starting up.
    * Either this method or {@link #initWithoutPrecompile} should be called first.
    */
-  synchronized Job.Result precompile(TreeLogger logger) throws UnableToCompleteException {
-    Map<String, String> defaultProps = new HashMap<String, String>();
-    defaultProps.put("user.agent", "safari");
-    defaultProps.put("locale", "en");
-
-    // Create a dummy job for the first compile.
-    // Its progress is not visible externally but will still be logged.
-    //
-    // If we ever start reporting progress on this job, we should make the module name consistent.
-    // (We don't know what the module name will change to before loading the module, so we use
-    // the original name.)
-    ProgressTable dummy = new ProgressTable();
-    Job job = new Job(originalModuleName, defaultProps, logger);
-    job.onSubmitted(dummy);
+  synchronized Job.Result precompile(Job job) throws UnableToCompleteException {
     Result result = compile(job);
     job.onFinished(result);
-
     assert result.isOk();
     return result;
   }
@@ -170,7 +156,7 @@
 
     boolean listenerFailed = false;
     try {
-      options.getRecompileListener().startedCompile(originalModuleName, compileId, compileDir);
+      options.getRecompileListener().startedCompile(inputModuleName, compileId, compileDir);
     } catch (Exception e) {
       compileLogger.log(TreeLogger.Type.WARN, "listener threw exception", e);
       listenerFailed = true;
@@ -188,7 +174,7 @@
       }
     } finally {
       try {
-        options.getRecompileListener().finishedCompile(originalModuleName, compilesDone, success);
+        options.getRecompileListener().finishedCompile(inputModuleName, compilesDone, success);
       } catch (Exception e) {
         compileLogger.log(TreeLogger.Type.WARN, "listener threw exception", e);
         listenerFailed = true;
@@ -215,12 +201,7 @@
    * Creates a dummy output directory without compiling the module.
    * Either this method or {@link #precompile} should be called first.
    */
-  synchronized Job.Result initWithoutPrecompile(TreeLogger parentLogger)
-      throws UnableToCompleteException {
-    ProgressTable dummy = new ProgressTable();
-    Map<String, String> bindingProps = ImmutableMap.of();
-    Job job = new Job(originalModuleName, bindingProps, parentLogger);
-    job.onSubmitted(dummy);
+  synchronized Job.Result initWithoutPrecompile(Job job) throws UnableToCompleteException {
 
     long startTime = System.currentTimeMillis();
     CompileDir compileDir = makeCompileDir(++compilesDone, job.getLogger());
@@ -228,14 +209,14 @@
 
     ModuleDef module = loadModule(compileLogger);
     String newModuleName = module.getName();  // includes any rename.
-    moduleName.set(newModuleName);
+    outputModuleName.set(newModuleName);
 
     lastBuild.set(compileDir);
 
     try {
       // Prepare directory.
       File outputDir = new File(
-          compileDir.getWarDir().getCanonicalPath() + "/" + getModuleName());
+          compileDir.getWarDir().getCanonicalPath() + "/" + getOutputModuleName());
       if (!outputDir.exists()) {
         if (!outputDir.mkdir()) {
           compileLogger.log(TreeLogger.Type.WARN, "cannot create directory: " + outputDir);
@@ -244,8 +225,8 @@
 
       // Creates a "module_name.nocache.js" that just forces a recompile.
       String moduleScript = PageUtil.loadResource(Recompiler.class, "nomodule.nocache.js");
-      moduleScript = moduleScript.replace("__MODULE_NAME__", getModuleName());
-      PageUtil.writeFile(outputDir.getCanonicalPath() + "/" + getModuleName() + ".nocache.js",
+      moduleScript = moduleScript.replace("__MODULE_NAME__", getOutputModuleName());
+      PageUtil.writeFile(outputDir.getCanonicalPath() + "/" + getOutputModuleName() + ".nocache.js",
           moduleScript);
 
     } catch (IOException e) {
@@ -268,7 +249,7 @@
       resources = ResourceLoaders.forPathAndFallback(options.getSourcePath(), resources);
       this.resourceLoader.set(resources);
 
-      incrementalBuilder = new IncrementalBuilder(originalModuleName,
+      incrementalBuilder = new IncrementalBuilder(inputModuleName,
           compileDir.getWarDir().getPath(), compileDir.getWorkDir().getPath(),
           compileDir.getGenDir().getPath(), resourceLoader.get());
       buildResultStatus = incrementalBuilder.build(compileLogger);
@@ -279,7 +260,7 @@
     }
 
     if (incrementalBuilder.isRootModuleKnown()) {
-      moduleName.set(incrementalBuilder.getRootModuleName());
+      outputModuleName.set(incrementalBuilder.getRootModuleName());
     }
     // Unlike a monolithic compile, the incremental builder can successfully build but have no new
     // output (for example when no files have changed). So it's important to only publish the new
@@ -298,7 +279,7 @@
     job.onCompilerProgress(
         new Progress.Compiling(job, 0, 2, "Loading modules"));
 
-    CompilerOptions loadOptions = new CompilerOptionsImpl(compileDir, originalModuleName, options);
+    CompilerOptions loadOptions = new CompilerOptionsImpl(compileDir, inputModuleName, options);
     compilerContext = compilerContextBuilder.options(loadOptions).build();
 
     ModuleDef module = loadModule(compileLogger);
@@ -307,7 +288,7 @@
 
     // Propagates module rename.
     String newModuleName = module.getName();
-    moduleName.set(newModuleName);
+    outputModuleName.set(newModuleName);
 
     // Check if we can skip the compile altogether.
     InputSummary input = new InputSummary(bindingProperties, module);
@@ -344,8 +325,18 @@
     return lastBuild.get().getLogFile();
   }
 
-  String getModuleName() {
-    return moduleName.get();
+  /**
+   * The module name that the recompiler passes as input to the GWT compiler (before renaming).
+   */
+  public String getInputModuleName() {
+    return inputModuleName;
+  }
+
+  /**
+   * The module name that the GWT compiler uses in compiled output (after renaming).
+   */
+  String getOutputModuleName() {
+    return outputModuleName.get();
   }
 
   ResourceLoader getResourceLoader() {
@@ -395,7 +386,7 @@
 
     // ModuleDefLoader.loadFromResources() checks for modified .gwt.xml files.
     ModuleDef moduleDef = ModuleDefLoader.loadFromResources(
-        logger, compilerContext, originalModuleName, resources, true);
+        logger, compilerContext, inputModuleName, resources, true);
     compilerContext = compilerContextBuilder.module(moduleDef).build();
 
     // A snapshot of the module's configuration before we modified it.
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceHandler.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceHandler.java
index d841530..a50dee4 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceHandler.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceHandler.java
@@ -100,7 +100,7 @@
       throw new RuntimeException("invalid request (shouldn't happen): " + target);
     }
 
-    Outbox box = outboxes.findByModuleName(moduleName);
+    Outbox box = outboxes.findByOutputModuleName(moduleName);
     if (box == null) {
       response.sendError(HttpServletResponse.SC_NOT_FOUND);
       logger.log(TreeLogger.WARN, "unknown module; returned not found for request: " + target);
@@ -280,7 +280,7 @@
   }
 
   private SourceMap loadSourceMap(String moduleName) {
-    Outbox box = outboxes.findByModuleName(moduleName);
+    Outbox box = outboxes.findByOutputModuleName(moduleName);
     return SourceMap.load(box.findSourceMapForOnePermutation());
   }
 }
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
index 9500126..33df1ce 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
@@ -151,9 +151,10 @@
 
   /**
    * Returns the location of the compiler output. (Changes after every recompile.)
+   * @param outputModuleName the module name that the GWT compiler used in its output.
    */
-  public File getCurrentWarDir(String moduleName) {
-    return outboxes.findByModuleName(moduleName).getWarDir();
+  public File getCurrentWarDir(String outputModuleName) {
+    return outboxes.findByOutputModuleName(outputModuleName).getWarDir();
   }
 
   private void handleRequest(String target, HttpServletRequest request,
@@ -198,7 +199,7 @@
     if (target.startsWith("/recompile/")) {
       setHandled(request);
       String moduleName = target.substring("/recompile/".length());
-      Outbox outbox = outboxes.findByModuleName(moduleName);
+      Outbox outbox = outboxes.findByOutputModuleName(moduleName);
       if (outbox == null) {
         response.sendError(HttpServletResponse.SC_NOT_FOUND);
         logger.log(TreeLogger.WARN, "not found: " + target);
@@ -211,7 +212,7 @@
       // cause a spurious recompile, resulting in an unexpected permutation being loaded later.
       //
       // It would be unsafe to allow a configuration property to be changed.
-      Job job = new Job(outbox.getModuleName(), getBindingProperties(request), logger);
+      Job job = new Job(outbox, getBindingProperties(request), logger);
       runner.submit(job);
       boolean ok = job.waitForResult().isOk();
 
@@ -224,7 +225,7 @@
     if (target.startsWith("/log/")) {
       setHandled(request);
       String moduleName = target.substring("/log/".length());
-      File file = outboxes.findByModuleName(moduleName).getCompileLog();
+      File file = outboxes.findByOutputModuleName(moduleName).getCompileLog();
       sendLogPage(moduleName, file, response);
       return;
     }
@@ -299,7 +300,7 @@
 
     int secondSlash = target.indexOf('/', 1);
     String moduleName = target.substring(1, secondSlash);
-    Outbox outbox = outboxes.findByModuleName(moduleName);
+    Outbox outbox = outboxes.findByOutputModuleName(moduleName);
 
     File file = outbox.getOutputFile(target);
     if (!file.isFile()) {
@@ -332,7 +333,7 @@
 
   private void sendModulePage(String moduleName, HttpServletResponse response, TreeLogger logger)
       throws IOException {
-    Outbox module = outboxes.findByModuleName(moduleName);
+    Outbox module = outboxes.findByOutputModuleName(moduleName);
     if (module == null) {
       response.sendError(HttpServletResponse.SC_NOT_FOUND);
       logger.log(TreeLogger.WARN, "module not found: " + moduleName);
@@ -357,8 +358,8 @@
 
     out.startTag("h1").text("Policy Files").endTag("h1").nl();
 
-    for (String moduleName : outboxes.getModuleNames()) {
-      Outbox module = outboxes.findByModuleName(moduleName);
+    for (String moduleName : outboxes.getOutputModuleNames()) {
+      Outbox module = outboxes.findByOutputModuleName(moduleName);
       File manifest = module.getExtraFile("rpcPolicyManifest/manifest.txt");
       if (manifest.isFile()) {
         out.startTag("h2").text(moduleName).endTag("h2").nl();
@@ -415,8 +416,8 @@
       return;
     }
 
-    for (String moduleName : outboxes.getModuleNames()) {
-      Outbox module = outboxes.findByModuleName(moduleName);
+    for (String moduleName : outboxes.getOutputModuleNames()) {
+      Outbox module = outboxes.findByOutputModuleName(moduleName);
       File policy = module.getOutputFile(moduleName + "/" + rest);
       if (policy.isFile()) {
         PageUtil.sendFile("text/plain", policy, response);