blob: e5ac9b4cb5d3802f94ef8f635313292a27d3f4d5 [file] [log] [blame]
/*
* 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.shell;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.Rules;
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.StandardGeneratorContext;
import com.google.gwt.dev.javac.rebind.RebindCache;
import com.google.gwt.dev.util.log.speedtracer.DevModeEventType;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import java.io.File;
/**
* Provides an environment for a {@link com.google.gwt.dev.shell.ModuleSpace}
* that works appropriately for the development shell.
*/
public class ShellModuleSpaceHost implements ModuleSpaceHost {
// TODO(jat): hack to try and serialize rebinds
private static final Object rebindLock = new Object[0];
protected final CompilationState compilationState;
protected final File genDir;
private final ArtifactAcceptor artifactAcceptor;
private CompilingClassLoader classLoader;
private final TreeLogger logger;
private final ModuleDef module;
private StandardRebindOracle rebindOracle;
private ModuleSpace space;
private RebindCache rebindCache;
/**
* @param module the module associated with the hosted module space
*/
public ShellModuleSpaceHost(TreeLogger logger,
CompilationState compilationState, ModuleDef module, File genDir,
ArtifactAcceptor artifactAcceptor, RebindCache rebindCache) {
this.logger = logger;
this.compilationState = compilationState;
this.module = module;
this.genDir = genDir;
this.artifactAcceptor = artifactAcceptor;
this.rebindCache = rebindCache;
}
public CompilingClassLoader getClassLoader() {
checkForModuleSpace();
return classLoader;
}
public String[] getEntryPointTypeNames() {
checkForModuleSpace();
return module.getEntryPointTypeNames();
}
public TreeLogger getLogger() {
return logger;
}
/**
* Invalidates the given source type name, so the next rebind request will
* generate a type again.
*/
public void invalidateRebind(String sourceTypeName) {
checkForModuleSpace();
rebindOracle.invalidateRebind(sourceTypeName);
}
public void onModuleReady(ModuleSpace readySpace)
throws UnableToCompleteException {
this.space = readySpace;
Event moduleSpaceHostReadyEvent = SpeedTracerLogger.start(DevModeEventType.MODULE_SPACE_HOST_READY);
try {
// Establish an environment for JavaScript property providers to run.
//
ModuleSpacePropertyOracle propOracle = new ModuleSpacePropertyOracle(
module.getProperties(), module.getActiveLinkerNames(), readySpace);
// Set up the rebind oracle for the module.
// It has to wait until now because we need to inject javascript.
//
Rules rules = module.getRules();
StandardGeneratorContext genCtx = new StandardGeneratorContext(
compilationState, module, genDir, new ArtifactSet(), false);
// Only enable generator result caching if we have a valid rebindCache
genCtx.setGeneratorResultCachingEnabled((rebindCache != null));
rebindOracle = new StandardRebindOracle(propOracle, rules, genCtx);
rebindOracle.setRebindCache(rebindCache);
// Create a completely isolated class loader which owns all classes
// associated with a particular module. This effectively builds a
// separate 'domain' for each running module, so that they all behave as
// though they are running separately. This allows the shell to run
// multiple modules, both in succession and simultaneously, without getting
// confused.
//
// Note that the compiling class loader has no parent. This keeps it from
// accidentally 'escaping' its domain and loading classes from the system
// class loader (the one that loaded the shell itself).
//
classLoader = new CompilingClassLoader(logger, compilationState, readySpace);
} finally {
moduleSpaceHostReadyEvent.end();
}
}
public String rebind(TreeLogger logger, String sourceTypeName)
throws UnableToCompleteException {
synchronized (rebindLock) {
checkForModuleSpace();
return rebindOracle.rebind(logger, sourceTypeName, new ArtifactAcceptor() {
public void accept(TreeLogger logger, ArtifactSet newlyGeneratedArtifacts)
throws UnableToCompleteException {
artifactAcceptor.accept(logger, newlyGeneratedArtifacts);
}
});
}
}
private void checkForModuleSpace() {
if (space == null) {
throw new IllegalStateException("Module initialization error");
}
}
}