Removes the completely spurious generatedResource directory.

The generatedResource directory was an artifact of earlier times.  We were literally writing generated resources out to temporary files, just so we could immediately read them back in.  This should speed up generators by avoiding most disk I/O.

http://gwt-code-reviews.appspot.com/289801/show
Review by: jat,bobv


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7819 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardGeneratedResource.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardGeneratedResource.java
index ea92ae0..e017532 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardGeneratedResource.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardGeneratedResource.java
@@ -20,12 +20,8 @@
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.linker.GeneratedResource;
 import com.google.gwt.dev.util.DiskCache;
-import com.google.gwt.util.tools.Utility;
 
 import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectInputStream;
@@ -38,24 +34,14 @@
 public class StandardGeneratedResource extends GeneratedResource {
   private static final DiskCache diskCache = new DiskCache();
 
-  private final long lastModified;
+  private final long lastModified = System.currentTimeMillis();
 
   private transient long token;
 
   public StandardGeneratedResource(Class<? extends Generator> generatorType,
-      String partialPath, File file) {
+      String partialPath, byte[] data) {
     super(StandardLinkerContext.class, generatorType, partialPath);
-    this.lastModified = file.lastModified();
-    FileInputStream fis = null;
-    try {
-      fis = new FileInputStream(file);
-      this.token = diskCache.transferFromStream(fis);
-    } catch (FileNotFoundException e) {
-      throw new RuntimeException("Unable to open file '"
-          + file.getAbsolutePath() + "'", e);
-    } finally {
-      Utility.close(fis);
-    }
+    this.token = diskCache.writeByteArray(data);
   }
 
   @Override
diff --git a/dev/core/src/com/google/gwt/dev/CompilePerms.java b/dev/core/src/com/google/gwt/dev/CompilePerms.java
index 8b7eb50..fb8c9e9 100644
--- a/dev/core/src/com/google/gwt/dev/CompilePerms.java
+++ b/dev/core/src/com/google/gwt/dev/CompilePerms.java
@@ -356,7 +356,7 @@
       assert (precompilationOptions.getDumpSignatureFile() == null);
       Precompilation precompilation = Precompile.precompile(logger,
           precompilationOptions, module, permId, onePerm,
-          precompilationOptions.getGenDir(), compilerWorkDir, null);
+          precompilationOptions.getGenDir(), null);
       if (precompilation == null) {
         return false;
       }
