Merging from releases/1.6@3878:3944
svn merge -r3878:3944 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3945 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 bb2a27d..26353b1 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
@@ -59,12 +59,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;
/**
@@ -114,7 +112,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;
@@ -124,17 +121,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());
@@ -271,77 +310,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;
}
@@ -414,11 +415,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,
@@ -426,14 +436,19 @@
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();
- Util.copy(logger, artifact.getContents(artifactLogger), outFile);
+ // TODO(scottb): figure out how to do a clean.
+ // assert !outFile.exists() : "Attempted to overwrite " +
+ // outFile.getPath();
+ Util.copy(artifactLogger, artifact.getContents(artifactLogger), outFile);
}
}
@@ -441,15 +456,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 6ead2f6..12faf69 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..f81cb76
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/GWTHosted.java
@@ -0,0 +1,188 @@
+/*
+ * 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.linker.ArtifactSet;
+import com.google.gwt.dev.cfg.ModuleDef;
+import com.google.gwt.dev.cfg.ModuleDefLoader;
+import com.google.gwt.dev.shell.ArtifactAcceptor;
+import com.google.gwt.dev.shell.GWTShellServletFilter;
+import com.google.gwt.dev.shell.ServletContainer;
+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 ArtifactAcceptor doCreateArtifactAcceptor(final ModuleDef module) {
+ return new ArtifactAcceptor() {
+ public void accept(TreeLogger logger, ArtifactSet newlyGeneratedArtifacts)
+ throws UnableToCompleteException {
+ servletFilter.relink(logger, module, newlyGeneratedArtifacts);
+ }
+ };
+ }
+
+ @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..2da8519 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -18,10 +18,13 @@
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.core.ext.linker.ArtifactSet;
+import com.google.gwt.core.ext.linker.EmittedArtifact;
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.ArtifactAcceptor;
import com.google.gwt.dev.shell.BrowserWidget;
import com.google.gwt.dev.shell.BrowserWidgetHost;
import com.google.gwt.dev.shell.BrowserWidgetHostChecker;
@@ -30,10 +33,12 @@
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.Util;
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 +165,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 +218,35 @@
}
}
+ /**
+ * Concrete class to implement all compiler options.
+ */
+ static class ShellOptionsImpl extends GWTCompilerOptionsImpl implements
+ ShellOptions, WorkDirs {
+ public File getCompilerOutputDir(ModuleDef moduleDef) {
+ return new File(getOutDir(), moduleDef.getDeployTo());
+ }
+
+ public File getShellPublicGenDir(ModuleDef moduleDef) {
+ return new File(getShellBaseWorkDir(moduleDef), "public");
+ }
+
+ /**
+ * The base shell work directory.
+ */
+ protected File getShellBaseWorkDir(ModuleDef moduleDef) {
+ return new File(new File(getWorkDir(), moduleDef.getName()), "shell");
+ }
+
+ /**
+ * Where generated files go by default until we are sure they are public;
+ * then they are copied into {@link #getShellPublicGenDir(ModuleDef)}.
+ */
+ protected File getShellPrivateGenDir(ModuleDef moduleDef) {
+ return new File(getShellBaseWorkDir(moduleDef), "gen");
+ }
+ }
+
private class BrowserWidgetHostImpl implements BrowserWidgetHost {
public BrowserWidgetHostImpl() {
}
@@ -244,14 +279,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 +321,6 @@
}
}
- public static final String GWT_SHELL_PATH = ".gwt-tmp" + File.separator
- + "shell";
-
private static Image[] icons;
static {
@@ -314,7 +341,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 +392,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 +410,6 @@
private ShellMainWindow mainWnd;
- private final CompilerOptionsImpl options = new CompilerOptionsImpl();
-
private int port;
private boolean runTomcat = true;
@@ -408,17 +435,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 +459,7 @@
}
public CompilerOptions getCompilerOptions() {
- return new CompilerOptionsImpl(options);
+ return new GWTCompilerOptionsImpl(options);
}
public int getPort() {
@@ -578,11 +604,31 @@
*/
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);
}
+ protected ArtifactAcceptor doCreateArtifactAcceptor(final ModuleDef module) {
+ return new ArtifactAcceptor() {
+ public void accept(TreeLogger logger, ArtifactSet artifacts)
+ throws UnableToCompleteException {
+
+ /*
+ * Copied from StandardLinkerContext.produceOutputDirectory() for legacy
+ * GWTShellServlet support.
+ */
+ for (EmittedArtifact artifact : artifacts.find(EmittedArtifact.class)) {
+ if (!artifact.isPrivate()) {
+ File outFile = new File(options.getShellPublicGenDir(module),
+ artifact.getPartialPath());
+ Util.copy(logger, artifact.getContents(logger), outFile);
+ }
+ }
+ }
+ };
+ }
+
/**
* Creates an instance of ShellModuleSpaceHost (or a derived class) using the
* specified constituent parts. This method is made to be overridden for
@@ -595,10 +641,12 @@
* @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) {
+ // Clear out the shell temp directory.
+ Util.recursiveDelete(options.getShellBaseWorkDir(moduleDef), true);
+ return new ShellModuleSpaceHost(logger, typeOracle, moduleDef,
+ options.getGenDir(), options.getShellPrivateGenDir(moduleDef),
+ doCreateArtifactAcceptor(moduleDef));
}
/**
@@ -712,29 +760,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 de667a7..627ef1e 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -43,6 +43,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;
@@ -57,8 +59,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));
@@ -72,32 +81,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() {
@@ -218,7 +222,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 {
@@ -331,14 +335,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 {
@@ -347,7 +349,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 {
@@ -359,7 +361,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);
@@ -385,10 +387,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 ebde69d..5f1287b 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/ArtifactAcceptor.java b/dev/core/src/com/google/gwt/dev/shell/ArtifactAcceptor.java
new file mode 100644
index 0000000..dfff75b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/ArtifactAcceptor.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * A callback interface to be notified when new resources are generated.
+ *
+ */
+public interface ArtifactAcceptor {
+ /**
+ * Called whenever new artifacts are generated.
+ */
+ void accept(TreeLogger logger, ArtifactSet newlyGeneratedArtifacts)
+ throws UnableToCompleteException;
+}
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..27ada88 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();
@@ -426,9 +425,8 @@
}
if (foundResource == null) {
- // Look for generated files
- File shellDir = new File(getOutputDir(), GWTShell.GWT_SHELL_PATH
- + File.separator + moduleName);
+ // Look for public generated files
+ File shellDir = getShellWorkDirs().getShellPublicGenDir(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..4b5c6a6
--- /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.
+ */
+ public 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/HostedModeServletConfigProxy.java b/dev/core/src/com/google/gwt/dev/shell/HostedModeServletConfigProxy.java
index 147ce16..f5b0378 100644
--- a/dev/core/src/com/google/gwt/dev/shell/HostedModeServletConfigProxy.java
+++ b/dev/core/src/com/google/gwt/dev/shell/HostedModeServletConfigProxy.java
@@ -47,6 +47,7 @@
* @return
* @see javax.servlet.ServletConfig#getInitParameterNames()
*/
+ @SuppressWarnings("unchecked")
public Enumeration<String> getInitParameterNames() {
return config.getInitParameterNames();
}
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..b68f90a 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;
}
/**
@@ -65,6 +64,7 @@
* @return
* @see javax.servlet.ServletContext#getAttributeNames()
*/
+ @SuppressWarnings("unchecked")
public Enumeration<String> getAttributeNames() {
return context.getAttributeNames();
}
@@ -78,6 +78,10 @@
return context.getContext(arg0);
}
+ public String getContextPath() {
+ return context.getContextPath();
+ }
+
/**
* @param arg0
* @return
@@ -178,9 +182,8 @@
return publicResource.getURL();
}
- // 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());
+ // Otherwise try the path in the shell's public generated directory
+ File shellDir = workDirs.getShellPublicGenDir(moduleDef);
File requestedFile = new File(shellDir, partialPath);
if (requestedFile.exists()) {
return requestedFile.toURI().toURL();
@@ -191,7 +194,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();
@@ -230,6 +234,7 @@
* @return
* @see javax.servlet.ServletContext#getResourcePaths(java.lang.String)
*/
+ @SuppressWarnings("unchecked")
public Set<String> getResourcePaths(String path) {
return context.getResourcePaths(path);
}
@@ -268,6 +273,7 @@
* @see javax.servlet.ServletContext#getServletNames()
*/
@Deprecated
+ @SuppressWarnings("unchecked")
public Enumeration<String> getServletNames() {
return context.getServletNames();
}
@@ -278,6 +284,7 @@
* @see javax.servlet.ServletContext#getServlets()
*/
@Deprecated
+ @SuppressWarnings("unchecked")
public Enumeration<Servlet> getServlets() {
return context.getServlets();
}
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..38f106f 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,6 @@
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 java.io.File;
@@ -35,13 +34,15 @@
protected final TypeOracle typeOracle;
+ private final ArtifactAcceptor artifactAcceptor;
+
private CompilingClassLoader classLoader;
private final TreeLogger logger;
private final ModuleDef module;
- private RebindOracle rebindOracle;
+ private StandardRebindOracle rebindOracle;
private final File shellDir;
@@ -52,15 +53,14 @@
* @param saveJsni
*/
public ShellModuleSpaceHost(TreeLogger logger, TypeOracle typeOracle,
- ModuleDef module, File genDir, File shellDir) {
+ ModuleDef module, File genDir, File shellDir,
+ ArtifactAcceptor artifactAcceptor) {
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.artifactAcceptor = artifactAcceptor;
}
public CompilingClassLoader getClassLoader() {
@@ -108,10 +108,15 @@
module.getCompilationState(), readySpace);
}
- public String rebind(TreeLogger rebindLogger, String sourceTypeName)
+ public String rebind(TreeLogger logger, String sourceTypeName)
throws UnableToCompleteException {
checkForModuleSpace();
- return rebindOracle.rebind(rebindLogger, sourceTypeName);
+ return rebindOracle.rebind(logger, sourceTypeName, new ArtifactAcceptor() {
+ public void accept(TreeLogger logger, ArtifactSet newlyGeneratedArtifacts)
+ throws UnableToCompleteException {
+ artifactAcceptor.accept(logger, newlyGeneratedArtifacts);
+ }
+ });
}
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..3d27016 100644
--- a/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
+++ b/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
@@ -53,14 +53,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(logger, newlyGeneratedArtifacts);
+ }
if (result == null) {
result = typeName;
}
@@ -125,7 +128,7 @@
}
}
- private final ArtifactSet artifactSet;
+ private final ArtifactSet allGeneratedArtifacts;
private final Map<String, String> cache = new HashMap<String, String>();
@@ -133,7 +136,7 @@
private final File genDir;
- private final File outDir;
+ private final File generatorResourcesDir;
private final PropertyOracle propOracle;
@@ -143,25 +146,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..9e327b0
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/WorkDirs.java
@@ -0,0 +1,36 @@
+/*
+ * 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 public generated files for a particular
+ * module.
+ */
+ File getShellPublicGenDir(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/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleGenericsSupportTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleGenericsSupportTest.java
deleted file mode 100644
index e69de29..0000000
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleGenericsSupportTest.java
+++ /dev/null
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/client/FooClient.java b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/client/FooClient.java
index e69de29..9b02688 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/client/FooClient.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/client/FooClient.java
@@ -0,0 +1,5 @@
+package com.google.gwt.dev.resource.impl.testdata.cpe1.org.example.foo.client;
+
+public class FooClient {
+ // test class
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/server/FooServer.java b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/server/FooServer.java
index e69de29..6f2c68c 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/server/FooServer.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/server/FooServer.java
@@ -0,0 +1,5 @@
+package com.google.gwt.dev.resource.impl.testdata.cpe1.org.example.foo.server;
+
+public class FooServer {
+ // test class
+}
\ No newline at end of file
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/eclipse/samples/DynaTable2/DynaTable2 compile.launch b/eclipse/samples/DynaTable2/DynaTable2 compile.launch
index 9d1d153..ff78aaf 100644
--- a/eclipse/samples/DynaTable2/DynaTable2 compile.launch
+++ b/eclipse/samples/DynaTable2/DynaTable2 compile.launch
@@ -17,7 +17,7 @@
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.GWTCompiler"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-wardir war -style PRETTY -logLevel INFO com.google.gwt.sample.dynatable.DynaTable"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out war -style PRETTY -logLevel INFO -extra extra com.google.gwt.sample.dynatable.DynaTable2"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="DynaTable2"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
</launchConfiguration>
diff --git a/eclipse/samples/DynaTable2/DynaTable2 shell.launch b/eclipse/samples/DynaTable2/DynaTable2 hosted.launch
similarity index 91%
rename from eclipse/samples/DynaTable2/DynaTable2 shell.launch
rename to eclipse/samples/DynaTable2/DynaTable2 hosted.launch
index cca8023..e25b728 100644
--- a/eclipse/samples/DynaTable2/DynaTable2 shell.launch
+++ b/eclipse/samples/DynaTable2/DynaTable2 hosted.launch
@@ -16,8 +16,8 @@
<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="DynaTable2"/> </runtimeClasspathEntry> "/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.GWTShell"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-wardir war -style PRETTY -logLevel INFO DynaTable.html"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.GWTHosted"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out war -style PRETTY -logLevel INFO -extra extra -startupUrl DynaTable2.html com.google.gwt.sample.dynatable.DynaTable2"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="DynaTable2"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
</launchConfiguration>
diff --git a/eclipse/samples/DynaTable2/DynaTable2 server.launch b/eclipse/samples/DynaTable2/DynaTable2 server.launch
index 4029b62..c2f361d 100644
--- a/eclipse/samples/DynaTable2/DynaTable2 server.launch
+++ b/eclipse/samples/DynaTable2/DynaTable2 server.launch
@@ -9,7 +9,7 @@
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="DynaTable2" path="1" type="4"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/DynaTable2/jetty-6.1.11.jar" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="GWT_TOOLS/lib/jetty/jetty-6.1.11.jar" path="3" type="3"/> "/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.mortbay.jetty.Main"/>
diff --git a/eclipse/samples/DynaTable2/build.xml b/eclipse/samples/DynaTable2/build.xml
index d810bd9..c003fe4 100644
--- a/eclipse/samples/DynaTable2/build.xml
+++ b/eclipse/samples/DynaTable2/build.xml
@@ -1,11 +1,12 @@
<project name="dynatable2" default="build" basedir=".">
<property name="gwt.install" location="../../../build/lib" />
- <property name="wardir" location="war" />
+ <property name="outdir" location="war" />
+ <property name="extradir" location="extra" />
<target name="javac" description="Compile project to WEB-INF/classes">
- <mkdir dir="${wardir}/WEB-INF/classes" />
+ <mkdir dir="${outdir}/WEB-INF/classes" />
<javac srcdir="../../../samples/dynatable/src"
- destdir="${wardir}/WEB-INF/classes"
+ destdir="${outdir}/WEB-INF/classes"
debug="true"
debuglevel="lines,vars,source"
source="1.5"
@@ -20,19 +21,21 @@
</target>
<target name="deploy" description="Copy output to the war folder">
- <mkdir dir="${wardir}/WEB-INF/lib" />
- <copy todir="${wardir}/WEB-INF/lib" file="${gwt.install}/gwt-servlet.jar" />
+ <mkdir dir="${outdir}/WEB-INF/lib" />
+ <copy todir="${outdir}/WEB-INF/lib" file="${gwt.install}/gwt-servlet.jar" />
</target>
<target name="gwtc" depends="javac" description="Compile to JavaScript">
<java classname="com.google.gwt.dev.GWTCompiler" fork="yes" failonerror="true">
<jvmarg value="-Xmx256M"/>
- <arg value="-wardir" />
- <arg file="war" />
- <arg value="com.google.gwt.sample.dynatable.DynaTable" />
+ <arg value="-out" />
+ <arg file="${outdir}" />
+ <arg value="-extra" />
+ <arg file="${extradir}" />
+ <arg value="com.google.gwt.sample.dynatable.DynaTable2" />
<classpath>
<pathelement location="../../../samples/dynatable/src" />
- <pathelement location="${wardir}/WEB-INF/classes" />
+ <pathelement location="${outdir}/WEB-INF/classes" />
<pathelement location="${gwt.install}/gwt-user.jar" />
<pathelement location="${gwt.install}/gwt-dev-windows.jar" />
</classpath>
@@ -40,11 +43,11 @@
</target>
<target name="server" depends="deploy" description="Run the deployed app in a Jetty server">
- <echo message="PLEASE BROWSE TO: http://localhost:8888/DynaTable.html"/>
+ <echo message="PLEASE BROWSE TO: http://localhost:8888/DynaTable2.html"/>
<java classname="org.mortbay.jetty.Main" fork="yes">
<arg value="8888" />
<arg value="-webapp" />
- <arg file="war" />
+ <arg file="${outdir}" />
<classpath>
<pathelement location="${gwt.install}/gwt-dev-windows.jar" />
</classpath>
@@ -55,12 +58,14 @@
<java classname="com.google.gwt.dev.GWTShell" fork="yes" failonerror="true">
<jvmarg value="-Xmx256M"/>
<jvmarg value="-Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
- <arg value="-wardir" />
- <arg file="war" />
- <arg value="http://localhost:8888/DynaTable.html" />
+ <arg value="-out" />
+ <arg file="${outdir}" />
+ <arg value="-extra" />
+ <arg file="${extradir}" />
+ <arg value="http://localhost:8888/DynaTable2.html" />
<classpath>
<pathelement location="../../../samples/dynatable/src" />
- <pathelement location="${wardir}/WEB-INF/classes" />
+ <pathelement location="${outdir}/WEB-INF/classes" />
<pathelement location="${gwt.install}/gwt-user.jar" />
<pathelement location="${gwt.install}/gwt-dev-windows.jar" />
</classpath>
@@ -70,13 +75,8 @@
<target name="build" depends="javac, gwtc, deploy" description="Build this project" />
<target name="clean" description="Cleans this project's intermediate and output files">
- <delete includeemptydirs="true" failonerror="false">
- <fileset dir="${wardir}" includes="*" excludes="DynaTable.html"/>
- </delete>
- <delete dir="${wardir}/WEB-INF/classes" failonerror="false" />
- <delete dir="${wardir}/WEB-INF/lib" failonerror="false" />
- <delete dir="${wardir}/WEB-INF/gwt-aux" failonerror="false" />
- <delete dir="${wardir}/WEB-INF/.gwt-tmp" failonerror="false" />
- <delete dir="www" failonerror="false" />
+ <delete dir="${outdir}/WEB-INF/classes" failonerror="false" />
+ <delete dir="${outdir}/gwtc" failonerror="false" />
+ <delete dir="${extradir}" failonerror="false" />
</target>
</project>
diff --git a/eclipse/samples/DynaTable2/war/DynaTable2.css b/eclipse/samples/DynaTable2/war/DynaTable2.css
new file mode 100644
index 0000000..ab81abf
--- /dev/null
+++ b/eclipse/samples/DynaTable2/war/DynaTable2.css
@@ -0,0 +1,85 @@
+
+body {
+ background-color: white;
+ color: black;
+ font-family: Arial, sans-serif;
+ font-size: small;
+ margin: 8px;
+ margin-top: 3px;
+}
+
+.DynaTable-DynaTableWidget {
+ width: 100%;
+ border: 1px solid #ACA899;
+}
+
+
+.DynaTable-DynaTableWidget .navbar {
+ width: 100%;
+ background-color: #ECE9D8;
+ vertical-align: middle;
+ border-bottom: 1px solid #ACA899;
+}
+
+.DynaTable-DynaTableWidget .navbar button {
+ width: 3em;
+ text-align: center;
+ vertical-align: middle;
+}
+
+.DynaTable-DynaTableWidget .navbar .status {
+ vertical-align: middle;
+ padding-right: 10px;
+}
+
+.DynaTable-DynaTableWidget .table {
+ margin: 10px;
+}
+
+.DynaTable-DynaTableWidget .table td.header {
+ text-align: left;
+ font-weight: bold;
+ text-decoration: underline;
+}
+
+.DynaTable-DynaTableWidget .table td.name {
+ width: 10em;
+}
+
+.DynaTable-DynaTableWidget .table td.desc {
+ width: 20em;
+}
+
+.DynaTable-DynaTableWidget .table td.sched {
+ width: 20em;
+}
+
+.DynaTable-DynaTableWidget .table td {
+ vertical-align: top;
+}
+
+.DynaTable-DayFilterWidget {
+ margin: 3em 1em 1em 0;
+ width: 10em;
+ padding: 0px 8px 0px 8px;
+ border: 1px solid #ACA899;
+}
+
+.DynaTable-DayFilterWidget button {
+ width: 4em;
+ margin: 8px 4px 8px 4px;
+}
+
+.DynaTable-ErrorDialog {
+ border: 2px outset;
+ background-color: white;
+ width: 50%;
+}
+
+.DynaTable-ErrorDialog .Caption {
+ background-color: #C3D9FF;
+ padding: 3px;
+ margin: 2px;
+ font-weight: bold;
+ cursor: default;
+}
diff --git a/eclipse/samples/DynaTable2/war/DynaTable2.html b/eclipse/samples/DynaTable2/war/DynaTable2.html
new file mode 100644
index 0000000..8f29e24
--- /dev/null
+++ b/eclipse/samples/DynaTable2/war/DynaTable2.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!-- -->
+<!-- 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 -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <link type="text/css" rel="stylesheet" href="DynaTable2.css">
+ <title></title>
+ </head>
+ <body>
+ <iframe src="javascript:''" id='__gwt_historyFrame' tabIndex='-1' style='width:0;height:0;border:0'></iframe>
+ <script type="text/javascript" language='javascript' src='gwtc/dynatable.nocache.js'></script>
+ <h1>School Schedule for Professors and Students</h1>
+ <table width="100%" border="0" summary="School Schedule for Professors and Students">
+ <tr valign="top">
+ <td id="calendar" align="center" width="90%">
+ </td>
+ <td id="days" align="center" width="10%">
+ </td>
+ </tr>
+ </table>
+ </body>
+</html>
diff --git a/eclipse/samples/DynaTable2/war/WEB-INF/web.xml b/eclipse/samples/DynaTable2/war/WEB-INF/web.xml
index 983aac0..1880c9e 100644
--- a/eclipse/samples/DynaTable2/war/WEB-INF/web.xml
+++ b/eclipse/samples/DynaTable2/war/WEB-INF/web.xml
@@ -1,16 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
- <!-- GWT REGENERATED BEGIN -->
- <servlet>
- <servlet-name>calendar</servlet-name>
- <servlet-class>com.google.gwt.sample.dynatable.server.SchoolCalendarServiceImpl</servlet-class>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>calendar</servlet-name>
- <url-pattern>/calendar</url-pattern>
- </servlet-mapping>
- <!-- GWT REGENERATED END -->
+ <servlet>
+ <servlet-name>calendar</servlet-name>
+ <servlet-class>com.google.gwt.sample.dynatable.server.SchoolCalendarServiceImpl</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>calendar</servlet-name>
+ <url-pattern>/gwtc/calendar</url-pattern>
+ </servlet-mapping>
</web-app>
diff --git a/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable2.gwt.xml b/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable2.gwt.xml
new file mode 100644
index 0000000..64a55e8
--- /dev/null
+++ b/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable2.gwt.xml
@@ -0,0 +1,20 @@
+<!-- -->
+<!-- Copyright 2007 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 -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module rename-to="dynatable" deploy-to="/gwtc">
+ <inherits name='com.google.gwt.user.User'/>
+ <entry-point class='com.google.gwt.sample.dynatable.client.DynaTable'/>
+</module>
+
+
diff --git a/user/build.xml b/user/build.xml
index 3cb3045..0539253 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -50,9 +50,10 @@
<classpath>
<pathelement location="${javac.out}" />
<pathelement location="${gwt.build}/out/dev/core/bin-test" />
+ <pathelement location="${gwt.tools.lib}/tomcat/servlet-api-2.4.jar" />
<pathelement location="${gwt.tools.lib}/junit/junit-3.8.1.jar" />
<pathelement location="${gwt.tools.lib}/selenium/selenium-java-client-driver.jar" />
- <pathelement location="${gwt.dev.staging.jar}" />
+ <pathelement location="${gwt.dev.jar}" />
</classpath>
</gwt.javac>
</target>
diff --git a/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java b/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java
index 9a7779b..0ecec17 100644
--- a/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java
+++ b/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java
@@ -15,137 +15,112 @@
*/
package com.google.gwt.i18n.client.impl;
-import java.util.ArrayList;
-import java.util.Collection;
+import com.google.gwt.core.client.JavaScriptObject;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
- * Read only Map used when returning <code>Constants</code> maps. Preserves
- * order. ConstantMap should only be created or modified by GWT, as constant
- * maps are constructed using a very stereotyped algorithm, which allows
- * <code>ConstantMap</code> to maintain order with very little code. In
- * specific, no elements are every removed from them and all elements are added
- * before the first user operation.
+ * Map used when creating <code>Constants</code> maps. This class is to be
+ * used only by the GWT code. The map is immediately wrapped in
+ * Collections.unmodifiableMap(..) preventing any changes after construction.
*/
-public class ConstantMap extends HashMap<String, String> {
+public class ConstantMap extends AbstractMap<String, String> {
- private static class DummyMapEntry implements Map.Entry<String, String> {
- private final String key;
+ /**
+ * A cache of a synthesized entry set.
+ */
+ private Set<Map.Entry<String, String>> entries;
- private final String value;
+ /**
+ * The original set of keys.
+ */
+ private final String[] keys;
- DummyMapEntry(String key, String value) {
- this.key = key;
- this.value = value;
- }
+ /*
+ * Stores a fast lookup in a JSO using ':' to prevent conflict with built-in
+ * JavaScript properties.
+ */
+ @SuppressWarnings("unused")
+ private JavaScriptObject map;
- public String getKey() {
- return key;
- }
+ public ConstantMap(String keys[], String values[]) {
+ this.keys = keys;
- public String getValue() {
- return value;
- }
+ init();
- public String setValue(String arg0) {
- throw new UnsupportedOperationException();
+ for (int i = 0; i < keys.length; ++i) {
+ putImpl(keys[i], values[i]);
}
}
- private class OrderedConstantSet<T> extends ArrayList<T> implements Set<T> {
- private class ImmutableIterator implements Iterator<T> {
- private final Iterator<T> base;
-
- ImmutableIterator(Iterator<T> base) {
- this.base = base;
- }
-
- public boolean hasNext() {
- return base.hasNext();
- }
-
- public T next() {
- return base.next();
- }
-
- public void remove() {
- throw new UnsupportedOperationException("Immutable set");
- }
- }
-
- @Override
- public void clear() {
- throw new UnsupportedOperationException("Immutable set");
- }
-
- @Override
- public Iterator<T> iterator() {
- Iterator<T> base = super.iterator();
- return new ImmutableIterator(base);
- }
- }
-
- private OrderedConstantSet<Map.Entry<String, String>> entries;
-
- private final OrderedConstantSet<String> keys = new OrderedConstantSet<String>();
-
- private OrderedConstantSet<String> values;
-
@Override
- public void clear() {
- throw unsupported("clear");
+ public boolean containsKey(Object key) {
+ return get(key) != null;
}
@Override
public Set<Map.Entry<String, String>> entrySet() {
if (entries == null) {
- entries = new OrderedConstantSet<Map.Entry<String, String>>();
- for (int i = 0; i < keys.size(); i++) {
- String key = keys.get(i);
- String value = get(key);
- entries.add(new DummyMapEntry(key, value));
+ Map<String, String> copy = new HashMap<String, String>();
+ for (String key : keys) {
+ copy.put(key, get(key));
}
+ entries = Collections.unmodifiableMap(copy).entrySet();
}
return entries;
}
@Override
+ public String get(Object key) {
+ return (key instanceof String) ? get((String) key) : null;
+ }
+
+ public native String get(String key) /*-{
+ // Prepend ':' to avoid conflicts with built-in Object properties.
+ return this.@com.google.gwt.i18n.client.impl.ConstantMap::map[':' + key];
+ }-*/;
+
+ @Override
public Set<String> keySet() {
- return keys;
- }
-
- @Override
- public String put(String key, String value) {
- // We may want to find a more efficient implementation later.
- boolean exists = keys.contains(key);
- if (!exists) {
- keys.add(key);
- }
- return super.put(key, value);
- }
-
- @Override
- public String remove(Object key) {
- throw unsupported("remove");
- }
-
- @Override
- public Collection<String> values() {
- if (values == null) {
- values = new OrderedConstantSet<String>();
- for (int i = 0; i < keys.size(); i++) {
- Object element = keys.get(i);
- values.add(this.get(element));
+ return new AbstractSet<String>() {
+ @Override
+ public boolean contains(Object o) {
+ return containsKey(o);
}
- }
- return values;
+
+ @Override
+ public Iterator<String> iterator() {
+ return Arrays.asList(keys).iterator();
+ }
+
+ @Override
+ public int size() {
+ return ConstantMap.this.size();
+ }
+ };
}
- private UnsupportedOperationException unsupported(String operation) {
- return new UnsupportedOperationException(operation
- + " not supported on a constant map");
+ @Override
+ public int size() {
+ return keys.length;
}
+
+ /**
+ * Overridable for testing purposes, see ConstantMapTest.
+ */
+ protected void init() {
+ map = JavaScriptObject.createObject();
+ }
+
+ protected native void putImpl(String key, String value) /*-{
+ // Prepend ':' to avoid conflicts with built-in Object properties.
+ this.@com.google.gwt.i18n.client.impl.ConstantMap::map[':' + key] = value;
+ }-*/;
}
diff --git a/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
index e18625c..a192966 100644
--- a/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
@@ -22,10 +22,16 @@
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
import com.google.gwt.user.rebind.AbstractGeneratorClassCreator;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
/**
* Creator for methods of the form Map getX() .
*/
class ConstantsMapMethodCreator extends AbstractLocalizableMethodCreator {
+
+ static final String GENERIC_STRING_MAP_TYPE = "java.util.Map<java.lang.String, java.lang.String>";
+
/**
* Constructor for localizable returnType method creator.
*
@@ -40,13 +46,13 @@
*
* @param logger TreeLogger instance for logging
* @param method method body to create
- * @param key value to create map from
+ * @param mapName name to create map from
* @param resourceList AbstractResource for key lookup
* @param locale locale to use for localized string lookup
*/
@Override
- public void createMethodFor(TreeLogger logger, JMethod method, String key,
- ResourceList resourceList, String locale) {
+ public void createMethodFor(TreeLogger logger, JMethod method,
+ String mapName, ResourceList resourceList, String locale) {
String methodName = method.getName();
if (method.getParameters().length > 0) {
error(
@@ -59,31 +65,53 @@
enableCache();
// check cache for array
String constantMapClassName = ConstantMap.class.getCanonicalName();
- println(constantMapClassName + " args = (" + constantMapClassName + ") cache.get("
- + wrap(methodName) + ");");
+ println(GENERIC_STRING_MAP_TYPE + " args = (" + GENERIC_STRING_MAP_TYPE
+ + ") cache.get(" + wrap(methodName) + ");");
// if not found create Map
println("if (args == null) {");
indent();
- println("args = new " + constantMapClassName + "();");
- String value;
+ println("args = new " + constantMapClassName + "(new String[] {");
+ String keyString;
try {
- value = resourceList.getRequiredStringExt(key, null);
+ keyString = resourceList.getRequiredStringExt(mapName, null);
} catch (MissingResourceException e) {
e.setDuring("getting key list");
throw e;
}
- String[] args = ConstantsStringArrayMethodCreator.split(value);
- for (int i = 0; i < args.length; i++) {
+ String[] keys = ConstantsStringArrayMethodCreator.split(keyString);
+ ResourceList resources = getResources();
+ SortedMap<String, String> map = new TreeMap<String, String>();
+ for (String key : keys) {
+ if (key.length() == 0) {
+ continue;
+ }
+
try {
- key = args[i];
- String keyValue = getResources().getString(key);
- println("args.put(" + wrap(key) + ", " + wrap(keyValue) + ");");
+ String value = resources.getRequiredString(key);
+ map.put(key, value);
} catch (MissingResourceException e) {
e.setDuring("implementing map");
throw e;
}
}
+
+ indent();
+ indent();
+ for (String key : map.keySet()) {
+ println(wrap(key) + ", ");
+ }
+ outdent();
+ println("},");
+ indent();
+ println("new String[] {");
+ for (String key : map.keySet()) {
+ String value = map.get(key);
+ println(wrap(value) + ",");
+ }
+ outdent();
+ println("});");
+ outdent();
println("cache.put(" + wrap(methodName) + ", args);");
outdent();
println("};");
diff --git a/user/src/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreator.java b/user/src/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreator.java
index 433f698..8a7272b 100644
--- a/user/src/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreator.java
@@ -23,7 +23,6 @@
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
-import com.google.gwt.i18n.client.impl.ConstantMap;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
import com.google.gwt.user.rebind.AbstractMethodCreator;
import com.google.gwt.user.rebind.SourceWriter;
@@ -125,7 +124,7 @@
namesToMethodCreators.put("getMap", new LookupMethodCreator(this, mapType) {
@Override
public String getReturnTypeName() {
- return ConstantMap.class.getCanonicalName();
+ return ConstantsMapMethodCreator.GENERIC_STRING_MAP_TYPE;
}
});
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImpl.java b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
index b9d1a5b..30da21c 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
@@ -33,16 +33,16 @@
*/
protected static boolean isMyListener(Object object) {
/*
- * The first test ensures the Object belongs to this module in hosted mode,
- * because this hosted mode class loader will have a different copy of the
- * EventListener class than some other module would have.
+ * The first test ensures the Object belongs to this module in web mode by
+ * ensuring this is not a JavaScriptObject. In web mode, foreign Java
+ * objects appear to be JavaScriptObject. See Cast.isJavaScriptObject().
*
- * However, in web mode we could still get a collision where another module
- * happens to use the same typeId. The second test ensures the Object is not
- * "foreign". See Cast.isJavaScriptObject().
+ * The second test then checks the exact type.
+ *
+ * TODO: make the generated code smaller!
*/
- return object instanceof com.google.gwt.user.client.EventListener
- && !(object instanceof JavaScriptObject);
+ return !(object instanceof JavaScriptObject)
+ && (object instanceof com.google.gwt.user.client.EventListener);
}
public native void eventCancelBubble(Event evt, boolean cancel) /*-{
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
diff --git a/user/super/com/google/gwt/emul/java/util/Collections.java b/user/super/com/google/gwt/emul/java/util/Collections.java
index 50963d9..fdb3c9a 100644
--- a/user/super/com/google/gwt/emul/java/util/Collections.java
+++ b/user/super/com/google/gwt/emul/java/util/Collections.java
@@ -102,6 +102,7 @@
throw new UnsupportedOperationException();
}
+ @Override
public boolean equals(Object o) {
return list.equals(o);
}
@@ -110,6 +111,7 @@
return list.get(index);
}
+ @Override
public int hashCode() {
return list.hashCode();
}
@@ -118,6 +120,7 @@
return list.indexOf(o);
}
+ @Override
public boolean isEmpty() {
return list.isEmpty();
}
@@ -155,6 +158,7 @@
this.entry = entry;
}
+ @Override
public boolean equals(Object o) {
return entry.equals(o);
}
@@ -167,6 +171,7 @@
return entry.getValue();
}
+ @Override
public int hashCode() {
return entry.hashCode();
}
@@ -175,6 +180,7 @@
throw new UnsupportedOperationException();
}
+ @Override
public String toString() {
return entry.toString();
}
@@ -186,14 +192,17 @@
super((Set<? extends Entry<K, V>>) s);
}
+ @Override
public boolean contains(Object o) {
return coll.contains(o);
}
+ @Override
public boolean containsAll(Collection<?> o) {
return coll.containsAll(o);
}
+ @Override
@SuppressWarnings("unchecked")
public Iterator<Map.Entry<K, V>> iterator() {
final Iterator<Map.Entry<K, V>> it = (Iterator<Entry<K, V>>) coll.iterator();
@@ -212,11 +221,13 @@
};
}
+ @Override
@SuppressWarnings("unchecked")
public Object[] toArray() {
return toArray(super.toArray());
}
+ @Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
Object[] result = super.toArray(a);
@@ -227,7 +238,10 @@
}
}
+ private transient UnmodifiableSet<Map.Entry<K, V>> entrySet;
+ private transient UnmodifiableSet<K> keySet;
private final Map<? extends K, ? extends V> map;
+ private transient UnmodifiableCollection<V> values;
public UnmodifiableMap(Map<? extends K, ? extends V> map) {
this.map = map;
@@ -246,9 +260,13 @@
}
public Set<Map.Entry<K, V>> entrySet() {
- return new UnmodifiableEntrySet<K, V>(map.entrySet());
+ if (entrySet == null) {
+ entrySet = new UnmodifiableEntrySet<K, V>(map.entrySet());
+ }
+ return entrySet;
}
+ @Override
public boolean equals(Object o) {
return map.equals(o);
}
@@ -257,6 +275,7 @@
return map.get(key);
}
+ @Override
public int hashCode() {
return map.hashCode();
}
@@ -266,7 +285,10 @@
}
public Set<K> keySet() {
- return unmodifiableSet(map.keySet());
+ if (keySet == null) {
+ keySet = new UnmodifiableSet<K>(map.keySet());
+ }
+ return keySet;
}
public V put(K key, V value) {
@@ -285,12 +307,16 @@
return map.size();
}
+ @Override
public String toString() {
return map.toString();
}
public Collection<V> values() {
- return unmodifiableCollection(map.values());
+ if (values == null) {
+ values = new UnmodifiableCollection<V>(map.values());
+ }
+ return values;
}
}
@@ -307,10 +333,12 @@
super(set);
}
+ @Override
public boolean equals(Object o) {
return coll.equals(o);
}
+ @Override
public int hashCode() {
return coll.hashCode();
}
diff --git a/user/test/com/google/gwt/i18n/ConstantMapTest.java b/user/test/com/google/gwt/i18n/ConstantMapTest.java
index 95a0b7f..8503fc7 100644
--- a/user/test/com/google/gwt/i18n/ConstantMapTest.java
+++ b/user/test/com/google/gwt/i18n/ConstantMapTest.java
@@ -17,19 +17,64 @@
import com.google.gwt.i18n.client.impl.ConstantMap;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
/**
- * TODO: document me.
+ * Test ConstantMap using Apache's tests.
*/
public class ConstantMapTest extends MapTestBase {
- protected Map makeEmptyMap() {
- return new ConstantMap();
+ private static final class ConstantMapNoJsni extends ConstantMap {
+ private Map<String, String> noJsniImpl;
+
+ private ConstantMapNoJsni(String[] keys, String[] values) {
+ super(keys, values);
+ }
+
+ @Override
+ public String get(String key) {
+ return noJsniImpl.get(key);
+ }
+
+ @Override
+ protected void init() {
+ noJsniImpl = new HashMap<String, String>();
+ }
+
+ @Override
+ protected void putImpl(String key, String value) {
+ noJsniImpl.put(key, value);
+ }
}
+ @Override
protected boolean isRemoveModifiable() {
return false;
}
+ @Override
+ protected Map<String, String> makeEmptyMap() {
+ return Collections.unmodifiableMap(new ConstantMapNoJsni(new String[] {},
+ new String[] {}));
+ }
+
+ @Override
+ protected Map<String, String> makeFullMap() {
+ String[] keys = Arrays.asList(getSampleKeys()).toArray(new String[0]);
+ String[] values = Arrays.asList(getSampleValues()).toArray(new String[0]);
+ return Collections.unmodifiableMap(new ConstantMapNoJsni(keys, values));
+ }
+
+ @Override
+ protected boolean useNullKey() {
+ return false;
+ }
+
+ @Override
+ protected boolean useNullValue() {
+ return false;
+ }
}
diff --git a/user/test/com/google/gwt/i18n/client/I18NTest.java b/user/test/com/google/gwt/i18n/client/I18NTest.java
index 5889825..394b090 100644
--- a/user/test/com/google/gwt/i18n/client/I18NTest.java
+++ b/user/test/com/google/gwt/i18n/client/I18NTest.java
@@ -20,7 +20,6 @@
import com.google.gwt.i18n.client.gen.Colors;
import com.google.gwt.i18n.client.gen.Shapes;
import com.google.gwt.i18n.client.gen.TestMessages;
-import com.google.gwt.i18n.client.impl.ConstantMap;
import com.google.gwt.i18n.client.resolutiontest.Inners;
import com.google.gwt.i18n.client.resolutiontest.Inners.ExtendsInnerInner;
import com.google.gwt.i18n.client.resolutiontest.Inners.HasInner;
@@ -37,6 +36,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.MissingResourceException;
@@ -189,161 +189,157 @@
TestConstants types = (TestConstants) GWT.create(TestConstants.class);
Map<String, String> map = types.mapABCD();
- assertEquals(4, map.size());
- assertEquals("valueA", map.get("keyA"));
- assertEquals("valueB", map.get("keyB"));
- assertEquals("valueC", map.get("keyC"));
- assertEquals("valueD", map.get("keyD"));
-
+ Map<String, String> expectedMap = getMapFromArrayUsingASimpleRule(new String[] {
+ "A", "B", "C", "D"});
assertNull(map.get("bogus"));
+ compareMapsComprehensively(map, expectedMap);
- Set<String> keys = map.keySet();
- Iterator<String> keyIter = keys.iterator();
- assertEquals("keyA", keyIter.next());
- assertEquals("keyB", keyIter.next());
- assertEquals("keyC", keyIter.next());
- assertEquals("keyD", keyIter.next());
- assertFalse(keyIter.hasNext());
-
- Collection<String> values = map.values();
- Iterator<String> valueIter = values.iterator();
- assertEquals("valueA", valueIter.next());
- assertEquals("valueB", valueIter.next());
- assertEquals("valueC", valueIter.next());
- assertEquals("valueD", valueIter.next());
- assertFalse(keyIter.hasNext());
-
+ /*
+ * Test if the returned map can be modified in any way. Things are working
+ * as expected if exceptions are thrown in each case.
+ */
+ String failureMessage = "Should have thrown UnsupportedOperationException";
+ /* test map operations */
try {
map.remove("keyA");
- fail("Should have thrown UnsupportedOperationException");
+ fail(failureMessage + " on map.remove");
} catch (UnsupportedOperationException e) {
- // good if an exception was caught
}
-
try {
- keys.clear();
- fail("Should have thrown UnsupportedOperationException");
+ map.put("keyA", "allA");
+ fail(failureMessage + "on map.put of existing key");
} catch (UnsupportedOperationException e) {
- // good if an exception was caught
+ }
+ try {
+ map.put("keyZ", "allZ");
+ fail(failureMessage + "on map.put of new key");
+ } catch (UnsupportedOperationException e) {
+ }
+ try {
+ map.clear();
+ fail(failureMessage + " on map.clear");
+ } catch (UnsupportedOperationException e) {
}
- // TODO: fixme -- values are supposed to be backed by the map and should
- // fail if modified
- // try {
- // Iterator nonmutableIter = keys.iterator();
- // nonmutableIter.next();
- // nonmutableIter.remove();
- // fail("Should have thrown UnsupportedOperationException");
- // } catch (UnsupportedOperationException e) {
- // // good if an exception was caught
- // }
+ /* test map.keySet() operations */
+ try {
+ map.keySet().add("keyZ");
+ fail(failureMessage + " on map.keySet().add");
+ } catch (UnsupportedOperationException e) {
+ }
+ try {
+ map.keySet().remove("keyA");
+ fail(failureMessage + " on map.keySet().remove");
+ } catch (UnsupportedOperationException e) {
+ }
+ try {
+ map.keySet().clear();
+ fail(failureMessage + " on map.keySet().clear");
+ } catch (UnsupportedOperationException e) {
+ }
+
+ /* test map.values() operations */
+ try {
+ map.values().add("valueZ");
+ fail(failureMessage + " on map.values().add");
+ } catch (UnsupportedOperationException e) {
+ }
+ try {
+ map.values().remove("valueA");
+ fail(failureMessage + " on map.values().clear()");
+ } catch (UnsupportedOperationException e) {
+ }
+ try {
+ map.values().clear();
+ fail(failureMessage + " on map.values().clear()");
+ } catch (UnsupportedOperationException e) {
+ }
+
+ /* test map.entrySet() operations */
+ Map.Entry<String, String> firstEntry = map.entrySet().iterator().next();
+ try {
+ map.entrySet().clear();
+ fail(failureMessage + "on map.entrySet().clear");
+ } catch (UnsupportedOperationException e) {
+ }
+ try {
+ map.entrySet().remove(firstEntry);
+ fail(failureMessage + " on map.entrySet().remove");
+ } catch (UnsupportedOperationException e) {
+ }
+ try {
+ map.entrySet().add(firstEntry);
+ fail(failureMessage + "on map.entrySet().add");
+ } catch (UnsupportedOperationException e) {
+ }
+ try {
+ firstEntry.setValue("allZ");
+ fail(failureMessage + "on firstEntry.setValue");
+ } catch (UnsupportedOperationException e) {
+ }
+ try {
+ map.clear();
+ fail(failureMessage + " on map.clear");
+ } catch (UnsupportedOperationException e) {
+ }
}
/**
- * Tests focus on just the key order, since ABCD exercises the map.
+ * Tests exercise the cache.
*/
public void testConstantMapBACD() {
TestConstants types = (TestConstants) GWT.create(TestConstants.class);
-
- ConstantMap map = (ConstantMap) types.mapBACD();
-
- Set<String> keys = map.keySet();
- Iterator<String> keyIter = keys.iterator();
- assertEquals("keyB", keyIter.next());
- assertEquals("keyA", keyIter.next());
- assertEquals("keyC", keyIter.next());
- assertEquals("keyD", keyIter.next());
-
- Collection<String> values = map.values();
- Iterator<String> valueIter = values.iterator();
- assertEquals("valueB", valueIter.next());
- assertEquals("valueA", valueIter.next());
- assertEquals("valueC", valueIter.next());
- assertEquals("valueD", valueIter.next());
+ Map<String, String> map = types.mapBACD();
+ Map<String, String> expectedMap = getMapFromArrayUsingASimpleRule(new String[] {
+ "B", "A", "C", "D"});
+ compareMapsComprehensively(map, expectedMap);
}
/**
- * Tests focus on correctness of entries, since ABCD exercises the map.
+ * Tests exercise the cache.
*/
public void testConstantMapBBB() {
TestConstants types = (TestConstants) GWT.create(TestConstants.class);
-
- ConstantMap map = (ConstantMap) types.mapBBB();
-
- assertEquals(1, map.size());
-
- Set<String> keys = map.keySet();
- assertEquals(1, keys.size());
- Iterator<String> keyIter = keys.iterator();
- assertEquals("keyB", keyIter.next());
-
- Collection<String> values = map.values();
- assertEquals(1, values.size());
- Iterator<String> valueIter = values.iterator();
- assertEquals("valueB", valueIter.next());
+ Map<String, String> map = types.mapBBB();
+ Map<String, String> expectedMap = getMapFromArrayUsingASimpleRule(new String[] {"B"});
+ compareMapsComprehensively(map, expectedMap);
}
/**
- * Tests focus on just the key order, since ABCD exercises the map.
+ * Tests exercise the cache and check if Map works as the declared return
+ * type.
*/
- public void testConstantMapDBCA() {
+ @SuppressWarnings("unchecked")
+ public void testConstantMapDCBA() {
TestConstants types = (TestConstants) GWT.create(TestConstants.class);
-
- ConstantMap map = (ConstantMap) types.mapDCBA();
-
- Set<String> keys = map.keySet();
- Iterator<String> keyIter = keys.iterator();
- assertEquals("keyD", keyIter.next());
- assertEquals("keyC", keyIter.next());
- assertEquals("keyB", keyIter.next());
- assertEquals("keyA", keyIter.next());
-
- Collection<String> values = map.values();
- Iterator<String> valueIter = values.iterator();
- assertEquals("valueD", valueIter.next());
- assertEquals("valueC", valueIter.next());
- assertEquals("valueB", valueIter.next());
- assertEquals("valueA", valueIter.next());
+ Map<String, String> map = types.mapDCBA();
+ Map<String, String> expectedMap = getMapFromArrayUsingASimpleRule(new String[] {
+ "D", "C", "B", "A"});
+ compareMapsComprehensively(map, expectedMap);
}
/**
* Tests focus on correctness of entries, since ABCD exercises the map.
*/
+ public void testConstantMapEmpty() {
+ TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ Map<String, String> map = types.mapEmpty();
+ Map<String, String> expectedMap = new HashMap<String, String>();
+ compareMapsComprehensively(map, expectedMap);
+ }
+
+ /**
+ * Tests exercise the cache and check if Map works as the declared return
+ * type.
+ */
public void testConstantMapXYZ() {
TestConstants types = (TestConstants) GWT.create(TestConstants.class);
-
- ConstantMap map = (ConstantMap) types.mapXYZ();
-
- assertEquals(3, map.size());
-
- Set<String> keys = map.keySet();
- assertEquals(3, keys.size());
- Iterator<String> keyIter = keys.iterator();
- assertEquals("keyX", keyIter.next());
- assertEquals("keyY", keyIter.next());
- assertEquals("keyZ", keyIter.next());
-
- Collection<String> values = map.values();
- assertEquals(3, values.size());
- Iterator<String> valueIter = values.iterator();
- assertEquals("valueZ", valueIter.next());
- assertEquals("valueZ", valueIter.next());
- assertEquals("valueZ", valueIter.next());
-
- Set<Map.Entry<String, String>> entries = map.entrySet();
- assertEquals(3, entries.size());
- Iterator<Map.Entry<String, String>> entryIter = entries.iterator();
- Map.Entry<String, String> entry;
-
- entry = entryIter.next();
- assertEquals("keyX", entry.getKey());
- assertEquals("valueZ", entry.getValue());
- entry = entryIter.next();
- assertEquals("keyY", entry.getKey());
- assertEquals("valueZ", entry.getValue());
- entry = entryIter.next();
- assertEquals("keyZ", entry.getKey());
- assertEquals("valueZ", entry.getValue());
+ Map<String, String> map = types.mapXYZ();
+ Map<String, String> expectedMap = new HashMap<String, String>();
+ expectedMap.put("keyX", "valueZ");
+ expectedMap.put("keyY", "valueZ");
+ expectedMap.put("keyZ", "valueZ");
+ compareMapsComprehensively(map, expectedMap);
}
public void testConstantStringArrays() {
@@ -451,28 +447,6 @@
assertEquals(Integer.MIN_VALUE, types.intMin());
}
- // Uncomment for desk tests
- // /**
- // * Tests focus on correctness of entries, since ABCD exercises the map.
- // */
- // public void testConstantMapEmpty() {
- // TestConstants types = (TestConstants) GWT.create(TestConstants.class);
- //
- // ConstantMap map = (ConstantMap) types.mapEmpty();
- //
- // assertEquals(0, map.size());
- //
- // Set keys = map.keySet();
- // assertEquals(0, keys.size());
- // Iterator keyIter = keys.iterator();
- // assertFalse(keyIter.hasNext());
- //
- // Collection values = map.values();
- // assertEquals(0, values.size());
- // Iterator valueIter = values.iterator();
- // assertFalse(valueIter.hasNext());
- // }
-
public void testLocalizableInner() {
// Check simple inner
LocalizableSimpleInner s = (LocalizableSimpleInner) GWT.create(Inners.LocalizableSimpleInner.class);
@@ -522,8 +496,9 @@
// Protected InnerClass
InnerClass innerClass = new Inners.InnerClass();
- String extendsAnotherInner = innerClass.testExtendsAnotherInner();
- assertEquals("{innerInner=4.321, outer=outer}", extendsAnotherInner);
+ Map<String, String> extendsAnotherInner = innerClass.testExtendsAnotherInner();
+ assertEquals("4.321", extendsAnotherInner.get("innerInner"));
+ assertEquals("outer", extendsAnotherInner.get("outer"));
// ExtendProtectedInner
String extendProtectedInner = innerClass.testExtendsProtectedInner();
@@ -588,6 +563,47 @@
}
}
+ private <T> boolean compare(Collection<T> collection1,
+ Collection<T> collection2) {
+ if (collection1 == null) {
+ return (collection2 == null);
+ }
+ if (collection2 == null) {
+ return false;
+ }
+ if (collection1.size() != collection2.size()) {
+ return false;
+ }
+ for (T element1 : collection1) {
+ boolean found = false;
+ for (T element2 : collection2) {
+ if (element1.equals(element2)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // compare the map, entrySet, keySet, and values
+ private void compareMapsComprehensively(Map<String, String> map,
+ Map<String, String> expectedMap) {
+ // checking both directions to verify that the equals implementation is
+ // correct both ways
+ assertEquals(expectedMap, map);
+ assertEquals(map, expectedMap);
+ assertEquals(expectedMap.entrySet(), map.entrySet());
+ assertEquals(map.entrySet(), expectedMap.entrySet());
+ assertEquals(expectedMap.keySet(), map.keySet());
+ assertEquals(map.keySet(), expectedMap.keySet());
+ assertTrue(compare(expectedMap.values(), map.values()));
+ assertTrue(compare(map.values(), expectedMap.values()));
+ }
+
private native void createDummyDictionaries() /*-{
$wnd.testDic = new Object();
$wnd.testDic.formattedMessage = "3 {2},{2},{2}, one {0}, two {1} {1}";
@@ -597,4 +613,12 @@
$wnd.emptyDic = new Object();
$wnd.malformedDic = 4;
}-*/;
+
+ private Map<String, String> getMapFromArrayUsingASimpleRule(String array[]) {
+ Map<String, String> map = new HashMap<String, String>();
+ for (String str : array) {
+ map.put("key" + str, "value" + str);
+ }
+ return map;
+ }
}
diff --git a/user/test/com/google/gwt/i18n/client/TestConstants.java b/user/test/com/google/gwt/i18n/client/TestConstants.java
index 0884f6e..e97674a 100644
--- a/user/test/com/google/gwt/i18n/client/TestConstants.java
+++ b/user/test/com/google/gwt/i18n/client/TestConstants.java
@@ -23,100 +23,98 @@
*/
public interface TestConstants extends com.google.gwt.i18n.client.Constants {
- /**
- * @gwt.key string
- */
- String getString();
+ boolean booleanFalse();
- String stringTrimsLeadingWhitespace();
-
- String stringDoesNotTrimTrailingThreeSpaces();
-
- String stringEmpty();
-
- String stringJapaneseRed();
-
- String stringJapaneseGreen();
-
- String stringJapaneseBlue();
-
- int intZero();
-
- int intOne();
-
- int intNegOne();
-
- int intMax();
-
- int intMin();
-
- float floatPi();
-
- float floatZero();
-
- float floatOne();
-
- float floatNegOne();
-
- float floatPosMax();
-
- float floatPosMin();
-
- float floatNegMax();
-
- float floatNegMin();
-
- double doublePi();
-
- double doubleZero();
-
- double doubleOne();
-
- double doubleNegOne();
-
- double doublePosMax();
-
- double doublePosMin();
+ boolean booleanTrue();
double doubleNegMax();
double doubleNegMin();
- String[] stringArrayABCDEFG();
+ double doubleNegOne();
- String[] stringArraySizeOneEmptyString();
+ double doubleOne();
- String[] stringArraySizeOneX();
+ double doublePi();
- String[] stringArraySizeTwoBothEmpty();
+ double doublePosMax();
- String[] stringArraySizeThreeAllEmpty();
+ double doublePosMin();
- String[] stringArraySizeTwoWithEscapedComma();
+ double doubleZero();
- String[] stringArraySizeOneWithBackslashX();
+ float floatNegMax();
- String[] stringArraySizeThreeWithDoubleBackslash();
+ float floatNegMin();
- boolean booleanFalse();
+ float floatNegOne();
- boolean booleanTrue();
+ float floatOne();
+
+ float floatPi();
+
+ float floatPosMax();
+
+ float floatPosMin();
+
+ float floatZero();
+
+ /**
+ * @gwt.key string
+ */
+ String getString();
+
+ int intMax();
+
+ int intMin();
+
+ int intNegOne();
+
+ int intOne();
+
+ int intZero();
Map<String, String> mapABCD();
- // raw type test
- @SuppressWarnings("unchecked")
- Map mapDCBA();
-
Map<String, String> mapBACD();
Map<String, String> mapBBB();
+ // raw type test
+ @SuppressWarnings("unchecked")
+ Map mapDCBA();
+
+ Map<String, String> mapEmpty();
+
+ // Map<String, String> mapWithMissingKey();
+
Map<String, String> mapXYZ();
- // uncomment for desk tests
- // Map mapWithMissingKey();
+ String[] stringArrayABCDEFG();
- // uncomment for desk tests
- // Map mapEmpty();
+ String[] stringArraySizeOneEmptyString();
+
+ String[] stringArraySizeOneWithBackslashX();
+
+ String[] stringArraySizeOneX();
+
+ String[] stringArraySizeThreeAllEmpty();
+
+ String[] stringArraySizeThreeWithDoubleBackslash();
+
+ String[] stringArraySizeTwoBothEmpty();
+
+ String[] stringArraySizeTwoWithEscapedComma();
+
+ String stringDoesNotTrimTrailingThreeSpaces();
+
+ String stringEmpty();
+
+ String stringJapaneseBlue();
+
+ String stringJapaneseGreen();
+
+ String stringJapaneseRed();
+
+ String stringTrimsLeadingWhitespace();
}
diff --git a/user/test/com/google/gwt/i18n/client/TestConstants.properties b/user/test/com/google/gwt/i18n/client/TestConstants.properties
index aeb7d51..35d7acf 100644
--- a/user/test/com/google/gwt/i18n/client/TestConstants.properties
+++ b/user/test/com/google/gwt/i18n/client/TestConstants.properties
@@ -81,7 +81,7 @@
# mapXYZ: "keyX", "keyY", "keyZ"
# map with a missing key (uncomment during desk tests; won't work in JUnit)
-# mapWithMissingKey: keyA, , keyB
+# mapWithMissingKey: keyA, asdf, keyB
-# empty map (uncomment during desk tests; won't work in JUnit)
-# mapEmpty:
+# empty map
+mapEmpty:
diff --git a/user/test/com/google/gwt/i18n/client/resolutiontest/Inners.java b/user/test/com/google/gwt/i18n/client/resolutiontest/Inners.java
index 566bdad..8abbc8b 100644
--- a/user/test/com/google/gwt/i18n/client/resolutiontest/Inners.java
+++ b/user/test/com/google/gwt/i18n/client/resolutiontest/Inners.java
@@ -140,10 +140,10 @@
}
/** Tests Protected Inner Class. */
- public String testExtendsAnotherInner() {
+ public Map<String, String> testExtendsAnotherInner() {
ExtendsAnotherInner clazz = (ExtendsAnotherInner) GWT.create(ExtendsAnotherInner.class);
- Map answer = clazz.extendsAnotherInner();
- return answer.toString();
+ Map<String, String> answer = clazz.extendsAnotherInner();
+ return answer;
}
/** Test for ExtendProtectedInner. */
@@ -164,7 +164,7 @@
}
/** Test maps in extension. */
- Map extendsAnotherInner();
+ Map<String, String> extendsAnotherInner();
}
/**
diff --git a/user/test/com/google/gwt/user/client/ui/DomEventBenchmark.java b/user/test/com/google/gwt/user/client/ui/DomEventBenchmark.java
new file mode 100644
index 0000000..c335615
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/DomEventBenchmark.java
@@ -0,0 +1,131 @@
+/*
+ * 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.user.client.ui;
+
+import com.google.gwt.benchmarks.client.Benchmark;
+import com.google.gwt.benchmarks.client.IntRange;
+import com.google.gwt.benchmarks.client.Operator;
+import com.google.gwt.benchmarks.client.RangeField;
+import com.google.gwt.benchmarks.client.Setup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Measures the speed with which event handlers can be added and removed to a
+ * few simple UI classes. This is here to allow us to compare the performance of
+ * the old event listeners and the new event handlers. This first version, of
+ * course, can only look at listeners, as handlers aren't here yet.
+ */
+public class DomEventBenchmark extends Benchmark {
+
+ /**
+ * Whether to use old listeners or new handlers.
+ */
+ // protected enum RegistrationStyle {
+ // OLD_LISTENERS, NEW_HANDLERS
+ // }
+ private static final int NUM_WIDGETS = 250;
+
+ protected final IntRange listenerRange =
+ new IntRange(4, 400, Operator.MULTIPLY, 10);
+
+ private List<SimpleCheckBox> widgets;
+
+ private List<ClickListener> listeners;
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.User";
+ }
+
+ // Required for JUnit
+ public void testSimpleCheckBoxAddAndRemoveForClicks() {
+ }
+
+ @Setup("reset")
+ public void testSimpleCheckBoxAddAndRemoveForClicks(
+ // @RangeEnum(RegistrationStyle.class) RegistrationStyle style,
+ @RangeField("listenerRange")
+ Integer numListeners) {
+
+ // The RegistrationStyle blank is here to be filled in when handlers arrive.
+ // Until then, just run the tests twice.
+
+ // if (RegistrationStyle.OLD_LISTENERS == style) {
+ for (SimpleCheckBox cb : widgets) {
+ for (int i = 0; i < numListeners; i++) {
+ cb.addClickListener(listeners.get(i));
+ }
+ }
+ for (SimpleCheckBox cb : widgets) {
+ for (int i = 0; i < numListeners; i++) {
+ cb.removeClickListener(listeners.get(i));
+ }
+ }
+ // }
+ }
+
+ // Required for JUnit
+ public void testSimpleCheckBoxAddForClicks() {
+ }
+
+ @Setup("reset")
+ public void testSimpleCheckBoxAddForClicks(
+ // @RangeEnum(RegistrationStyle.class) RegistrationStyle style,
+ @RangeField("listenerRange")
+ Integer numListeners) {
+
+ // The RegistrationStyle blank is here to be filled in when handlers arrive.
+ // Until then, just run the tests twice.
+
+ // if (RegistrationStyle.OLD_LISTENERS == style) {
+ for (SimpleCheckBox cb : widgets) {
+ for (int i = 0; i < numListeners; i++) {
+ cb.addClickListener(listeners.get(i));
+ }
+ }
+ // }
+ }
+
+ void reset(/* RegistrationStyle style , */Integer numListeners) {
+ RootPanel root = RootPanel.get();
+ root.clear();
+ widgets = new ArrayList<SimpleCheckBox>();
+ listeners = new ArrayList<ClickListener>();
+
+ for (int i = 0; i < NUM_WIDGETS; i++) {
+ SimpleCheckBox cb = new SimpleCheckBox();
+ widgets.add(cb);
+ root.add(cb);
+ }
+
+ for (int i = 0; i < numListeners; i++) {
+ listeners.add(new ClickListener() {
+ public void onClick(Widget sender) {
+ }
+ });
+ }
+ }
+
+ // /**
+ // * Cannot do this until we fix our inability to synthesize events,
+ // * pending...
+ // */
+ // public void testDispatch() {
+ //
+ // }
+}
diff --git a/user/test/com/google/gwt/user/server/rpc/MockHttpServletRequest.java b/user/test/com/google/gwt/user/server/rpc/MockHttpServletRequest.java
index 85fb169..8cd0375 100644
--- a/user/test/com/google/gwt/user/server/rpc/MockHttpServletRequest.java
+++ b/user/test/com/google/gwt/user/server/rpc/MockHttpServletRequest.java
@@ -37,7 +37,7 @@
throw new UnsupportedOperationException();
}
- public Enumeration getAttributeNames() {
+ public Enumeration<String> getAttributeNames() {
throw new UnsupportedOperationException();
}
@@ -73,11 +73,11 @@
throw new UnsupportedOperationException();
}
- public Enumeration getHeaderNames() {
+ public Enumeration<String> getHeaderNames() {
throw new UnsupportedOperationException();
}
- public Enumeration getHeaders(String arg0) {
+ public Enumeration<String> getHeaders(String arg0) {
throw new UnsupportedOperationException();
}
@@ -97,7 +97,7 @@
throw new UnsupportedOperationException();
}
- public Enumeration getLocales() {
+ public Enumeration<Locale> getLocales() {
throw new UnsupportedOperationException();
}
@@ -117,11 +117,11 @@
throw new UnsupportedOperationException();
}
- public Map getParameterMap() {
+ public Map<String, String[]> getParameterMap() {
throw new UnsupportedOperationException();
}
- public Enumeration getParameterNames() {
+ public Enumeration<String> getParameterNames() {
throw new UnsupportedOperationException();
}
diff --git a/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTest.java b/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTest.java
index c881d1b..6914928 100644
--- a/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTest.java
+++ b/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTest.java
@@ -55,7 +55,7 @@
private class MockHttpServletRequestContextPath extends
MockHttpServletRequest {
private String contextPath;
-
+
@Override
public String getContextPath() {
return contextPath;
@@ -65,11 +65,15 @@
private class MockServletConfig implements ServletConfig {
private ServletContext context;
+ public MockServletConfig(ServletContext context) {
+ this.context = context;
+ }
+
public String getInitParameter(String arg0) {
throw new UnsupportedOperationException();
}
- public Enumeration getInitParameterNames() {
+ public Enumeration<String> getInitParameterNames() {
throw new UnsupportedOperationException();
}
@@ -78,17 +82,11 @@
}
public String getServletName() {
- throw new UnsupportedOperationException();
- }
-
- void setContext(ServletContext context) {
- this.context = context;
+ return "MockServlet";
}
}
private class MockServletContext implements ServletContext {
- private ServletConfig config;
- private Throwable exLogged;
private String messageLogged;
public MockServletContext() {
@@ -98,7 +96,7 @@
throw new UnsupportedOperationException();
}
- public Enumeration getAttributeNames() {
+ public Enumeration<String> getAttributeNames() {
throw new UnsupportedOperationException();
}
@@ -110,7 +108,7 @@
throw new UnsupportedOperationException();
}
- public Enumeration getInitParameterNames() {
+ public Enumeration<String> getInitParameterNames() {
throw new UnsupportedOperationException();
}
@@ -146,7 +144,7 @@
throw new UnsupportedOperationException();
}
- public Set getResourcePaths(String arg0) {
+ public Set<String> getResourcePaths(String arg0) {
throw new UnsupportedOperationException();
}
@@ -162,11 +160,11 @@
throw new UnsupportedOperationException();
}
- public Enumeration getServletNames() {
+ public Enumeration<String> getServletNames() {
throw new UnsupportedOperationException();
}
- public Enumeration getServlets() {
+ public Enumeration<String> getServlets() {
throw new UnsupportedOperationException();
}
@@ -180,7 +178,6 @@
public void log(String arg0, Throwable arg1) {
messageLogged = arg0;
- exLogged = arg1;
}
public void removeAttribute(String arg0) {
@@ -189,22 +186,16 @@
public void setAttribute(String arg0, Object arg1) {
throw new UnsupportedOperationException();
}
-
- void setConfig(ServletConfig config) {
- this.config = config;
- }
}
public void testDoGetSerializationPolicy_FailToOpenMD5Resource()
throws ServletException {
- MockServletConfig mockConfig = new MockServletConfig();
MockServletContext mockContext = new MockServletContext() {
public InputStream getResourceAsStream(String resource) {
return null;
}
};
- mockConfig.context = mockContext;
- mockContext.config = mockConfig;
+ MockServletConfig mockConfig = new MockServletConfig(mockContext);
RemoteServiceServlet rss = new RemoteServiceServlet();
@@ -229,10 +220,8 @@
*/
public void testDoGetSerializationPolicy_ModuleInSeparateServlet()
throws ServletException {
- MockServletConfig mockConfig = new MockServletConfig();
MockServletContext mockContext = new MockServletContext();
- mockConfig.context = mockContext;
- mockContext.config = mockConfig;
+ MockServletConfig mockConfig = new MockServletConfig(mockContext);
RemoteServiceServlet rss = new RemoteServiceServlet();
@@ -257,7 +246,6 @@
SerializationException {
final String resourceHash = "12345";
final String resourcePath = SerializationPolicyLoader.getSerializationPolicyFileName(resourceHash);
- MockServletConfig mockConfig = new MockServletConfig();
MockServletContext mockContext = new MockServletContext() {
public InputStream getResourceAsStream(String resource) {
if (resourcePath.equals(resource)) {
@@ -274,8 +262,7 @@
return null;
}
};
- mockConfig.context = mockContext;
- mockContext.config = mockConfig;
+ MockServletConfig mockConfig = new MockServletConfig(mockContext);
RemoteServiceServlet rss = new RemoteServiceServlet();
@@ -298,16 +285,18 @@
assertNotValidDeserialize(serializationPolicy, Baz.class);
}
- private void assertDeserializeFields(SerializationPolicy policy, Class clazz) {
+ private void assertDeserializeFields(SerializationPolicy policy,
+ Class<?> clazz) {
assertTrue(policy.shouldDeserializeFields(clazz));
}
private void assertNotDeserializeFields(SerializationPolicy policy,
- Class clazz) {
+ Class<?> clazz) {
assertFalse(policy.shouldDeserializeFields(clazz));
}
- private void assertNotValidDeserialize(SerializationPolicy policy, Class clazz) {
+ private void assertNotValidDeserialize(SerializationPolicy policy,
+ Class<?> clazz) {
try {
policy.validateDeserialize(clazz);
fail("assertNotValidDeserialize: " + clazz.getName()
@@ -317,7 +306,7 @@
}
}
- private void assertValidDeserialize(SerializationPolicy policy, Class clazz)
+ private void assertValidDeserialize(SerializationPolicy policy, Class<?> clazz)
throws SerializationException {
policy.validateDeserialize(clazz);
}