Initial support for WAR deployment. GWTCompiler happens to be backwards-compatible with the legacy format, but the behavior of the shell differs. Therefore we created a new entry point, GWTHosted, which is the new GWTShell and runs with WAR assumptions. Summary of WAR mode: - Assumes output folder is in WAR format - Runs Jetty; embeds GWTShellServletFilter to autogenerate modules on demand - Uses true linking (and the new relinking); dumps resources and generated selection script directly into output folder - Ignores the <servlet> tag; servlets must be initialized via WEB-INF/web.xml in the output folder Summary of legacy mode: - Same behavior as GWT 1.5 - Uses Tomcat (but we want to eventually replace with Jetty); uses GWTShellServlet - Serves files directly from public path and work directory; uses the old HostedModeLinker to generate the selection script - <servlet> tag still works Additionally, a GWT module file now supports a "deploy-to" attribute at the top level, which allows the subdirectory within the output folder for a module to be overridden (the default is the fully-qualified module name). Patch by: scottb, bruce, bobv (two-pair programming) Review by: bobv, scottb git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@3890 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/build.xml b/dev/core/build.xml index bcc6f13..e5090e6 100755 --- a/dev/core/build.xml +++ b/dev/core/build.xml
@@ -26,6 +26,7 @@ <zipfileset src="${gwt.tools.lib}/apache/tapestry-util-text-4.0.2.jar" /> <zipfileset src="${gwt.tools.lib}/apache/ant-1.6.5.jar" /> <zipfileset src="${gwt.tools.lib}/eclipse/jdt-3.3.1.jar" /> + <zipfileset src="${gwt.tools.lib}/jetty/jetty-6.1.11.jar" /> <zipfileset src="${gwt.tools.lib}/tomcat/ant-launcher-1.6.5.jar" /> <zipfileset src="${gwt.tools.lib}/tomcat/catalina-1.0.jar" /> <zipfileset src="${gwt.tools.lib}/tomcat/catalina-optional-1.0.jar" />
diff --git a/dev/core/src/com/google/gwt/core/ext/Linker.java b/dev/core/src/com/google/gwt/core/ext/Linker.java index 5cce5e6..5dc6ff1 100644 --- a/dev/core/src/com/google/gwt/core/ext/Linker.java +++ b/dev/core/src/com/google/gwt/core/ext/Linker.java
@@ -23,6 +23,19 @@ * the relative ordering of the Linkers. Exact order of Linker execution will be * determined by the order of <code>add-linker</code> tags in the module * configuration. + * + * <p> + * A new instance of a linker is created each time a module is compiled or + * during hosted mode when a module first loads (or is refreshed). During a + * compile, {@link #link(TreeLogger, LinkerContext, ArtifactSet)} will be called + * exactly once, and the artifact set will contain any and all generated + * artifacts. . In hosted mode, + * {@link #link(TreeLogger, LinkerContext, ArtifactSet)} is called initially, + * but with no generated artifacts. If any artifacts are subsequently generated + * during the course of running hosted mode, + * {@link #relink(TreeLogger, LinkerContext, ArtifactSet)} will be called with + * the new artifacts. + * </p> */ public abstract class Linker { /** @@ -42,4 +55,26 @@ */ public abstract ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts) throws UnableToCompleteException; + + /** + * Re-invoke the Linker with newly generated artifacts. Linkers that need to + * reference the original artifact set passed into + * {@link #link(TreeLogger, LinkerContext, ArtifactSet)} should retain a copy + * of the original artifact set in an instance variable. + * + * @param logger the TreeLogger to record to + * @param context provides access to the Linker's environment + * @param newArtifacts an unmodifiable view of the newly generated artifacts + * @return the new artifacts that should be propagated through the linker + * chain; it is not necessary to return any artifacts from the + * original link (or previous calls to relink) that have not been + * modified + * @throws UnableToCompleteException if compilation violates assumptions made + * by the Linker or for errors encountered by the Linker + */ + @SuppressWarnings("unused") + public ArtifactSet relink(TreeLogger logger, LinkerContext context, + ArtifactSet newArtifacts) throws UnableToCompleteException { + return newArtifacts; + } }
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/ArtifactSet.java b/dev/core/src/com/google/gwt/core/ext/linker/ArtifactSet.java index 96435bc..6e865c0 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/ArtifactSet.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/ArtifactSet.java
@@ -177,4 +177,9 @@ public <T> T[] toArray(T[] a) { return treeSet.toArray(a); } + + @Override + public String toString() { + return treeSet.toString(); + } }
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/EmittedArtifact.java b/dev/core/src/com/google/gwt/core/ext/linker/EmittedArtifact.java index 85c4ed2..96bc46b 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/EmittedArtifact.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/EmittedArtifact.java
@@ -27,6 +27,9 @@ * be emitted by the compiler into the module's output directory. This type may * be extended by Linker providers to provide alternative implementations of * {@link #getContents(TreeLogger)}. + * + * TODO(bobv): provide a timestamp so we can make the time on output files match + * that of input files? */ public abstract class EmittedArtifact extends Artifact<EmittedArtifact> {
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java index fd058b6..290de43 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
@@ -58,12 +58,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.SortedSet; -import java.util.Stack; import java.util.TreeSet; /** @@ -107,7 +105,6 @@ private final SortedSet<ConfigurationProperty> configurationProperties; private final JJSOptions jjsOptions; - private final List<Class<? extends Linker>> linkerClasses; private final Map<Class<? extends Linker>, String> linkerShortNames = new HashMap<Class<? extends Linker>, String>(); private final String moduleFunctionName; @@ -117,17 +114,59 @@ private final Map<String, StandardCompilationResult> resultsByStrongName = new HashMap<String, StandardCompilationResult>(); private final SortedSet<SelectionProperty> selectionProperties; + private final Linker[] linkers; + public StandardLinkerContext(TreeLogger logger, ModuleDef module, - JJSOptions jjsOptions) { + JJSOptions jjsOptions) throws UnableToCompleteException { logger = logger.branch(TreeLogger.DEBUG, "Constructing StandardLinkerContext", null); this.jjsOptions = jjsOptions; this.moduleFunctionName = module.getFunctionName(); this.moduleName = module.getName(); - this.linkerClasses = new ArrayList<Class<? extends Linker>>( - module.getActiveLinkers()); - linkerClasses.add(module.getActivePrimaryLinker()); + + // Sort the linkers into the order they should actually run. + List<Class<? extends Linker>> sortedLinkers = new ArrayList<Class<? extends Linker>>(); + + // Get all the pre-linkers first. + for (Class<? extends Linker> linkerClass : module.getActiveLinkers()) { + Order order = linkerClass.getAnnotation(LinkerOrder.class).value(); + assert (order != null); + if (order == Order.PRE) { + sortedLinkers.add(linkerClass); + } + } + + // Get the primary linker. + sortedLinkers.add(module.getActivePrimaryLinker()); + + // Get all the post-linkers IN REVERSE ORDER. + { + List<Class<? extends Linker>> postLinkerClasses = new ArrayList<Class<? extends Linker>>(); + for (Class<? extends Linker> linkerClass : module.getActiveLinkers()) { + Order order = linkerClass.getAnnotation(LinkerOrder.class).value(); + assert (order != null); + if (order == Order.POST) { + postLinkerClasses.add(linkerClass); + } + } + Collections.reverse(postLinkerClasses); + sortedLinkers.addAll(postLinkerClasses); + } + + linkers = new Linker[sortedLinkers.size()]; + int i = 0; + for (Class<? extends Linker> linkerClass : sortedLinkers) { + try { + linkers[i++] = linkerClass.newInstance(); + } catch (InstantiationException e) { + logger.log(TreeLogger.ERROR, "Unable to create Linker", e); + throw new UnableToCompleteException(); + } catch (IllegalAccessException e) { + logger.log(TreeLogger.ERROR, "Unable to create Linker", e); + throw new UnableToCompleteException(); + } + } for (Map.Entry<String, Class<? extends Linker>> entry : module.getLinkers().entrySet()) { linkerShortNames.put(entry.getValue(), entry.getKey()); @@ -262,77 +301,39 @@ /** * Run the linker stack. */ - public ArtifactSet invokeLinkerStack(TreeLogger logger) + public ArtifactSet invokeLink(TreeLogger logger) throws UnableToCompleteException { ArtifactSet workingArtifacts = new ArtifactSet(artifacts); - Stack<Linker> linkerStack = new Stack<Linker>(); - EnumSet<Order> phasePre = EnumSet.of(Order.PRE, Order.PRIMARY); - EnumSet<Order> phasePost = EnumSet.of(Order.POST); - - // Instantiate instances of the Linkers - for (Class<? extends Linker> clazz : linkerClasses) { - Linker linker; - - // Create an instance of the Linker - try { - linker = clazz.newInstance(); - linkerStack.push(linker); - } catch (InstantiationException e) { - logger.log(TreeLogger.ERROR, "Unable to create LinkerContextShim", e); - throw new UnableToCompleteException(); - } catch (IllegalAccessException e) { - logger.log(TreeLogger.ERROR, "Unable to create LinkerContextShim", e); - throw new UnableToCompleteException(); - } - - // Detemine if we need to invoke the Linker in the current link phase - Order order = clazz.getAnnotation(LinkerOrder.class).value(); - if (!phasePre.contains(order)) { - continue; - } - - // The primary Linker is guaranteed to be last in the order - if (order == Order.PRIMARY) { - assert linkerClasses.get(linkerClasses.size() - 1).equals(clazz); - } - + for (Linker linker : linkers) { TreeLogger linkerLogger = logger.branch(TreeLogger.TRACE, "Invoking Linker " + linker.getDescription(), null); - workingArtifacts.freeze(); try { workingArtifacts = linker.link(linkerLogger, this, workingArtifacts); - } catch (Exception e) { + } catch (Throwable e) { linkerLogger.log(TreeLogger.ERROR, "Failed to link", e); throw new UnableToCompleteException(); } } + return workingArtifacts; + } - // Pop the primary linker off of the stack - linkerStack.pop(); + public ArtifactSet invokeRelink(TreeLogger logger, + ArtifactSet newlyGeneratedArtifacts) throws UnableToCompleteException { + ArtifactSet workingArtifacts = new ArtifactSet(newlyGeneratedArtifacts); - // Unwind the stack - while (!linkerStack.isEmpty()) { - Linker linker = linkerStack.pop(); - Class<? extends Linker> linkerType = linker.getClass(); - - // See if the Linker should be run in the current phase - Order order = linkerType.getAnnotation(LinkerOrder.class).value(); - if (phasePost.contains(order)) { - TreeLogger linkerLogger = logger.branch(TreeLogger.TRACE, - "Invoking Linker " + linker.getDescription(), null); - - workingArtifacts.freeze(); - try { - workingArtifacts = linker.link(linkerLogger, this, workingArtifacts); - } catch (Exception e) { - linkerLogger.log(TreeLogger.ERROR, "Failed to link", e); - throw new UnableToCompleteException(); - } + for (Linker linker : linkers) { + TreeLogger linkerLogger = logger.branch(TreeLogger.TRACE, + "Invoking relink on Linker " + linker.getDescription(), null); + workingArtifacts.freeze(); + try { + workingArtifacts = linker.relink(linkerLogger, this, workingArtifacts); + } catch (Throwable e) { + linkerLogger.log(TreeLogger.ERROR, "Failed to relink", e); + throw new UnableToCompleteException(); } } - return workingArtifacts; } @@ -402,11 +403,20 @@ return out.toString(); } + /** + * Writes artifacts into output directories in the standard way. + * + * @param logger logs the operation + * @param artifacts the set of artifacts to write + * @param outputPath the output path for deployable artifacts + * @param extraPath optional extra path for non-deployable artifacts + * @throws UnableToCompleteException + */ public void produceOutputDirectory(TreeLogger logger, ArtifactSet artifacts, - File moduleOutDir, File moduleAuxDir) throws UnableToCompleteException { + File outputPath, File extraPath) throws UnableToCompleteException { - logger = logger.branch(TreeLogger.INFO, "Linking compilation into " - + moduleOutDir.getPath(), null); + logger = logger.branch(TreeLogger.TRACE, "Linking compilation into " + + outputPath.getPath(), null); for (EmittedArtifact artifact : artifacts.find(EmittedArtifact.class)) { TreeLogger artifactLogger = logger.branch(TreeLogger.DEBUG, @@ -414,13 +424,18 @@ File outFile; if (artifact.isPrivate()) { - outFile = new File(getLinkerAuxDir(moduleAuxDir, artifact.getLinker()), - artifact.getPartialPath()); + if (extraPath == null) { + continue; + } + outFile = new File(getExtraPathForLinker(extraPath, + artifact.getLinker()), artifact.getPartialPath()); } else { - outFile = new File(moduleOutDir, artifact.getPartialPath()); + outFile = new File(outputPath, artifact.getPartialPath()); } - assert !outFile.exists() : "Attempted to overwrite " + outFile.getPath(); + // TODO(scottb): figure out how to do a clean. + // assert !outFile.exists() : "Attempted to overwrite " + + // outFile.getPath(); Util.copy(logger, artifact.getContents(artifactLogger), outFile); } } @@ -429,15 +444,11 @@ * Creates a linker-specific subdirectory in the module's auxiliary output * directory. */ - private File getLinkerAuxDir(File moduleAuxDir, + private File getExtraPathForLinker(File extraPath, Class<? extends Linker> linkerType) { - // The auxiliary directory is create lazily - if (!moduleAuxDir.exists()) { - moduleAuxDir.mkdirs(); - } assert linkerShortNames.containsKey(linkerType) : linkerType.getName() + " unknown"; - File toReturn = new File(moduleAuxDir, linkerShortNames.get(linkerType)); + File toReturn = new File(extraPath, linkerShortNames.get(linkerType)); if (!toReturn.exists()) { toReturn.mkdirs(); }
diff --git a/dev/core/src/com/google/gwt/dev/CompileArgProcessor.java b/dev/core/src/com/google/gwt/dev/CompileArgProcessor.java new file mode 100644 index 0000000..d19ae45 --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/CompileArgProcessor.java
@@ -0,0 +1,42 @@ +/* + * 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; + +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.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 ArgHandlerModuleName(options)); + } + + /* + * Overridden to make public. + */ + @Override + public final boolean processArgs(String[] args) { + return super.processArgs(args); + } + + @Override + protected abstract String getName(); +}
diff --git a/dev/core/src/com/google/gwt/dev/CompilePerms.java b/dev/core/src/com/google/gwt/dev/CompilePerms.java index 17b1042..997fb74 100644 --- a/dev/core/src/com/google/gwt/dev/CompilePerms.java +++ b/dev/core/src/com/google/gwt/dev/CompilePerms.java
@@ -116,7 +116,8 @@ return true; } } - static class ArgProcessor extends Link.ArgProcessor { + + static class ArgProcessor extends CompileArgProcessor { public ArgProcessor(CompilePermsOptions options) { super(options); registerHandler(new ArgHandlerPerms(options)); @@ -129,7 +130,7 @@ } /** - * Concrete class to implement all compiler options. + * Concrete class to implement compiler perm options. */ static class CompilePermsOptionsImpl extends CompileTaskOptionsImpl implements CompilePermsOptions {
diff --git a/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java b/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java index b2f0295..9c093c0 100644 --- a/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java +++ b/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java
@@ -24,14 +24,13 @@ */ class CompileTaskOptionsImpl implements CompileTaskOptions { - public static final String GWT_COMPILER_DIR = ".gwt-tmp" + File.separatorChar - + "compiler"; + public static final String GWT_TMP_DIR = "gwt-tmp"; - private File compilerWorkDir; private Type logLevel; private String moduleName; private File outDir; private boolean useGuiLogger; + private File workDir; public CompileTaskOptionsImpl() { } @@ -48,11 +47,7 @@ } public File getCompilerWorkDir() { - if (compilerWorkDir == null) { - compilerWorkDir = new File(getOutDir(), GWT_COMPILER_DIR + File.separator - + moduleName); - } - return compilerWorkDir; + return new File(new File(getWorkDir(), getModuleName()), "compiler"); } public Type getLogLevel() { @@ -87,4 +82,14 @@ this.useGuiLogger = useGuiLogger; } -} \ No newline at end of file + /** + * 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; + } +}
diff --git a/dev/core/src/com/google/gwt/dev/CompilerOptions.java b/dev/core/src/com/google/gwt/dev/CompilerOptions.java index 85b4afc..0b568e4 100644 --- a/dev/core/src/com/google/gwt/dev/CompilerOptions.java +++ b/dev/core/src/com/google/gwt/dev/CompilerOptions.java
@@ -15,13 +15,11 @@ */ package com.google.gwt.dev; -import com.google.gwt.dev.jjs.JJSOptions; -import com.google.gwt.dev.util.arg.OptionGenDir; -import com.google.gwt.dev.util.arg.OptionValidateOnly; +import com.google.gwt.dev.Link.LinkOptions; +import com.google.gwt.dev.Precompile.PrecompileOptions; /** * The complete set of options for the GWT compiler. */ -public interface CompilerOptions extends JJSOptions, CompileTaskOptions, - OptionGenDir, OptionValidateOnly { +public interface CompilerOptions extends PrecompileOptions, LinkOptions { }
diff --git a/dev/core/src/com/google/gwt/dev/CompilerOptionsImpl.java b/dev/core/src/com/google/gwt/dev/CompilerOptionsImpl.java deleted file mode 100644 index dcc29bf..0000000 --- a/dev/core/src/com/google/gwt/dev/CompilerOptionsImpl.java +++ /dev/null
@@ -1,98 +0,0 @@ -/* - * 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; - -import com.google.gwt.core.ext.TreeLogger.Type; -import com.google.gwt.dev.jjs.JJSOptionsImpl; - -import java.io.File; - -/** - * Concrete class to implement all compiler options. - */ -public class CompilerOptionsImpl extends JJSOptionsImpl implements - CompilerOptions { - private File genDir; - private Type logLevel; - private String moduleName; - private File outDir; - private boolean useGuiLogger; - private boolean validateOnly; - - public CompilerOptionsImpl() { - } - - public CompilerOptionsImpl(CompilerOptions other) { - copyFrom(other); - } - - public void copyFrom(CompilerOptions other) { - super.copyFrom(other); - setGenDir(other.getGenDir()); - setLogLevel(other.getLogLevel()); - setOutDir(other.getOutDir()); - setUseGuiLogger(other.isUseGuiLogger()); - setValidateOnly(false); - } - - public File getGenDir() { - return genDir; - } - - public Type getLogLevel() { - return logLevel; - } - - public String getModuleName() { - return moduleName; - } - - public File getOutDir() { - return outDir; - } - - public boolean isUseGuiLogger() { - return useGuiLogger; - } - - public boolean isValidateOnly() { - return validateOnly; - } - - public void setGenDir(File genDir) { - this.genDir = genDir; - } - - public void setLogLevel(Type logLevel) { - this.logLevel = logLevel; - } - - public void setModuleName(String moduleName) { - this.moduleName = moduleName; - } - - public void setOutDir(File outDir) { - this.outDir = outDir; - } - - public void setUseGuiLogger(boolean useGuiLogger) { - this.useGuiLogger = useGuiLogger; - } - - public void setValidateOnly(boolean validateOnly) { - this.validateOnly = validateOnly; - } -} \ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java index 3f89bfd..9e90603 100644 --- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java +++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -19,7 +19,10 @@ 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.Precompile.CompilerOptionsImpl; +import com.google.gwt.dev.Precompile.PrecompileOptionsImpl; +import com.google.gwt.dev.util.arg.ArgHandlerExtraDir; + +import java.io.File; /** * The main executable entry point for the GWT Java to JavaScript compiler. @@ -29,6 +32,7 @@ static final class ArgProcessor extends Precompile.ArgProcessor { public ArgProcessor(CompilerOptions options) { super(options); + registerHandler(new ArgHandlerExtraDir(options)); } @Override @@ -37,6 +41,32 @@ } } + static class GWTCompilerOptionsImpl extends PrecompileOptionsImpl implements + CompilerOptions { + + private File extraDir; + + public GWTCompilerOptionsImpl() { + } + + public GWTCompilerOptionsImpl(CompilerOptions other) { + copyFrom(other); + } + + public void copyFrom(CompilerOptions other) { + super.copyFrom(other); + setExtraDir(other.getExtraDir()); + } + + public File getExtraDir() { + return extraDir; + } + + public void setExtraDir(File extraDir) { + this.extraDir = extraDir; + } + } + public static void main(String[] args) { /* * NOTE: main always exits with a call to System.exit to terminate any @@ -44,7 +74,7 @@ * shutdown AWT related threads, since the contract for their termination is * still implementation-dependent. */ - final CompilerOptions options = new CompilerOptionsImpl(); + final CompilerOptions options = new GWTCompilerOptionsImpl(); if (new ArgProcessor(options).processArgs(args)) { CompileTask task = new CompileTask() { public boolean run(TreeLogger logger) throws UnableToCompleteException { @@ -60,10 +90,10 @@ System.exit(1); } - private final CompilerOptionsImpl options; + private final GWTCompilerOptionsImpl options; public GWTCompiler(CompilerOptions options) { - this.options = new CompilerOptionsImpl(options); + this.options = new GWTCompilerOptionsImpl(options); } public boolean run(TreeLogger logger) throws UnableToCompleteException {
diff --git a/dev/core/src/com/google/gwt/dev/GWTHosted.java b/dev/core/src/com/google/gwt/dev/GWTHosted.java new file mode 100644 index 0000000..c8da35e --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/GWTHosted.java
@@ -0,0 +1,185 @@ +/* + * 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; + +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.cfg.ModuleDef; +import com.google.gwt.dev.cfg.ModuleDefLoader; +import com.google.gwt.dev.shell.GWTShellServletFilter; +import com.google.gwt.dev.shell.ServletContainer; +import com.google.gwt.dev.shell.ShellModuleSpaceHost; +import com.google.gwt.dev.shell.jetty.JettyLauncher; +import com.google.gwt.dev.util.PerfLogger; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; +import com.google.gwt.util.tools.ArgHandlerExtra; +import com.google.gwt.util.tools.ArgHandlerString; + +import java.io.PrintWriter; +import java.util.HashSet; +import java.util.Set; + +/** + * The main executable class for the hosted mode shell. + */ +public class GWTHosted extends GWTShell { + + /** + * Handles the set of modules that can be passed at the end of the command + * line. + */ + 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); + } + + @Override + public String getPurpose() { + return "Specifies the set of modules to host"; + } + + @Override + public String[] getTagArgs() { + return new String[] {"module"}; + } + } + + /** + * Handles a startup url that can be passed on the command line. + */ + protected class ArgHandlerStartupURLs extends ArgHandlerString { + + @Override + public String getPurpose() { + return "Automatically launches the specified URL"; + } + + @Override + public String getTag() { + return "-startupUrl"; + } + + @Override + public String[] getTagArgs() { + return new String[] {"url"}; + } + + @Override + public boolean setString(String arg) { + addStartupURL(arg); + return true; + } + } + + public static void main(String[] args) { + /* + * NOTE: main always exits with a call to System.exit to terminate any + * non-daemon threads that were started in Generators. Typically, this is to + * 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(); + } + System.exit(0); + } + + private Set<ModuleDef> modules = new HashSet<ModuleDef>(); + + private ServletContainer server; + + private GWTShellServletFilter servletFilter; + + public GWTHosted() { + super(false, true); + registerHandler(new ArgHandlerStartupURLs()); + registerHandler(new ArgHandlerModulesExtra()); + } + + public boolean addModule(TreeLogger logger, String moduleName) { + try { + ModuleDef moduleDef = ModuleDefLoader.loadFromClassPath(logger, + moduleName); + modules.add(moduleDef); + return true; + } catch (UnableToCompleteException e) { + System.err.println("Unable to load module '" + moduleName + "'"); + return false; + } + } + + @Override + protected ShellModuleSpaceHost doCreateShellModuleSpaceHost( + TreeLogger logger, TypeOracle typeOracle, ModuleDef moduleDef) { + return new ShellModuleSpaceHost(logger, typeOracle, moduleDef, + options.getGenDir(), options.getShellWorkDir(moduleDef), servletFilter); + } + + @Override + protected void shutDown() { + if (server != null) { + try { + server.stop(); + } catch (UnableToCompleteException e) { + // Already logged. + } + server = null; + } + } + + @Override + protected int startUpServer() { + PerfLogger.start("GWTShell.startup (Jetty launch)"); + JettyLauncher launcher = new JettyLauncher(); + try { + TreeLogger serverLogger = getTopLogger().branch(TreeLogger.INFO, + "Starting HTTP on port " + getPort(), null); + ModuleDef[] moduleArray = modules.toArray(new ModuleDef[modules.size()]); + for (ModuleDef moduleDef : moduleArray) { + String[] servletPaths = moduleDef.getServletPaths(); + if (servletPaths.length > 0) { + serverLogger.log(TreeLogger.WARN, + "Ignoring legacy <servlet> tag(s) in module '" + + moduleDef.getName() + + "'; add servlet tags to your web.xml instead"); + } + } + servletFilter = new GWTShellServletFilter(serverLogger, options, + moduleArray); + server = launcher.start(serverLogger, getPort(), options.getOutDir(), + servletFilter); + } catch (UnableToCompleteException e) { + PerfLogger.end(); + return -1; + } + assert (server != null); + + PerfLogger.end(); + return server.getPort(); + } + +}
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java index 7a56d3d..24ad277 100644 --- a/dev/core/src/com/google/gwt/dev/GWTShell.java +++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -19,7 +19,7 @@ import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.TreeLogger.Type; import com.google.gwt.core.ext.typeinfo.TypeOracle; -import com.google.gwt.dev.Precompile.CompilerOptionsImpl; +import com.google.gwt.dev.GWTCompiler.GWTCompilerOptionsImpl; import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.cfg.ModuleDefLoader; import com.google.gwt.dev.shell.BrowserWidget; @@ -30,10 +30,11 @@ import com.google.gwt.dev.shell.PlatformSpecific; import com.google.gwt.dev.shell.ShellMainWindow; import com.google.gwt.dev.shell.ShellModuleSpaceHost; +import com.google.gwt.dev.shell.WorkDirs; import com.google.gwt.dev.shell.tomcat.EmbeddedTomcatServer; -import com.google.gwt.dev.util.PerfLogger; import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization; import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions; +import com.google.gwt.dev.util.arg.ArgHandlerExtraDir; import com.google.gwt.dev.util.arg.ArgHandlerGenDir; import com.google.gwt.dev.util.arg.ArgHandlerLogLevel; import com.google.gwt.dev.util.arg.ArgHandlerOutDir; @@ -160,9 +161,10 @@ } /** - * Handles the list of startup urls that can be passed on the command line. + * Handles the list of startup urls that can be passed at the end of the + * command line. */ - protected class ArgHandlerStartupURLs extends ArgHandlerExtra { + protected class ArgHandlerStartupURLsExtra extends ArgHandlerExtra { @Override public boolean addExtraArg(String arg) { @@ -212,6 +214,20 @@ } } + /** + * Concrete class to implement all compiler options. + */ + static class ShellOptionsImpl extends GWTCompilerOptionsImpl implements + ShellOptions, WorkDirs { + public File getCompilerOutputDir(ModuleDef moduleDef) { + return new File(getWorkDir(), moduleDef.getDeployTo()); + } + + public File getShellWorkDir(ModuleDef moduleDef) { + return new File(new File(getWorkDir(), moduleDef.getName()), "shell"); + } + } + private class BrowserWidgetHostImpl implements BrowserWidgetHost { public BrowserWidgetHostImpl() { } @@ -244,14 +260,9 @@ ModuleDef moduleDef = loadModule(moduleName, logger); assert (moduleDef != null); - // Create a sandbox for the module. - // - File shellDir = new File(options.getOutDir(), GWT_SHELL_PATH - + File.separator + moduleName); - TypeOracle typeOracle = moduleDef.getTypeOracle(logger); ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(logger, - typeOracle, moduleDef, options.getGenDir(), shellDir); + typeOracle, moduleDef); return host; } finally { Cursor normalCursor = display.getSystemCursor(SWT.CURSOR_ARROW); @@ -291,9 +302,6 @@ } } - public static final String GWT_SHELL_PATH = ".gwt-tmp" + File.separator - + "shell"; - private static Image[] icons; static { @@ -314,7 +322,7 @@ } public static String computeHostRegex(String url) { - // the enture URL up to the first slash not prefixed by a slash or colon. + // the entire URL up to the first slash not prefixed by a slash or colon. String raw = url.split("(?<![:/])/")[0]; // escape the dots and put a begin line specifier on the result return "^" + raw.replaceAll("[.]", "[.]"); @@ -365,6 +373,8 @@ */ protected final Display display = Display.getDefault(); + protected final ShellOptionsImpl options = new ShellOptionsImpl(); + /** * Cheat on the first load's refresh by assuming the module loaded by * {@link com.google.gwt.dev.shell.GWTShellServlet} is still fresh. This @@ -381,8 +391,6 @@ private ShellMainWindow mainWnd; - private final CompilerOptionsImpl options = new CompilerOptionsImpl(); - private int port; private boolean runTomcat = true; @@ -408,17 +416,16 @@ registerHandler(new ArgHandlerLogLevel(options)); registerHandler(new ArgHandlerGenDir(options)); + registerHandler(new ArgHandlerExtraDir(options)); if (!noURLs) { - registerHandler(new ArgHandlerStartupURLs()); + registerHandler(new ArgHandlerStartupURLsExtra()); } registerHandler(new ArgHandlerOutDir(options)); registerHandler(new ArgHandlerScriptStyle(options)); - registerHandler(new ArgHandlerEnableAssertions(options)); - registerHandler(new ArgHandlerDisableAggressiveOptimization(options)); } @@ -433,7 +440,7 @@ } public CompilerOptions getCompilerOptions() { - return new CompilerOptionsImpl(options); + return new GWTCompilerOptionsImpl(options); } public int getPort() { @@ -578,7 +585,7 @@ */ protected void compile(TreeLogger logger, ModuleDef moduleDef) throws UnableToCompleteException { - CompilerOptions newOptions = new CompilerOptionsImpl(options); + CompilerOptions newOptions = new GWTCompilerOptionsImpl(options); newOptions.setModuleName(moduleDef.getName()); new GWTCompiler(newOptions).run(logger); } @@ -595,10 +602,9 @@ * @return ShellModuleSpaceHost instance */ protected ShellModuleSpaceHost doCreateShellModuleSpaceHost( - TreeLogger logger, TypeOracle typeOracle, ModuleDef moduleDef, - File genDir, File shellDir) { - return new ShellModuleSpaceHost(logger, typeOracle, moduleDef, genDir, - shellDir); + TreeLogger logger, TypeOracle typeOracle, ModuleDef moduleDef) { + return new ShellModuleSpaceHost(logger, typeOracle, moduleDef, + options.getGenDir(), options.getShellWorkDir(moduleDef), null); } /** @@ -712,29 +718,30 @@ initializeLogger(); if (runTomcat) { - // Start the HTTP server. - // Use a new thread so that logging that occurs during startup is - // displayed immediately. - // - final int serverPort = getPort(); - - PerfLogger.start("GWTShell.startup (Tomcat launch)"); - String whyFailed = EmbeddedTomcatServer.start(getTopLogger(), serverPort, - options.getOutDir()); - PerfLogger.end(); - - if (whyFailed != null) { - System.err.println(whyFailed); + int resultPort = startUpServer(); + if (resultPort < 0) { return false; } - - // Record what port Tomcat is actually running on. - port = EmbeddedTomcatServer.getPort(); + port = resultPort; } return true; } + protected int startUpServer() { + // TODO(bruce): make tomcat work in terms of the modular launcher + String whyFailed = EmbeddedTomcatServer.start(getTopLogger(), getPort(), + options); + + // TODO(bruce): test that we can remove this old approach in favor of + // a better, logger-based error reporting + if (whyFailed != null) { + System.err.println(whyFailed); + return -1; + } + return EmbeddedTomcatServer.getPort(); + } + private Shell createTrackedBrowserShell() { final Shell shell = new Shell(display); FillLayout fillLayout = new FillLayout();
diff --git a/dev/core/src/com/google/gwt/dev/Link.java b/dev/core/src/com/google/gwt/dev/Link.java index 2bc55cd..d458108 100644 --- a/dev/core/src/com/google/gwt/dev/Link.java +++ b/dev/core/src/com/google/gwt/dev/Link.java
@@ -27,11 +27,8 @@ import com.google.gwt.dev.cfg.ModuleDefLoader; import com.google.gwt.dev.cfg.StaticPropertyOracle; import com.google.gwt.dev.util.Util; -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.util.tools.ToolBase; +import com.google.gwt.dev.util.arg.ArgHandlerExtraDir; +import com.google.gwt.dev.util.arg.OptionExtraDir; import java.io.File; import java.util.HashMap; @@ -42,21 +39,16 @@ * to compile, and a ready-to-compile AST. */ public class Link { + /** + * Options for Link. + */ + public interface LinkOptions extends CompileTaskOptions, OptionExtraDir { + } - static class ArgProcessor extends ToolBase { - public ArgProcessor(CompileTaskOptions options) { - registerHandler(new ArgHandlerLogLevel(options)); - registerHandler(new ArgHandlerTreeLoggerFlag(options)); - registerHandler(new ArgHandlerOutDir(options)); - registerHandler(new ArgHandlerModuleName(options)); - } - - /* - * Overridden to make public. - */ - @Override - public boolean processArgs(String[] args) { - return super.processArgs(args); + static class ArgProcessor extends CompileArgProcessor { + public ArgProcessor(LinkOptions options) { + super(options); + registerHandler(new ArgHandlerExtraDir(options)); } @Override @@ -65,6 +57,35 @@ } } + /** + * Concrete class to implement link options. + */ + static class LinkOptionsImpl extends CompileTaskOptionsImpl implements + LinkOptions { + + private File extraDir; + + public LinkOptionsImpl() { + } + + public LinkOptionsImpl(LinkOptions other) { + copyFrom(other); + } + + public void copyFrom(LinkOptions other) { + super.copyFrom(other); + setExtraDir(other.getExtraDir()); + } + + public File getExtraDir() { + return extraDir; + } + + public void setExtraDir(File extraDir) { + this.extraDir = extraDir; + } + } + public static ArtifactSet link(TreeLogger logger, ModuleDef module, Precompilation precompilation, File[] jsFiles) throws UnableToCompleteException { @@ -80,7 +101,7 @@ * shutdown AWT related threads, since the contract for their termination is * still implementation-dependent. */ - final CompileTaskOptions options = new CompileTaskOptionsImpl(); + final LinkOptions options = new LinkOptionsImpl(); if (new ArgProcessor(options).processArgs(args)) { CompileTask task = new CompileTask() { public boolean run(TreeLogger logger) throws UnableToCompleteException { @@ -110,7 +131,7 @@ } linkerContext.addOrReplaceArtifacts(precompilation.getGeneratedArtifacts()); - return linkerContext.invokeLinkerStack(logger); + return linkerContext.invokeLink(logger); } private static void finishPermuation(TreeLogger logger, Permutation perm, @@ -143,17 +164,17 @@ /** * This is the output directory for private files. */ - private File moduleAuxDir; + private File moduleExtraDir; /** * This is the output directory for public files. */ private File moduleOutDir; - private final CompileTaskOptionsImpl options; + private final LinkOptionsImpl options; - public Link(CompileTaskOptions options) { - this.options = new CompileTaskOptionsImpl(options); + public Link(LinkOptions options) { + this.options = new LinkOptionsImpl(options); } public boolean run(TreeLogger logger) throws UnableToCompleteException { @@ -197,7 +218,7 @@ jsFiles); if (artifacts != null) { linkerContext.produceOutputDirectory(branch, artifacts, moduleOutDir, - moduleAuxDir); + moduleExtraDir); branch.log(TreeLogger.INFO, "Link succeeded"); return true; } @@ -207,9 +228,11 @@ private void init(TreeLogger logger) throws UnableToCompleteException { module = ModuleDefLoader.loadFromClassPath(logger, options.getModuleName()); - moduleOutDir = new File(options.getOutDir(), module.getName()); + moduleOutDir = new File(options.getOutDir(), module.getDeployTo()); Util.recursiveDelete(moduleOutDir, true); - moduleAuxDir = new File(options.getOutDir(), module.getName() + "-aux"); - Util.recursiveDelete(moduleAuxDir, false); + if (options.getExtraDir() != null) { + moduleExtraDir = new File(options.getExtraDir(), module.getDeployTo()); + Util.recursiveDelete(moduleExtraDir, false); + } } }
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java index 8465ac5..0dd403a 100644 --- a/dev/core/src/com/google/gwt/dev/Precompile.java +++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -30,11 +30,11 @@ import com.google.gwt.dev.jdt.RebindOracle; import com.google.gwt.dev.jdt.RebindPermutationOracle; import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd; -import com.google.gwt.dev.jjs.UnifiedAst; import com.google.gwt.dev.jjs.JJSOptions; import com.google.gwt.dev.jjs.JJSOptionsImpl; import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler; import com.google.gwt.dev.jjs.JsOutputOption; +import com.google.gwt.dev.jjs.UnifiedAst; import com.google.gwt.dev.shell.StandardRebindOracle; import com.google.gwt.dev.util.Util; import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization; @@ -42,6 +42,8 @@ import com.google.gwt.dev.util.arg.ArgHandlerGenDir; import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle; import com.google.gwt.dev.util.arg.ArgHandlerValidateOnlyFlag; +import com.google.gwt.dev.util.arg.OptionGenDir; +import com.google.gwt.dev.util.arg.OptionValidateOnly; import java.io.File; import java.util.HashSet; @@ -56,8 +58,15 @@ */ public class Precompile { - static class ArgProcessor extends Link.ArgProcessor { - public ArgProcessor(CompilerOptions options) { + /** + * The set of options for the precompiler. + */ + public interface PrecompileOptions extends JJSOptions, CompileTaskOptions, + OptionGenDir, OptionValidateOnly { + } + + static class ArgProcessor extends CompileArgProcessor { + public ArgProcessor(PrecompileOptions options) { super(options); registerHandler(new ArgHandlerGenDir(options)); registerHandler(new ArgHandlerScriptStyle(options)); @@ -71,32 +80,27 @@ return Precompile.class.getName(); } } - /** - * Concrete class to implement all compiler options. - */ - static class CompilerOptionsImpl extends CompileTaskOptionsImpl implements - CompilerOptions { + static class PrecompileOptionsImpl extends CompileTaskOptionsImpl implements + PrecompileOptions { private File genDir; private final JJSOptionsImpl jjsOptions = new JJSOptionsImpl(); private boolean validateOnly; - public CompilerOptionsImpl() { + public PrecompileOptionsImpl() { } - public CompilerOptionsImpl(CompilerOptions other) { + public PrecompileOptionsImpl(PrecompileOptions other) { copyFrom(other); } - public void copyFrom(CompilerOptions other) { + public void copyFrom(PrecompileOptions other) { super.copyFrom(other); + jjsOptions.copyFrom(other); + setGenDir(other.getGenDir()); setValidateOnly(other.isValidateOnly()); - - setAggressivelyOptimize(other.isAggressivelyOptimize()); - setEnableAssertions(other.isEnableAssertions()); - setOutput(other.getOutput()); } public File getGenDir() { @@ -217,7 +221,7 @@ * shutdown AWT related threads, since the contract for their termination is * still implementation-dependent. */ - final CompilerOptions options = new CompilerOptionsImpl(); + final PrecompileOptions options = new PrecompileOptionsImpl(); if (new ArgProcessor(options).processArgs(args)) { CompileTask task = new CompileTask() { public boolean run(TreeLogger logger) throws UnableToCompleteException { @@ -328,14 +332,12 @@ } } - private File generatorResourcesDir; - private ModuleDef module; - private final CompilerOptionsImpl options; + private final PrecompileOptionsImpl options; - public Precompile(CompilerOptions options) { - this.options = new CompilerOptionsImpl(options); + public Precompile(PrecompileOptions options) { + this.options = new PrecompileOptionsImpl(options); } public boolean run(TreeLogger logger) throws UnableToCompleteException { @@ -344,7 +346,7 @@ TreeLogger branch = logger.branch(TreeLogger.INFO, "Validating compilation " + module.getName()); if (validate(branch, options, module, options.getGenDir(), - generatorResourcesDir)) { + options.getCompilerWorkDir())) { branch.log(TreeLogger.INFO, "Validation succeeded"); return true; } else { @@ -356,7 +358,7 @@ TreeLogger branch = logger.branch(TreeLogger.INFO, "Precompiling module " + module.getName()); Precompilation precompilation = precompile(branch, options, module, - options.getGenDir(), generatorResourcesDir); + options.getGenDir(), options.getCompilerWorkDir()); if (precompilation != null) { Util.writeObjectAsFile(branch, new File(options.getCompilerWorkDir(), PRECOMPILATION_FILENAME), precompilation); @@ -382,10 +384,6 @@ this.module = ModuleDefLoader.loadFromClassPath(logger, options.getModuleName()); - // Place generated resources inside the work dir. - generatorResourcesDir = new File(compilerWorkDir, "generated"); - generatorResourcesDir.mkdirs(); - // TODO: All JDT checks now before even building TypeOracle? module.getCompilationState().compile(logger); }
diff --git a/dev/core/src/com/google/gwt/dev/ShellOptions.java b/dev/core/src/com/google/gwt/dev/ShellOptions.java new file mode 100644 index 0000000..71ea4e8 --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/ShellOptions.java
@@ -0,0 +1,29 @@ +/* + * 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; + +import com.google.gwt.dev.jjs.JJSOptions; +import com.google.gwt.dev.util.arg.OptionExtraDir; +import com.google.gwt.dev.util.arg.OptionGenDir; +import com.google.gwt.dev.util.arg.OptionLogLevel; +import com.google.gwt.dev.util.arg.OptionOutDir; + +/** + * The complete set of options for the GWT compiler. + */ +public interface ShellOptions extends JJSOptions, OptionLogLevel, OptionOutDir, + OptionGenDir, OptionExtraDir { +}
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 3d6efb6..b4e4b1e 100644 --- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java +++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -87,6 +87,8 @@ private CompilationState compilationState; + private String deployTo; + private final List<String> entryPointTypeNames = new ArrayList<String>(); private final Set<File> gwtXmlFiles = new HashSet<File>(); @@ -264,6 +266,17 @@ return compilationState; } + /** + * Returns the desired deployment path within the output directory. The + * returned value will start and end with a <code>'/'</code> character. + */ + public String getDeployTo() { + String result = (deployTo == null) ? ('/' + getName() + '/') : deployTo; + assert result.startsWith("/"); + assert result.endsWith("/"); + return result; + } + public synchronized String[] getEntryPointTypeNames() { final int n = entryPointTypeNames.size(); return entryPointTypeNames.toArray(new String[n]); @@ -368,6 +381,26 @@ } /** + * Set the deployment path for this module. Setting this value to + * <code>null</code> or the empty string will default to the fully-qualified + * module name. + */ + public void setDeployTo(String deployTo) { + if (deployTo != null && deployTo.length() == 0) { + deployTo = null; + } else { + assert deployTo.startsWith("/"); + // Ensure ends with trailing slash. + if (!deployTo.endsWith("/")) { + deployTo += '/'; + } + assert deployTo.endsWith("/"); + } + + this.deployTo = deployTo; + } + + /** * Override the module's apparent name. Setting this value to * <code>null<code> will disable the name override. */
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java index a0c2e94..bd394eb 100644 --- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java +++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
@@ -921,6 +921,7 @@ } protected final String __module_1_rename_to = ""; + protected final String __module_2_deploy_to = ""; private final PropertyAttrCvt bindingPropAttrCvt = new PropertyAttrCvt( BindingProperty.class); @@ -967,11 +968,21 @@ registerAttributeConverter(Class.class, classAttrCvt); } - protected Schema __module_begin(NullableName renameTo) { + protected Schema __module_begin(NullableName renameTo, String deployTo) + throws UnableToCompleteException { + + if (deployTo != null && deployTo.length() > 0) { + // Only absolute paths, although it is okay to have multiple slashes. + if (!deployTo.startsWith("/")) { + logger.log(TreeLogger.ERROR, "deploy-to '" + deployTo + + "' must begin with forward slash (e.g. '/foo')"); + throw new UnableToCompleteException(); + } + } return bodySchema; } - protected void __module_end(NullableName renameTo) { + protected void __module_end(NullableName renameTo, String deployTo) { // Maybe infer source and public. // if (!foundExplicitSourceOrSuperSource) { @@ -986,6 +997,7 @@ // We do this in __module_end so this value is never inherited moduleDef.setNameOverride(renameTo.token); + moduleDef.setDeployTo(deployTo); } /**
diff --git a/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java b/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java index 670af09..8330b81 100644 --- a/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java +++ b/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
@@ -19,7 +19,6 @@ import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.linker.impl.HostedModeLinker; import com.google.gwt.core.ext.linker.impl.StandardLinkerContext; -import com.google.gwt.dev.GWTShell; import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.cfg.ModuleDefLoader; import com.google.gwt.dev.jjs.JJSOptionsImpl; @@ -117,7 +116,7 @@ private int nextRequestId; - private File outDir; + private WorkDirs workDirs; private final Object requestIdLock = new Object(); @@ -427,8 +426,7 @@ if (foundResource == null) { // Look for generated files - File shellDir = new File(getOutputDir(), GWTShell.GWT_SHELL_PATH - + File.separator + moduleName); + File shellDir = getShellWorkDirs().getShellWorkDir(moduleDef); File requestedFile = new File(shellDir, partialPath); if (requestedFile.exists()) { try { @@ -441,11 +439,10 @@ /* * If the user is coming from compiled web-mode, check the linker output - * directory for the real bootstrap file. We'll default to using the - * output directory of the first linker defined in the <set-linker> tab. + * directory for the real bootstrap file. */ if (foundResource == null) { - File moduleDir = new File(getOutputDir(), moduleName); + File moduleDir = getShellWorkDirs().getCompilerOutputDir(moduleDef); File requestedFile = new File(moduleDir, partialPath); if (requestedFile.exists()) { try { @@ -617,21 +614,21 @@ } } - private synchronized File getOutputDir() { - if (outDir == null) { - ServletContext servletContext = getServletContext(); - final String attr = "com.google.gwt.dev.shell.outdir"; - outDir = (File) servletContext.getAttribute(attr); - assert (outDir != null); - } - return outDir; - } - @SuppressWarnings("unchecked") private Map<String, String[]> getParameterMap(HttpServletRequest request) { return request.getParameterMap(); } + private synchronized WorkDirs getShellWorkDirs() { + if (workDirs == null) { + ServletContext servletContext = getServletContext(); + final String attr = "com.google.gwt.dev.shell.workdirs"; + workDirs = (WorkDirs) servletContext.getAttribute(attr); + assert (workDirs != null); + } + return workDirs; + } + private String guessMimeType(String fullPath) { int dot = fullPath.lastIndexOf('.'); if (dot != -1) { @@ -951,7 +948,7 @@ // ServeletContext.getResourceAsStream() // ServletContext context = new HostedModeServletContextProxy( - getServletContext(), moduleDef, getOutputDir()); + getServletContext(), moduleDef, getShellWorkDirs()); ServletConfig config = new HostedModeServletConfigProxy( getServletConfig(), context);
diff --git a/dev/core/src/com/google/gwt/dev/shell/GWTShellServletFilter.java b/dev/core/src/com/google/gwt/dev/shell/GWTShellServletFilter.java new file mode 100644 index 0000000..e8c599e --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/GWTShellServletFilter.java
@@ -0,0 +1,155 @@ +/* + * 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.core.ext.linker.impl.StandardLinkerContext; +import com.google.gwt.dev.ShellOptions; +import com.google.gwt.dev.cfg.ModuleDef; + +import org.apache.commons.collections.map.AbstractReferenceMap; +import org.apache.commons.collections.map.ReferenceIdentityMap; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +/** + * Built-in servlet for convenient access to the public path of a specified + * module. + */ +public class GWTShellServletFilter implements Filter { + + private final Map<String, ModuleDef> autogenScripts = new HashMap<String, ModuleDef>(); + /** + * Maintains a persistent map of linker contexts for each module, for + * incremental re-link with new generated artifacts. + */ + @SuppressWarnings("unchecked") + private final Map<ModuleDef, StandardLinkerContext> linkerContextsByModule = new ReferenceIdentityMap( + AbstractReferenceMap.WEAK, AbstractReferenceMap.HARD, true); + + private TreeLogger logger; + + private final ShellOptions options; + + public GWTShellServletFilter(TreeLogger logger, ShellOptions options, + ModuleDef[] moduleDefs) { + this.logger = logger; + this.options = options; + for (ModuleDef moduleDef : moduleDefs) { + String scriptName = moduleDef.getDeployTo() + moduleDef.getName() + + ".nocache.js"; + autogenScripts.put(scriptName, moduleDef); + } + } + + public void destroy() { + } + + public void doFilter(ServletRequest req, ServletResponse resp, + FilterChain chain) throws IOException, ServletException { + + if (req instanceof HttpServletRequest) { + HttpServletRequest request = (HttpServletRequest) req; + String pathInfo = request.getRequestURI(); + logger.log(TreeLogger.TRACE, "Request for: " + pathInfo); + ModuleDef moduleDef = autogenScripts.get(pathInfo); + if (moduleDef != null) { + /* + * If the '?compiled' request property is specified, don't + * auto-generate. + * + * TODO(scottb): does this even do anything anymore? + * + * TODO(scottb): how do we avoid clobbering a compiled selection script? + */ + if (req.getParameter("compiled") == null) { + try { + // Run the linkers for hosted mode. + hostedModeLink(logger.branch(TreeLogger.TRACE, "Request for '" + + pathInfo + "' maps to script generator for module '" + + moduleDef.getName() + "'"), moduleDef); + } catch (UnableToCompleteException e) { + /* + * The error will have already been logged. Continue, since this + * could actually be a request for a static file that happens to + * have an unfortunately confusing name. + */ + } + } + } + } + + // Do normal handling, knowing that the linkers may have run earlier to + // produce files we are just about to serve. + chain.doFilter(req, resp); + } + + public void init(FilterConfig filterConfig) throws ServletException { + } + + /** + * Called when new generated artifacts are produced. + */ + void relink(TreeLogger logger, ModuleDef moduleDef, ArtifactSet newArtifacts) + throws UnableToCompleteException { + StandardLinkerContext context = linkerContextsByModule.get(moduleDef); + assert context != null; + + ArtifactSet artifacts = context.invokeRelink(logger, newArtifacts); + dumpArtifacts(logger, moduleDef, context, artifacts); + } + + private void dumpArtifacts(TreeLogger logger, ModuleDef moduleDef, + StandardLinkerContext context, ArtifactSet artifacts) + throws UnableToCompleteException { + File outputPath = new File(options.getOutDir(), moduleDef.getDeployTo()); + File extraPath = null; + if (options.getExtraDir() != null) { + extraPath = new File(options.getExtraDir(), moduleDef.getDeployTo()); + } + context.produceOutputDirectory(logger, artifacts, outputPath, extraPath); + } + + private void hostedModeLink(TreeLogger logger, ModuleDef moduleDef) + throws UnableToCompleteException { + String moduleName = moduleDef.getName(); + logger.log(TreeLogger.TRACE, "Running linkers for module " + moduleName); + + // TODO: blow away artifacts from a previous link. + + // Perform the initial link. + StandardLinkerContext context = new StandardLinkerContext(logger, + moduleDef, options); + ArtifactSet artifacts = context.invokeLink(logger); + dumpArtifacts(logger, moduleDef, context, artifacts); + + // Save off a new active link state (which may overwrite an old one). + linkerContextsByModule.put(moduleDef, context); + } +}
diff --git a/dev/core/src/com/google/gwt/dev/shell/HostedModeServletContextProxy.java b/dev/core/src/com/google/gwt/dev/shell/HostedModeServletContextProxy.java index 5270bf1..852bc65 100644 --- a/dev/core/src/com/google/gwt/dev/shell/HostedModeServletContextProxy.java +++ b/dev/core/src/com/google/gwt/dev/shell/HostedModeServletContextProxy.java
@@ -15,7 +15,6 @@ */ package com.google.gwt.dev.shell; -import com.google.gwt.dev.GWTShell; import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.resource.Resource; @@ -43,13 +42,13 @@ * Avoid pinning my moduleDef. */ private final WeakReference<ModuleDef> moduleDefRef; - private final File outDir; + private final WorkDirs workDirs; HostedModeServletContextProxy(ServletContext context, ModuleDef moduleDef, - File outDir) { + WorkDirs workDirs) { this.context = context; this.moduleDefRef = new WeakReference<ModuleDef>(moduleDef); - this.outDir = outDir; + this.workDirs = workDirs; } /** @@ -78,6 +77,10 @@ return context.getContext(arg0); } + public String getContextPath() { + return context.getContextPath(); + } + /** * @param arg0 * @return @@ -179,8 +182,7 @@ } // Otherwise try the path but rooted in the shell's output directory - File shellDir = new File(outDir, GWTShell.GWT_SHELL_PATH + File.separator - + moduleDef.getName()); + File shellDir = workDirs.getShellWorkDir(moduleDef); File requestedFile = new File(shellDir, partialPath); if (requestedFile.exists()) { return requestedFile.toURI().toURL(); @@ -191,7 +193,8 @@ * directory for the file. We'll default to using the output directory of * the first linker defined in the <set-linker> tab. */ - requestedFile = new File(new File(outDir, moduleDef.getName()), partialPath); + File linkDir = workDirs.getCompilerOutputDir(moduleDef); + requestedFile = new File(linkDir, partialPath); if (requestedFile.exists()) { try { return requestedFile.toURI().toURL();
diff --git a/dev/core/src/com/google/gwt/dev/shell/ServletContainer.java b/dev/core/src/com/google/gwt/dev/shell/ServletContainer.java new file mode 100644 index 0000000..732998a --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/ServletContainer.java
@@ -0,0 +1,53 @@ +/* + * 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.UnableToCompleteException; + +/** + * An instance of a servlet container that can be used by the shell. It is + * assumed that this servlet container serves a web app from the root directory + * specified by a call to + * {@link ServletContainerLauncher#setAppRootDir(java.io.File)}. + */ +public interface ServletContainer { + + /** + * Provides the port on which the server is actually running, which can be + * useful when automatic port selection was requested. + */ + int getPort(); + + /** + * Causes the web app to pick up changes made within the app root dir while + * running. This method cannot be called after {@link #stop()} has been + * called. + * + * TODO(bruce): need to determine whether all the important servlet containers + * will let us do this (e.g. ensure they don't lock files we would need to + * update) + * + * @throws UnableToCompleteException + */ + void refresh() throws UnableToCompleteException; + + /** + * Stops the running servlet container. It cannot be restarted after this. + * + * @throws UnableToCompleteException + */ + void stop() throws UnableToCompleteException; +}
diff --git a/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java b/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java new file mode 100644 index 0000000..e3896e2 --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java
@@ -0,0 +1,33 @@ +/* + * 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 java.io.File; + +import javax.servlet.Filter; + +/** + * Defines the service provider interface for launching servlet containers that + * can be used by the shell. + */ +public interface ServletContainerLauncher { + + ServletContainer start(TreeLogger topLogger, int port, File appRootDir, + Filter shellServletFilter) throws UnableToCompleteException; +}
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 39cb165..311c564 100644 --- a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java +++ b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
@@ -21,7 +21,7 @@ import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.cfg.Rules; -import com.google.gwt.dev.jdt.RebindOracle; +import com.google.gwt.dev.shell.StandardRebindOracle.ArtifactAcceptor; import java.io.File; @@ -41,7 +41,9 @@ private final ModuleDef module; - private RebindOracle rebindOracle; + private StandardRebindOracle rebindOracle; + + private final GWTShellServletFilter servletFilter; private final File shellDir; @@ -52,15 +54,14 @@ * @param saveJsni */ public ShellModuleSpaceHost(TreeLogger logger, TypeOracle typeOracle, - ModuleDef module, File genDir, File shellDir) { + ModuleDef module, File genDir, File shellDir, + GWTShellServletFilter servletFilter) { this.logger = logger; this.typeOracle = typeOracle; this.module = module; this.genDir = genDir; - - // Combine the user's output dir with the module name to get the - // module-specific output dir. this.shellDir = shellDir; + this.servletFilter = servletFilter; } public CompilingClassLoader getClassLoader() { @@ -108,10 +109,19 @@ module.getCompilationState(), readySpace); } - public String rebind(TreeLogger rebindLogger, String sourceTypeName) + public String rebind(final TreeLogger rebindLogger, String sourceTypeName) throws UnableToCompleteException { checkForModuleSpace(); - return rebindOracle.rebind(rebindLogger, sourceTypeName); + + ArtifactAcceptor artifactAcceptor = (servletFilter == null) ? null + : new ArtifactAcceptor() { + public void accept(ArtifactSet newlyGeneratedArtifacts) + throws UnableToCompleteException { + servletFilter.relink(rebindLogger, module, newlyGeneratedArtifacts); + } + }; + + return rebindOracle.rebind(rebindLogger, sourceTypeName, artifactAcceptor); } private void checkForModuleSpace() {
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 332f7de..64687f5 100644 --- a/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java +++ b/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
@@ -25,7 +25,6 @@ import com.google.gwt.core.ext.linker.GeneratedResource; import com.google.gwt.core.ext.linker.impl.StandardGeneratedResource; import com.google.gwt.core.ext.typeinfo.JClassType; -import com.google.gwt.core.ext.typeinfo.NotFoundException; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.cfg.PublicOracle; import com.google.gwt.dev.javac.CompilationState; @@ -175,7 +174,7 @@ } } - private final ArtifactSet artifactSet; + private final ArtifactSet allGeneratedArtifacts; private final Set<GeneratedUnitWithFile> committedGeneratedCups = new HashSet<GeneratedUnitWithFile>(); @@ -185,9 +184,11 @@ private final File genDir; - private final Set<String> generatedTypeNames = new HashSet<String>(); + private final File generatorResourcesDir; - private final File outDir; + private ArtifactSet newlyGeneratedArtifacts = new ArtifactSet(); + + private final Set<String> newlyGeneratedTypeNames = new HashSet<String>(); private final Map<OutputStream, PendingResource> pendingResourcesByOutputStream = new IdentityHashMap<OutputStream, PendingResource>(); @@ -203,13 +204,13 @@ */ public StandardGeneratorContext(CompilationState compilationState, PropertyOracle propOracle, PublicOracle publicOracle, File genDir, - File outDir, ArtifactSet artifactSet) { + File generatorResourcesDir, ArtifactSet allGeneratedArtifacts) { this.compilationState = compilationState; this.propOracle = propOracle; this.publicOracle = publicOracle; this.genDir = genDir; - this.outDir = outDir; - this.artifactSet = artifactSet; + this.generatorResourcesDir = generatorResourcesDir; + this.allGeneratedArtifacts = allGeneratedArtifacts; } /** @@ -233,8 +234,8 @@ */ public void commitArtifact(TreeLogger logger, Artifact<?> artifact) throws UnableToCompleteException { - // The artifactSet will be null in hosted mode, since we never run Linkers - artifactSet.replace(artifact); + allGeneratedArtifacts.replace(artifact); + newlyGeneratedArtifacts.add(artifact); } public GeneratedResource commitResource(TreeLogger logger, OutputStream os) @@ -279,9 +280,9 @@ * uncommitted compilation units and to force committed compilation units to * be parsed and added to the type oracle. * - * @return types generated during this object's lifetime + * @return any newly generated artifacts since the last call */ - public final JClassType[] finish(TreeLogger logger) + public final ArtifactSet finish(TreeLogger logger) throws UnableToCompleteException { abortUncommittedResources(logger); @@ -317,21 +318,16 @@ compilationState.compile(logger); } - // Return the generated types. + // Make sure all generated types can be found in TypeOracle. TypeOracle typeOracle = getTypeOracle(); - JClassType[] genTypes = new JClassType[genTypeNames.size()]; - int next = 0; - for (Iterator<String> iter = genTypeNames.iterator(); iter.hasNext();) { - String genTypeName = iter.next(); - try { - genTypes[next++] = typeOracle.getType(genTypeName); - } catch (NotFoundException e) { + for (String genTypeName : genTypeNames) { + if (typeOracle.findType(genTypeName) == null) { String msg = "Unable to find recently-generated type '" + genTypeName; logger.log(TreeLogger.ERROR, msg, null); throw new UnableToCompleteException(); } } - return genTypes; + return newlyGeneratedArtifacts; } finally { // Remind the user if there uncommitted cups. @@ -346,14 +342,11 @@ uncommittedGeneratedCupsByPrintWriter.clear(); committedGeneratedCups.clear(); - generatedTypeNames.clear(); + newlyGeneratedTypeNames.clear(); + newlyGeneratedArtifacts = new ArtifactSet(); } } - public File getOutputDir() { - return outDir; - } - public final PropertyOracle getPropertyOracle() { return propOracle; } @@ -380,7 +373,7 @@ } // Has anybody tried to create this type during this iteration? - if (generatedTypeNames.contains(typeName)) { + if (newlyGeneratedTypeNames.contains(typeName)) { final String msg = "A request to create type '" + typeName + "' was received while the type itself was being created; this might be a generator or configuration bug"; @@ -398,7 +391,7 @@ } GeneratedUnitWithFile gcup = new GeneratedUnitWithFile(qualifiedSourceName); uncommittedGeneratedCupsByPrintWriter.put(gcup.pw, gcup); - generatedTypeNames.add(typeName); + newlyGeneratedTypeNames.add(typeName); return gcup.pw; } @@ -443,7 +436,7 @@ } // See if the file is already committed. - SortedSet<GeneratedResource> resources = artifactSet.find(GeneratedResource.class); + SortedSet<GeneratedResource> resources = allGeneratedArtifacts.find(GeneratedResource.class); for (GeneratedResource resource : resources) { if (partialPath.equals(resource.getPartialPath())) { return null; @@ -462,7 +455,8 @@ } // Record that this file is pending. - PendingResource pendingResource = new PendingResource(outDir, partialPath); + PendingResource pendingResource = new PendingResource( + generatorResourcesDir, partialPath); OutputStream os = pendingResource.getOutputStream(); pendingResourcesByOutputStream.put(os, pendingResource);
diff --git a/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java b/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java index 3cf0c7f..94e7a88 100644 --- a/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java +++ b/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
@@ -41,6 +41,18 @@ public class StandardRebindOracle implements RebindOracle { /** + * A call-back interface to be notified when new types are generated. + * + */ + public interface ArtifactAcceptor { + /** + * Called if new artifacts are generated. + */ + void accept(ArtifactSet newlyGeneratedArtifacts) + throws UnableToCompleteException; + } + + /** * Makes the actual deferred binding decision by examining rules. */ private final class Rebinder { @@ -53,14 +65,17 @@ public Rebinder() { genCtx = new StandardGeneratorContext(compilationState, propOracle, - publicOracle, genDir, outDir, artifactSet); + publicOracle, genDir, generatorResourcesDir, allGeneratedArtifacts); } - public String rebind(TreeLogger logger, String typeName) - throws UnableToCompleteException { + public String rebind(TreeLogger logger, String typeName, + ArtifactAcceptor artifactAcceptor) throws UnableToCompleteException { String result = tryRebind(logger, typeName); - genCtx.finish(logger); + ArtifactSet newlyGeneratedArtifacts = genCtx.finish(logger); + if (!newlyGeneratedArtifacts.isEmpty() && artifactAcceptor != null) { + artifactAcceptor.accept(newlyGeneratedArtifacts); + } if (result == null) { result = typeName; } @@ -125,7 +140,7 @@ } } - private final ArtifactSet artifactSet; + private final ArtifactSet allGeneratedArtifacts; private final Map<String, String> cache = new HashMap<String, String>(); @@ -133,7 +148,7 @@ private final File genDir; - private final File outDir; + private final File generatorResourcesDir; private final PropertyOracle propOracle; @@ -143,25 +158,30 @@ public StandardRebindOracle(CompilationState compilationState, PropertyOracle propOracle, PublicOracle publicOracle, Rules rules, - File genDir, File moduleOutDir, ArtifactSet artifactSet) { + File genDir, File generatorResourcesDir, ArtifactSet allGeneratedArtifacts) { this.compilationState = compilationState; this.propOracle = propOracle; this.publicOracle = publicOracle; this.rules = rules; this.genDir = genDir; - this.outDir = moduleOutDir; - this.artifactSet = artifactSet; + this.generatorResourcesDir = generatorResourcesDir; + this.allGeneratedArtifacts = allGeneratedArtifacts; } public String rebind(TreeLogger logger, String typeName) throws UnableToCompleteException { + return rebind(logger, typeName, null); + } + + public String rebind(TreeLogger logger, String typeName, + ArtifactAcceptor artifactAcceptor) throws UnableToCompleteException { String result = cache.get(typeName); if (result == null) { logger = Messages.TRACE_TOPLEVEL_REBIND.branch(logger, typeName, null); Rebinder rebinder = new Rebinder(); - result = rebinder.rebind(logger, typeName); + result = rebinder.rebind(logger, typeName, artifactAcceptor); cache.put(typeName, result); Messages.TRACE_TOPLEVEL_REBIND_RESULT.log(logger, result, null);
diff --git a/dev/core/src/com/google/gwt/dev/shell/WorkDirs.java b/dev/core/src/com/google/gwt/dev/shell/WorkDirs.java new file mode 100644 index 0000000..fd62396 --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/WorkDirs.java
@@ -0,0 +1,35 @@ +/* + * 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.dev.cfg.ModuleDef; + +import java.io.File; + +/** + * Provides information about work directories. + */ +public interface WorkDirs { + /** + * Gets the compiler output directory for a particular module. + */ + File getCompilerOutputDir(ModuleDef moduleDef); + + /** + * Gets the shell work directory for a particular module. + */ + File getShellWorkDir(ModuleDef moduleDef); +}
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 new file mode 100644 index 0000000..9a6b12b --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
@@ -0,0 +1,256 @@ +/* + * 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.jetty; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.dev.shell.ServletContainer; +import com.google.gwt.dev.shell.ServletContainerLauncher; + +import org.mortbay.jetty.Handler; +import org.mortbay.jetty.Server; +import org.mortbay.jetty.nio.SelectChannelConnector; +import org.mortbay.jetty.servlet.FilterHolder; +import org.mortbay.jetty.webapp.WebAppContext; +import org.mortbay.log.Log; +import org.mortbay.log.Logger; + +import java.io.File; + +import javax.servlet.Filter; + +/** + * A launcher for an embedded Jetty server. + */ +public class JettyLauncher implements ServletContainerLauncher { + + /** + * An adapter for the Jetty logging system to GWT's TreeLogger. This + * implementation class is only public to allow {@link Log} to instantiate it. + * + * The weird static data / default construction setup is a game we play with + * {@link Log}'s static initializer to prevent the initial log message from + * going to stderr. + */ + public static final class JettyTreeLogger implements Logger { + private static Type nextBranchLevel; + private static TreeLogger nextLogger; + + /** + * Returns true if the default constructor can be called. + */ + public static boolean isDefaultConstructionReady() { + return nextLogger != null; + } + + /** + * Call to set initial state for default construction; must be called again + * each time before a default instantiation occurs. + */ + public static void setDefaultConstruction(TreeLogger logger, + Type branchLevel) { + if (logger == null || branchLevel == null) { + throw new NullPointerException(); + } + nextLogger = logger; + nextBranchLevel = branchLevel; + } + + private final Type branchLevel; + private final TreeLogger logger; + + public JettyTreeLogger() { + this(nextLogger, nextBranchLevel); + nextLogger = null; + nextBranchLevel = null; + } + + public JettyTreeLogger(TreeLogger logger, Type branchLevel) { + if (logger == null || branchLevel == null) { + throw new NullPointerException(); + } + this.branchLevel = branchLevel; + this.logger = logger; + } + + public void debug(String msg, Object arg0, Object arg1) { + logger.log(TreeLogger.DEBUG, format(msg, arg0, arg1)); + } + + public void debug(String msg, Throwable th) { + logger.log(TreeLogger.DEBUG, msg, th); + } + + public Logger getLogger(String name) { + return new JettyTreeLogger(logger.branch(branchLevel, name), branchLevel); + } + + public void info(String msg, Object arg0, Object arg1) { + logger.log(TreeLogger.INFO, format(msg, arg0, arg1)); + } + + public boolean isDebugEnabled() { + return logger.isLoggable(TreeLogger.DEBUG); + } + + public void setDebugEnabled(boolean enabled) { + // ignored + } + + public void warn(String msg, Object arg0, Object arg1) { + logger.log(TreeLogger.WARN, format(msg, arg0, arg1)); + } + + public void warn(String msg, Throwable th) { + logger.log(TreeLogger.WARN, msg, th); + } + + /** + * Copied from org.mortbay.log.StdErrLog. + */ + private String format(String msg, Object arg0, Object arg1) { + int i0 = msg.indexOf("{}"); + int i1 = i0 < 0 ? -1 : msg.indexOf("{}", i0 + 2); + + if (arg1 != null && i1 >= 0) { + msg = msg.substring(0, i1) + arg1 + msg.substring(i1 + 2); + } + if (arg0 != null && i0 >= 0) { + msg = msg.substring(0, i0) + arg0 + msg.substring(i0 + 2); + } + return msg; + } + } + + private static class JettyServletContainer implements ServletContainer { + + private final int actualPort; + private final File appRootDir; + private final TreeLogger logger; + private final WebAppContext wac; + + public JettyServletContainer(TreeLogger logger, WebAppContext wac, + int actualPort, File appRootDir) { + this.logger = logger; + this.wac = wac; + this.actualPort = actualPort; + this.appRootDir = appRootDir; + } + + public int getPort() { + return actualPort; + } + + public void refresh() throws UnableToCompleteException { + String msg = "Reloading web app to reflect changes in " + + appRootDir.getAbsolutePath(); + TreeLogger branch = logger.branch(TreeLogger.INFO, msg); + try { + wac.stop(); + } catch (Exception e) { + branch.log(TreeLogger.ERROR, "Unable to stop embedded Jetty server", e); + throw new UnableToCompleteException(); + } + + try { + wac.start(); + } catch (Exception e) { + branch.log(TreeLogger.ERROR, "Unable to stop embedded Jetty server", e); + throw new UnableToCompleteException(); + } + + branch.log(TreeLogger.INFO, "Reload completed successfully"); + } + + public void stop() throws UnableToCompleteException { + TreeLogger branch = logger.branch(TreeLogger.INFO, + "Stopping Jetty server"); + try { + wac.stop(); + } catch (Exception e) { + branch.log(TreeLogger.ERROR, "Unable to stop embedded Jetty server", e); + throw new UnableToCompleteException(); + } + branch.log(TreeLogger.INFO, "Stopped successfully"); + } + } + + @SuppressWarnings("unchecked") + public ServletContainer start(TreeLogger logger, int port, File appRootDir, + Filter shellServletFilter) throws UnableToCompleteException { + checkStartParams(logger, port, appRootDir); + + // The dance we do with Jetty's logging system. + System.setProperty("VERBOSE", "true"); + JettyTreeLogger.setDefaultConstruction(logger, TreeLogger.INFO); + System.setProperty("org.mortbay.log.class", JettyTreeLogger.class.getName()); + // Force initialization. + Log.isDebugEnabled(); + if (JettyTreeLogger.isDefaultConstructionReady()) { + // The log system was already initialized and did not use our + // newly-constructed logger, set it explicitly now. + Log.setLog(new JettyTreeLogger()); + } + + Server server = new Server(); + SelectChannelConnector connector = new SelectChannelConnector(); + connector.setPort(port); + connector.setHost("127.0.0.1"); + server.addConnector(connector); + + // Create a new web app in the war directory. + WebAppContext wac = new WebAppContext(appRootDir.getAbsolutePath(), "/"); + + // Prevent file locking on windows; pick up file changes. + wac.getInitParams().put( + "org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false"); + + // Setup the shell servlet filter to generate nocache.js files (and run + // the hosted mode linker stack. + FilterHolder filterHolder = new FilterHolder(); + filterHolder.setFilter(shellServletFilter); + wac.addFilter(filterHolder, "/*", Handler.ALL); + + server.setHandler(wac); + server.setStopAtShutdown(true); + + 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(); + } + } + + private void checkStartParams(TreeLogger logger, int port, File appRootDir) { + if (logger == null) { + throw new NullPointerException("logger cannot be null"); + } + + if (port < 0 || port > 65535) { + throw new IllegalArgumentException( + "port must be either 0 (for auto) or less than 65536"); + } + + if (appRootDir == null) { + throw new NullPointerException("app root direcotry cannot be null"); + } + } + +}
diff --git a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java index 0ebbe02..1fc2d9b 100644 --- a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java +++ b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
@@ -21,6 +21,7 @@ import com.google.gwt.dev.resource.impl.PathPrefix; import com.google.gwt.dev.resource.impl.PathPrefixSet; import com.google.gwt.dev.resource.impl.ResourceOracleImpl; +import com.google.gwt.dev.shell.WorkDirs; import com.google.gwt.util.tools.Utility; import org.apache.catalina.Connector; @@ -60,13 +61,13 @@ } public static synchronized String start(TreeLogger topLogger, int port, - File outDir) { + WorkDirs workDirs) { if (sTomcat != null) { throw new IllegalStateException("Embedded Tomcat is already running"); } try { - new EmbeddedTomcatServer(topLogger, port, outDir); + new EmbeddedTomcatServer(topLogger, port, workDirs); return null; } catch (LifecycleException e) { String msg = e.getMessage(); @@ -145,7 +146,7 @@ private final TreeLogger startupBranchLogger; private EmbeddedTomcatServer(final TreeLogger topLogger, int listeningPort, - final File outDir) throws LifecycleException { + final WorkDirs workDirs) throws LifecycleException { if (topLogger == null) { throw new NullPointerException("No logger specified"); } @@ -222,7 +223,7 @@ if (StandardHost.PRE_INSTALL_EVENT.equals(event.getType())) { StandardContext webapp = (StandardContext) event.getData(); publishShellLoggerAttribute(logger, topLogger, webapp); - publishShellOutDirAttribute(logger, outDir, webapp); + publishShellWorkDirsAttribute(logger, workDirs, webapp); } } }); @@ -411,12 +412,12 @@ } /** - * Publish the shell's output dir as an attribute. This attribute is used to + * Publish the shell's work dir as an attribute. This attribute is used to * find it out of the thin air within the shell servlet. */ - private void publishShellOutDirAttribute(TreeLogger logger, - File outDirToPublish, StandardContext webapp) { - final String attr = "com.google.gwt.dev.shell.outdir"; - publishAttributeToWebApp(logger, webapp, attr, outDirToPublish); + private void publishShellWorkDirsAttribute(TreeLogger logger, + WorkDirs workDirs, StandardContext webapp) { + final String attr = "com.google.gwt.dev.shell.workdirs"; + publishAttributeToWebApp(logger, webapp, attr, workDirs); } }
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerExtraDir.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerExtraDir.java new file mode 100644 index 0000000..42626cf --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerExtraDir.java
@@ -0,0 +1,45 @@ +/* + * 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 com.google.gwt.util.tools.ArgHandlerDir; + +import java.io.File; + +/** + * Argument handler for processing the extra directory option. + */ +public final class ArgHandlerExtraDir extends ArgHandlerDir { + + private final OptionExtraDir option; + + public ArgHandlerExtraDir(OptionExtraDir option) { + this.option = option; + } + + public String getPurpose() { + return "The directory into which extra, non-deployed files will be written"; + } + + public String getTag() { + return "-extra"; + } + + @Override + public void setDir(File dir) { + option.setExtraDir(dir); + } +} \ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionExtraDir.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionExtraDir.java new file mode 100644 index 0000000..586f41f --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionExtraDir.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 output directory for extra artifacts. + */ +public interface OptionExtraDir { + + /** + * Returns the extra resource directory. + */ + File getExtraDir(); + + /** + * Sets the extra resource directory. + */ + void setExtraDir(File dir); +}
diff --git a/eclipse/dev/linux/.classpath b/eclipse/dev/linux/.classpath index 3cc771f..4b09998 100644 --- a/eclipse/dev/linux/.classpath +++ b/eclipse/dev/linux/.classpath
@@ -9,6 +9,7 @@ <classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar" sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.3.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/jetty/jetty-6.1.11.jar" sourcepath="/GWT_TOOLS/lib/jetty/jetty-6.1.11-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar" sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/ant-launcher-1.6.5.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-1.0.jar"/>
diff --git a/eclipse/dev/mac/.classpath b/eclipse/dev/mac/.classpath index f9ad860..3832d9a 100644 --- a/eclipse/dev/mac/.classpath +++ b/eclipse/dev/mac/.classpath
@@ -9,6 +9,7 @@ <classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar" sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.3.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/jetty/jetty-6.1.11.jar" sourcepath="/GWT_TOOLS/lib/jetty/jetty-6.1.11-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar" sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/ant-launcher-1.6.5.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-1.0.jar"/>
diff --git a/eclipse/dev/windows/.classpath b/eclipse/dev/windows/.classpath index ff4799f..70fc175 100644 --- a/eclipse/dev/windows/.classpath +++ b/eclipse/dev/windows/.classpath
@@ -9,6 +9,7 @@ <classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar" sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.3.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/jetty/jetty-6.1.11.jar" sourcepath="/GWT_TOOLS/lib/jetty/jetty-6.1.11-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar" sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/ant-launcher-1.6.5.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-1.0.jar"/>
diff --git a/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java b/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java index e5e9747..7e11b43 100644 --- a/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java +++ b/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java
@@ -119,12 +119,13 @@ if (serializationPolicy == null) { // Failed to get the requested serialization policy; use the default - getServletContext().log( + log( "WARNING: Failed to get the SerializationPolicy '" + strongName + "' for module '" + moduleBaseURL - + "'; a legacy, 1.3.3 compatible, serialization policy will be used. You may experience SerializationExceptions as a result."); + + "'; a legacy, 1.3.3 compatible, serialization policy will be used. You may experience SerializationExceptions as a result.", + null); serializationPolicy = RPC.getDefaultSerializationPolicy(); } @@ -164,7 +165,7 @@ return RPC.invokeAndEncodeResponse(this, rpcRequest.getMethod(), rpcRequest.getParameters(), rpcRequest.getSerializationPolicy()); } catch (IncompatibleRemoteServiceException ex) { - getServletContext().log( + log( "An IncompatibleRemoteServiceException was thrown while processing this call.", ex); return RPC.encodeResponseForFailure(null, ex); @@ -197,7 +198,7 @@ modulePath = new URL(moduleBaseURL).getPath(); } catch (MalformedURLException ex) { // log the information, we will default - getServletContext().log("Malformed moduleBaseURL: " + moduleBaseURL, ex); + log("Malformed moduleBaseURL: " + moduleBaseURL, ex); } } @@ -214,7 +215,7 @@ + ", is not in the same web application as this servlet, " + contextPath + ". Your module may not be properly configured or your client and server code maybe out of date."; - getServletContext().log(message); + log(message, null); } else { // Strip off the context path from the module base URL. It should be a // strict prefix. @@ -232,19 +233,17 @@ serializationPolicy = SerializationPolicyLoader.loadFromStream(is, null); } catch (ParseException e) { - getServletContext().log( - "ERROR: Failed to parse the policy file '" - + serializationPolicyFilePath + "'", e); + log("ERROR: Failed to parse the policy file '" + + serializationPolicyFilePath + "'", e); } catch (IOException e) { - getServletContext().log( - "ERROR: Could not read the policy file '" - + serializationPolicyFilePath + "'", e); + log("ERROR: Could not read the policy file '" + + serializationPolicyFilePath + "'", e); } } else { String message = "ERROR: The serialization policy file '" + serializationPolicyFilePath + "' was not found; did you forget to include it in this deployment?"; - getServletContext().log(message); + log(message, null); } } finally { if (is != null) { @@ -324,7 +323,7 @@ * Override this method in order to control the parsing of the incoming * request. For example, you may want to bypass the check of the Content-Type * and character encoding headers in the request, as some proxies re-write the - * request headers. Note that bypassing these checks may expose the servlet to + * request headers. Note that bypassing these checks may expose the servlet to * some cross-site vulnerabilities. * * @param request the incoming request