diff --git a/dev/core/src/com/google/gwt/dev/Compiler.java b/dev/core/src/com/google/gwt/dev/Compiler.java
index b3dabb2..7024343 100644
--- a/dev/core/src/com/google/gwt/dev/Compiler.java
+++ b/dev/core/src/com/google/gwt/dev/Compiler.java
@@ -179,12 +179,10 @@
       for (String moduleName : options.getModuleNames()) {
         ModuleDef module = ModuleDefLoader.loadFromClassPath(logger,
             moduleName, true);
-        File compilerWorkDir = options.getCompilerWorkDir(moduleName);
 
         if (options.isValidateOnly()) {
           if (!Precompile.validate(logger, options, module,
-              options.getGenDir(), compilerWorkDir,
-              options.getDumpSignatureFile())) {
+              options.getGenDir(), options.getDumpSignatureFile())) {
             return false;
           }
         } else {
@@ -195,7 +193,7 @@
           // Optimize early since permutation compiles will run in process.
           options.setOptimizePrecompile(true);
           Precompilation precompilation = Precompile.precompile(branch,
-              options, module, options.getGenDir(), compilerWorkDir,
+              options, module, options.getGenDir(),
               options.getDumpSignatureFile());
 
           if (precompilation == null) {
diff --git a/dev/core/src/com/google/gwt/dev/DevMode.java b/dev/core/src/com/google/gwt/dev/DevMode.java
index f348824..8fa62d2 100644
--- a/dev/core/src/com/google/gwt/dev/DevMode.java
+++ b/dev/core/src/com/google/gwt/dev/DevMode.java
@@ -220,11 +220,6 @@
       return sclArgs;
     }
 
-    @Override
-    public File getShellBaseWorkDir(ModuleDef moduleDef) {
-      return new File(new File(getWorkDir(), moduleDef.getName()), "shell");
-    }
-
     public File getWarDir() {
       return warDir;
     }
@@ -368,7 +363,6 @@
         // Create a hard reference to the module to avoid gc-ing it until we
         // actually load the module from the browser.
         startupModules.put(module.getName(), module);
-        Util.recursiveDelete(options.getShellBaseWorkDir(module), false);
         if (!options.isNoServer()) {
           validateServletTags(moduleBranch, servletValidator, module, webXml);
         }
diff --git a/dev/core/src/com/google/gwt/dev/DevModeBase.java b/dev/core/src/com/google/gwt/dev/DevModeBase.java
index a70c7b0..0aafe2a 100644
--- a/dev/core/src/com/google/gwt/dev/DevModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/DevModeBase.java
@@ -38,7 +38,6 @@
 import com.google.gwt.dev.ui.DoneCallback;
 import com.google.gwt.dev.ui.DoneEvent;
 import com.google.gwt.dev.util.BrowserInfo;
-import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
 import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
 import com.google.gwt.dev.util.arg.OptionGenDir;
@@ -58,7 +57,6 @@
 import java.util.Map;
 import java.util.Random;
 import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * The main executable class for the hosted mode shell. This class must not have
@@ -434,14 +432,6 @@
       OptionLogLevel, OptionGenDir, OptionNoServer, OptionPort,
       OptionCodeServerPort, OptionStartupURLs, OptionRemoteUI,
       OptionBindAddress {
-
-    /**
-     * The base shell work directory.
-     * 
-     * @param moduleDef
-     * @return working directory base
-     */
-    File getShellBaseWorkDir(ModuleDef moduleDef);
   }
 
   /**
@@ -509,10 +499,6 @@
       return remoteUIHostPort;
     }
 
-    public File getShellBaseWorkDir(ModuleDef moduleDef) {
-      return new File(new File(getWorkDir(), moduleDef.getName()), "shell");
-    }
-
     public List<String> getStartupURLs() {
       return Collections.unmodifiableList(startupURLs);
     }
@@ -659,8 +645,6 @@
 
   private static final Random RNG = new Random();
 
-  private static final AtomicLong uniqueId = new AtomicLong();
-
   public static String normalizeURL(String unknownUrlText, int port, String host) {
     if (unknownUrlText.indexOf(":") != -1) {
       // Assume it's a full url.
@@ -822,15 +806,10 @@
   protected final ShellModuleSpaceHost doCreateShellModuleSpaceHost(
       TreeLogger logger, CompilationState compilationState, ModuleDef moduleDef)
       throws UnableToCompleteException {
-    // Clear out the shell temp directory.
-    File shellBaseWorkDir = options.getShellBaseWorkDir(moduleDef);
-    File sessionWorkDir = new File(shellBaseWorkDir,
-        String.valueOf(uniqueId.getAndIncrement()));
-    Util.recursiveDelete(sessionWorkDir, false);
     ArtifactAcceptor artifactAcceptor = createArtifactAcceptor(logger,
         moduleDef);
     return new ShellModuleSpaceHost(logger, compilationState, moduleDef,
-        options.getGenDir(), new File(sessionWorkDir, "gen"), artifactAcceptor);
+        options.getGenDir(), artifactAcceptor);
   }
 
   protected abstract void doShutDownServer();
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index 90c4330..0aab621 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -172,12 +172,10 @@
 
       for (ModuleDef module : modules) {
         String moduleName = module.getName();
-        File compilerWorkDir = options.getCompilerWorkDir(moduleName);
 
         if (options.isValidateOnly()) {
           if (!Precompile.validate(logger, options, module,
-              options.getGenDir(), compilerWorkDir,
-              options.getDumpSignatureFile())) {
+              options.getGenDir(), options.getDumpSignatureFile())) {
             return false;
           }
         } else {
@@ -188,7 +186,7 @@
           // Optimize early since permutation compiles will run in process.
           options.setOptimizePrecompile(true);
           Precompilation precompilation = Precompile.precompile(logger,
-              options, module, options.getGenDir(), compilerWorkDir,
+              options, module, options.getGenDir(),
               options.getDumpSignatureFile());
 
           if (precompilation == null) {
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 9af6433..601e63d 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -105,7 +105,8 @@
     }
 
     public File getShellPublicGenDir(ModuleDef moduleDef) {
-      return new File(getShellBaseWorkDir(moduleDef), "public");
+      File moduleWorkDir = new File(getWorkDir(), moduleDef.getName());
+      return new File(moduleWorkDir, "public");
     }
 
     @Override
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index d2aac7b..b1b420c 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -299,13 +299,13 @@
 
     public DistillerRebindPermutationOracle(ModuleDef module,
         CompilationState compilationState, ArtifactSet generatorArtifacts,
-        PropertyPermutations perms, File genDir, File generatorResourcesDir) {
+        PropertyPermutations perms, File genDir) {
       this.compilationState = compilationState;
       permutations = new Permutation[perms.size()];
       propertyOracles = new StaticPropertyOracle[perms.size()];
       rebindOracles = new RebindOracle[perms.size()];
       generatorContext = new StandardGeneratorContext(compilationState, module,
-          genDir, generatorResourcesDir, generatorArtifacts);
+          genDir, generatorArtifacts);
       BindingProperty[] orderedProps = perms.getOrderedProperties();
       SortedSet<ConfigurationProperty> configPropSet = module.getProperties().getConfigurationProperties();
       ConfigurationProperty[] configProps = configPropSet.toArray(new ConfigurationProperty[configPropSet.size()]);
@@ -425,16 +425,15 @@
    * @param module the module to compile
    * @param genDir optional directory to dump generated source, may be
    *          <code>null</code>
-   * @param generatorResourcesDir required directory to dump generator resources
    * @return the precompilation
    */
   public static Precompilation precompile(TreeLogger logger,
       JJSOptions jjsOptions, ModuleDef module, File genDir,
-      File generatorResourcesDir, File dumpSignatureFile) {
+      File dumpSignatureFile) {
     PropertyPermutations allPermutations = new PropertyPermutations(
         module.getProperties(), module.getActiveLinkerNames());
     return precompile(logger, jjsOptions, module, 0, allPermutations, genDir,
-        generatorResourcesDir, dumpSignatureFile);
+        dumpSignatureFile);
   }
 
   /**
@@ -445,11 +444,9 @@
    * @param module the module to compile
    * @param genDir optional directory to dump generated source, may be
    *          <code>null</code>
-   * @param generatorResourcesDir required directory to dump generator resources
    */
   public static boolean validate(TreeLogger logger, JJSOptions jjsOptions,
-      ModuleDef module, File genDir, File generatorResourcesDir,
-      File dumpSignatureFile) {
+      ModuleDef module, File genDir, File dumpSignatureFile) {
     try {
       CompilationState compilationState = module.getCompilationState(logger);
       if (dumpSignatureFile != null) {
@@ -474,7 +471,7 @@
       DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
           module, compilationState, generatorArtifacts,
           new PropertyPermutations(module.getProperties(),
-              module.getActiveLinkerNames()), genDir, generatorResourcesDir);
+              module.getActiveLinkerNames()), genDir);
       // Allow GC later.
       compilationState = null;
       if (dumpSignatureFile != null) {
@@ -495,8 +492,7 @@
 
   static Precompilation precompile(TreeLogger logger, JJSOptions jjsOptions,
       ModuleDef module, int permutationBase,
-      PropertyPermutations allPermutations, File genDir,
-      File generatorResourcesDir, File dumpSignatureFile) {
+      PropertyPermutations allPermutations, File genDir, File dumpSignatureFile) {
 
     try {
       CompilationState compilationState = module.getCompilationState(logger);
@@ -514,8 +510,7 @@
 
       ArtifactSet generatedArtifacts = new ArtifactSet();
       DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
-          module, compilationState, generatedArtifacts, allPermutations,
-          genDir, generatorResourcesDir);
+          module, compilationState, generatedArtifacts, allPermutations, genDir);
       // Allow GC later.
       compilationState = null;
       PerfLogger.start("Precompile");
@@ -694,7 +689,7 @@
           TreeLogger branch = logger.branch(TreeLogger.INFO,
               "Validating compilation " + module.getName());
           if (!validate(branch, options, module, options.getGenDir(),
-              compilerWorkDir, options.getDumpSignatureFile())) {
+              options.getDumpSignatureFile())) {
             branch.log(TreeLogger.ERROR, "Validation failed");
             return false;
           }
