001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.shell;
017:
018: import com.google.gwt.core.ext.TreeLogger;
019: import com.google.gwt.core.ext.UnableToCompleteException;
020: import com.google.gwt.core.ext.typeinfo.TypeOracle;
021: import com.google.gwt.dev.cfg.ModuleDef;
022: import com.google.gwt.dev.cfg.ModuleDefLoader;
023: import com.google.gwt.dev.cfg.Rules;
024: import com.google.gwt.dev.jdt.ByteCodeCompiler;
025: import com.google.gwt.dev.jdt.RebindOracle;
026: import com.google.gwt.dev.jdt.SourceOracle;
027:
028: import java.io.File;
029: import java.util.HashMap;
030: import java.util.Map;
031:
032: /**
033: * Provides an environment for a {@link com.google.gwt.dev.shell.ModuleSpace}
034: * that works appropriately for the development shell.
035: */
036: public class ShellModuleSpaceHost implements ModuleSpaceHost {
037:
038: private static Map<ModuleDef, ByteCodeCompiler> byteCodeCompilersByModule = new HashMap<ModuleDef, ByteCodeCompiler>();
039:
040: protected final File genDir;
041:
042: protected final TypeOracle typeOracle;
043:
044: private CompilingClassLoader classLoader;
045:
046: private final TreeLogger logger;
047:
048: private final ModuleDef module;
049:
050: private final File outDir;
051:
052: private RebindOracle rebindOracle;
053:
054: private final boolean saveJsni;
055:
056: private ModuleSpace space;
057:
058: /**
059: * @param module the module associated with the hosted module space
060: * @param saveJsni
061: */
062: public ShellModuleSpaceHost(TreeLogger logger,
063: TypeOracle typeOracle, ModuleDef module, File genDir,
064: File outDir, boolean saveJsni) {
065: this .logger = logger;
066: this .typeOracle = typeOracle;
067: this .module = module;
068: this .genDir = genDir;
069: this .saveJsni = saveJsni;
070:
071: // Combine the user's output dir with the module name to get the
072: // module-specific output dir.
073: this .outDir = new File(outDir, module.getName());
074: }
075:
076: public CompilingClassLoader getClassLoader() {
077: checkForModuleSpace();
078: return classLoader;
079: }
080:
081: public String[] getEntryPointTypeNames() {
082: checkForModuleSpace();
083: return module.getEntryPointTypeNames();
084: }
085:
086: public TreeLogger getLogger() {
087: return logger;
088: }
089:
090: public void onModuleReady(ModuleSpace readySpace)
091: throws UnableToCompleteException {
092: this .space = readySpace;
093:
094: // Create a host for the hosted mode compiler.
095: // We add compilation units to it as deferred binding generators write them.
096: //
097: SourceOracle srcOracle = new HostedModeSourceOracle(typeOracle,
098: saveJsni ? genDir : null);
099:
100: // Create or find the compiler to be used by the compiling class loader.
101: //
102: ByteCodeCompiler compiler = getOrCreateByteCodeCompiler(srcOracle);
103:
104: // Establish an environment for JavaScript property providers to run.
105: //
106: ModuleSpacePropertyOracle propOracle = new ModuleSpacePropertyOracle(
107: module.getProperties(), readySpace);
108:
109: // Set up the rebind oracle for the module.
110: // It has to wait until now because we need to inject javascript.
111: //
112: Rules rules = module.getRules();
113: rebindOracle = new StandardRebindOracle(typeOracle, propOracle,
114: module, rules, genDir, outDir, module.getCacheManager());
115:
116: // Create a completely isolated class loader which owns all classes
117: // associated with a particular module. This effectively builds a
118: // separate 'domain' for each running module, so that they all behave as
119: // though they are running separately. This allows the shell to run
120: // multiple modules, both in succession and simultaneously, without getting
121: // confused.
122: //
123: // Note that the compiling class loader has no parent. This keeps it from
124: // accidentally 'escaping' its domain and loading classes from the system
125: // class loader (the one that loaded the shell itself).
126: //
127: classLoader = new CompilingClassLoader(logger, compiler,
128: typeOracle);
129: }
130:
131: public String rebind(TreeLogger rebindLogger, String sourceTypeName)
132: throws UnableToCompleteException {
133: checkForModuleSpace();
134: return rebindOracle.rebind(rebindLogger, sourceTypeName);
135: }
136:
137: ByteCodeCompiler getOrCreateByteCodeCompiler(SourceOracle srcOracle) {
138: ByteCodeCompiler compiler;
139: synchronized (byteCodeCompilersByModule) {
140: compiler = byteCodeCompilersByModule.get(module);
141: if (compiler == null) {
142: compiler = new ByteCodeCompiler(srcOracle, module
143: .getCacheManager());
144: if (ModuleDefLoader.getEnableCachingModules()) {
145: byteCodeCompilersByModule.put(module, compiler);
146: }
147: }
148: }
149: return compiler;
150: }
151:
152: private void checkForModuleSpace() {
153: if (space == null) {
154: throw new IllegalStateException(
155: "Module initialization error");
156: }
157: }
158: }
|