@@ -704,8 +699,7 @@
               "Precompiling module " + module.getName());
 
           Precompilation precompilation = precompile(branch, options, module,
-              options.getGenDir(), compilerWorkDir,
-              options.getDumpSignatureFile());
+              options.getGenDir(), options.getDumpSignatureFile());
           if (precompilation == null) {
             branch.log(TreeLogger.ERROR, "Precompilation failed");
             return false;
diff --git a/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java b/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java
index 0b2aff8..3d59619 100644
--- a/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java
+++ b/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java
@@ -43,11 +43,12 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedSet;
+import java.util.Map.Entry;
 
 /**
  * Manages generators and generated units during a single compilation.
@@ -171,35 +172,49 @@
   /**
    * Manages a resource that is in the process of being created by a generator.
    */
-  private static class PendingResource {
+  private static class PendingResource extends OutputStream {
 
-    private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    private ByteArrayOutputStream baos = new ByteArrayOutputStream();
     private final String partialPath;
-    private final File pendingFile;
 
-    public PendingResource(File outDir, String partialPath) {
+    public PendingResource(String partialPath) {
       this.partialPath = partialPath;
-      this.pendingFile = new File(outDir, partialPath);
     }
 
-    public void commit(TreeLogger logger) throws UnableToCompleteException {
-      logger = logger.branch(TreeLogger.TRACE, "Writing generated resource '"
-          + pendingFile.getAbsolutePath() + "'", null);
-
-      Util.writeBytesToFile(logger, pendingFile, baos.toByteArray());
-    }
-
-    public File getFile() {
-      return pendingFile;
-    }
-
-    public OutputStream getOutputStream() {
-      return baos;
+    public void abort() {
+      baos = null;
     }
 
     public String getPartialPath() {
       return partialPath;
     }
+
+    public byte[] takeBytes() {
+      byte[] result = baos.toByteArray();
+      baos = null;
+      return result;
+    }
+
+    public void write(byte[] b) throws IOException {
+      if (baos == null) {
+        throw new IOException("stream closed");
+      }
+      baos.write(b);
+    }
+
+    public void write(byte[] b, int off, int len) throws IOException {
+      if (baos == null) {
+        throw new IOException("stream closed");
+      }
+      baos.write(b, off, len);
+    }
+
+    public void write(int b) throws IOException {
+      if (baos == null) {
+        throw new IOException("stream closed");
+      }
+      baos.write(b);
+    }
   }
 
   private static DiskCache diskCache = new DiskCache();
@@ -214,8 +229,6 @@
 
   private final File genDir;
 
-  private final File generatorResourcesDir;
-
   private final Map<Class<? extends Generator>, Generator> generators = new IdentityHashMap<Class<? extends Generator>, Generator>();
 
   private final ModuleDef module;
@@ -224,7 +237,7 @@
 
   private final Set<String> newlyGeneratedTypeNames = new HashSet<String>();
 
-  private final Map<OutputStream, PendingResource> pendingResourcesByOutputStream = new IdentityHashMap<OutputStream, PendingResource>();
+  private final Map<String, PendingResource> pendingResources = new HashMap<String, PendingResource>();
 
   private transient PropertyOracle propOracle;
 
@@ -235,12 +248,10 @@
    * available in the supplied type oracle although it isn't strictly required.
    */
   public StandardGeneratorContext(CompilationState compilationState,
-      ModuleDef module, File genDir, File generatorResourcesDir,
-      ArtifactSet allGeneratedArtifacts) {
+      ModuleDef module, File genDir, ArtifactSet allGeneratedArtifacts) {
     this.compilationState = compilationState;
     this.module = module;
     this.genDir = genDir;
-    this.generatorResourcesDir = generatorResourcesDir;
     this.allGeneratedArtifacts = allGeneratedArtifacts;
   }
 
@@ -271,8 +282,7 @@
    * Adds an Artifact to the ArtifactSet if one has been provided to the
    * context.
    */
-  public void commitArtifact(TreeLogger logger, Artifact<?> artifact)
-      throws UnableToCompleteException {
+  public void commitArtifact(TreeLogger logger, Artifact<?> artifact) {
     allGeneratedArtifacts.replace(artifact);
     newlyGeneratedArtifacts.add(artifact);
   }
@@ -280,32 +290,28 @@
   public GeneratedResource commitResource(TreeLogger logger, OutputStream os)
       throws UnableToCompleteException {
 
-    // Find the pending resource using its output stream as a key.
-    PendingResource pendingResource = pendingResourcesByOutputStream.get(os);
-    if (pendingResource != null) {
-      // Actually write the bytes to disk.
-      pendingResource.commit(logger);
-
-      // Add the GeneratedResource to the ArtifactSet
-      GeneratedResource toReturn = new StandardGeneratedResource(
-          currentGenerator, pendingResource.getPartialPath(),
-          pendingResource.getFile());
-      commitArtifact(logger, toReturn);
-
-      /*
-       * The resource is now no longer pending, so remove it from the map. If
-       * the commit above throws an exception, it's okay to leave the entry in
-       * the map because it will be reported later as not having been committed,
-       * which is accurate.
-       */
-      pendingResourcesByOutputStream.remove(os);
-
-      return toReturn;
-    } else {
+    PendingResource pendingResource = null;
+    String partialPath = null;
+    if (os instanceof PendingResource) {
+      pendingResource = (PendingResource) os;
+      partialPath = pendingResource.getPartialPath();
+      // Make sure it's ours by looking it up in the map.
+      if (pendingResource != pendingResources.get(partialPath)) {
+        pendingResource = null;
+      }
+    }
+    if (pendingResource == null) {
       logger.log(TreeLogger.WARN,
           "Generator attempted to commit an unknown OutputStream", null);
       throw new UnableToCompleteException();
     }
+
+    // Add the GeneratedResource to the ArtifactSet
+    GeneratedResource toReturn = new StandardGeneratedResource(
+        currentGenerator, partialPath, pendingResource.takeBytes());
+    commitArtifact(logger, toReturn);
+    pendingResources.remove(pendingResource.getPartialPath());
+    return toReturn;
   }
 
   /**
@@ -508,8 +514,7 @@
     }
 
     // Disallow absolute paths.
-    File f = new File(partialPath);
-    if (f.isAbsolute()) {
+    if (new File(partialPath).isAbsolute()) {
       logger.log(
           TreeLogger.ERROR,
           "Resource paths are intended to be relative to the compiled output directory and cannot be absolute",
@@ -542,27 +547,19 @@
     }
 
     // See if the file is pending.
-    for (Iterator<PendingResource> iter = pendingResourcesByOutputStream.values().iterator(); iter.hasNext();) {
-      PendingResource pendingResource = iter.next();
-      if (pendingResource.getPartialPath().equals(partialPath)) {
-        // It is already pending.
-        logger.log(TreeLogger.WARN, "The file '" + partialPath
-            + "' is already a pending resource", null);
-        return null;
-      }
+    if (pendingResources.containsKey(partialPath)) {
+      // It is already pending.
+      logger.log(TreeLogger.WARN, "The file '" + partialPath
+          + "' is already a pending resource", null);
+      return null;
     }
-
-    // Record that this file is pending.
-    PendingResource pendingResource = new PendingResource(
-        generatorResourcesDir, partialPath);
-    OutputStream os = pendingResource.getOutputStream();
-    pendingResourcesByOutputStream.put(os, pendingResource);
-
-    return os;
+    PendingResource pendingResource = new PendingResource(partialPath);
+    pendingResources.put(partialPath, pendingResource);
+    return pendingResource;
   }
 
   private void abortUncommittedResources(TreeLogger logger) {
-    if (pendingResourcesByOutputStream.isEmpty()) {
+    if (pendingResources.isEmpty()) {
       // Nothing to do.
       return;
     }
@@ -573,14 +570,10 @@
         "The following resources will not be created because they were never committed (did you forget to call commit()?)",
         null);
 
-    try {
-      for (Iterator<PendingResource> iter = pendingResourcesByOutputStream.values().iterator(); iter.hasNext();) {
-        PendingResource pendingResource = iter.next();
-        logger.log(TreeLogger.WARN,
-            pendingResource.getFile().getAbsolutePath(), null);
-      }
-    } finally {
-      pendingResourcesByOutputStream.clear();
+    for (Entry<String, PendingResource> entry : pendingResources.entrySet()) {
+      logger.log(TreeLogger.WARN, entry.getKey());
+      entry.getValue().abort();
     }
+    pendingResources.clear();
   }
 }
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 f69db8f..313903e 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
@@ -48,8 +48,6 @@
 
   private StandardRebindOracle rebindOracle;
 
-  private final File shellDir;
-
   private ModuleSpace space;
 
   /**
@@ -58,12 +56,11 @@
    */
   public ShellModuleSpaceHost(TreeLogger logger,
       CompilationState compilationState, ModuleDef module, File genDir,
-      File shellDir, ArtifactAcceptor artifactAcceptor) {
+      ArtifactAcceptor artifactAcceptor) {
     this.logger = logger;
     this.compilationState = compilationState;
     this.module = module;
     this.genDir = genDir;
-    this.shellDir = shellDir;
     this.artifactAcceptor = artifactAcceptor;
   }
 
@@ -95,7 +92,7 @@
     //
     Rules rules = module.getRules();
     StandardGeneratorContext genCtx = new StandardGeneratorContext(
-        compilationState, module, genDir, shellDir, new ArtifactSet());
+        compilationState, module, genDir, new ArtifactSet());
     rebindOracle = new StandardRebindOracle(propOracle, rules, genCtx);
 
     // Create a completely isolated class loader which owns all classes
diff --git a/dev/core/src/com/google/gwt/dev/util/Util.java b/dev/core/src/com/google/gwt/dev/util/Util.java
index 2a9f5b5..bea4dbe 100644
--- a/dev/core/src/com/google/gwt/dev/util/Util.java
+++ b/dev/core/src/com/google/gwt/dev/util/Util.java
@@ -736,6 +736,19 @@
     }
   }
 
+  /**
+   * Reads an entire input stream as bytes. Closes the input stream.
+   */
+  public static byte[] readStreamAsBytes(InputStream in) {
+    try {
+      ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+      copy(in, out);
+      return out.toByteArray();
+    } catch (IOException e) {
+      return null;
+    }
+  }
+
   public static <T> T readStreamAsObject(InputStream inputStream, Class<T> type)
       throws ClassNotFoundException, IOException {
     ObjectInputStream objectInputStream = null;
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 b0fcc9e..89af6d5 100644
--- a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
@@ -23,7 +23,6 @@
 import com.google.gwt.core.ext.SelectionProperty;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.linker.Artifact;
 import com.google.gwt.core.ext.linker.ArtifactSet;
 import com.google.gwt.core.ext.linker.GeneratedResource;
 import com.google.gwt.dev.cfg.ModuleDef;
@@ -130,9 +129,6 @@
       TreeLogger.NULL, Collections.<Resource> emptySet());
   private final TreeLogger mockLogger = TreeLogger.NULL;
   private final PropertyOracle mockPropOracle = new MockPropertyOracle();
-  private int tempFileCounter;
-  private final File tempGenDir;
-  private final File tempOutDir;
   /**
    * Stores the File objects to delete in the order they were created. Delete
    * them in reverse order.
@@ -140,10 +136,8 @@
   private final List<File> toDelete = new ArrayList<File>();
 
   public StandardGeneratorContextTest() {
-    tempGenDir = createTempDir("gwt-gen-");
-    tempOutDir = createTempDir("gwt-out-");
     genCtx = new StandardGeneratorContext(mockCompilationState,
-        new MockModuleDef(), tempGenDir, tempOutDir, artifactSet);
+        new MockModuleDef(), null, artifactSet);
     genCtx.setPropertyOracle(mockPropOracle);
     genCtx.setCurrentGenerator(Generator.class);
   }
@@ -195,27 +189,15 @@
    */
   public void testTryCreateResource_commitCalledTwice()
       throws UnableToCompleteException, IOException {
-    String path = createTempOutFilename();
+    String path = "testTryCreateResource/commitCalledTwice";
     OutputStream os = genCtx.tryCreateResource(mockLogger, path);
     os.write("going to call commit twice after this...".getBytes(Util.DEFAULT_ENCODING));
     genCtx.setCurrentGenerator(MockGenerator.class);
     GeneratedResource res = genCtx.commitResource(mockLogger, os);
     assertEquals(path, res.getPartialPath());
     assertEquals(MockGenerator.class, res.getGenerator());
-    File createdFile = new File(tempOutDir, path);
-    assertTrue(createdFile.exists());
     assertEquals(1, artifactSet.size());
-
-    // we need the unqualified nextArt to avoid a bug in Sun JDK1.6.0 on
-    // linux... generatedResource = artifactSet.iterator().next() dies, but
-    // this two-step equivalent does not.
-    @SuppressWarnings("unchecked")
-    Artifact nextArt = artifactSet.iterator().next();
-    GeneratedResource generatedResource = (GeneratedResource) nextArt;
-
-    assertEquals(path, generatedResource.getPartialPath());
-    assertEquals(MockGenerator.class, generatedResource.getGenerator());
-    rememberToDelete(createdFile);
+    assertTrue(artifactSet.contains(res));
     try {
       genCtx.commitResource(mockLogger, os);
       fail("Calling commit() again on the same stream object should have caused an exception");
@@ -228,17 +210,19 @@
 
   public void testTryCreateResource_commitNotCalled()
       throws UnableToCompleteException, IOException {
-    String path = createTempOutFilename();
+    String path = "testTryCreateResource/commitNotCalled";
     OutputStream os = genCtx.tryCreateResource(mockLogger, path);
     byte[] arrayWritten = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
     os.write(arrayWritten);
 
     // Note that we're *not* committing before calling finish().
     genCtx.finish(mockLogger);
-
-    File wouldBeCreatedFile = new File(tempOutDir, path);
-    assertFalse(wouldBeCreatedFile.exists());
     assertEquals(0, artifactSet.size());
+    try {
+      os.write(arrayWritten);
+      fail("Expected IOException for writing after abort");
+    } catch (IOException expected) {
+    }
   }
 
   public void testTryCreateResource_commitWithBadStream() {
@@ -270,22 +254,20 @@
   public void testTryCreateResource_creationWorksBetweenFinishes()
       throws UnableToCompleteException, IOException {
     genCtx.finish(mockLogger);
-    testTryCreateResource_normalCompletionWithoutSubDir();
+    testTryCreateResource_normalCompletion("creationWorksBetweenFinishes1");
     genCtx.finish(mockLogger);
-    testTryCreateResource_normalCompletionWithoutSubDir();
+    testTryCreateResource_normalCompletion("creationWorksBetweenFinishes2");
     genCtx.finish(mockLogger);
   }
 
   public void testTryCreateResource_duplicateCreationAfterCommit()
       throws UnableToCompleteException, UnsupportedEncodingException,
       IOException {
-    String path = createTempOutFilename();
+    String path = "testTryCreateResource/duplicateCreationAfterCommit";
     OutputStream os1 = genCtx.tryCreateResource(mockLogger, path);
     os1.write("going to call commit twice after this...".getBytes(Util.DEFAULT_ENCODING));
     genCtx.commitResource(mockLogger, os1);
-    File createdFile = new File(tempOutDir, path);
-    assertTrue(createdFile.exists());
-    rememberToDelete(createdFile);
+    assertEquals(1, artifactSet.size());
 
     OutputStream os2 = genCtx.tryCreateResource(mockLogger, path);
     assertNull(os2);
@@ -293,7 +275,7 @@
 
   public void testTryCreateResource_duplicateCreationAttempt()
       throws UnableToCompleteException {
-    String path = createTempOutFilename();
+    String path = "testTryCreateResource/duplicateCreationAttempt";
     OutputStream os1 = genCtx.tryCreateResource(mockLogger, path);
     assertNotNull(os1);
     OutputStream os2 = genCtx.tryCreateResource(mockLogger, path);
@@ -315,20 +297,19 @@
 
   public void testTryCreateResource_normalCompletionWithoutSubDir()
       throws UnableToCompleteException, IOException {
-    String path = createTempOutFilename();
-    testTryCreateResource_normalCompletion(null, path);
+    String path = "normalCompletionWithoutSubDir";
+    testTryCreateResource_normalCompletion(path);
   }
 
   public void testTryCreateResource_normalCompletionWithSubDir()
       throws UnableToCompleteException, IOException {
-    String subdir = createTempOutFilename();
-    String filename = createTempOutFilename();
-    testTryCreateResource_normalCompletion(subdir, filename);
+    String filename = "testTryCreateResource/normalCompletionWithSubDir";
+    testTryCreateResource_normalCompletion(filename);
   }
 
   /**
-   * Tests that tryCreateResource() returns <code>null</code> when the
-   * specified file is already on the public path.
+   * Tests that tryCreateResource() returns <code>null</code> when the specified
+   * file is already on the public path.
    * 
    * @throws UnableToCompleteException
    * @throws IOException
@@ -342,6 +323,21 @@
     assertEquals(0, artifactSet.size());
   }
 
+  public void testTryCreateResource_writeAfterCommit()
+      throws UnableToCompleteException, IOException {
+    String path = "normalCompletionWithoutSubDir";
+    OutputStream os = genCtx.tryCreateResource(mockLogger, path);
+    assertNotNull(os);
+    byte[] arrayWritten = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    os.write(arrayWritten);
+    genCtx.commitResource(mockLogger, os);
+    try {
+      os.write(arrayWritten);
+      fail("Expected IOException for writing after commit");
+    } catch (IOException expected) {
+    }
+  }
+
   @Override
   protected void tearDown() throws Exception {
     for (int i = toDelete.size() - 1; i >= 0; --i) {
@@ -351,52 +347,18 @@
     }
   }
 
-  private File createTempDir(String prefix) {
-    String baseTempPath = System.getProperty("java.io.tmpdir");
-    File newTempDir;
-    do {
-      newTempDir = new File(baseTempPath, prefix + System.currentTimeMillis());
-    } while (!newTempDir.mkdirs());
-    rememberToDelete(newTempDir);
-    return newTempDir;
-  }
-
-  private String createTempOutFilename() {
-    File tempFile;
-    do {
-      tempFile = new File(tempOutDir, System.currentTimeMillis() + "-"
-          + (++tempFileCounter) + ".gwt.tmp");
-    } while (tempFile.exists());
-    return tempFile.getName();
-  }
-
-  private void rememberToDelete(File f) {
-    toDelete.add(f);
-  }
-
-  private void testTryCreateResource_normalCompletion(String subdir, String name)
+  private void testTryCreateResource_normalCompletion(String name)
       throws UnableToCompleteException, IOException {
-    if (subdir != null) {
-      name = subdir + "/" + name;
-    }
     OutputStream os = genCtx.tryCreateResource(mockLogger, name);
     assertNotNull(os);
     byte[] arrayWritten = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
     os.write(arrayWritten);
-    genCtx.commitResource(mockLogger, os);
-
-    if (subdir != null) {
-      File createdDir = new File(tempOutDir, subdir);
-      assertTrue(createdDir.exists());
-      rememberToDelete(createdDir);
-    }
-
-    File createdFile = new File(tempOutDir, name);
-    assertTrue(createdFile.exists());
-    rememberToDelete(createdFile);
+    GeneratedResource res = genCtx.commitResource(mockLogger, os);
+    assertEquals(name, res.getPartialPath());
+    assertTrue(artifactSet.contains(res));
 
     // Read the file.
-    byte[] arrayRead = Util.readFileAsBytes(createdFile);
+    byte[] arrayRead = Util.readStreamAsBytes(res.getContents(mockLogger));
     assertTrue(Arrays.equals(arrayWritten, arrayRead));
   }