Merging from releases/1.6@3739:3876
svn merge -r3739:HEAD \
https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
Extensive merge conflicts in JavaToJavaScriptCompiler were resolved by
disabling SOYC -- BobV will re-enable it with his upcoming commit.
A patch for StandardGeneratorContext is also included to avoid a build break,
which will be committed to releases/1.6 at the same time branch-info is
updated, and will be skipped in the revision for the next merge.
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3877 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/Artifact.java b/dev/core/src/com/google/gwt/core/ext/linker/Artifact.java
index f5fe286..a54eaea 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/Artifact.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/Artifact.java
@@ -17,6 +17,8 @@
import com.google.gwt.core.ext.Linker;
+import java.io.Serializable;
+
/**
* A base type for all artifacts relating to the link process. In order to
* ensure stable output between runs of the compiler, Artifact types must
@@ -27,8 +29,9 @@
* to.
*/
public abstract class Artifact<C extends Artifact<C>> implements
- Comparable<Artifact<?>> {
- private final Class<? extends Linker> linker;
+ Comparable<Artifact<?>>, Serializable {
+ private final String linkerName;
+ private transient Class<? extends Linker> linker;
/**
* Constructor.
@@ -37,6 +40,7 @@
*/
protected Artifact(Class<? extends Linker> linker) {
assert linker != null;
+ this.linkerName = linker.getName();
this.linker = linker;
}
@@ -65,6 +69,17 @@
* Returns the Linker that created the Artifact.
*/
public final Class<? extends Linker> getLinker() {
+ // linker is null when deserialized.
+ if (linker == null) {
+ try {
+ Class<?> clazz = Class.forName(linkerName, false,
+ Thread.currentThread().getContextClassLoader());
+ linker = clazz.asSubclass(Linker.class);
+ } catch (ClassNotFoundException e) {
+ // The class may not be available.
+ linker = Linker.class;
+ }
+ }
return linker;
}
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 c04ad6d..96435bc 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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.core.ext.linker;
+import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -25,7 +26,7 @@
/**
* Provides stable ordering and de-duplication of artifacts.
*/
-public final class ArtifactSet implements SortedSet<Artifact<?>> {
+public final class ArtifactSet implements SortedSet<Artifact<?>>, Serializable {
private SortedSet<Artifact<?>> treeSet = new TreeSet<Artifact<?>>();
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/GeneratedResource.java b/dev/core/src/com/google/gwt/core/ext/linker/GeneratedResource.java
index 28c9400..3bb8000 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/GeneratedResource.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/GeneratedResource.java
@@ -24,11 +24,13 @@
* during the compilation process.
*/
public abstract class GeneratedResource extends EmittedArtifact {
- private final Class<? extends Generator> generatorType;
+ private final String generatorTypeName;
+ private transient Class<? extends Generator> generatorType;
protected GeneratedResource(Class<? extends Linker> linkerType,
Class<? extends Generator> generatorType, String partialPath) {
super(linkerType, partialPath);
+ this.generatorTypeName = generatorType.getName();
this.generatorType = generatorType;
}
@@ -36,6 +38,17 @@
* The type of Generator that created the resource.
*/
public final Class<? extends Generator> getGenerator() {
+ // generatorType is null when deserialized.
+ if (generatorType == null) {
+ try {
+ Class<?> clazz = Class.forName(generatorTypeName, false,
+ Thread.currentThread().getContextClassLoader());
+ generatorType = clazz.asSubclass(Generator.class);
+ } catch (ClassNotFoundException e) {
+ // The class may not be available.
+ generatorType = Generator.class;
+ }
+ }
return generatorType;
}
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationResult.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationResult.java
index 9a99727..e8cdb0d 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationResult.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationResult.java
@@ -15,13 +15,12 @@
*/
package com.google.gwt.core.ext.linker.impl;
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.CompilationResult;
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.dev.util.Util;
import java.io.File;
+import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.util.Collections;
import java.util.Comparator;
@@ -37,11 +36,8 @@
*/
public class StandardCompilationResult extends CompilationResult {
- /**
- * Smaller maps come before larger maps, then we compare the concatenation of
- * every value.
- */
- public static final Comparator<SortedMap<SelectionProperty, String>> MAP_COMPARATOR = new Comparator<SortedMap<SelectionProperty, String>>() {
+ private static final class MapComparator implements
+ Comparator<SortedMap<SelectionProperty, String>>, Serializable {
public int compare(SortedMap<SelectionProperty, String> arg0,
SortedMap<SelectionProperty, String> arg1) {
int diff = arg0.size() - arg1.size();
@@ -64,21 +60,25 @@
return sb0.toString().compareTo(sb1.toString());
}
- };
+ }
+
+ /**
+ * Smaller maps come before larger maps, then we compare the concatenation of
+ * every value.
+ */
+ public static final Comparator<SortedMap<SelectionProperty, String>> MAP_COMPARATOR = new MapComparator();
private final File cacheFile;
- private SoftReference<String> js;
+ private transient SoftReference<String> js;
private final SortedSet<SortedMap<SelectionProperty, String>> propertyValues = new TreeSet<SortedMap<SelectionProperty, String>>(
MAP_COMPARATOR);
private final String strongName;
- public StandardCompilationResult(TreeLogger logger, String js,
- String strongName, File cacheDir) throws UnableToCompleteException {
+ public StandardCompilationResult(String js, String strongName, File cacheFile) {
super(StandardLinkerContext.class);
this.js = new SoftReference<String>(js);
this.strongName = strongName;
- cacheFile = new File(cacheDir, strongName);
- Util.writeStringAsFile(logger, cacheFile, js);
+ this.cacheFile = cacheFile;
}
/**
@@ -93,9 +93,16 @@
}
public String getJavaScript() {
- String toReturn = js.get();
+ String toReturn = null;
+ if (js != null) {
+ toReturn = js.get();
+ }
if (toReturn == null) {
toReturn = Util.readFileAsString(cacheFile);
+ if (toReturn == null) {
+ throw new RuntimeException("Unexpectedly unable to read JS file '"
+ + cacheFile.getAbsolutePath() + "'");
+ }
js = new SoftReference<String>(toReturn);
}
return toReturn;
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 fbc9675..fc6e785 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
@@ -26,7 +26,6 @@
import com.google.gwt.core.ext.linker.PublicResource;
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
-import com.google.gwt.dev.GWTCompiler;
import com.google.gwt.dev.cfg.BindingProperty;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.Property;
@@ -112,63 +111,31 @@
};
private final ArtifactSet artifacts = new ArtifactSet();
- private final File compilationsDir;
+
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>();
- /**
- * This is the output directory for private files.
- */
- private final File moduleAuxDir;
private final String moduleFunctionName;
private final String moduleName;
- /**
- * This is the root directory for the output of a particular module's
- * compilation.
- */
- private final File moduleOutDir;
private final Map<String, StandardSelectionProperty> propertiesByName = new HashMap<String, StandardSelectionProperty>();
private final Map<String, StandardCompilationResult> resultsByStrongName = new HashMap<String, StandardCompilationResult>();
private final SortedSet<SelectionProperty> selectionProperties;
public StandardLinkerContext(TreeLogger logger, ModuleDef module,
- File moduleOutDir, File generatorDir, JJSOptions jjsOptions) {
+ JJSOptions jjsOptions) {
logger = logger.branch(TreeLogger.DEBUG,
"Constructing StandardLinkerContext", null);
this.jjsOptions = jjsOptions;
this.moduleFunctionName = module.getFunctionName();
this.moduleName = module.getName();
- this.moduleOutDir = moduleOutDir;
this.linkerClasses = new ArrayList<Class<? extends Linker>>(
module.getActiveLinkers());
linkerClasses.add(module.getActivePrimaryLinker());
- if (moduleOutDir != null) {
- compilationsDir = new File(moduleOutDir.getParentFile(),
- GWTCompiler.GWT_COMPILER_DIR + File.separator + moduleName
- + File.separator + "compilations");
-
- Util.recursiveDelete(compilationsDir, true);
- compilationsDir.mkdirs();
- logger.log(TreeLogger.SPAM, "compilationsDir: "
- + compilationsDir.getPath(), null);
-
- this.moduleAuxDir = new File(moduleOutDir.getParentFile(), moduleName
- + "-aux");
- if (moduleAuxDir.exists()) {
- Util.recursiveDelete(moduleAuxDir, false);
- }
- logger.log(TreeLogger.SPAM, "mouduleAuxDir: " + moduleAuxDir.getPath(),
- null);
- } else {
- compilationsDir = null;
- moduleAuxDir = null;
- }
-
for (Map.Entry<String, Class<? extends Linker>> entry : module.getLinkers().entrySet()) {
linkerShortNames.put(entry.getValue(), entry.getKey());
}
@@ -255,15 +222,19 @@
/**
* Gets or creates a CompilationResult for the given JavaScript program.
*/
- public StandardCompilationResult getCompilation(TreeLogger logger, String js)
+ public StandardCompilationResult getCompilation(TreeLogger logger, File jsFile)
throws UnableToCompleteException {
-
- byte[] bytes = Util.getBytes(js);
+ byte[] bytes = Util.readFileAsBytes(jsFile);
+ if (bytes == null) {
+ logger.log(TreeLogger.ERROR, "Unable to read file '"
+ + jsFile.getAbsolutePath() + "'");
+ throw new UnableToCompleteException();
+ }
String strongName = Util.computeStrongName(bytes);
StandardCompilationResult result = resultsByStrongName.get(strongName);
if (result == null) {
- result = new StandardCompilationResult(logger, js, strongName,
- compilationsDir);
+ result = new StandardCompilationResult(Util.toString(bytes), strongName,
+ jsFile);
resultsByStrongName.put(result.getStrongName(), result);
artifacts.add(result);
}
@@ -295,119 +266,10 @@
return propertiesByName.get(name);
}
- public boolean isOutputCompact() {
- return jjsOptions.getOutput().shouldMinimize();
- }
-
- @Override
- public ArtifactSet link(TreeLogger logger, LinkerContext context,
- ArtifactSet artifacts) throws UnableToCompleteException {
-
- logger = logger.branch(TreeLogger.INFO, "Linking compilation into "
- + moduleOutDir.getPath(), null);
-
- artifacts = invokeLinkerStack(logger);
-
- for (EmittedArtifact artifact : artifacts.find(EmittedArtifact.class)) {
- TreeLogger artifactLogger = logger.branch(TreeLogger.DEBUG,
- "Emitting resource " + artifact.getPartialPath(), null);
-
- File outFile;
- if (artifact.isPrivate()) {
- outFile = new File(getLinkerAuxDir(artifact.getLinker()),
- artifact.getPartialPath());
- } else {
- outFile = new File(moduleOutDir, artifact.getPartialPath());
- }
-
- assert !outFile.exists() : "Attempted to overwrite " + outFile.getPath();
- Util.copy(logger, artifact.getContents(artifactLogger), outFile);
- }
-
- return artifacts;
- }
-
- public String optimizeJavaScript(TreeLogger logger, String program)
- throws UnableToCompleteException {
- logger = logger.branch(TreeLogger.DEBUG, "Attempting to optimize JS", null);
- JsParser parser = new JsParser();
- Reader r = new StringReader(program);
- JsProgram jsProgram = new JsProgram();
- JsScope topScope = jsProgram.getScope();
- JsName funcName = topScope.declareName(getModuleFunctionName());
- funcName.setObfuscatable(false);
-
- try {
- SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(
- StandardLinkerContext.class, "Linker-derived JS");
- parser.setSourceInfo(sourceInfo);
- parser.parseInto(topScope, jsProgram.getGlobalBlock(), r, 1);
- } catch (IOException e) {
- logger.log(TreeLogger.ERROR, "Unable to parse JavaScript", e);
- throw new UnableToCompleteException();
- } catch (JsParserException e) {
- logger.log(TreeLogger.ERROR, "Unable to parse JavaScript", e);
- throw new UnableToCompleteException();
- }
-
- JsSymbolResolver.exec(jsProgram);
- JsUnusedFunctionRemover.exec(jsProgram);
-
- switch (jjsOptions.getOutput()) {
- case OBFUSCATED:
- /*
- * We can't apply the regular JsStringInterner to the JsProgram that
- * we've just created. In the normal case, the JsStringInterner adds an
- * additional statement to the program's global JsBlock, however we
- * don't know exactly what the form and structure of our JsProgram are,
- * so we'll limit the scope of the modifications to each top-level
- * function within the program.
- */
- TopFunctionStringInterner.exec(jsProgram);
- JsObfuscateNamer.exec(jsProgram);
- break;
- case PRETTY:
- // We don't intern strings in pretty mode to improve readability
- JsPrettyNamer.exec(jsProgram);
- break;
- case DETAILED:
- // As above with OBFUSCATED
- TopFunctionStringInterner.exec(jsProgram);
- JsVerboseNamer.exec(jsProgram);
- break;
- default:
- throw new InternalCompilerException("Unknown output mode");
- }
-
- DefaultTextOutput out = new DefaultTextOutput(
- jjsOptions.getOutput().shouldMinimize());
- JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out);
- v.accept(jsProgram);
- return out.toString();
- }
-
- /**
- * Creates a linker-specific subdirectory in the module's auxiliary output
- * directory.
- */
- private File getLinkerAuxDir(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));
- if (!toReturn.exists()) {
- toReturn.mkdirs();
- }
- return toReturn;
- }
-
/**
* Run the linker stack.
*/
- private ArtifactSet invokeLinkerStack(TreeLogger logger)
+ public ArtifactSet invokeLinkerStack(TreeLogger logger)
throws UnableToCompleteException {
ArtifactSet workingArtifacts = new ArtifactSet(artifacts);
Stack<Linker> linkerStack = new Stack<Linker>();
@@ -480,4 +342,115 @@
return workingArtifacts;
}
+
+ public boolean isOutputCompact() {
+ return jjsOptions.getOutput().shouldMinimize();
+ }
+
+ @Override
+ public ArtifactSet link(TreeLogger logger, LinkerContext context,
+ ArtifactSet artifacts) throws UnableToCompleteException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String optimizeJavaScript(TreeLogger logger, String program)
+ throws UnableToCompleteException {
+ logger = logger.branch(TreeLogger.DEBUG, "Attempting to optimize JS", null);
+ JsParser parser = new JsParser();
+ Reader r = new StringReader(program);
+ JsProgram jsProgram = new JsProgram();
+ JsScope topScope = jsProgram.getScope();
+ JsName funcName = topScope.declareName(getModuleFunctionName());
+ funcName.setObfuscatable(false);
+
+ try {
+ SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(
+ StandardLinkerContext.class, "Linker-derived JS");
+ parser.setSourceInfo(sourceInfo);
+ parser.parseInto(topScope, jsProgram.getGlobalBlock(), r, 1);
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to parse JavaScript", e);
+ throw new UnableToCompleteException();
+ } catch (JsParserException e) {
+ logger.log(TreeLogger.ERROR, "Unable to parse JavaScript", e);
+ throw new UnableToCompleteException();
+ }
+
+ JsSymbolResolver.exec(jsProgram);
+ JsUnusedFunctionRemover.exec(jsProgram);
+
+ switch (jjsOptions.getOutput()) {
+ case OBFUSCATED:
+ /*
+ * We can't apply the regular JsStringInterner to the JsProgram that
+ * we've just created. In the normal case, the JsStringInterner adds an
+ * additional statement to the program's global JsBlock, however we
+ * don't know exactly what the form and structure of our JsProgram are,
+ * so we'll limit the scope of the modifications to each top-level
+ * function within the program.
+ */
+ TopFunctionStringInterner.exec(jsProgram);
+ JsObfuscateNamer.exec(jsProgram);
+ break;
+ case PRETTY:
+ // We don't intern strings in pretty mode to improve readability
+ JsPrettyNamer.exec(jsProgram);
+ break;
+ case DETAILED:
+ // As above with OBFUSCATED
+ TopFunctionStringInterner.exec(jsProgram);
+ JsVerboseNamer.exec(jsProgram);
+ break;
+ default:
+ throw new InternalCompilerException("Unknown output mode");
+ }
+
+ DefaultTextOutput out = new DefaultTextOutput(
+ jjsOptions.getOutput().shouldMinimize());
+ JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out);
+ v.accept(jsProgram);
+ return out.toString();
+ }
+
+ public void produceOutputDirectory(TreeLogger logger, ArtifactSet artifacts,
+ File moduleOutDir, File moduleAuxDir) throws UnableToCompleteException {
+
+ logger = logger.branch(TreeLogger.INFO, "Linking compilation into "
+ + moduleOutDir.getPath(), null);
+
+ for (EmittedArtifact artifact : artifacts.find(EmittedArtifact.class)) {
+ TreeLogger artifactLogger = logger.branch(TreeLogger.DEBUG,
+ "Emitting resource " + artifact.getPartialPath(), null);
+
+ File outFile;
+ if (artifact.isPrivate()) {
+ outFile = new File(getLinkerAuxDir(moduleAuxDir, artifact.getLinker()),
+ artifact.getPartialPath());
+ } else {
+ outFile = new File(moduleOutDir, artifact.getPartialPath());
+ }
+
+ assert !outFile.exists() : "Attempted to overwrite " + outFile.getPath();
+ Util.copy(logger, artifact.getContents(artifactLogger), outFile);
+ }
+ }
+
+ /**
+ * Creates a linker-specific subdirectory in the module's auxiliary output
+ * directory.
+ */
+ private File getLinkerAuxDir(File moduleAuxDir,
+ 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));
+ if (!toReturn.exists()) {
+ toReturn.mkdirs();
+ }
+ return toReturn;
+ }
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java
index 401b1b8..2a1a0bd 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java
@@ -19,13 +19,37 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.PublicResource;
import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.util.Util;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.Serializable;
/**
* The standard implementation of {@link PublicResource}.
*/
public class StandardPublicResource extends PublicResource {
+
+ /**
+ * Serializes a public resource via a snapshot of the content.
+ */
+ private static final class SerializedPublicResource extends PublicResource {
+ private final byte[] data;
+
+ protected SerializedPublicResource(String partialPath, byte[] data) {
+ super(StandardLinkerContext.class, partialPath);
+ this.data = data;
+ }
+
+ @Override
+ public InputStream getContents(TreeLogger logger)
+ throws UnableToCompleteException {
+ return new ByteArrayInputStream(data);
+ }
+ }
+
private final Resource resource;
public StandardPublicResource(String partialPath, Resource resource) {
@@ -38,4 +62,18 @@
throws UnableToCompleteException {
return resource.openContents();
}
+
+ private Object writeReplace() {
+ if (resource instanceof Serializable) {
+ return this;
+ }
+ // Resource is not serializable, must replace myself.
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Util.copy(resource.openContents(), baos);
+ return new SerializedPublicResource(getPartialPath(), baos.toByteArray());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSelectionProperty.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSelectionProperty.java
index 14972c1..5f71786 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSelectionProperty.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSelectionProperty.java
@@ -40,8 +40,7 @@
activeValue = null;
}
name = p.getName();
- provider = p.getProvider() == null ? null
- : p.getProvider().getBody().toSource();
+ provider = p.getProvider() == null ? null : p.getProvider().getBody();
values = Collections.unmodifiableSortedSet(new TreeSet<String>(
Arrays.asList(p.getDefinedValues())));
}
diff --git a/dev/core/src/com/google/gwt/dev/CompilePerms.java b/dev/core/src/com/google/gwt/dev/CompilePerms.java
new file mode 100644
index 0000000..17b1042
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/CompilePerms.java
@@ -0,0 +1,267 @@
+/*
+ * 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.dev.CompileTaskRunner.CompileTask;
+import com.google.gwt.dev.PermutationCompiler.ResultsHandler;
+import com.google.gwt.dev.jjs.UnifiedAst;
+import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.util.tools.ArgHandlerString;
+
+import java.io.File;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Performs the first phase of compilation, generating the set of permutations
+ * to compile, and a ready-to-compile AST.
+ */
+public class CompilePerms {
+
+ /**
+ * Options for CompilePerms.
+ */
+ public interface CompilePermsOptions extends CompileTaskOptions, OptionPerms {
+ }
+
+ /**
+ * Handles options for which permutations to compile.
+ */
+ public interface OptionPerms {
+ /**
+ * Gets the ordered set of permutations to compile. Returns a zero-length
+ * array if all permutations should be compiled.
+ */
+ int[] getPermsToCompile();
+
+ /**
+ * Adds another permutation to compile.
+ */
+ void setPermsToCompile(int[] permsToCompile);
+ }
+
+ /**
+ * Argument handler for specifying the which perms to run.
+ */
+ protected static final class ArgHandlerPerms extends ArgHandlerString {
+ private final OptionPerms option;
+
+ public ArgHandlerPerms(OptionPerms option) {
+ this.option = option;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Comma-delimited list of 0-based permutations to compile";
+ }
+
+ @Override
+ public String getTag() {
+ return "-perms";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"permlist"};
+ }
+
+ @Override
+ public boolean setString(String str) {
+ String[] split = str.split(",");
+ if (split.length < 1) {
+ System.err.println(getTag()
+ + " requires a comma-delimited list of integers");
+ return false;
+ }
+
+ SortedSet<Integer> permSet = new TreeSet<Integer>();
+ for (String item : split) {
+ try {
+ int value = Integer.parseInt(item);
+ if (value < 0) {
+ System.err.println(getTag() + " error: negative value '" + value
+ + "' is not allowed");
+ return false;
+ }
+ permSet.add(value);
+ } catch (NumberFormatException e) {
+ System.err.println(getTag()
+ + " requires a comma-delimited list of integers; '" + item
+ + "' is not an integer");
+ return false;
+ }
+ }
+ int[] permsToCompile = new int[permSet.size()];
+ int i = 0;
+ for (int perm : permSet) {
+ permsToCompile[i++] = perm;
+ }
+ option.setPermsToCompile(permsToCompile);
+ return true;
+ }
+ }
+ static class ArgProcessor extends Link.ArgProcessor {
+ public ArgProcessor(CompilePermsOptions options) {
+ super(options);
+ registerHandler(new ArgHandlerPerms(options));
+ }
+
+ @Override
+ protected String getName() {
+ return CompilePerms.class.getName();
+ }
+ }
+
+ /**
+ * Concrete class to implement all compiler options.
+ */
+ static class CompilePermsOptionsImpl extends CompileTaskOptionsImpl implements
+ CompilePermsOptions {
+
+ private int[] permsToCompile = new int[0];
+
+ public CompilePermsOptionsImpl() {
+ }
+
+ public CompilePermsOptionsImpl(CompilePermsOptions other) {
+ copyFrom(other);
+ }
+
+ public void copyFrom(CompilePermsOptions other) {
+ super.copyFrom(other);
+
+ setPermsToCompile(other.getPermsToCompile());
+ }
+
+ public int[] getPermsToCompile() {
+ return permsToCompile.clone();
+ }
+
+ public void setPermsToCompile(int[] permsToCompile) {
+ this.permsToCompile = permsToCompile.clone();
+ }
+ }
+
+ public static String compile(TreeLogger logger, Permutation permutation,
+ UnifiedAst unifiedAst) {
+ try {
+ return JavaToJavaScriptCompiler.compilePermutation(logger, unifiedAst,
+ permutation.getRebindAnswers());
+ } catch (UnableToCompleteException e) {
+ // We intentionally don't pass in the exception here since the real
+ // cause has been logged.
+ return null;
+ }
+ }
+
+ 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.
+ */
+ final CompilePermsOptions options = new CompilePermsOptionsImpl();
+ if (new ArgProcessor(options).processArgs(args)) {
+ CompileTask task = new CompileTask() {
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ return new CompilePerms(options).run(logger);
+ }
+ };
+ if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
+ // Exit w/ success code.
+ System.exit(0);
+ }
+ }
+ // Exit w/ non-success code.
+ System.exit(1);
+ }
+
+ /**
+ * Return the filename corresponding to the given permutation number,
+ * one-based.
+ */
+ static File makePermFilename(File compilerWorkDir, int permNumber) {
+ return new File(compilerWorkDir, "permutation-" + permNumber + ".js");
+ }
+
+ private final CompilePermsOptionsImpl options;
+
+ public CompilePerms(CompilePermsOptions options) {
+ this.options = new CompilePermsOptionsImpl(options);
+ }
+
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ File precompilationFile = new File(options.getCompilerWorkDir(),
+ Precompile.PRECOMPILATION_FILENAME);
+ if (!precompilationFile.exists()) {
+ logger.log(TreeLogger.ERROR, "File not found '"
+ + precompilationFile.getAbsolutePath()
+ + "'; please run Precompile first");
+ return false;
+ }
+ Precompilation precompilation;
+ try {
+ /*
+ * TODO: don't bother deserializing the generated artifacts.
+ */
+ precompilation = Util.readFileAsObject(precompilationFile,
+ Precompilation.class);
+ } catch (ClassNotFoundException e) {
+ logger.log(TreeLogger.ERROR, "Unable to deserialize '"
+ + precompilationFile.getAbsolutePath() + "'", e);
+ return false;
+ }
+ Permutation[] perms = precompilation.getPermutations();
+ UnifiedAst unifiedAst = precompilation.getUnifiedAst();
+ int[] permsToRun = options.getPermsToCompile();
+
+ if (permsToRun.length == 0) {
+ // Compile them all.
+ permsToRun = new int[perms.length];
+ for (int i = 0; i < permsToRun.length; ++i) {
+ permsToRun[i] = i;
+ }
+ } else {
+ // Range check the supplied perms.
+ for (int permToRun : permsToRun) {
+ if (permToRun >= perms.length) {
+ logger.log(TreeLogger.ERROR, "The specified perm number '"
+ + permToRun + "' is too big; the maximum value is "
+ + (perms.length - 1) + "'");
+ return false;
+ }
+ }
+ }
+
+ final TreeLogger branch = logger.branch(TreeLogger.INFO, "Compiling "
+ + permsToRun.length + " permutations");
+ PermutationCompiler multiThread = new PermutationCompiler(branch,
+ unifiedAst, perms, permsToRun);
+ multiThread.go(new ResultsHandler() {
+ public void addResult(Permutation permutation, int permNum, String js)
+ throws UnableToCompleteException {
+ Util.writeStringAsFile(branch, makePermFilename(
+ options.getCompilerWorkDir(), permNum), js);
+ }
+ });
+ branch.log(TreeLogger.INFO, "Permutation compile succeeded");
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/CompileTaskOptions.java b/dev/core/src/com/google/gwt/dev/CompileTaskOptions.java
new file mode 100644
index 0000000..dd345fc
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/CompileTaskOptions.java
@@ -0,0 +1,28 @@
+/*
+ * 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.OptionGuiLogger;
+import com.google.gwt.dev.util.arg.OptionLogLevel;
+import com.google.gwt.dev.util.arg.OptionModuleName;
+import com.google.gwt.dev.util.arg.OptionOutDir;
+
+/**
+ * A common set of options for all compile tasks.
+ */
+public interface CompileTaskOptions extends OptionGuiLogger, OptionModuleName,
+ OptionLogLevel, OptionOutDir {
+}
diff --git a/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java b/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java
new file mode 100644
index 0000000..b2f0295
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java
@@ -0,0 +1,90 @@
+/*
+ * 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 java.io.File;
+
+/**
+ * Concrete class to implement compiler task options.
+ */
+class CompileTaskOptionsImpl implements CompileTaskOptions {
+
+ public static final String GWT_COMPILER_DIR = ".gwt-tmp" + File.separatorChar
+ + "compiler";
+
+ private File compilerWorkDir;
+ private Type logLevel;
+ private String moduleName;
+ private File outDir;
+ private boolean useGuiLogger;
+
+ public CompileTaskOptionsImpl() {
+ }
+
+ public CompileTaskOptionsImpl(CompileTaskOptions other) {
+ copyFrom(other);
+ }
+
+ public void copyFrom(CompileTaskOptions other) {
+ setLogLevel(other.getLogLevel());
+ setModuleName(other.getModuleName());
+ setOutDir(other.getOutDir());
+ setUseGuiLogger(other.isUseGuiLogger());
+ }
+
+ public File getCompilerWorkDir() {
+ if (compilerWorkDir == null) {
+ compilerWorkDir = new File(getOutDir(), GWT_COMPILER_DIR + File.separator
+ + moduleName);
+ }
+ return compilerWorkDir;
+ }
+
+ public Type getLogLevel() {
+ return logLevel;
+ }
+
+ public String getModuleName() {
+ return moduleName;
+ }
+
+ public File getOutDir() {
+ return outDir;
+ }
+
+ public boolean isUseGuiLogger() {
+ return useGuiLogger;
+ }
+
+ 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;
+ }
+
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/CompileTaskRunner.java b/dev/core/src/com/google/gwt/dev/CompileTaskRunner.java
new file mode 100644
index 0000000..a5efcfb
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/CompileTaskRunner.java
@@ -0,0 +1,119 @@
+/*
+ * 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.dev.util.log.AbstractTreeLogger;
+import com.google.gwt.dev.util.log.DetachedTreeLoggerWindow;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+
+/**
+ * Used to run compiler tasks with the appropriate logger.
+ */
+public class CompileTaskRunner {
+
+ /**
+ * A task to run with a logger based on options.
+ */
+ public interface CompileTask {
+ boolean run(TreeLogger logger) throws UnableToCompleteException;
+ }
+
+ /**
+ * Runs the main action with an appropriate logger. If a gui-based TreeLogger
+ * is used, this method will not return until its window is closed by the
+ * user.
+ */
+ public static boolean runWithAppropriateLogger(CompileTaskOptions options,
+ final CompileTask task) {
+ // Set any platform specific system properties.
+ BootStrapPlatform.applyPlatformHacks();
+
+ if (options.isUseGuiLogger()) {
+ // Initialize a tree logger window.
+ DetachedTreeLoggerWindow loggerWindow = DetachedTreeLoggerWindow.getInstance(
+ "Build Output for " + options.getModuleName(), 800, 600, true);
+
+ // Eager AWT initialization for OS X to ensure safe coexistence with SWT.
+ BootStrapPlatform.maybeInitializeAWT();
+
+ final AbstractTreeLogger logger = loggerWindow.getLogger();
+ logger.setMaxDetail(options.getLogLevel());
+ final boolean[] success = new boolean[1];
+
+ // Compiler will be spawned onto a second thread, UI thread for tree
+ // logger will remain on the main.
+ Thread compilerThread = new Thread(new Runnable() {
+ public void run() {
+ success[0] = doRun(logger, task);
+ }
+ });
+
+ compilerThread.setName("GWTCompiler Thread");
+ compilerThread.start();
+ loggerWindow.run();
+
+ // Even if the tree logger window is closed, we wait for the compiler
+ // to finish.
+ waitForThreadToTerminate(compilerThread);
+
+ return success[0];
+ } else {
+ PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
+ logger.setMaxDetail(options.getLogLevel());
+ return doRun(logger, task);
+ }
+ }
+
+ private static boolean doRun(TreeLogger logger, CompileTask task) {
+ try {
+ return task.run(logger);
+ } catch (UnableToCompleteException e) {
+ // Assume logged.
+ } catch (Throwable e) {
+ logger.log(TreeLogger.ERROR, "Unexpected", e);
+ }
+ return false;
+ }
+
+ /**
+ * Waits for a thread to terminate before it returns. This method is a
+ * non-cancellable task, in that it will defer thread interruption until it is
+ * done.
+ *
+ * @param godot the thread that is being waited on.
+ */
+ private static void waitForThreadToTerminate(final Thread godot) {
+ // Goetz pattern for non-cancellable tasks.
+ // http://www-128.ibm.com/developerworks/java/library/j-jtp05236.html
+ boolean isInterrupted = false;
+ try {
+ while (true) {
+ try {
+ godot.join();
+ return;
+ } catch (InterruptedException e) {
+ isInterrupted = true;
+ }
+ }
+ } finally {
+ if (isInterrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/CompilerOptions.java b/dev/core/src/com/google/gwt/dev/CompilerOptions.java
new file mode 100644
index 0000000..85b4afc
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/CompilerOptions.java
@@ -0,0 +1,27 @@
+/*
+ * 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.OptionGenDir;
+import com.google.gwt.dev.util.arg.OptionValidateOnly;
+
+/**
+ * The complete set of options for the GWT compiler.
+ */
+public interface CompilerOptions extends JJSOptions, CompileTaskOptions,
+ OptionGenDir, OptionValidateOnly {
+}
diff --git a/dev/core/src/com/google/gwt/dev/CompilerOptionsImpl.java b/dev/core/src/com/google/gwt/dev/CompilerOptionsImpl.java
new file mode 100644
index 0000000..dcc29bf
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/CompilerOptionsImpl.java
@@ -0,0 +1,98 @@
+/*
+ * 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 b11b457..3f89bfd 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -17,173 +17,26 @@
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.impl.StandardLinkerContext;
-import com.google.gwt.dev.cfg.BindingProperty;
-import com.google.gwt.dev.cfg.ConfigurationProperty;
-import com.google.gwt.dev.cfg.ModuleDef;
-import com.google.gwt.dev.cfg.ModuleDefLoader;
-import com.google.gwt.dev.cfg.PropertyPermutations;
-import com.google.gwt.dev.cfg.Rules;
-import com.google.gwt.dev.cfg.StaticPropertyOracle;
-import com.google.gwt.dev.javac.CompilationState;
-import com.google.gwt.dev.javac.CompilationUnit;
-import com.google.gwt.dev.jdt.RebindOracle;
-import com.google.gwt.dev.jdt.RebindPermutationOracle;
-import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
-import com.google.gwt.dev.jjs.JJSOptions;
-import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
-import com.google.gwt.dev.jjs.JsOutputOption;
-import com.google.gwt.dev.shell.StandardRebindOracle;
-import com.google.gwt.dev.util.PerfLogger;
-import com.google.gwt.dev.util.Util;
-import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
-import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
-import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
-import com.google.gwt.dev.util.arg.ArgHandlerTreeLoggerFlag;
-import com.google.gwt.dev.util.log.AbstractTreeLogger;
-import com.google.gwt.dev.util.log.DetachedTreeLoggerWindow;
-import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
-import com.google.gwt.util.tools.ArgHandlerDisableAggressiveOptimization;
-import com.google.gwt.util.tools.ArgHandlerEnableAssertions;
-import com.google.gwt.util.tools.ArgHandlerExtra;
-import com.google.gwt.util.tools.ArgHandlerFlag;
-import com.google.gwt.util.tools.ArgHandlerOutDir;
-import com.google.gwt.util.tools.ArgHandlerString;
-import com.google.gwt.util.tools.ToolBase;
-
-import java.io.File;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.SortedSet;
+import com.google.gwt.dev.CompilePerms.CompilePermsOptionsImpl;
+import com.google.gwt.dev.CompileTaskRunner.CompileTask;
+import com.google.gwt.dev.Precompile.CompilerOptionsImpl;
/**
* The main executable entry point for the GWT Java to JavaScript compiler.
*/
-public class GWTCompiler extends ToolBase {
+public class GWTCompiler {
- private class ArgHandlerModuleName extends ArgHandlerExtra {
-
- @Override
- public boolean addExtraArg(String arg) {
- setModuleName(arg);
- return true;
+ static final class ArgProcessor extends Precompile.ArgProcessor {
+ public ArgProcessor(CompilerOptions options) {
+ super(options);
}
@Override
- public String getPurpose() {
- return "Specifies the name of the module to compile";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"module"};
- }
-
- @Override
- public boolean isRequired() {
- return true;
+ protected String getName() {
+ return GWTCompiler.class.getName();
}
}
- private class ArgHandlerStoryOfYourCompile extends ArgHandlerString {
- @Override
- public String getPurpose() {
- return "Generate the story of your compile";
- }
-
- @Override
- public String getTag() {
- return "-soyc";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"/path/to/report/dir"};
- }
-
- @Override
- public boolean setString(String str) {
- jjsOptions.setSoycOutputDir(str);
- return true;
- }
- }
-
- /**
- * Argument handler for making the compiler run in "validation" mode.
- */
- private class ArgHandlerValidateOnlyFlag extends ArgHandlerFlag {
-
- public String getPurpose() {
- return "Validate all source code, but do not compile";
- }
-
- public String getTag() {
- return "-validateOnly";
- }
-
- public boolean setFlag() {
- jjsOptions.setValidateOnly(true);
- return true;
- }
- }
-
- private class DistillerRebindPermutationOracle implements
- RebindPermutationOracle {
-
- private StaticPropertyOracle[] propertyOracles;
- private RebindOracle[] rebindOracles;
-
- public DistillerRebindPermutationOracle(ArtifactSet generatorArtifacts,
- PropertyPermutations perms) {
- propertyOracles = new StaticPropertyOracle[perms.size()];
- rebindOracles = new RebindOracle[perms.size()];
- BindingProperty[] orderedProps = perms.getOrderedProperties();
- SortedSet<ConfigurationProperty> configPropSet = module.getProperties().getConfigurationProperties();
- ConfigurationProperty[] configProps = configPropSet.toArray(new ConfigurationProperty[configPropSet.size()]);
- for (int i = 0; i < rebindOracles.length; ++i) {
- String[] orderedPropValues = perms.getOrderedPropertyValues(i);
- propertyOracles[i] = new StaticPropertyOracle(orderedProps,
- orderedPropValues, configProps);
- rebindOracles[i] = new StandardRebindOracle(compilationState,
- propertyOracles[i], module, rules, genDir, generatorResourcesDir,
- generatorArtifacts);
- }
- }
-
- public String[] getAllPossibleRebindAnswers(TreeLogger logger,
- String requestTypeName) throws UnableToCompleteException {
-
- String msg = "Computing all possible rebind results for '"
- + requestTypeName + "'";
- logger = logger.branch(TreeLogger.DEBUG, msg, null);
-
- Set<String> answers = new HashSet<String>();
-
- for (RebindOracle rebindOracle : rebindOracles) {
- String resultTypeName = rebindOracle.rebind(logger, requestTypeName);
- answers.add(resultTypeName);
- }
- return Util.toArray(String.class, answers);
- }
-
- public int getPermuationCount() {
- return rebindOracles.length;
- }
-
- public StaticPropertyOracle getPropertyOracle(int permNumber) {
- return propertyOracles[permNumber];
- }
-
- public RebindOracle getRebindOracle(int permNumber) {
- return rebindOracles[permNumber];
- }
- }
-
- public static final String GWT_COMPILER_DIR = ".gwt-tmp" + File.separatorChar
- + "compiler";
-
public static void main(String[] args) {
/*
* NOTE: main always exits with a call to System.exit to terminate any
@@ -191,9 +44,14 @@
* shutdown AWT related threads, since the contract for their termination is
* still implementation-dependent.
*/
- GWTCompiler compiler = new GWTCompiler();
- if (compiler.processArgs(args)) {
- if (compiler.run()) {
+ final CompilerOptions options = new CompilerOptionsImpl();
+ if (new ArgProcessor(options).processArgs(args)) {
+ CompileTask task = new CompileTask() {
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ return new GWTCompiler(options).run(logger);
+ }
+ };
+ if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
// Exit w/ success code.
System.exit(0);
}
@@ -202,305 +60,34 @@
System.exit(1);
}
- private CompilationState compilationState;
+ private final CompilerOptionsImpl options;
- private File genDir;
-
- private File generatorResourcesDir;
-
- private JJSOptions jjsOptions = new JJSOptions();
-
- private Type logLevel;
-
- private ModuleDef module;
-
- private String moduleName;
-
- private File outDir;
-
- private Rules rules;
-
- private boolean useGuiLogger;
-
- public GWTCompiler() {
- registerHandler(new ArgHandlerLogLevel() {
- @Override
- public void setLogLevel(Type level) {
- logLevel = level;
- }
- });
-
- registerHandler(new ArgHandlerGenDir() {
- @Override
- public void setDir(File dir) {
- genDir = dir;
- }
- });
-
- registerHandler(new ArgHandlerOutDir() {
- @Override
- public void setDir(File dir) {
- outDir = dir;
- }
- });
-
- registerHandler(new ArgHandlerTreeLoggerFlag() {
- @Override
- public boolean setFlag() {
- useGuiLogger = true;
- return true;
- }
- });
-
- registerHandler(new ArgHandlerModuleName());
-
- registerHandler(new ArgHandlerScriptStyle(jjsOptions));
-
- registerHandler(new ArgHandlerStoryOfYourCompile());
-
- registerHandler(new ArgHandlerEnableAssertions(jjsOptions));
-
- registerHandler(new ArgHandlerDisableAggressiveOptimization() {
- @Override
- public boolean setFlag() {
- GWTCompiler.this.setAggressivelyOptimize(false);
- return true;
- }
- });
-
- registerHandler(new ArgHandlerValidateOnlyFlag());
+ public GWTCompiler(CompilerOptions options) {
+ this.options = new CompilerOptionsImpl(options);
}
- public void distill(TreeLogger logger, ModuleDef moduleDef)
- throws UnableToCompleteException {
- this.module = moduleDef;
- this.compilationState = moduleDef.getCompilationState();
-
- // Set up all the initial state.
- checkModule(logger);
-
- // Place generated resources inside the out dir as a sibling to the module
- generatorResourcesDir = new File(outDir, GWT_COMPILER_DIR + File.separator
- + moduleDef.getName() + File.separator + "generated");
-
- // Tweak the output directory so that output lives under the module name.
- outDir = new File(outDir, module.getName());
-
- // Clean the outDir.
- Util.recursiveDelete(outDir, true);
-
- // Clean out the generated resources directory and/or create it.
- Util.recursiveDelete(generatorResourcesDir, true);
- generatorResourcesDir.mkdirs();
-
- // TODO: All JDT checks now before even building TypeOracle?
- compilationState.compile(logger);
-
- rules = module.getRules();
- String[] declEntryPts;
- if (jjsOptions.isValidateOnly()) {
- // TODO: revisit this.. do we even need to run JJS?
- logger.log(TreeLogger.INFO, "Validating compilation " + module.getName(),
- null);
- // Pretend that every single compilation unit is an entry point.
- Set<CompilationUnit> compilationUnits = compilationState.getCompilationUnits();
- declEntryPts = new String[compilationUnits.size()];
- int i = 0;
- for (CompilationUnit unit : compilationUnits) {
- declEntryPts[i++] = unit.getTypeName();
- }
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ if (options.isValidateOnly()) {
+ return new Precompile(options).run(logger);
} else {
- logger.log(TreeLogger.INFO, "Compiling module " + module.getName(), null);
- // Use the real entry points.
- declEntryPts = module.getEntryPointTypeNames();
- }
-
- ArtifactSet generatorArtifacts = new ArtifactSet();
- DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
- generatorArtifacts, new PropertyPermutations(module.getProperties()));
-
- WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
- compilationState, rpo);
- JavaToJavaScriptCompiler jjs = new JavaToJavaScriptCompiler(logger,
- frontEnd, declEntryPts, jjsOptions);
-
- if (jjsOptions.isValidateOnly()) {
- logger.log(TreeLogger.INFO, "Validation succeeded", null);
- return;
- }
-
- StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
- module, outDir, generatorResourcesDir, jjsOptions);
- compilePermutations(logger, jjs, rpo, linkerContext);
-
- logger.log(TreeLogger.INFO, "Compilation succeeded", null);
- linkerContext.addOrReplaceArtifacts(generatorArtifacts);
- linkerContext.link(logger, linkerContext, null);
- }
-
- public File getGenDir() {
- return genDir;
- }
-
- public Type getLogLevel() {
- return logLevel;
- }
-
- public String getModuleName() {
- return moduleName;
- }
-
- public boolean getUseGuiLogger() {
- return useGuiLogger;
- }
-
- public void setAggressivelyOptimize(boolean aggressive) {
- jjsOptions.setAggressivelyOptimize(aggressive);
- }
-
- public void setCompilerOptions(JJSOptions options) {
- jjsOptions.copyFrom(options);
- }
-
- public void setGenDir(File dir) {
- genDir = dir;
- }
-
- public void setLogLevel(Type level) {
- this.logLevel = level;
- }
-
- public void setModuleName(String name) {
- moduleName = name;
- }
-
- public void setOutDir(File outDir) {
- this.outDir = outDir;
- }
-
- public void setStyleDetailed() {
- jjsOptions.setOutput(JsOutputOption.DETAILED);
- }
-
- public void setStyleObfuscated() {
- jjsOptions.setOutput(JsOutputOption.OBFUSCATED);
- }
-
- public void setStylePretty() {
- jjsOptions.setOutput(JsOutputOption.PRETTY);
- }
-
- /**
- * Ensure the module has at least one entry point (except in validation mode).
- */
- private void checkModule(TreeLogger logger) throws UnableToCompleteException {
- if (!jjsOptions.isValidateOnly()
- && module.getEntryPointTypeNames().length == 0) {
- logger.log(TreeLogger.ERROR, "Module has no entry points defined", null);
- throw new UnableToCompleteException();
- }
- }
-
- private void compilePermutations(TreeLogger logger,
- JavaToJavaScriptCompiler jjs, DistillerRebindPermutationOracle rpo,
- StandardLinkerContext linkerContext) throws UnableToCompleteException {
-
- int permCount = rpo.getPermuationCount();
- PerfLogger.start("Compiling " + permCount + " permutations");
- Permutation[] perms = new Permutation[permCount];
- for (int i = 0; i < permCount; ++i) {
- perms[i] = new Permutation(i, rpo.getRebindOracle(i),
- rpo.getPropertyOracle(i));
- }
- PermutationCompiler permCompiler = new PermutationCompiler(logger, jjs,
- perms);
- permCompiler.go(linkerContext);
- }
-
- /**
- * Runs the compiler. If a gui-based TreeLogger is used, this method will not
- * return until its window is closed by the user.
- *
- * @return success from the compiler, <code>true</code> if the compile
- * completed without errors, <code>false</code> otherwise.
- */
- private boolean run() {
- // Set any platform specific system properties.
- BootStrapPlatform.applyPlatformHacks();
-
- if (useGuiLogger) {
- // Initialize a tree logger window.
- DetachedTreeLoggerWindow loggerWindow = DetachedTreeLoggerWindow.getInstance(
- "Build Output for " + moduleName, 800, 600, true);
-
- // Eager AWT initialization for OS X to ensure safe coexistence with SWT.
- BootStrapPlatform.maybeInitializeAWT();
-
- final AbstractTreeLogger logger = loggerWindow.getLogger();
- final boolean[] success = new boolean[1];
-
- // Compiler will be spawned onto a second thread, UI thread for tree
- // logger will remain on the main.
- Thread compilerThread = new Thread(new Runnable() {
- public void run() {
- success[0] = GWTCompiler.this.run(logger);
+ logger = logger.branch(TreeLogger.INFO, "Compiling module "
+ + options.getModuleName());
+ if (new Precompile(options).run(logger)) {
+ /*
+ * TODO: use the in-memory result of Precompile to run CompilePerms
+ * instead of serializing through the file system.
+ */
+ CompilePermsOptionsImpl permsOptions = new CompilePermsOptionsImpl();
+ permsOptions.copyFrom(options);
+ if (new CompilePerms(permsOptions).run(logger)) {
+ if (new Link(options).run(logger)) {
+ logger.log(TreeLogger.INFO, "Compilation succeeded");
+ return true;
+ }
}
- });
-
- compilerThread.setName("GWTCompiler Thread");
- compilerThread.start();
- loggerWindow.run();
-
- // Even if the tree logger window is closed, we wait for the compiler
- // to finish.
- waitForThreadToTerminate(compilerThread);
-
- return success[0];
- } else {
- return run(new PrintWriterTreeLogger());
- }
- }
-
- private boolean run(AbstractTreeLogger logger) {
- try {
- logger.setMaxDetail(logLevel);
-
- ModuleDef moduleDef = ModuleDefLoader.loadFromClassPath(logger,
- moduleName);
- distill(logger, moduleDef);
- return true;
- } catch (UnableToCompleteException e) {
- // We intentionally don't pass in the exception here since the real
- // cause has been logged.
- logger.log(TreeLogger.ERROR, "Build failed", null);
+ }
+ logger.log(TreeLogger.ERROR, "Compilation failed");
return false;
}
}
-
- /**
- * Waits for a thread to terminate before it returns. This method is a
- * non-cancellable task, in that it will defer thread interruption until it is
- * done.
- *
- * @param godot the thread that is being waited on.
- */
- private void waitForThreadToTerminate(final Thread godot) {
- // Goetz pattern for non-cancellable tasks.
- // http://www-128.ibm.com/developerworks/java/library/j-jtp05236.html
- boolean isInterrupted = false;
- try {
- while (true) {
- try {
- godot.join();
- return;
- } catch (InterruptedException e) {
- isInterrupted = true;
- }
- }
- } finally {
- if (isInterrupted) {
- Thread.currentThread().interrupt();
- }
- }
- }
}
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 663a4e8..7a56d3d 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -19,9 +19,9 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.Precompile.CompilerOptionsImpl;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
-import com.google.gwt.dev.jjs.JJSOptions;
import com.google.gwt.dev.shell.BrowserWidget;
import com.google.gwt.dev.shell.BrowserWidgetHost;
import com.google.gwt.dev.shell.BrowserWidgetHostChecker;
@@ -32,15 +32,15 @@
import com.google.gwt.dev.shell.ShellModuleSpaceHost;
import com.google.gwt.dev.shell.tomcat.EmbeddedTomcatServer;
import com.google.gwt.dev.util.PerfLogger;
+import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
+import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
+import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
-import com.google.gwt.util.tools.ArgHandlerDisableAggressiveOptimization;
-import com.google.gwt.util.tools.ArgHandlerEnableAssertions;
import com.google.gwt.util.tools.ArgHandlerExtra;
import com.google.gwt.util.tools.ArgHandlerFlag;
-import com.google.gwt.util.tools.ArgHandlerOutDir;
import com.google.gwt.util.tools.ArgHandlerString;
import com.google.gwt.util.tools.ToolBase;
@@ -246,12 +246,12 @@
// Create a sandbox for the module.
//
- File shellDir = new File(outDir, GWT_SHELL_PATH + File.separator
- + moduleName);
+ File shellDir = new File(options.getOutDir(), GWT_SHELL_PATH
+ + File.separator + moduleName);
TypeOracle typeOracle = moduleDef.getTypeOracle(logger);
ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(logger,
- typeOracle, moduleDef, genDir, shellDir);
+ typeOracle, moduleDef, options.getGenDir(), shellDir);
return host;
} finally {
Cursor normalCursor = display.getSystemCursor(SWT.CURSOR_ARROW);
@@ -365,8 +365,6 @@
*/
protected final Display display = Display.getDefault();
- protected File outDir;
-
/**
* Cheat on the first load's refresh by assuming the module loaded by
* {@link com.google.gwt.dev.shell.GWTShellServlet} is still fresh. This
@@ -379,16 +377,12 @@
private final List<Shell> browserShells = new ArrayList<Shell>();
- private File genDir;
-
private boolean headlessMode = false;
- private final JJSOptions jjsOptions = new JJSOptions();
-
- private TreeLogger.Type logLevel;
-
private ShellMainWindow mainWnd;
+ private final CompilerOptionsImpl options = new CompilerOptionsImpl();
+
private int port;
private boolean runTomcat = true;
@@ -411,47 +405,21 @@
registerHandler(new ArgHandlerWhitelist());
registerHandler(new ArgHandlerBlacklist());
- registerHandler(new ArgHandlerLogLevel() {
- @Override
- protected Type getDefaultLogLevel() {
- return doGetDefaultLogLevel();
- }
+ registerHandler(new ArgHandlerLogLevel(options));
- @Override
- public void setLogLevel(Type level) {
- logLevel = level;
- }
- });
-
- registerHandler(new ArgHandlerGenDir() {
- @Override
- public void setDir(File dir) {
- genDir = dir;
- }
- });
+ registerHandler(new ArgHandlerGenDir(options));
if (!noURLs) {
registerHandler(new ArgHandlerStartupURLs());
}
- registerHandler(new ArgHandlerOutDir() {
- @Override
- public void setDir(File dir) {
- outDir = dir;
- }
- });
+ registerHandler(new ArgHandlerOutDir(options));
- registerHandler(new ArgHandlerScriptStyle(jjsOptions));
+ registerHandler(new ArgHandlerScriptStyle(options));
- registerHandler(new ArgHandlerEnableAssertions(jjsOptions));
+ registerHandler(new ArgHandlerEnableAssertions(options));
- registerHandler(new ArgHandlerDisableAggressiveOptimization() {
- @Override
- public boolean setFlag() {
- jjsOptions.setAggressivelyOptimize(false);
- return true;
- }
- });
+ registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
}
public void addStartupURL(String url) {
@@ -464,16 +432,8 @@
}
}
- public File getGenDir() {
- return genDir;
- }
-
- public Type getLogLevel() {
- return logLevel;
- }
-
- public File getOutDir() {
- return outDir;
+ public CompilerOptions getCompilerOptions() {
+ return new CompilerOptionsImpl(options);
}
public int getPort() {
@@ -599,20 +559,8 @@
}
}
- public void setCompilerOptions(JJSOptions options) {
- jjsOptions.copyFrom(options);
- }
-
- public void setGenDir(File genDir) {
- this.genDir = genDir;
- }
-
- public void setLogLevel(Type level) {
- this.logLevel = level;
- }
-
- public void setOutDir(File outDir) {
- this.outDir = outDir;
+ public void setCompilerOptions(CompilerOptions options) {
+ this.options.copyFrom(options);
}
public void setPort(int port) {
@@ -630,13 +578,9 @@
*/
protected void compile(TreeLogger logger, ModuleDef moduleDef)
throws UnableToCompleteException {
- GWTCompiler compiler = new GWTCompiler();
- compiler.setCompilerOptions(jjsOptions);
- compiler.setGenDir(genDir);
- compiler.setOutDir(outDir);
- compiler.setModuleName(moduleDef.getName());
- compiler.setLogLevel(logLevel);
- compiler.distill(logger, moduleDef);
+ CompilerOptions newOptions = new CompilerOptionsImpl(options);
+ newOptions.setModuleName(moduleDef.getName());
+ new GWTCompiler(newOptions).run(logger);
}
/**
@@ -685,7 +629,7 @@
protected void initializeLogger() {
final AbstractTreeLogger logger = mainWnd.getLogger();
- logger.setMaxDetail(logLevel);
+ logger.setMaxDetail(options.getLogLevel());
}
/**
@@ -776,7 +720,7 @@
PerfLogger.start("GWTShell.startup (Tomcat launch)");
String whyFailed = EmbeddedTomcatServer.start(getTopLogger(), serverPort,
- outDir);
+ options.getOutDir());
PerfLogger.end();
if (whyFailed != null) {
diff --git a/dev/core/src/com/google/gwt/dev/Link.java b/dev/core/src/com/google/gwt/dev/Link.java
new file mode 100644
index 0000000..2bc55cd
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/Link.java
@@ -0,0 +1,215 @@
+/*
+ * 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.core.ext.linker.SelectionProperty;
+import com.google.gwt.core.ext.linker.impl.StandardCompilationResult;
+import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
+import com.google.gwt.dev.CompileTaskRunner.CompileTask;
+import com.google.gwt.dev.cfg.BindingProperty;
+import com.google.gwt.dev.cfg.ModuleDef;
+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 java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Performs the first phase of compilation, generating the set of permutations
+ * to compile, and a ready-to-compile AST.
+ */
+public class Link {
+
+ 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);
+ }
+
+ @Override
+ protected String getName() {
+ return Link.class.getName();
+ }
+ }
+
+ public static ArtifactSet link(TreeLogger logger, ModuleDef module,
+ Precompilation precompilation, File[] jsFiles)
+ throws UnableToCompleteException {
+ StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
+ module, precompilation.getUnifiedAst().getOptions());
+ return doLink(logger, linkerContext, precompilation, jsFiles);
+ }
+
+ 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.
+ */
+ final CompileTaskOptions options = new CompileTaskOptionsImpl();
+ if (new ArgProcessor(options).processArgs(args)) {
+ CompileTask task = new CompileTask() {
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ return new Link(options).run(logger);
+ }
+ };
+ if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
+ // Exit w/ success code.
+ System.exit(0);
+ }
+ }
+ // Exit w/ non-success code.
+ System.exit(1);
+ }
+
+ private static ArtifactSet doLink(TreeLogger logger,
+ StandardLinkerContext linkerContext, Precompilation precompilation,
+ File[] jsFiles) throws UnableToCompleteException {
+ Permutation[] perms = precompilation.getPermutations();
+ if (perms.length != jsFiles.length) {
+ throw new IllegalArgumentException(
+ "Mismatched jsFiles.length and permutation count");
+ }
+
+ for (int i = 0; i < perms.length; ++i) {
+ finishPermuation(logger, perms[i], jsFiles[i], linkerContext);
+ }
+
+ linkerContext.addOrReplaceArtifacts(precompilation.getGeneratedArtifacts());
+ return linkerContext.invokeLinkerStack(logger);
+ }
+
+ private static void finishPermuation(TreeLogger logger, Permutation perm,
+ File jsFile, StandardLinkerContext linkerContext)
+ throws UnableToCompleteException {
+ StandardCompilationResult compilation = linkerContext.getCompilation(
+ logger, jsFile);
+ StaticPropertyOracle[] propOracles = perm.getPropertyOracles();
+ for (StaticPropertyOracle propOracle : propOracles) {
+ BindingProperty[] orderedProps = propOracle.getOrderedProps();
+ String[] orderedPropValues = propOracle.getOrderedPropValues();
+ Map<SelectionProperty, String> unboundProperties = new HashMap<SelectionProperty, String>();
+ for (int i = 0; i < orderedProps.length; i++) {
+ SelectionProperty key = linkerContext.getProperty(orderedProps[i].getName());
+ if (key.tryGetValue() != null) {
+ /*
+ * The view of the Permutation doesn't include properties with defined
+ * values.
+ */
+ continue;
+ }
+ unboundProperties.put(key, orderedPropValues[i]);
+ }
+ compilation.addSelectionPermutation(unboundProperties);
+ }
+ }
+
+ private ModuleDef module;
+
+ /**
+ * This is the output directory for private files.
+ */
+ private File moduleAuxDir;
+
+ /**
+ * This is the output directory for public files.
+ */
+ private File moduleOutDir;
+
+ private final CompileTaskOptionsImpl options;
+
+ public Link(CompileTaskOptions options) {
+ this.options = new CompileTaskOptionsImpl(options);
+ }
+
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ init(logger);
+ File precompilationFile = new File(options.getCompilerWorkDir(),
+ Precompile.PRECOMPILATION_FILENAME);
+ if (!precompilationFile.exists()) {
+ logger.log(TreeLogger.ERROR, "File not found '"
+ + precompilationFile.getAbsolutePath()
+ + "'; please run Precompile first");
+ return false;
+ }
+
+ Precompilation precompilation;
+ try {
+ precompilation = Util.readFileAsObject(precompilationFile,
+ Precompilation.class);
+ } catch (ClassNotFoundException e) {
+ logger.log(TreeLogger.ERROR, "Unable to deserialize '"
+ + precompilationFile.getAbsolutePath() + "'", e);
+ return false;
+ }
+ Permutation[] perms = precompilation.getPermutations();
+ File[] jsFiles = new File[perms.length];
+ for (int i = 0; i < perms.length; ++i) {
+ jsFiles[i] = CompilePerms.makePermFilename(options.getCompilerWorkDir(),
+ i);
+ if (!jsFiles[i].exists()) {
+ logger.log(TreeLogger.ERROR, "File not found '"
+ + precompilationFile.getAbsolutePath()
+ + "'; please compile all permutations");
+ return false;
+ }
+ }
+
+ TreeLogger branch = logger.branch(TreeLogger.INFO, "Linking module "
+ + module.getName());
+ StandardLinkerContext linkerContext = new StandardLinkerContext(branch,
+ module, precompilation.getUnifiedAst().getOptions());
+ ArtifactSet artifacts = doLink(branch, linkerContext, precompilation,
+ jsFiles);
+ if (artifacts != null) {
+ linkerContext.produceOutputDirectory(branch, artifacts, moduleOutDir,
+ moduleAuxDir);
+ branch.log(TreeLogger.INFO, "Link succeeded");
+ return true;
+ }
+ branch.log(TreeLogger.ERROR, "Link failed");
+ return false;
+ }
+
+ private void init(TreeLogger logger) throws UnableToCompleteException {
+ module = ModuleDefLoader.loadFromClassPath(logger, options.getModuleName());
+ moduleOutDir = new File(options.getOutDir(), module.getName());
+ Util.recursiveDelete(moduleOutDir, true);
+ moduleAuxDir = new File(options.getOutDir(), module.getName() + "-aux");
+ Util.recursiveDelete(moduleAuxDir, false);
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/Permutation.java b/dev/core/src/com/google/gwt/dev/Permutation.java
index 64ae9f3..13ca881 100644
--- a/dev/core/src/com/google/gwt/dev/Permutation.java
+++ b/dev/core/src/com/google/gwt/dev/Permutation.java
@@ -16,34 +16,46 @@
package com.google.gwt.dev;
import com.google.gwt.dev.cfg.StaticPropertyOracle;
-import com.google.gwt.dev.jdt.RebindOracle;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
/**
* Represents the state of a single permutation for compile.
- *
- * @see PermutationCompiler
*/
-public final class Permutation {
- private final int number;
- private final StaticPropertyOracle propertyOracle;
- private final RebindOracle rebindOracle;
+public final class Permutation implements Serializable {
+ private final List<StaticPropertyOracle> propertyOracles = new ArrayList<StaticPropertyOracle>();
+ private final SortedMap<String, String> rebindAnswers = new TreeMap<String, String>();
- public Permutation(int number, RebindOracle rebindOracle,
- StaticPropertyOracle propertyOracle) {
- this.number = number;
- this.rebindOracle = rebindOracle;
- this.propertyOracle = propertyOracle;
+ public Permutation(StaticPropertyOracle propertyOracle) {
+ this.propertyOracles.add(propertyOracle);
}
- public int getNumber() {
- return number;
+ public StaticPropertyOracle[] getPropertyOracles() {
+ return propertyOracles.toArray(new StaticPropertyOracle[propertyOracles.size()]);
}
- public StaticPropertyOracle getPropertyOracle() {
- return propertyOracle;
+ public SortedMap<String, String> getRebindAnswers() {
+ return rebindAnswers;
}
- public RebindOracle getRebindOracle() {
- return rebindOracle;
+ public void mergeFrom(Permutation other) {
+ assert rebindAnswers.equals(other.rebindAnswers);
+ assert !propertyOracles.isEmpty();
+ assert !other.propertyOracles.isEmpty();
+ propertyOracles.addAll(other.propertyOracles);
+ other.propertyOracles.clear();
+ }
+
+ public void putRebindAnswer(String requestType, String resultType) {
+ rebindAnswers.put(requestType, resultType);
+ }
+
+ public void reduceRebindAnswers(Set<String> liveRebindRequests) {
+ rebindAnswers.keySet().retainAll(liveRebindRequests);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/PermutationCompiler.java b/dev/core/src/com/google/gwt/dev/PermutationCompiler.java
index 7513e1c..f89b102 100644
--- a/dev/core/src/com/google/gwt/dev/PermutationCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/PermutationCompiler.java
@@ -17,17 +17,13 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.linker.SelectionProperty;
-import com.google.gwt.core.ext.linker.impl.StandardCompilationResult;
-import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
import com.google.gwt.dev.cfg.BindingProperty;
import com.google.gwt.dev.cfg.StaticPropertyOracle;
+import com.google.gwt.dev.jjs.UnifiedAst;
import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.util.PerfLogger;
-import java.util.HashMap;
-import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -40,13 +36,21 @@
public class PermutationCompiler {
/**
+ * Hands back results as they are finished.
+ */
+ public interface ResultsHandler {
+ void addResult(Permutation permutation, int permNum, String js)
+ throws UnableToCompleteException;
+ }
+
+ /**
* A Result for a permutation that failed to compile.
*/
private static final class FailedResult extends Result {
private Throwable exception;
- public FailedResult(Permutation perm, Throwable exception) {
- super(perm);
+ public FailedResult(Permutation perm, int permNum, Throwable exception) {
+ super(perm, permNum);
this.exception = exception;
}
@@ -60,42 +64,51 @@
*/
private static final class PermutationTask implements Callable<String> {
private static void logProperties(TreeLogger logger,
- StaticPropertyOracle propOracle) {
- BindingProperty[] props = propOracle.getOrderedProps();
- String[] values = propOracle.getOrderedPropValues();
- if (logger.isLoggable(TreeLogger.DEBUG)) {
- logger = logger.branch(TreeLogger.DEBUG, "Setting properties", null);
- for (int i = 0; i < props.length; i++) {
- String name = props[i].getName();
- String value = values[i];
- logger.log(TreeLogger.TRACE, name + " = " + value, null);
+ StaticPropertyOracle[] propOracles) {
+ for (StaticPropertyOracle propOracle : propOracles) {
+ BindingProperty[] props = propOracle.getOrderedProps();
+ String[] values = propOracle.getOrderedPropValues();
+ if (logger.isLoggable(TreeLogger.DEBUG)) {
+ logger = logger.branch(TreeLogger.DEBUG, "Setting properties", null);
+ for (int i = 0; i < props.length; i++) {
+ String name = props[i].getName();
+ String value = values[i];
+ logger.log(TreeLogger.TRACE, name + " = " + value, null);
+ }
}
}
}
- private final JavaToJavaScriptCompiler jjs;
+ private final UnifiedAst unifiedAst;
private final TreeLogger logger;
private final Permutation perm;
+ private final int permNum;
- public PermutationTask(TreeLogger logger, JavaToJavaScriptCompiler jjs,
- Permutation perm) {
+ public PermutationTask(TreeLogger logger, UnifiedAst unifiedAst,
+ Permutation perm, int permNum) {
this.logger = logger;
- this.jjs = jjs;
+ this.unifiedAst = unifiedAst;
this.perm = perm;
+ this.permNum = permNum;
}
public String call() throws Exception {
- PerfLogger.start("Permutation #" + (perm.getNumber() + 1));
+ PerfLogger.start("Permutation #" + permNum);
try {
- TreeLogger branch = logger.branch(TreeLogger.TRACE,
- "Analyzing permutation #" + (perm.getNumber() + 1));
- logProperties(branch, perm.getPropertyOracle());
- return jjs.compile(branch, perm.getRebindOracle());
+ TreeLogger branch = logger.branch(TreeLogger.TRACE, "Permutation #"
+ + permNum);
+ logProperties(branch, perm.getPropertyOracles());
+ return JavaToJavaScriptCompiler.compilePermutation(branch, unifiedAst,
+ perm.getRebindAnswers());
} finally {
PerfLogger.end();
}
}
+ public int getPermNum() {
+ return permNum;
+ }
+
public Permutation getPermutation() {
return perm;
}
@@ -106,9 +119,15 @@
*/
private abstract static class Result {
private final Permutation perm;
+ private final int permNum;
- public Result(Permutation perm) {
+ public Result(Permutation perm, int permNum) {
this.perm = perm;
+ this.permNum = permNum;
+ }
+
+ public int getPermNum() {
+ return permNum;
}
public Permutation getPermutation() {
@@ -122,8 +141,8 @@
private static final class SuccessResult extends Result {
private final String js;
- public SuccessResult(Permutation perm, String js) {
- super(perm);
+ public SuccessResult(Permutation perm, int permNum, String js) {
+ super(perm, permNum);
this.js = js;
}
@@ -183,7 +202,8 @@
boolean definitelyFinalThread = (threadCount.get() == 1);
try {
String result = currentTask.call();
- results.add(new SuccessResult(currentTask.getPermutation(), result));
+ results.add(new SuccessResult(currentTask.getPermutation(),
+ currentTask.getPermNum(), result));
} catch (OutOfMemoryError e) {
if (definitelyFinalThread) {
// OOM on the final thread, this is a truly unrecoverable failure.
@@ -191,7 +211,7 @@
exitFinalThread(new Runnable() {
public void run() {
results.add(new FailedResult(currentTask.getPermutation(),
- new UnableToCompleteException()));
+ currentTask.getPermNum(), new UnableToCompleteException()));
}
});
}
@@ -211,7 +231,8 @@
outOfMemoryRetryAction.run();
} catch (Throwable e) {
// Unexpected error compiling, this is unrecoverable.
- results.add(new FailedResult(currentTask.getPermutation(), e));
+ results.add(new FailedResult(currentTask.getPermutation(),
+ currentTask.getPermNum(), e));
throw new ThreadDeath();
}
}
@@ -270,7 +291,7 @@
/**
* A marker Result that tells the main thread all work is done.
*/
- private static final Result FINISHED_RESULT = new Result(null) {
+ private static final Result FINISHED_RESULT = new Result(null, -1) {
};
private static long getPotentialFreeMemory() {
@@ -305,18 +326,17 @@
private final TreeLogger logger;
- public PermutationCompiler(TreeLogger logger, JavaToJavaScriptCompiler jjs,
- Permutation[] perms) {
- this.logger = logger.branch(TreeLogger.DEBUG, "Compiling " + perms.length
- + " permutations");
- this.astMemoryUsage = jjs.getAstMemoryUsage();
- for (Permutation perm : perms) {
- tasks.add(new PermutationTask(this.logger, jjs, perm));
+ public PermutationCompiler(TreeLogger logger, UnifiedAst unifiedAst,
+ Permutation[] perms, int[] permsToRun) {
+ this.logger = logger;
+ this.astMemoryUsage = unifiedAst.getAstMemoryUsage();
+ for (int permToRun : permsToRun) {
+ tasks.add(new PermutationTask(logger, unifiedAst, perms[permToRun],
+ permToRun));
}
}
- public void go(StandardLinkerContext linkerContext)
- throws UnableToCompleteException {
+ public void go(ResultsHandler handler) throws UnableToCompleteException {
int initialThreadCount = computeInitialThreadCount();
Thread[] workerThreads = new Thread[initialThreadCount];
for (int i = 0; i < initialThreadCount; ++i) {
@@ -333,7 +353,8 @@
assert threadCount.get() == 0;
return;
} else if (result instanceof SuccessResult) {
- finishPermuation(logger, linkerContext, (SuccessResult) result);
+ String js = ((SuccessResult) result).getJs();
+ handler.addResult(result.getPermutation(), result.getPermNum(), js);
} else if (result instanceof FailedResult) {
FailedResult failedResult = (FailedResult) result;
throw logAndTranslateException(failedResult.getException());
@@ -415,30 +436,6 @@
return result;
}
- private void finishPermuation(TreeLogger logger,
- StandardLinkerContext linkerContext, SuccessResult result)
- throws UnableToCompleteException {
- Permutation perm = result.getPermutation();
- StandardCompilationResult compilation = linkerContext.getCompilation(
- logger, result.getJs());
- StaticPropertyOracle propOracle = perm.getPropertyOracle();
- BindingProperty[] orderedProps = propOracle.getOrderedProps();
- String[] orderedPropValues = propOracle.getOrderedPropValues();
- Map<SelectionProperty, String> unboundProperties = new HashMap<SelectionProperty, String>();
- for (int i = 0; i < orderedProps.length; i++) {
- SelectionProperty key = linkerContext.getProperty(orderedProps[i].getName());
- if (key.tryGetValue() != null) {
- /*
- * The view of the Permutation doesn't include properties with defined
- * values.
- */
- continue;
- }
- unboundProperties.put(key, orderedPropValues[i]);
- }
- compilation.addSelectionPermutation(unboundProperties);
- }
-
private UnableToCompleteException logAndTranslateException(Throwable e) {
if (e instanceof UnableToCompleteException) {
return (UnableToCompleteException) e;
diff --git a/dev/core/src/com/google/gwt/dev/Precompilation.java b/dev/core/src/com/google/gwt/dev/Precompilation.java
new file mode 100644
index 0000000..8eb7438
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/Precompilation.java
@@ -0,0 +1,73 @@
+/*
+ * 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.linker.ArtifactSet;
+import com.google.gwt.dev.jjs.UnifiedAst;
+
+import java.io.Serializable;
+
+/**
+ * The result of compilation phase 1, includes a unified AST and metadata
+ * relevant to each permutation.
+ */
+public class Precompilation implements Serializable {
+ /*
+ * TODO: don't make this whole class serializable, instead dump the
+ * independent members out to a file so that the generated artifacts are
+ * optional to deserialize.
+ */
+ private ArtifactSet generatedArtifacts;
+ private final Permutation[] permutations;
+ private final UnifiedAst unifiedAst;
+
+ /**
+ * Constructs a new precompilation.
+ *
+ * @param unifiedAst the unified AST used by
+ * {@link com.google.gwt.dev.jjs.JavaToJavaScriptCompiler}
+ * @param permutations the set of permutations that can be run
+ * @param generatedArtifacts the set of artifacts created by generators
+ */
+ public Precompilation(UnifiedAst unifiedAst, Permutation[] permutations,
+ ArtifactSet generatedArtifacts) {
+ this.unifiedAst = unifiedAst;
+ this.permutations = permutations;
+ this.generatedArtifacts = generatedArtifacts;
+ }
+
+ /**
+ * Returns the set of generated artifacts from the precompile phase.
+ */
+ public ArtifactSet getGeneratedArtifacts() {
+ return generatedArtifacts;
+ }
+
+ /**
+ * Returns the set of permutations to run.
+ */
+ public Permutation[] getPermutations() {
+ return permutations;
+ }
+
+ /**
+ * Returns the unified AST used by
+ * {@link com.google.gwt.dev.jjs.JavaToJavaScriptCompiler}.
+ */
+ public UnifiedAst getUnifiedAst() {
+ return unifiedAst;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
new file mode 100644
index 0000000..8465ac5
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -0,0 +1,392 @@
+/*
+ * 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.CompileTaskRunner.CompileTask;
+import com.google.gwt.dev.cfg.BindingProperty;
+import com.google.gwt.dev.cfg.ConfigurationProperty;
+import com.google.gwt.dev.cfg.ModuleDef;
+import com.google.gwt.dev.cfg.ModuleDefLoader;
+import com.google.gwt.dev.cfg.PropertyPermutations;
+import com.google.gwt.dev.cfg.Rules;
+import com.google.gwt.dev.cfg.StaticPropertyOracle;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.jdt.RebindOracle;
+import com.google.gwt.dev.jdt.RebindPermutationOracle;
+import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
+import com.google.gwt.dev.jjs.UnifiedAst;
+import com.google.gwt.dev.jjs.JJSOptions;
+import com.google.gwt.dev.jjs.JJSOptionsImpl;
+import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
+import com.google.gwt.dev.jjs.JsOutputOption;
+import com.google.gwt.dev.shell.StandardRebindOracle;
+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.ArgHandlerGenDir;
+import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
+import com.google.gwt.dev.util.arg.ArgHandlerValidateOnlyFlag;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+
+/**
+ * Performs the first phase of compilation, generating the set of permutations
+ * to compile, and a ready-to-compile AST.
+ */
+public class Precompile {
+
+ static class ArgProcessor extends Link.ArgProcessor {
+ public ArgProcessor(CompilerOptions options) {
+ super(options);
+ registerHandler(new ArgHandlerGenDir(options));
+ registerHandler(new ArgHandlerScriptStyle(options));
+ registerHandler(new ArgHandlerEnableAssertions(options));
+ registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
+ registerHandler(new ArgHandlerValidateOnlyFlag(options));
+ }
+
+ @Override
+ protected String getName() {
+ return Precompile.class.getName();
+ }
+ }
+ /**
+ * Concrete class to implement all compiler options.
+ */
+ static class CompilerOptionsImpl extends CompileTaskOptionsImpl implements
+ CompilerOptions {
+
+ private File genDir;
+ private final JJSOptionsImpl jjsOptions = new JJSOptionsImpl();
+ private boolean validateOnly;
+
+ public CompilerOptionsImpl() {
+ }
+
+ public CompilerOptionsImpl(CompilerOptions other) {
+ copyFrom(other);
+ }
+
+ public void copyFrom(CompilerOptions other) {
+ super.copyFrom(other);
+
+ setGenDir(other.getGenDir());
+ setValidateOnly(other.isValidateOnly());
+
+ setAggressivelyOptimize(other.isAggressivelyOptimize());
+ setEnableAssertions(other.isEnableAssertions());
+ setOutput(other.getOutput());
+ }
+
+ public File getGenDir() {
+ return genDir;
+ }
+
+ public JsOutputOption getOutput() {
+ return jjsOptions.getOutput();
+ }
+
+ public boolean isAggressivelyOptimize() {
+ return jjsOptions.isAggressivelyOptimize();
+ }
+
+ public boolean isEnableAssertions() {
+ return jjsOptions.isEnableAssertions();
+ }
+
+ public boolean isValidateOnly() {
+ return validateOnly;
+ }
+
+ public void setAggressivelyOptimize(boolean aggressivelyOptimize) {
+ jjsOptions.setAggressivelyOptimize(aggressivelyOptimize);
+ }
+
+ public void setEnableAssertions(boolean enableAssertions) {
+ jjsOptions.setEnableAssertions(enableAssertions);
+ }
+
+ public void setGenDir(File genDir) {
+ this.genDir = genDir;
+ }
+
+ public void setOutput(JsOutputOption output) {
+ jjsOptions.setOutput(output);
+ }
+
+ public void setValidateOnly(boolean validateOnly) {
+ this.validateOnly = validateOnly;
+ }
+ }
+
+ private static class DistillerRebindPermutationOracle implements
+ RebindPermutationOracle {
+
+ private Permutation[] permutations;
+ private StaticPropertyOracle[] propertyOracles;
+ private RebindOracle[] rebindOracles;
+
+ public DistillerRebindPermutationOracle(ModuleDef module,
+ ArtifactSet generatorArtifacts, PropertyPermutations perms,
+ File genDir, File generatorResourcesDir) {
+ permutations = new Permutation[perms.size()];
+ propertyOracles = new StaticPropertyOracle[perms.size()];
+ rebindOracles = new RebindOracle[perms.size()];
+ BindingProperty[] orderedProps = perms.getOrderedProperties();
+ SortedSet<ConfigurationProperty> configPropSet = module.getProperties().getConfigurationProperties();
+ ConfigurationProperty[] configProps = configPropSet.toArray(new ConfigurationProperty[configPropSet.size()]);
+ Rules rules = module.getRules();
+ for (int i = 0; i < rebindOracles.length; ++i) {
+ String[] orderedPropValues = perms.getOrderedPropertyValues(i);
+ propertyOracles[i] = new StaticPropertyOracle(orderedProps,
+ orderedPropValues, configProps);
+ rebindOracles[i] = new StandardRebindOracle(
+ module.getCompilationState(), propertyOracles[i], module, rules,
+ genDir, generatorResourcesDir, generatorArtifacts);
+ permutations[i] = new Permutation(propertyOracles[i]);
+ }
+ }
+
+ public String[] getAllPossibleRebindAnswers(TreeLogger logger,
+ String requestTypeName) throws UnableToCompleteException {
+
+ String msg = "Computing all possible rebind results for '"
+ + requestTypeName + "'";
+ logger = logger.branch(TreeLogger.DEBUG, msg, null);
+
+ Set<String> answers = new HashSet<String>();
+
+ for (int i = 0; i < getPermuationCount(); ++i) {
+ String resultTypeName = rebindOracles[i].rebind(logger, requestTypeName);
+ answers.add(resultTypeName);
+ // Record the correct answer into each permutation.
+ permutations[i].putRebindAnswer(requestTypeName, resultTypeName);
+ }
+ return Util.toArray(String.class, answers);
+ }
+
+ public int getPermuationCount() {
+ return rebindOracles.length;
+ }
+
+ public Permutation[] getPermutations() {
+ return permutations;
+ }
+
+ public StaticPropertyOracle getPropertyOracle(int permNumber) {
+ return propertyOracles[permNumber];
+ }
+
+ public RebindOracle getRebindOracle(int permNumber) {
+ return rebindOracles[permNumber];
+ }
+ }
+
+ static final String PERM_COUNT_FILENAME = "permCount.txt";
+
+ static final String PRECOMPILATION_FILENAME = "precompilation.ser";
+
+ /**
+ * Performs a command-line precompile.
+ */
+ 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.
+ */
+ final CompilerOptions options = new CompilerOptionsImpl();
+ if (new ArgProcessor(options).processArgs(args)) {
+ CompileTask task = new CompileTask() {
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ return new Precompile(options).run(logger);
+ }
+ };
+ if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
+ // Exit w/ success code.
+ System.exit(0);
+ }
+ }
+ // Exit w/ non-success code.
+ System.exit(1);
+ }
+
+ /**
+ * Precompiles the given module.
+ *
+ * @param logger a logger to use
+ * @param jjsOptions a set of compiler options
+ * @param module the module to compile
+ * @param genDir optional directory to dump generated source, may be
+ * <code>null</code>
+ * @param generatorResourcesDir required directory to dump generator resources
+ * @return the precompilation
+ */
+ public static Precompilation precompile(TreeLogger logger,
+ JJSOptions jjsOptions, ModuleDef module, File genDir,
+ File generatorResourcesDir) {
+ try {
+ String[] declEntryPts = module.getEntryPointTypeNames();
+ if (declEntryPts.length == 0) {
+ logger.log(TreeLogger.ERROR, "Module has no entry points defined", null);
+ throw new UnableToCompleteException();
+ }
+
+ ArtifactSet generatedArtifacts = new ArtifactSet();
+ DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
+ module, generatedArtifacts, new PropertyPermutations(
+ module.getProperties()), genDir, generatorResourcesDir);
+
+ WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
+ module.getCompilationState(), rpo);
+ UnifiedAst unifiedAst = JavaToJavaScriptCompiler.precompile(logger,
+ frontEnd, declEntryPts, jjsOptions, rpo.getPermuationCount() == 1);
+
+ // Merge all identical permutations together.
+ Permutation[] permutations = rpo.getPermutations();
+ // Sort the permutations by an ordered key to ensure determinism.
+ SortedMap<String, Permutation> merged = new TreeMap<String, Permutation>();
+ for (Permutation permutation : permutations) {
+ permutation.reduceRebindAnswers(unifiedAst.getRebindRequests());
+ // Arbitrarily choose as a key the stringified map of rebind answers.
+ String rebindResultsString = permutation.getRebindAnswers().toString();
+ if (merged.containsKey(rebindResultsString)) {
+ Permutation existing = merged.get(rebindResultsString);
+ existing.mergeFrom(permutation);
+ } else {
+ merged.put(rebindResultsString, permutation);
+ }
+ }
+ permutations = merged.values().toArray(new Permutation[merged.size()]);
+ return new Precompilation(unifiedAst, permutations, generatedArtifacts);
+ } catch (UnableToCompleteException e) {
+ // We intentionally don't pass in the exception here since the real
+ // cause has been logged.
+ return null;
+ }
+ }
+
+ /**
+ * Validates the given module can be compiled.
+ *
+ * @param logger a logger to use
+ * @param jjsOptions a set of compiler options
+ * @param module the module to compile
+ * @param genDir optional directory to dump generated source, may be
+ * <code>null</code>
+ * @param generatorResourcesDir required directory to dump generator resources
+ */
+ public static boolean validate(TreeLogger logger, JJSOptions jjsOptions,
+ ModuleDef module, File genDir, File generatorResourcesDir) {
+ try {
+ String[] declEntryPts = module.getEntryPointTypeNames();
+ if (declEntryPts.length == 0) {
+ // Pretend that every single compilation unit is an entry point.
+ Set<CompilationUnit> compilationUnits = module.getCompilationState().getCompilationUnits();
+ declEntryPts = new String[compilationUnits.size()];
+ int i = 0;
+ for (CompilationUnit unit : compilationUnits) {
+ declEntryPts[i++] = unit.getTypeName();
+ }
+ }
+
+ ArtifactSet generatorArtifacts = new ArtifactSet();
+ DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
+ module, generatorArtifacts, new PropertyPermutations(
+ module.getProperties()), genDir, generatorResourcesDir);
+
+ WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
+ module.getCompilationState(), rpo);
+ JavaToJavaScriptCompiler.precompile(logger, frontEnd, declEntryPts,
+ jjsOptions, true);
+ return true;
+ } catch (UnableToCompleteException e) {
+ // Already logged.
+ return false;
+ }
+ }
+
+ private File generatorResourcesDir;
+
+ private ModuleDef module;
+
+ private final CompilerOptionsImpl options;
+
+ public Precompile(CompilerOptions options) {
+ this.options = new CompilerOptionsImpl(options);
+ }
+
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ if (options.isValidateOnly()) {
+ init(logger);
+ TreeLogger branch = logger.branch(TreeLogger.INFO,
+ "Validating compilation " + module.getName());
+ if (validate(branch, options, module, options.getGenDir(),
+ generatorResourcesDir)) {
+ branch.log(TreeLogger.INFO, "Validation succeeded");
+ return true;
+ } else {
+ branch.log(TreeLogger.ERROR, "Validation failed");
+ return false;
+ }
+ } else {
+ init(logger);
+ TreeLogger branch = logger.branch(TreeLogger.INFO, "Precompiling module "
+ + module.getName());
+ Precompilation precompilation = precompile(branch, options, module,
+ options.getGenDir(), generatorResourcesDir);
+ if (precompilation != null) {
+ Util.writeObjectAsFile(branch, new File(options.getCompilerWorkDir(),
+ PRECOMPILATION_FILENAME), precompilation);
+ Util.writeStringAsFile(branch, new File(options.getCompilerWorkDir(),
+ PERM_COUNT_FILENAME),
+ String.valueOf(precompilation.getPermutations().length));
+ branch.log(TreeLogger.INFO,
+ "Precompilation succeeded, number of permutations: "
+ + precompilation.getPermutations().length);
+ return true;
+ }
+ branch.log(TreeLogger.ERROR, "Precompilation failed");
+ return false;
+ }
+ }
+
+ private void init(TreeLogger logger) throws UnableToCompleteException {
+ // Clean out the work dir and/or create it.
+ File compilerWorkDir = options.getCompilerWorkDir();
+ Util.recursiveDelete(compilerWorkDir, true);
+ compilerWorkDir.mkdirs();
+
+ 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/cfg/DefaultPropertyProvider.java b/dev/core/src/com/google/gwt/dev/cfg/DefaultPropertyProvider.java
deleted file mode 100644
index ddb7c7b..0000000
--- a/dev/core/src/com/google/gwt/dev/cfg/DefaultPropertyProvider.java
+++ /dev/null
@@ -1,70 +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.cfg;
-
-import com.google.gwt.dev.js.JsParser;
-import com.google.gwt.dev.js.JsParserException;
-import com.google.gwt.dev.js.ast.JsBlock;
-import com.google.gwt.dev.js.ast.JsExprStmt;
-import com.google.gwt.dev.js.ast.JsFunction;
-import com.google.gwt.dev.js.ast.JsProgram;
-import com.google.gwt.dev.js.ast.JsStatement;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.List;
-
-/**
- * A property provider that reports property values specified literally in a
- * host HTML page.
- */
-public class DefaultPropertyProvider extends PropertyProvider {
-
- /*
- * TODO: this references 'parent' literally, which could be a problem if you
- * were to include the selector script in the host page itself rather than in
- * an iframe.
- */
- public DefaultPropertyProvider(ModuleDef module, Property property) {
- super(module, property);
- String src = "function () {";
- src += "return __gwt_getMetaProperty(\"";
- src += property.getName();
- src += "\"); }";
- setBody(parseFunction(src));
- }
-
- private JsBlock parseFunction(String jsniSrc) {
- Throwable caught = null;
- try {
- JsProgram jsPgm = new JsProgram();
- JsParser jsParser = new JsParser();
- StringReader r = new StringReader(jsniSrc);
- jsParser.setSourceInfo(jsPgm.createSourceInfoSynthetic(
- DefaultPropertyProvider.class, "Default property provider for "
- + getProperty().getName()));
- List<JsStatement> stmts = jsParser.parse(jsPgm.getScope(), r, 1);
- JsFunction fn = (JsFunction) ((JsExprStmt) stmts.get(0)).getExpression();
- return fn.getBody();
- } catch (IOException e) {
- caught = e;
- } catch (JsParserException e) {
- caught = e;
- }
- throw new RuntimeException(
- "Internal error parsing source for default property provider", caught);
- }
-}
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 405e93c..3d6efb6 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -408,7 +408,11 @@
* one possible value and no existing provider.
*/
if (prop.getProvider() == null && prop.getAllowedValues().length > 1) {
- prop.setProvider(new DefaultPropertyProvider(this, prop));
+ String src = "{";
+ src += "return __gwt_getMetaProperty(\"";
+ src += prop.getName();
+ src += "\"); }";
+ prop.setProvider(new PropertyProvider(src));
}
}
}
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 2477a25..ebde69d 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
@@ -214,7 +214,6 @@
}
protected Schema __property_provider_begin(BindingProperty property) {
- property.setProvider(new PropertyProvider(moduleDef, property));
return fChild = new PropertyProviderBodySchema();
}
@@ -233,7 +232,7 @@
int lineNumber = childSchema.getStartLineNumber();
JsFunction fn = parseJsBlock(lineNumber, script);
- property.getProvider().setBody(fn.getBody());
+ property.setProvider(new PropertyProvider(fn.getBody().toSource()));
}
protected Schema __public_begin(String path, String includes,
diff --git a/dev/core/src/com/google/gwt/dev/cfg/Property.java b/dev/core/src/com/google/gwt/dev/cfg/Property.java
index ad30a8b..5615672 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/Property.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/Property.java
@@ -15,10 +15,12 @@
*/
package com.google.gwt.dev.cfg;
+import java.io.Serializable;
+
/**
* Represents an abstract module property.
*/
-public abstract class Property implements Comparable<Property> {
+public abstract class Property implements Comparable<Property>, Serializable {
protected final String name;
diff --git a/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java b/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java
index 13c44d6..55f5f17 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * 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
@@ -15,36 +15,20 @@
*/
package com.google.gwt.dev.cfg;
-import com.google.gwt.dev.js.ast.JsBlock;
+import java.io.Serializable;
/**
* Produces a deferred binding property value by executing JavaScript code.
*/
-public class PropertyProvider {
+public class PropertyProvider implements Serializable {
- private JsBlock body;
+ private final String body;
- private final ModuleDef module;
- private final Property property;
-
- public PropertyProvider(ModuleDef module, Property property) {
- this.module = module;
- this.property = property;
- }
-
- public JsBlock getBody() {
- return body;
- }
-
- public ModuleDef getModule() {
- return module;
- }
-
- public Property getProperty() {
- return property;
- }
-
- public void setBody(JsBlock body) {
+ public PropertyProvider(String body) {
this.body = body;
}
+
+ public String getBody() {
+ return body;
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java b/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
index f501fd2..d0cb379 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
@@ -19,11 +19,13 @@
import com.google.gwt.core.ext.PropertyOracle;
import com.google.gwt.core.ext.TreeLogger;
+import java.io.Serializable;
+
/**
* An implementation of {@link PropertyOracle} that contains property values,
* rather than computing them.
*/
-public class StaticPropertyOracle implements PropertyOracle {
+public class StaticPropertyOracle implements PropertyOracle, Serializable {
private final ConfigurationProperty[] configProps;
diff --git a/dev/core/src/com/google/gwt/dev/jdt/RebindPermutationOracle.java b/dev/core/src/com/google/gwt/dev/jdt/RebindPermutationOracle.java
index 8108e76..a8b010c 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/RebindPermutationOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/RebindPermutationOracle.java
@@ -29,6 +29,4 @@
*/
String[] getAllPossibleRebindAnswers(TreeLogger logger, String sourceTypeName)
throws UnableToCompleteException;
-
- int getPermuationCount();
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java b/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
index c80e722..6e9e162 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
@@ -15,100 +15,13 @@
*/
package com.google.gwt.dev.jjs;
+import com.google.gwt.dev.util.arg.OptionAggressivelyOptimize;
+import com.google.gwt.dev.util.arg.OptionEnableAssertions;
+import com.google.gwt.dev.util.arg.OptionScriptStyle;
+
/**
* Controls options for the {@link JavaToJavaScriptCompiler}.
*/
-public class JJSOptions {
-
- private boolean aggressivelyOptimize = true;
- private boolean enableAssertions = false;
- private JsOutputOption output = JsOutputOption.OBFUSCATED;
- private String soycOutputPath = null;
- private boolean validateOnly = false;
-
- public JJSOptions() {
- }
-
- public JJSOptions(JJSOptions other) {
- copyFrom(other);
- }
-
- public void copyFrom(JJSOptions other) {
- this.aggressivelyOptimize = other.aggressivelyOptimize;
- this.enableAssertions = other.enableAssertions;
- this.soycOutputPath = other.soycOutputPath;
- this.output = other.output;
- this.validateOnly = other.validateOnly;
- }
-
- /**
- * Returns the output format setting.
- */
- public JsOutputOption getOutput() {
- return output;
- }
-
- /**
- * Returns the path of the SOYC output directory, if it has been set.
- */
- public String getSoycOutputDir() {
- return soycOutputPath;
- }
-
- /**
- * Returns true if the compiler should aggressively optimize.
- */
- public boolean isAggressivelyOptimize() {
- return aggressivelyOptimize;
- }
-
- /**
- * Returns true if the compiler should generate code to check assertions.
- */
- public boolean isEnableAssertions() {
- return enableAssertions;
- }
-
- /**
- * /** Returns true if the compiler should run in validation mode, not
- * producing any output.
- */
- public boolean isValidateOnly() {
- return validateOnly;
- }
-
- /**
- * Sets whether or not the compiler should aggressively optimize.
- */
- public void setAggressivelyOptimize(boolean aggressivelyOptimize) {
- this.aggressivelyOptimize = aggressivelyOptimize;
- }
-
- /**
- * Sets whether or not the compiler should generate code to check assertions.
- */
- public void setEnableAssertions(boolean enableAssertions) {
- this.enableAssertions = enableAssertions;
- }
-
- /**
- * Sets the compiler output option.
- */
- public void setOutput(JsOutputOption output) {
- this.output = output;
- }
-
- /**
- * Sets the output path of the SOYC reports.
- */
- public void setSoycOutputDir(String path) {
- this.soycOutputPath = path;
- }
-
- /**
- * Sets whether or not the compiler should run in validation mode.
- */
- public void setValidateOnly(boolean validateOnly) {
- this.validateOnly = validateOnly;
- }
+public interface JJSOptions extends OptionAggressivelyOptimize,
+ OptionEnableAssertions, OptionScriptStyle {
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java b/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
new file mode 100644
index 0000000..8873c41
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
@@ -0,0 +1,65 @@
+/*
+ * 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.jjs;
+
+import java.io.Serializable;
+
+/**
+ * Concrete class to implement all JJS options.
+ */
+public class JJSOptionsImpl implements JJSOptions, Serializable {
+
+ private boolean aggressivelyOptimize = true;
+ private boolean enableAssertions;
+ private JsOutputOption output = JsOutputOption.OBFUSCATED;
+
+ public JJSOptionsImpl() {
+ }
+
+ public JJSOptionsImpl(JJSOptions other) {
+ copyFrom(other);
+ }
+
+ public void copyFrom(JJSOptions other) {
+ setAggressivelyOptimize(other.isAggressivelyOptimize());
+ setEnableAssertions(other.isEnableAssertions());
+ setOutput(other.getOutput());
+ }
+
+ public JsOutputOption getOutput() {
+ return output;
+ }
+
+ public boolean isAggressivelyOptimize() {
+ return aggressivelyOptimize;
+ }
+
+ public boolean isEnableAssertions() {
+ return enableAssertions;
+ }
+
+ public void setAggressivelyOptimize(boolean aggressivelyOptimize) {
+ this.aggressivelyOptimize = aggressivelyOptimize;
+ }
+
+ public void setEnableAssertions(boolean enableAssertions) {
+ this.enableAssertions = enableAssertions;
+ }
+
+ public void setOutput(JsOutputOption output) {
+ this.output = output;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index edf1d27..10ef174 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -17,10 +17,10 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.jdt.RebindOracle;
import com.google.gwt.dev.jdt.RebindPermutationOracle;
import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
import com.google.gwt.dev.jjs.InternalCompilerException.NodeInfo;
+import com.google.gwt.dev.jjs.UnifiedAst.AST;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
import com.google.gwt.dev.jjs.ast.JClassType;
@@ -54,6 +54,7 @@
import com.google.gwt.dev.jjs.impl.MethodInliner;
import com.google.gwt.dev.jjs.impl.PostOptimizationCompoundAssignmentNormalizer;
import com.google.gwt.dev.jjs.impl.Pruner;
+import com.google.gwt.dev.jjs.impl.RecordRebinds;
import com.google.gwt.dev.jjs.impl.ReplaceRebinds;
import com.google.gwt.dev.jjs.impl.ResolveRebinds;
import com.google.gwt.dev.jjs.impl.TypeMap;
@@ -69,7 +70,6 @@
import com.google.gwt.dev.js.JsSymbolResolver;
import com.google.gwt.dev.js.JsUnusedFunctionRemover;
import com.google.gwt.dev.js.JsVerboseNamer;
-import com.google.gwt.dev.js.SourceInfoHistogram;
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.util.DefaultTextOutput;
import com.google.gwt.dev.util.PerfLogger;
@@ -80,23 +80,362 @@
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
- * Compiles the Java <code>JProgram</code> representation into its corresponding
- * JavaScript source.
+ * Compiles the Java <code>JProgram</code> representation into its
+ * corresponding JavaScript source.
*/
public class JavaToJavaScriptCompiler {
+ /**
+ * Compiles a particular permutation, based on a precompiled unified AST.
+ *
+ * @param logger the logger to use
+ * @param unifiedAst the result of a
+ * {@link #precompile(TreeLogger, WebModeCompilerFrontEnd, String[], JJSOptions, boolean)}
+ * @param rebindAnswers the set of rebind answers to resolve all outstanding
+ * rebind decisions
+ * @return the output JavaScript
+ * @throws UnableToCompleteException if an error other than
+ * {@link OutOfMemoryError} occurs
+ */
+ public static String compilePermutation(TreeLogger logger,
+ UnifiedAst unifiedAst, Map<String, String> rebindAnswers)
+ throws UnableToCompleteException {
+ try {
+ if (JProgram.isTracingEnabled()) {
+ System.out.println("------------------------------------------------------------");
+ System.out.println("| (new permuation) |");
+ System.out.println("------------------------------------------------------------");
+ }
+
+ AST ast = unifiedAst.getFreshAst();
+ JProgram jprogram = ast.getJProgram();
+ JsProgram jsProgram = ast.getJsProgram();
+ JJSOptions options = unifiedAst.getOptions();
+
+ ResolveRebinds.exec(jprogram, rebindAnswers);
+
+ // (4) Optimize the normalized Java AST for each permutation.
+ optimize(options, jprogram);
+
+ // (5) "Normalize" the high-level Java tree into a lower-level tree more
+ // suited for JavaScript code generation. Don't go reordering these
+ // willy-nilly because there are some subtle interdependencies.
+ LongCastNormalizer.exec(jprogram);
+ JsoDevirtualizer.exec(jprogram);
+ CatchBlockNormalizer.exec(jprogram);
+ PostOptimizationCompoundAssignmentNormalizer.exec(jprogram);
+ LongEmulationNormalizer.exec(jprogram);
+ CastNormalizer.exec(jprogram);
+ ArrayNormalizer.exec(jprogram);
+ EqualityNormalizer.exec(jprogram);
+
+ // (6) Perform further post-normalization optimizations
+ // Prune everything
+ Pruner.exec(jprogram, false);
+
+ // (7) Generate a JavaScript code DOM from the Java type declarations
+ jprogram.typeOracle.recomputeClinits();
+ GenerateJavaScriptAST.exec(jprogram, jsProgram, options.getOutput());
+
+ // Allow GC.
+ jprogram = null;
+
+ // (8) Normalize the JS AST.
+ // Fix invalid constructs created during JS AST gen.
+ JsNormalizer.exec(jsProgram);
+ // Resolve all unresolved JsNameRefs.
+ JsSymbolResolver.exec(jsProgram);
+
+ // (9) Optimize the JS AST.
+ if (options.isAggressivelyOptimize()) {
+ boolean didChange;
+ do {
+ if (Thread.interrupted()) {
+ throw new InterruptedException();
+ }
+
+ didChange = false;
+ // Remove unused functions, possible
+ didChange = JsStaticEval.exec(jsProgram) || didChange;
+ // Inline JavaScript function invocations
+ didChange = JsInliner.exec(jsProgram) || didChange;
+ // Remove unused functions, possible
+ didChange = JsUnusedFunctionRemover.exec(jsProgram) || didChange;
+ } while (didChange);
+ }
+
+ // (10) Obfuscate
+ switch (options.getOutput()) {
+ case OBFUSCATED:
+ JsStringInterner.exec(jsProgram);
+ JsObfuscateNamer.exec(jsProgram);
+ break;
+ case PRETTY:
+ // We don't intern strings in pretty mode to improve readability
+ JsPrettyNamer.exec(jsProgram);
+ break;
+ case DETAILED:
+ JsStringInterner.exec(jsProgram);
+ JsVerboseNamer.exec(jsProgram);
+ break;
+ default:
+ throw new InternalCompilerException("Unknown output mode");
+ }
+
+ // (11) Perform any post-obfuscation normalizations.
+
+ // Work around an IE7 bug,
+ // http://code.google.com/p/google-web-toolkit/issues/detail?id=1440
+ JsIEBlockSizeVisitor.exec(jsProgram);
+
+ // (12) Generate the final output text.
+ DefaultTextOutput out = new DefaultTextOutput(
+ options.getOutput().shouldMinimize());
+ JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out);
+ v.accept(jsProgram);
+ return out.toString();
+ } catch (Throwable e) {
+ throw logAndTranslateException(logger, e);
+ }
+ }
+
+ /**
+ * Performs a precompilation, returning a unified AST.
+ *
+ * @param logger the logger to use
+ * @param compilerFrontEnd the compiler front ent
+ * @param declEntryPts the set of entry classes
+ * @param options the compiler options
+ * @param singlePermutation if true, do not pre-optimize the resulting AST or
+ * allow serialization of the result
+ * @return the unified AST used to drive permutation compiles
+ * @throws UnableToCompleteException if an error other than
+ * {@link OutOfMemoryError} occurs
+ */
+ public static UnifiedAst precompile(TreeLogger logger,
+ WebModeCompilerFrontEnd compilerFrontEnd, String[] declEntryPts,
+ JJSOptions options, boolean singlePermutation)
+ throws UnableToCompleteException {
+
+ if (declEntryPts.length == 0) {
+ throw new IllegalArgumentException("entry point(s) required");
+ }
+
+ RebindPermutationOracle rpo = compilerFrontEnd.getRebindPermutationOracle();
+
+ // Find all the possible rebound entry points.
+ Set<String> allEntryPoints = new TreeSet<String>();
+ for (String element : declEntryPts) {
+ String[] all = rpo.getAllPossibleRebindAnswers(logger, element);
+ Util.addAll(allEntryPoints, all);
+ }
+ allEntryPoints.addAll(JProgram.CODEGEN_TYPES_SET);
+ allEntryPoints.addAll(JProgram.INDEX_TYPES_SET);
+
+ // Compile the source and get the compiler so we can get the parse tree
+ //
+ CompilationUnitDeclaration[] goldenCuds = compilerFrontEnd.getCompilationUnitDeclarations(
+ logger, allEntryPoints.toArray(new String[0]));
+
+ // Check for compilation problems. We don't log here because any problems
+ // found here will have already been logged by AbstractCompiler.
+ //
+ checkForErrors(logger, goldenCuds, false);
+
+ PerfLogger.start("Build AST");
+ JProgram jprogram = new JProgram();
+ JsProgram jsProgram = new JsProgram();
+
+ try {
+ long usedMemoryBefore = singlePermutation ? 0 : getUsedMemory();
+
+ /*
+ * (1) Build a flattened map of TypeDeclarations => JType. The resulting
+ * map contains entries for all reference types. BuildTypeMap also parses
+ * all JSNI.
+ */
+ TypeMap typeMap = new TypeMap(jprogram);
+ TypeDeclaration[] allTypeDeclarations = BuildTypeMap.exec(typeMap,
+ goldenCuds, jsProgram);
+
+ // BuildTypeMap can uncover syntactic JSNI errors; report & abort
+ checkForErrors(logger, goldenCuds, true);
+
+ // Compute all super type/sub type info
+ jprogram.typeOracle.computeBeforeAST();
+
+ // (2) Create our own Java AST from the JDT AST.
+ GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram, jsProgram,
+ options.isEnableAssertions());
+
+ long usedMemoryAfter = singlePermutation ? 0 : getUsedMemory();
+ long memoryDelta = usedMemoryAfter - usedMemoryBefore;
+ long astMemoryUsage = (long) (memoryDelta * 1.5);
+
+ // GenerateJavaAST can uncover semantic JSNI errors; report & abort
+ checkForErrors(logger, goldenCuds, true);
+
+ // Allow GC
+ goldenCuds = null;
+ typeMap = null;
+ allTypeDeclarations = null;
+
+ // (3) Perform Java AST normalizations.
+
+ FixAssignmentToUnbox.exec(jprogram);
+
+ /*
+ * TODO: If we defer this until later, we could maybe use the results of
+ * the assertions to enable more optimizations.
+ */
+ if (options.isEnableAssertions()) {
+ // Turn into assertion checking calls.
+ AssertionNormalizer.exec(jprogram);
+ } else {
+ // Remove all assert statements.
+ AssertionRemover.exec(jprogram);
+ }
+
+ // Replace GWT.create calls with JGwtCreate nodes.
+ ReplaceRebinds.exec(logger, jprogram, rpo);
+
+ // Resolve entry points, rebinding non-static entry points.
+ findEntryPoints(logger, rpo, declEntryPts, jprogram);
+
+ // Replace references to JSO subtypes with JSO itself.
+ JavaScriptObjectNormalizer.exec(jprogram);
+
+ /*
+ * (4) Optimize the normalized Java AST for the common AST. By doing
+ * optimizations early in the multiple permutation scenario, we're saving
+ * work. However, we can't fully optimize because we don't yet know the
+ * deferred binding decisions.
+ *
+ * Don't bother optimizing early if there's only one permutation.
+ */
+ if (!singlePermutation) {
+ optimize(options, jprogram);
+ }
+
+ Set<String> rebindRequests = new HashSet<String>();
+ RecordRebinds.exec(jprogram, rebindRequests);
+
+ return new UnifiedAst(options, new AST(jprogram, jsProgram),
+ singlePermutation, astMemoryUsage, rebindRequests);
+ } catch (Throwable e) {
+ throw logAndTranslateException(logger, e);
+ } finally {
+ PerfLogger.end();
+ }
+ }
+
+ protected static void optimize(JJSOptions options, JProgram jprogram)
+ throws InterruptedException {
+ /*
+ * Record the beginning of optimizations; this turns on certain checks that
+ * guard against problematic late construction of things like class
+ * literals.
+ */
+ jprogram.beginOptimizations();
+
+ boolean didChange;
+ do {
+ if (Thread.interrupted()) {
+ throw new InterruptedException();
+ }
+
+ // Recompute clinits each time, they can become empty.
+ jprogram.typeOracle.recomputeClinits();
+
+ didChange = false;
+ // Remove unreferenced types, fields, methods, [params, locals]
+ didChange = Pruner.exec(jprogram, true) || didChange;
+ // finalize locals, params, fields, methods, classes
+ didChange = Finalizer.exec(jprogram) || didChange;
+ // rewrite non-polymorphic calls as static calls; update all call sites
+ didChange = MakeCallsStatic.exec(jprogram) || didChange;
+
+ // type flow tightening
+ // - fields, locals based on assignment
+ // - params based on assignment and call sites
+ // - method bodies based on return statements
+ // - polymorphic methods based on return types of all implementors
+ // - optimize casts and instance of
+ didChange = TypeTightener.exec(jprogram) || didChange;
+
+ // tighten method call bindings
+ didChange = MethodCallTightener.exec(jprogram) || didChange;
+
+ // dead code removal??
+ didChange = DeadCodeElimination.exec(jprogram) || didChange;
+
+ if (options.isAggressivelyOptimize()) {
+ // inlining
+ didChange = MethodInliner.exec(jprogram) || didChange;
+ }
+ // prove that any types that have been culled from the main tree are
+ // unreferenced due to type tightening?
+ } while (didChange);
+ }
+
+ private static void checkForErrors(TreeLogger logger,
+ CompilationUnitDeclaration[] cuds, boolean itemizeErrors)
+ throws UnableToCompleteException {
+ boolean compilationFailed = false;
+ if (cuds.length == 0) {
+ compilationFailed = true;
+ }
+ Set<IProblem> problemSet = new HashSet<IProblem>();
+ for (CompilationUnitDeclaration cud : cuds) {
+ CompilationResult result = cud.compilationResult();
+ if (result.hasErrors()) {
+ compilationFailed = true;
+ // Early out if we don't need to itemize.
+ if (!itemizeErrors) {
+ break;
+ }
+ TreeLogger branch = logger.branch(TreeLogger.ERROR, "Errors in "
+ + String.valueOf(result.getFileName()), null);
+ IProblem[] errors = result.getErrors();
+ for (IProblem problem : errors) {
+ if (problemSet.contains(problem)) {
+ continue;
+ }
+
+ problemSet.add(problem);
+
+ // Strip the initial code from each error.
+ //
+ String msg = problem.toString();
+ msg = msg.substring(msg.indexOf(' '));
+
+ // Append 'file (line): msg' to the error message.
+ //
+ int line = problem.getSourceLineNumber();
+ StringBuffer msgBuf = new StringBuffer();
+ msgBuf.append("Line ");
+ msgBuf.append(line);
+ msgBuf.append(": ");
+ msgBuf.append(msg);
+ branch.log(TreeLogger.ERROR, msgBuf.toString(), null);
+ }
+ }
+ }
+ if (compilationFailed) {
+ logger.log(TreeLogger.ERROR, "Cannot proceed due to previous errors",
+ null);
+ throw new UnableToCompleteException();
+ }
+ }
+
private static JMethodCall createReboundModuleLoad(TreeLogger logger,
JProgram program, JReferenceType reboundEntryType,
String originalMainClassName) throws UnableToCompleteException {
@@ -127,9 +466,9 @@
+ originalMainClassName + "' must not be abstract", null);
throw new UnableToCompleteException();
}
-
SourceInfo sourceInfo = reboundEntryType.getSourceInfo().makeChild(
JavaToJavaScriptCompiler.class, "Rebound entry point");
+
JExpression qualifier = null;
if (!entryMethod.isStatic()) {
qualifier = JGwtCreate.createInstantiationExpression(program, sourceInfo,
@@ -151,11 +490,10 @@
private static void findEntryPoints(TreeLogger logger,
RebindPermutationOracle rpo, String[] mainClassNames, JProgram program)
throws UnableToCompleteException {
- JMethod bootStrapMethod = program.createMethod(
- program.createSourceInfoSynthetic(JavaToJavaScriptCompiler.class,
- "Bootstrap method"), "init".toCharArray(),
- program.getIndexedType("EntryMethodHolder"), program.getTypeVoid(),
- false, true, true, false, false);
+ SourceInfo sourceInfo = program.createSourceInfoSynthetic(JavaToJavaScriptCompiler.class,
+ "Bootstrap method");
+ JMethod bootStrapMethod = program.createMethod(sourceInfo, "init".toCharArray(),
+ null, program.getTypeVoid(), false, true, true, false, false);
bootStrapMethod.freezeParamTypes();
JMethodBody body = (JMethodBody) bootStrapMethod.getBody();
@@ -232,466 +570,15 @@
}
private static long getUsedMemory() {
+ System.gc();
long used = Runtime.getRuntime().totalMemory()
- Runtime.getRuntime().freeMemory();
assert (used > 0);
return used;
}
- /**
- * Create a variable assignment to invoke a call to the statistics collector.
- *
- * <pre>
- * Stats.isStatsAvailable() &&
- * Stats.onModuleStart("mainClassName");
- * </pre>
- */
- private static JStatement makeStatsCalls(JProgram program,
- String mainClassName) {
- SourceInfo sourceInfo = program.createSourceInfoSynthetic(
- JavaToJavaScriptCompiler.class, "onModuleStart() stats call");
- JMethod isStatsAvailableMethod = program.getIndexedMethod("Stats.isStatsAvailable");
- JMethod onModuleStartMethod = program.getIndexedMethod("Stats.onModuleStart");
-
- JMethodCall availableCall = new JMethodCall(program, sourceInfo, null,
- isStatsAvailableMethod);
- JMethodCall onModuleStartCall = new JMethodCall(program, sourceInfo, null,
- onModuleStartMethod);
- onModuleStartCall.getArgs().add(
- program.getLiteralString(sourceInfo, mainClassName));
-
- JBinaryOperation amp = new JBinaryOperation(program, sourceInfo,
- program.getTypePrimitiveBoolean(), JBinaryOperator.AND, availableCall,
- onModuleStartCall);
-
- return amp.makeStatement();
- }
-
- private final long astMemoryUsage;
- private final String[] declEntryPoints;
- private final Object myLockObject = new Object();
- private final JJSOptions options;
- private final Set<IProblem> problemSet = new HashSet<IProblem>();
- private JProgram savedJProgram = null;
- private JsProgram savedJsProgram = null;
- private final byte[] serializedAst;
-
- public JavaToJavaScriptCompiler(TreeLogger logger,
- WebModeCompilerFrontEnd compiler, String[] declEntryPts)
- throws UnableToCompleteException {
- this(logger, compiler, declEntryPts, new JJSOptions());
- }
-
- public JavaToJavaScriptCompiler(TreeLogger logger,
- WebModeCompilerFrontEnd compiler, String[] declEntryPts,
- JJSOptions compilerOptions) throws UnableToCompleteException {
-
- if (declEntryPts.length == 0) {
- throw new IllegalArgumentException("entry point(s) required");
- }
-
- this.options = new JJSOptions(compilerOptions);
-
- // Remember these for subsequent compiles.
- //
- this.declEntryPoints = declEntryPts;
-
- RebindPermutationOracle rpo = compiler.getRebindPermutationOracle();
-
- if (!options.isValidateOnly()) {
- // Find all the possible rebound entry points.
- Set<String> allEntryPoints = new TreeSet<String>();
- for (String element : declEntryPts) {
- String[] all = rpo.getAllPossibleRebindAnswers(logger, element);
- Util.addAll(allEntryPoints, all);
- }
- allEntryPoints.addAll(JProgram.CODEGEN_TYPES_SET);
- allEntryPoints.addAll(JProgram.INDEX_TYPES_SET);
- declEntryPts = allEntryPoints.toArray(new String[0]);
- }
-
- // Compile the source and get the compiler so we can get the parse tree
- //
- CompilationUnitDeclaration[] goldenCuds = compiler.getCompilationUnitDeclarations(
- logger, declEntryPts);
-
- // Check for compilation problems. We don't log here because any problems
- // found here will have already been logged by AbstractCompiler.
- //
- checkForErrors(logger, goldenCuds, false);
-
- PerfLogger.start("Build AST");
- boolean enableDescendants = compilerOptions.getSoycOutputDir() != null;
- JProgram jprogram = savedJProgram = new JProgram();
- jprogram.setEnableSourceInfoDescendants(enableDescendants);
- JsProgram jsProgram = savedJsProgram = new JsProgram();
- jsProgram.setEnableSourceInfoDescendants(enableDescendants);
-
- long memoryDelta;
- try {
- System.gc();
- long usedMemoryBefore = getUsedMemory();
- /*
- * (1) Build a flattened map of TypeDeclarations => JType. The resulting
- * map contains entries for all reference types. BuildTypeMap also parses
- * all JSNI.
- */
- TypeMap typeMap = new TypeMap(jprogram);
- TypeDeclaration[] allTypeDeclarations = BuildTypeMap.exec(typeMap,
- goldenCuds, jsProgram);
-
- // BuildTypeMap can uncover syntactic JSNI errors; report & abort
- checkForErrors(logger, goldenCuds, true);
-
- // Compute all super type/sub type info
- jprogram.typeOracle.computeBeforeAST();
-
- // (2) Create our own Java AST from the JDT AST.
- GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram, jsProgram,
- options.isEnableAssertions());
-
- System.gc();
- long usedMemoryAfter = getUsedMemory();
- memoryDelta = usedMemoryAfter - usedMemoryBefore;
- long localAstMemoryUsage = (long) (memoryDelta * 1.5);
-
- // GenerateJavaAST can uncover semantic JSNI errors; report & abort
- checkForErrors(logger, goldenCuds, true);
-
- // Allow GC
- goldenCuds = null;
- typeMap = null;
- allTypeDeclarations = null;
-
- // (3) Perform Java AST normalizations.
-
- FixAssignmentToUnbox.exec(jprogram);
-
- /*
- * TODO: If we defer this until later, we could maybe use the results of
- * the assertions to enable more optimizations.
- */
- if (options.isEnableAssertions()) {
- // Turn into assertion checking calls.
- AssertionNormalizer.exec(jprogram);
- } else {
- // Remove all assert statements.
- AssertionRemover.exec(jprogram);
- }
-
- // Replace GWT.create calls with JGwtCreate nodes.
- ReplaceRebinds.exec(logger, jprogram, rpo);
-
- // Resolve entry points, rebinding non-static entry points.
- findEntryPoints(logger, rpo, declEntryPoints, jprogram);
-
- // Replace references to JSO subtypes with JSO itself.
- JavaScriptObjectNormalizer.exec(jprogram);
-
- /*
- * (4) Optimize the normalized Java AST for the common AST. By doing
- * optimizations early in the multiple permutation scenario, we're saving
- * work. However, we can't fully optimized because we don't yet know the
- * deferred binding decisions.
- *
- * Don't bother optimizing early if there's only one permutation.
- */
- if (rpo.getPermuationCount() > 1) {
- optimize(jprogram);
-
- PerfLogger.start("serialize");
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream os = new ObjectOutputStream(baos);
- os.writeObject(jprogram);
- os.writeObject(jsProgram);
- os.close();
- serializedAst = baos.toByteArray();
- PerfLogger.end();
-
- // Very rough heuristic.
- this.astMemoryUsage = Math.max(localAstMemoryUsage,
- serializedAst.length * 4);
- logger.log(TreeLogger.TRACE, "Estimated AST memory usage: "
- + astMemoryUsage + " = Math.max(" + memoryDelta + " * 1.5, "
- + serializedAst.length + " * 4)");
- } else {
- this.astMemoryUsage = localAstMemoryUsage;
- this.serializedAst = null;
- }
- } catch (IOException e) {
- throw new RuntimeException(
- "Should be impossible to get an IOException reading an in-memory stream",
- e);
- } catch (Throwable e) {
- throw logAndTranslateException(logger, e);
- } finally {
- PerfLogger.end();
- synchronized (myLockObject) {
- /*
- * JLS 17.4.4: ensure all changes are visible to any other thread
- * calling compile.
- *
- * TODO: is this necessary?
- */
- }
- }
- }
-
- /**
- * Creates finished JavaScript source code from the specified Java compilation
- * units.
- */
- public String compile(TreeLogger logger, RebindOracle rebindOracle)
- throws UnableToCompleteException {
-
- JProgram jprogram = null;
- JsProgram jsProgram = null;
-
- synchronized (myLockObject) {
- if (savedJProgram != null && savedJsProgram != null) {
- jprogram = savedJProgram;
- jsProgram = savedJsProgram;
- savedJProgram = null;
- savedJsProgram = null;
- } else {
- if (serializedAst == null) {
- throw new IllegalStateException("No serialized AST was cached.");
- }
- try {
- /*
- * Force all AST deserializations to occur in sequence; this reduces
- * the chance of multiple threads going OOM at the same time.
- */
- synchronized (myLockObject) {
- PerfLogger.start("deserialize");
- ByteArrayInputStream bais = new ByteArrayInputStream(serializedAst);
- ObjectInputStream is;
- is = new ObjectInputStream(bais);
- jprogram = (JProgram) is.readObject();
- jsProgram = (JsProgram) is.readObject();
- PerfLogger.end();
- }
- } catch (IOException e) {
- throw new RuntimeException(
- "Should be impossible for memory based streams", e);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(
- "Should be impossible when deserializing in process", e);
- }
- }
- }
-
- try {
- return doCompile(logger, jprogram, jsProgram, rebindOracle);
- } catch (Throwable e) {
- // Allow GC before logging exception in case it was an OOM.
- jprogram = null;
- jsProgram = null;
- throw logAndTranslateException(logger, e);
- }
- }
-
- public long getAstMemoryUsage() {
- return astMemoryUsage;
- }
-
- protected String doCompile(TreeLogger logger, JProgram jprogram,
- JsProgram jsProgram, RebindOracle rebindOracle)
- throws InterruptedException {
- if (JProgram.isTracingEnabled()) {
- System.out.println("------------------------------------------------------------");
- System.out.println("| (new permuation) |");
- System.out.println("------------------------------------------------------------");
- }
-
- ResolveRebinds.exec(logger, jprogram, rebindOracle);
-
- // (4) Optimize the normalized Java AST for each permutation.
- optimize(jprogram);
-
- // (5) "Normalize" the high-level Java tree into a lower-level tree more
- // suited for JavaScript code generation. Don't go reordering these
- // willy-nilly because there are some subtle interdependencies.
- LongCastNormalizer.exec(jprogram);
- JsoDevirtualizer.exec(jprogram);
- CatchBlockNormalizer.exec(jprogram);
- PostOptimizationCompoundAssignmentNormalizer.exec(jprogram);
- LongEmulationNormalizer.exec(jprogram);
- CastNormalizer.exec(jprogram);
- ArrayNormalizer.exec(jprogram);
- EqualityNormalizer.exec(jprogram);
-
- // (6) Perform further post-normalization optimizations
- // Prune everything
- Pruner.exec(jprogram, false);
-
- // (7) Generate a JavaScript code DOM from the Java type declarations
- jprogram.typeOracle.recomputeClinits();
- GenerateJavaScriptAST.exec(jprogram, jsProgram, options.getOutput());
-
- // Allow GC.
- jprogram = null;
-
- // (8) Normalize the JS AST.
- // Fix invalid constructs created during JS AST gen.
- JsNormalizer.exec(jsProgram);
- // Resolve all unresolved JsNameRefs.
- JsSymbolResolver.exec(jsProgram);
-
- // (9) Optimize the JS AST.
- if (options.isAggressivelyOptimize()) {
- boolean didChange;
- do {
- if (Thread.interrupted()) {
- throw new InterruptedException();
- }
-
- didChange = false;
- // Remove unused functions, possible
- didChange = JsStaticEval.exec(jsProgram) || didChange;
- // Inline JavaScript function invocations
- didChange = JsInliner.exec(jsProgram) || didChange;
- // Remove unused functions, possible
- didChange = JsUnusedFunctionRemover.exec(jsProgram) || didChange;
- } while (didChange);
- }
-
- // (10) Obfuscate
- switch (options.getOutput()) {
- case OBFUSCATED:
- JsStringInterner.exec(jsProgram);
- JsObfuscateNamer.exec(jsProgram);
- break;
- case PRETTY:
- // We don't intern strings in pretty mode to improve readability
- JsPrettyNamer.exec(jsProgram);
- break;
- case DETAILED:
- JsStringInterner.exec(jsProgram);
- JsVerboseNamer.exec(jsProgram);
- break;
- default:
- throw new InternalCompilerException("Unknown output mode");
- }
-
- // (11) Perform any post-obfuscation normalizations.
-
- // Work around an IE7 bug,
- // http://code.google.com/p/google-web-toolkit/issues/detail?id=1440
- JsIEBlockSizeVisitor.exec(jsProgram);
-
- // Write the SOYC reports into the output
- if (options.getSoycOutputDir() != null) {
- SourceInfoHistogram.exec(jsProgram, options.getSoycOutputDir());
- }
-
- // (12) Generate the final output text.
- DefaultTextOutput out = new DefaultTextOutput(
- options.getOutput().shouldMinimize());
- JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out);
- v.accept(jsProgram);
- return out.toString();
- }
-
- protected void optimize(JProgram jprogram) throws InterruptedException {
- /*
- * Record the beginning of optimations; this turns on certain checks that
- * guard against problematic late construction of things like class
- * literals.
- */
- jprogram.beginOptimizations();
-
- boolean didChange;
- do {
- if (Thread.interrupted()) {
- throw new InterruptedException();
- }
-
- // Recompute clinits each time, they can become empty.
- jprogram.typeOracle.recomputeClinits();
-
- didChange = false;
- // Remove unreferenced types, fields, methods, [params, locals]
- didChange = Pruner.exec(jprogram, true) || didChange;
- // finalize locals, params, fields, methods, classes
- didChange = Finalizer.exec(jprogram) || didChange;
- // rewrite non-polymorphic calls as static calls; update all call sites
- didChange = MakeCallsStatic.exec(jprogram) || didChange;
-
- // type flow tightening
- // - fields, locals based on assignment
- // - params based on assignment and call sites
- // - method bodies based on return statements
- // - polymorphic methods based on return types of all implementors
- // - optimize casts and instance of
- didChange = TypeTightener.exec(jprogram) || didChange;
-
- // tighten method call bindings
- didChange = MethodCallTightener.exec(jprogram) || didChange;
-
- // dead code removal??
- didChange = DeadCodeElimination.exec(jprogram) || didChange;
-
- if (options.isAggressivelyOptimize()) {
- // inlining
- didChange = MethodInliner.exec(jprogram) || didChange;
- }
- // prove that any types that have been culled from the main tree are
- // unreferenced due to type tightening?
- } while (didChange);
- }
-
- private void checkForErrors(TreeLogger logger,
- CompilationUnitDeclaration[] cuds, boolean itemizeErrors)
- throws UnableToCompleteException {
- boolean compilationFailed = false;
- if (cuds.length == 0) {
- compilationFailed = true;
- }
- for (CompilationUnitDeclaration cud : cuds) {
- CompilationResult result = cud.compilationResult();
- if (result.hasErrors()) {
- compilationFailed = true;
- // Early out if we don't need to itemize.
- if (!itemizeErrors) {
- break;
- }
- TreeLogger branch = logger.branch(TreeLogger.ERROR, "Errors in "
- + String.valueOf(result.getFileName()), null);
- IProblem[] errors = result.getErrors();
- for (IProblem problem : errors) {
- if (problemSet.contains(problem)) {
- continue;
- }
-
- problemSet.add(problem);
-
- // Strip the initial code from each error.
- //
- String msg = problem.toString();
- msg = msg.substring(msg.indexOf(' '));
-
- // Append 'file (line): msg' to the error message.
- //
- int line = problem.getSourceLineNumber();
- StringBuffer msgBuf = new StringBuffer();
- msgBuf.append("Line ");
- msgBuf.append(line);
- msgBuf.append(": ");
- msgBuf.append(msg);
- branch.log(TreeLogger.ERROR, msgBuf.toString(), null);
- }
- }
- }
- if (compilationFailed) {
- logger.log(TreeLogger.ERROR, "Cannot proceed due to previous errors",
- null);
- throw new UnableToCompleteException();
- }
- }
-
- private UnableToCompleteException logAndTranslateException(TreeLogger logger,
- Throwable e) {
+ private static UnableToCompleteException logAndTranslateException(
+ TreeLogger logger, Throwable e) {
if (e instanceof UnableToCompleteException) {
// just rethrow
return (UnableToCompleteException) e;
@@ -732,4 +619,33 @@
return new UnableToCompleteException();
}
}
+
+ /**
+ * Create a variable assignment to invoke a call to the statistics collector.
+ *
+ * <pre>
+ * Stats.isStatsAvailable() &&
+ * Stats.onModuleStart("mainClassName");
+ * </pre>
+ */
+ private static JStatement makeStatsCalls(JProgram program,
+ String mainClassName) {
+ SourceInfo sourceInfo = program.createSourceInfoSynthetic(
+ JavaToJavaScriptCompiler.class, "onModuleStart() stats call");
+ JMethod isStatsAvailableMethod = program.getIndexedMethod("Stats.isStatsAvailable");
+ JMethod onModuleStartMethod = program.getIndexedMethod("Stats.onModuleStart");
+
+ JMethodCall availableCall = new JMethodCall(program, sourceInfo, null,
+ isStatsAvailableMethod);
+ JMethodCall onModuleStartCall = new JMethodCall(program, sourceInfo, null,
+ onModuleStartMethod);
+ onModuleStartCall.getArgs().add(program.getLiteralString(sourceInfo, mainClassName));
+
+ JBinaryOperation amp = new JBinaryOperation(program, sourceInfo,
+ program.getTypePrimitiveBoolean(), JBinaryOperator.AND, availableCall,
+ onModuleStartCall);
+
+ return amp.makeStatement();
+ }
+
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/UnifiedAst.java b/dev/core/src/com/google/gwt/dev/jjs/UnifiedAst.java
new file mode 100644
index 0000000..a5e85b0
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/UnifiedAst.java
@@ -0,0 +1,208 @@
+/*
+ * 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.jjs;
+
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.util.PerfLogger;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Represents a unified, non-permutation specific AST. This AST is used to drive
+ * per-permutation compiles.
+ */
+public final class UnifiedAst implements Serializable {
+
+ /**
+ * Encapsulates the combined programs.
+ */
+ static final class AST {
+ private JProgram jProgram;
+ private JsProgram jsProgram;
+
+ public AST(JProgram jProgram, JsProgram jsProgram) {
+ this.jProgram = jProgram;
+ this.jsProgram = jsProgram;
+ }
+
+ JProgram getJProgram() {
+ return jProgram;
+ }
+
+ JsProgram getJsProgram() {
+ return jsProgram;
+ }
+ }
+
+ /**
+ * Estimated AST memory usage.
+ */
+ private long astMemoryUsage;
+
+ /**
+ * The original AST; nulled out once consumed (by the first call to
+ * {@link #getFreshAst()}.
+ */
+ private transient AST initialAst;
+
+ /**
+ * Used for internal synchronization.
+ */
+ private transient Object myLockObject = new Object();
+
+ /**
+ * The compilation options.
+ */
+ private final JJSOptions options;
+
+ /**
+ * The set of all live rebind request types in the AST.
+ */
+ private final SortedSet<String> rebindRequests;
+
+ /**
+ * The serialized form of savedAst.
+ */
+ private byte[] serializedAst;
+
+ /**
+ * If <code>true</code>, only one permutation will be run, so we don't need
+ * to serialize our AST (unless this whole object is about to be serialized).
+ */
+ private transient boolean singlePermutation;
+
+ public UnifiedAst(JJSOptions options, AST initialAst,
+ boolean singlePermutation, long astMemoryUsage, Set<String> rebindRequests) {
+ this.options = new JJSOptionsImpl(options);
+ this.initialAst = initialAst;
+ this.singlePermutation = singlePermutation;
+ this.astMemoryUsage = astMemoryUsage;
+ this.rebindRequests = Collections.unmodifiableSortedSet(new TreeSet<String>(
+ rebindRequests));
+ }
+
+ /**
+ * Returns a rough estimate of how much memory an AST will take up.
+ */
+ public long getAstMemoryUsage() {
+ return astMemoryUsage;
+ }
+
+ /**
+ * Returns the active set of JJS options associated with this compile.
+ */
+ public JJSOptions getOptions() {
+ return new JJSOptionsImpl(options);
+ }
+
+ /**
+ * Returns the set of live rebind requests in the AST.
+ */
+ public SortedSet<String> getRebindRequests() {
+ return rebindRequests;
+ }
+
+ AST getFreshAst() {
+ synchronized (myLockObject) {
+ if (initialAst != null) {
+ if (!singlePermutation && serializedAst == null) {
+ // Must preserve a serialized copy for future calls.
+ serializeAst();
+ }
+ AST result = initialAst;
+ initialAst = null;
+ return result;
+ } else {
+ if (serializedAst == null) {
+ throw new IllegalStateException("No serialized AST was cached.");
+ }
+ return deserializeAst();
+ }
+ }
+ }
+
+ private AST deserializeAst() {
+ try {
+ PerfLogger.start("deserialize");
+ ByteArrayInputStream bais = new ByteArrayInputStream(serializedAst);
+ ObjectInputStream is;
+ is = new ObjectInputStream(bais);
+ JProgram jprogram = (JProgram) is.readObject();
+ JsProgram jsProgram = (JsProgram) is.readObject();
+ return new AST(jprogram, jsProgram);
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Should be impossible for memory based streams", e);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(
+ "Should be impossible when deserializing in process", e);
+ } finally {
+ PerfLogger.end();
+ }
+ }
+
+ /**
+ * Re-initialize lock object.
+ */
+ private Object readResolve() {
+ myLockObject = new Object();
+ return this;
+ }
+
+ private void serializeAst() {
+ try {
+ assert (initialAst != null);
+ assert (serializedAst == null);
+ PerfLogger.start("serialize");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream os = new ObjectOutputStream(baos);
+ os.writeObject(initialAst.getJProgram());
+ os.writeObject(initialAst.getJsProgram());
+ os.close();
+ serializedAst = baos.toByteArray();
+
+ // Very rough heuristic.
+ astMemoryUsage = Math.max(astMemoryUsage, serializedAst.length * 4);
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Should be impossible for memory based streams", e);
+ } finally {
+ PerfLogger.end();
+ }
+ }
+
+ /**
+ * Force byte serialization of AST before writing.
+ */
+ private Object writeReplace() {
+ synchronized (myLockObject) {
+ if (serializedAst == null) {
+ serializeAst();
+ }
+ }
+ return this;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
index eaab6ad..3a86ae0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
@@ -116,6 +116,9 @@
&& !stmts.isEmpty()) {
// clinit() calls cannot be inlined unless they are empty
possibleToInline = false;
+ } else if (!body.locals.isEmpty()) {
+ // methods with local variables cannot be inlined
+ possibleToInline = false;
} else {
JMultiExpression multi = createMultiExpressionFromBody(body,
ignoringReturnValueFor == x);
@@ -474,6 +477,7 @@
this.method = method;
}
+ @Override
public void endVisit(JMethodCall x, Context ctx) {
if (x.getTarget() == method) {
isRecursive = true;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index f3bb111..ce55dad 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -479,7 +479,7 @@
@Override
public boolean visit(JBinaryOperation x, Context ctx) {
// special string concat handling
- if (x.getOp() == JBinaryOperator.ADD
+ if ((x.getOp() == JBinaryOperator.ADD || x.getOp() == JBinaryOperator.ASG_ADD)
&& x.getType() == program.getTypeJavaLangString()) {
rescueByConcat(x.getLhs().getType());
rescueByConcat(x.getRhs().getType());
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/RecordRebinds.java b/dev/core/src/com/google/gwt/dev/jjs/impl/RecordRebinds.java
new file mode 100644
index 0000000..489043b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/RecordRebinds.java
@@ -0,0 +1,62 @@
+/*
+ * 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.jjs.impl;
+
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JGwtCreate;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JReboundEntryPoint;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+
+import java.util.Set;
+
+/**
+ * Records all live rebinds.
+ */
+public class RecordRebinds {
+
+ private class RebindVisitor extends JVisitor {
+ @Override
+ public void endVisit(JGwtCreate x, Context ctx) {
+ String reqType = x.getSourceType().getName().replace('$', '.');
+ liveRebindRequests.add(reqType);
+ }
+
+ @Override
+ public void endVisit(JReboundEntryPoint x, Context ctx) {
+ String reqType = x.getSourceType().getName().replace('$', '.');
+ liveRebindRequests.add(reqType);
+ }
+ }
+
+ public static void exec(JProgram program, Set<String> liveRebindRequests) {
+ new RecordRebinds(program, liveRebindRequests).execImpl();
+ }
+
+ private final JProgram program;
+ private final Set<String> liveRebindRequests;
+
+ private RecordRebinds(JProgram program, Set<String> liveRebindRequests) {
+ this.program = program;
+ this.liveRebindRequests = liveRebindRequests;
+ }
+
+ private void execImpl() {
+ RebindVisitor rebinder = new RebindVisitor();
+ rebinder.accept(program);
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
index d0cbdd7..841735a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
@@ -15,9 +15,6 @@
*/
package com.google.gwt.dev.jjs.impl;
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.jdt.RebindOracle;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JClassType;
@@ -29,6 +26,7 @@
import com.google.gwt.dev.jjs.ast.JType;
import java.util.List;
+import java.util.Map;
/**
* Replaces any "GWT.create()" calls with a new expression for the actual result
@@ -70,29 +68,23 @@
}
}
- public static boolean exec(TreeLogger logger, JProgram program,
- RebindOracle rebindOracle) {
- return new ResolveRebinds(logger, program, rebindOracle).execImpl();
+ public static boolean exec(JProgram program, Map<String, String> rebindAnswers) {
+ return new ResolveRebinds(program, rebindAnswers).execImpl();
}
- private final TreeLogger logger;
private final JProgram program;
- private final RebindOracle rebindOracle;
+ private final Map<String, String> rebindAnswers;
- private ResolveRebinds(TreeLogger logger, JProgram program,
- RebindOracle rebindOracle) {
- this.logger = logger;
+ private ResolveRebinds(JProgram program, Map<String, String> rebindAnswers) {
this.program = program;
- this.rebindOracle = rebindOracle;
+ this.rebindAnswers = rebindAnswers;
}
public JClassType rebind(JType type) {
// Rebinds are always on a source type name.
String reqType = type.getName().replace('$', '.');
- String reboundClassName;
- try {
- reboundClassName = rebindOracle.rebind(logger, reqType);
- } catch (UnableToCompleteException e) {
+ String reboundClassName = rebindAnswers.get(reqType);
+ if (reboundClassName == null) {
// The fact that we already compute every rebind permutation before
// compiling should prevent this case from ever happening in real life.
//
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
index a8262fb..749bd5a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
@@ -652,9 +652,13 @@
* Find a replacement method. If the original method is abstract, this will
* return the leaf, final implementation of the method. If the method is
* already concrete, but enclosed by an abstract type, the overriding method
- * from the leaf concrete type will be returned.
+ * from the leaf concrete type will be returned. If the method is static,
+ * return <code>null</code> no matter what.
*/
private JMethod getSingleConcreteMethod(JMethod method) {
+ if (method.isStatic()) {
+ return null;
+ }
if (getSingleConcreteType(method.getEnclosingType()) != null) {
return getSingleConcrete(method, overriders);
} else {
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 b36d31c..670af09 100644
--- a/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
+++ b/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
@@ -22,7 +22,7 @@
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.JJSOptions;
+import com.google.gwt.dev.jjs.JJSOptionsImpl;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.HttpHeaders;
import com.google.gwt.dev.util.Util;
@@ -547,7 +547,7 @@
"Generating a script selection script for module " + moduleName);
StandardLinkerContext context = new StandardLinkerContext(logger,
- getModuleDef(logger, moduleName), null, null, new JJSOptions());
+ getModuleDef(logger, moduleName), new JJSOptionsImpl());
HostedModeLinker linker = new HostedModeLinker();
return linker.generateSelectionScript(logger, context,
context.getArtifacts());
diff --git a/dev/core/src/com/google/gwt/dev/util/Util.java b/dev/core/src/com/google/gwt/dev/util/Util.java
index 6f3d637..aabd864 100644
--- a/dev/core/src/com/google/gwt/dev/util/Util.java
+++ b/dev/core/src/com/google/gwt/dev/util/Util.java
@@ -40,11 +40,14 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.Reader;
+import java.io.Serializable;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
@@ -140,6 +143,19 @@
return toHexString(md5.digest());
}
+ public static void copy(InputStream is, OutputStream os) throws IOException {
+ try {
+ byte[] buf = new byte[8 * 1024];
+ int i;
+ while ((i = is.read(buf)) != -1) {
+ os.write(buf, 0, i);
+ }
+ } finally {
+ Utility.close(is);
+ Utility.close(os);
+ }
+ }
+
public static boolean copy(TreeLogger logger, File in, File out)
throws UnableToCompleteException {
try {
@@ -548,6 +564,43 @@
return null;
}
+ public static <T extends Serializable> T readFileAsObject(File file,
+ Class<T> type) throws ClassNotFoundException {
+ FileInputStream fileInputStream = null;
+ ObjectInputStream objectInputStream = null;
+ try {
+ fileInputStream = new FileInputStream(file);
+ objectInputStream = new ObjectInputStream(fileInputStream);
+ return type.cast(objectInputStream.readObject());
+ } catch (IOException e) {
+ return null;
+ } finally {
+ Utility.close(objectInputStream);
+ Utility.close(fileInputStream);
+ }
+ }
+
+ public static Serializable[] readFileAsObjects(File file,
+ Class<? extends Serializable>... types) throws ClassNotFoundException {
+ FileInputStream fileInputStream = null;
+ ObjectInputStream objectInputStream = null;
+ try {
+ fileInputStream = new FileInputStream(file);
+ objectInputStream = new ObjectInputStream(fileInputStream);
+ Serializable[] results = new Serializable[types.length];
+ for (int i = 0; i < results.length; ++i) {
+ Object object = objectInputStream.readObject();
+ results[i] = types[i].cast(object);
+ }
+ return results;
+ } catch (IOException e) {
+ return null;
+ } finally {
+ Utility.close(objectInputStream);
+ Utility.close(fileInputStream);
+ }
+ }
+
public static String readFileAsString(File file) {
byte[] bytes = readFileAsBytes(file);
if (bytes != null) {
@@ -974,24 +1027,26 @@
}
}
- public static void writeStringAsFile(TreeLogger logger, File file,
- String string) throws UnableToCompleteException {
+ /**
+ * Serializes an object and writes it to a file.
+ */
+ public static void writeObjectAsFile(TreeLogger logger, File file,
+ Serializable... objects) throws UnableToCompleteException {
FileOutputStream stream = null;
- OutputStreamWriter writer = null;
- BufferedWriter buffered = null;
+ ObjectOutputStream objectStream = null;
try {
- stream = new FileOutputStream(file);
- writer = new OutputStreamWriter(stream, DEFAULT_ENCODING);
- buffered = new BufferedWriter(writer);
file.getParentFile().mkdirs();
- buffered.write(string);
+ stream = new FileOutputStream(file);
+ objectStream = new ObjectOutputStream(stream);
+ for (Serializable object : objects) {
+ objectStream.writeObject(object);
+ }
} catch (IOException e) {
logger.log(TreeLogger.ERROR, "Unable to write file: "
+ file.getAbsolutePath(), e);
throw new UnableToCompleteException();
} finally {
- Utility.close(buffered);
- Utility.close(writer);
+ Utility.close(objectStream);
Utility.close(stream);
}
}
@@ -1016,16 +1071,25 @@
return true;
}
- private static void copy(InputStream is, OutputStream os) throws IOException {
+ public static void writeStringAsFile(TreeLogger logger, File file,
+ String string) throws UnableToCompleteException {
+ FileOutputStream stream = null;
+ OutputStreamWriter writer = null;
+ BufferedWriter buffered = null;
try {
- byte[] buf = new byte[8 * 1024];
- int i;
- while ((i = is.read(buf)) != -1) {
- os.write(buf, 0, i);
- }
+ stream = new FileOutputStream(file);
+ writer = new OutputStreamWriter(stream, DEFAULT_ENCODING);
+ buffered = new BufferedWriter(writer);
+ file.getParentFile().mkdirs();
+ buffered.write(string);
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to write file: "
+ + file.getAbsolutePath(), e);
+ throw new UnableToCompleteException();
} finally {
- Utility.close(is);
- Utility.close(os);
+ Utility.close(buffered);
+ Utility.close(writer);
+ Utility.close(stream);
}
}
diff --git a/dev/core/src/com/google/gwt/util/tools/ArgHandlerDisableAggressiveOptimization.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableAggressiveOptimization.java
similarity index 69%
rename from dev/core/src/com/google/gwt/util/tools/ArgHandlerDisableAggressiveOptimization.java
rename to dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableAggressiveOptimization.java
index f464ea4..b3b4579 100644
--- a/dev/core/src/com/google/gwt/util/tools/ArgHandlerDisableAggressiveOptimization.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableAggressiveOptimization.java
@@ -13,13 +13,22 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.util.tools;
+package com.google.gwt.dev.util.arg;
+
+import com.google.gwt.util.tools.ArgHandlerFlag;
/**
* Handles the -XdisableAggressiveOptimization command line flag.
*/
-public abstract class ArgHandlerDisableAggressiveOptimization extends
+public final class ArgHandlerDisableAggressiveOptimization extends
ArgHandlerFlag {
+ private final OptionAggressivelyOptimize option;
+
+ public ArgHandlerDisableAggressiveOptimization(
+ OptionAggressivelyOptimize option) {
+ this.option = option;
+ }
+
@Override
public String getPurpose() {
return "Troubleshooting: Prevent the web mode compiler from performing "
@@ -35,4 +44,10 @@
public boolean isUndocumented() {
return true;
}
+
+ @Override
+ public boolean setFlag() {
+ option.setAggressivelyOptimize(false);
+ return true;
+ }
}
diff --git a/dev/core/src/com/google/gwt/util/tools/ArgHandlerEnableAssertions.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerEnableAssertions.java
similarity index 72%
rename from dev/core/src/com/google/gwt/util/tools/ArgHandlerEnableAssertions.java
rename to dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerEnableAssertions.java
index f37fa97..9697b1c 100644
--- a/dev/core/src/com/google/gwt/util/tools/ArgHandlerEnableAssertions.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerEnableAssertions.java
@@ -13,19 +13,19 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.util.tools;
+package com.google.gwt.dev.util.arg;
-import com.google.gwt.dev.jjs.JJSOptions;
+import com.google.gwt.util.tools.ArgHandlerFlag;
/**
* Handles the -ea command line flag.
*/
-public class ArgHandlerEnableAssertions extends ArgHandlerFlag {
+public final class ArgHandlerEnableAssertions extends ArgHandlerFlag {
- private final JJSOptions optionsToModify;
+ private final OptionEnableAssertions option;
- public ArgHandlerEnableAssertions(JJSOptions optionsToModify) {
- this.optionsToModify = optionsToModify;
+ public ArgHandlerEnableAssertions(OptionEnableAssertions option) {
+ this.option = option;
}
@Override
@@ -40,7 +40,7 @@
@Override
public boolean setFlag() {
- optionsToModify.setEnableAssertions(true);
+ option.setEnableAssertions(true);
return true;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerGenDir.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerGenDir.java
index 07ed09c..e9bc414 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerGenDir.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerGenDir.java
@@ -17,10 +17,18 @@
import com.google.gwt.util.tools.ArgHandlerDir;
+import java.io.File;
+
/**
- * Argument handler for processing the code generation directory flag.
+ * Argument handler for processing the code generation directory flag.
*/
-public abstract class ArgHandlerGenDir extends ArgHandlerDir {
+public final class ArgHandlerGenDir extends ArgHandlerDir {
+
+ private final OptionGenDir option;
+
+ public ArgHandlerGenDir(OptionGenDir option) {
+ this.option = option;
+ }
public String getPurpose() {
return "The directory into which generated files will be written for review";
@@ -29,4 +37,9 @@
public String getTag() {
return "-gen";
}
+
+ @Override
+ public void setDir(File dir) {
+ option.setGenDir(dir);
+ }
}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerLogLevel.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerLogLevel.java
index 0008eb9..f2bf710 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerLogLevel.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerLogLevel.java
@@ -21,7 +21,7 @@
/**
* Argument handler for processing the log level flag.
*/
-public abstract class ArgHandlerLogLevel extends ArgHandler {
+public final class ArgHandlerLogLevel extends ArgHandler {
private static final String OPTIONS_STRING = computeOptionsString();
@@ -40,7 +40,13 @@
return sb.toString();
}
- public final String[] getDefaultArgs() {
+ private final OptionLogLevel options;
+
+ public ArgHandlerLogLevel(OptionLogLevel options) {
+ this.options = options;
+ }
+
+ public String[] getDefaultArgs() {
return new String[] {getTag(), getDefaultLogLevel().name()};
}
@@ -60,7 +66,7 @@
if (startIndex + 1 < args.length) {
try {
Type level = Type.valueOf(args[startIndex + 1]);
- setLogLevel(level);
+ options.setLogLevel(level);
return 1;
} catch (IllegalArgumentException e) {
// Argument did not match any enum value; fall through to error case.
@@ -72,8 +78,6 @@
return -1;
}
- public abstract void setLogLevel(Type level);
-
protected Type getDefaultLogLevel() {
return Type.INFO;
}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerModuleName.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerModuleName.java
new file mode 100644
index 0000000..3dab092
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerModuleName.java
@@ -0,0 +1,51 @@
+/*
+ * 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.ArgHandlerExtra;
+
+/**
+ * Argument handler for module name, which has no option profix.
+ */
+public final class ArgHandlerModuleName extends ArgHandlerExtra {
+
+ private final OptionModuleName option;
+
+ public ArgHandlerModuleName(OptionModuleName option) {
+ this.option = option;
+ }
+
+ @Override
+ public boolean addExtraArg(String arg) {
+ option.setModuleName(arg);
+ return true;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Specifies the name of the module to compile";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"module"};
+ }
+
+ @Override
+ public boolean isRequired() {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerOutDir.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerOutDir.java
new file mode 100644
index 0000000..bf5a5b1
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerOutDir.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2006 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 output directory flag.
+ */
+public final class ArgHandlerOutDir extends ArgHandlerDir {
+
+ private final OptionOutDir option;
+
+ public ArgHandlerOutDir(OptionOutDir option) {
+ this.option = option;
+ }
+
+ public String[] getDefaultArgs() {
+ return new String[] {"-out", System.getProperty("user.dir")};
+ }
+
+ public String getPurpose() {
+ return "The directory to write output files into (defaults to current)";
+ }
+
+ public String getTag() {
+ return "-out";
+ }
+
+ @Override
+ public void setDir(File dir) {
+ option.setOutDir(dir);
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerScriptStyle.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerScriptStyle.java
index fff73c9..3c9b5c0 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerScriptStyle.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerScriptStyle.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.dev.util.arg;
-import com.google.gwt.dev.jjs.JJSOptions;
import com.google.gwt.dev.jjs.JsOutputOption;
import com.google.gwt.util.tools.ArgHandler;
@@ -24,10 +23,10 @@
*/
public final class ArgHandlerScriptStyle extends ArgHandler {
- private final JJSOptions optionsToModify;
+ private final OptionScriptStyle option;
- public ArgHandlerScriptStyle(JJSOptions optionsToModify) {
- this.optionsToModify = optionsToModify;
+ public ArgHandlerScriptStyle(OptionScriptStyle option) {
+ this.option = option;
}
public String[] getDefaultArgs() {
@@ -50,13 +49,13 @@
if (startIndex + 1 < args.length) {
String style = args[startIndex + 1].toLowerCase();
if (style.startsWith("obf")) {
- optionsToModify.setOutput(JsOutputOption.OBFUSCATED);
+ option.setOutput(JsOutputOption.OBFUSCATED);
return 1;
} else if ("pretty".equals(style)) {
- optionsToModify.setOutput(JsOutputOption.PRETTY);
+ option.setOutput(JsOutputOption.PRETTY);
return 1;
} else if ("detailed".equals(style)) {
- optionsToModify.setOutput(JsOutputOption.DETAILED);
+ option.setOutput(JsOutputOption.DETAILED);
return 1;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerTreeLoggerFlag.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerTreeLoggerFlag.java
index a88facb..fe8331d 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerTreeLoggerFlag.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerTreeLoggerFlag.java
@@ -18,9 +18,15 @@
import com.google.gwt.util.tools.ArgHandlerFlag;
/**
- * Argument handler for processing the tree logger boolean flag.
+ * Argument handler for processing the GUI tree logger boolean flag.
*/
-public abstract class ArgHandlerTreeLoggerFlag extends ArgHandlerFlag {
+public final class ArgHandlerTreeLoggerFlag extends ArgHandlerFlag {
+
+ private final OptionGuiLogger option;
+
+ public ArgHandlerTreeLoggerFlag(OptionGuiLogger option) {
+ this.option = option;
+ }
public String getPurpose() {
return "Logs output in a graphical tree view";
@@ -30,5 +36,8 @@
return "-treeLogger";
}
- public abstract boolean setFlag();
+ public boolean setFlag() {
+ option.setUseGuiLogger(true);
+ return true;
+ }
}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerValidateOnlyFlag.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerValidateOnlyFlag.java
new file mode 100644
index 0000000..7740786
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerValidateOnlyFlag.java
@@ -0,0 +1,43 @@
+/*
+ * 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.ArgHandlerFlag;
+
+/**
+ * Handles the -validateOnly command line flag.
+ */
+public final class ArgHandlerValidateOnlyFlag extends ArgHandlerFlag {
+
+ private final OptionValidateOnly option;
+
+ public ArgHandlerValidateOnlyFlag(OptionValidateOnly option) {
+ this.option = option;
+ }
+
+ public String getPurpose() {
+ return "Validate all source code, but do not compile";
+ }
+
+ public String getTag() {
+ return "-validateOnly";
+ }
+
+ public boolean setFlag() {
+ option.setValidateOnly(true);
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionAggressivelyOptimize.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionAggressivelyOptimize.java
new file mode 100644
index 0000000..889a25f
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionAggressivelyOptimize.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.util.arg;
+
+/**
+ * Option to determine whether the compiler should aggressively optimize.
+ */
+public interface OptionAggressivelyOptimize {
+
+ /**
+ * Returns true if the compiler should aggressively optimize.
+ */
+ boolean isAggressivelyOptimize();
+
+ /**
+ * Sets whether or not the compiler should aggressively optimize.
+ */
+ void setAggressivelyOptimize(boolean aggressivelyOptimize);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionEnableAssertions.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionEnableAssertions.java
new file mode 100644
index 0000000..609d95b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionEnableAssertions.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.util.arg;
+
+/**
+ * Option to determine whether the compiler should generate code to check
+ * assertions.
+ */
+public interface OptionEnableAssertions {
+
+ /**
+ * Returns true if the compiler should generate code to check assertions.
+ */
+ boolean isEnableAssertions();
+
+ /**
+ * Sets whether or not the compiler should generate code to check assertions.
+ */
+ void setEnableAssertions(boolean enableAssertions);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionGenDir.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionGenDir.java
new file mode 100644
index 0000000..ff2e253
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionGenDir.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 generated resource directory.
+ */
+public interface OptionGenDir {
+
+ /**
+ * Returns the generated resource directory.
+ */
+ File getGenDir();
+
+ /**
+ * Sets the generated resource directory.
+ */
+ void setGenDir(File dir);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionGuiLogger.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionGuiLogger.java
new file mode 100644
index 0000000..56205ba
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionGuiLogger.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.util.arg;
+
+/**
+ * Option to set whether to use a GUI logger instead of stdout.
+ */
+public interface OptionGuiLogger {
+
+ /**
+ * Returns true if a GUI logger should be used.
+ */
+ boolean isUseGuiLogger();
+
+ /**
+ * Sets whether or not to use a GUI logger.
+ */
+ void setUseGuiLogger(boolean useGuiLogger);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionLogLevel.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionLogLevel.java
new file mode 100644
index 0000000..ebef78d
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionLogLevel.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 com.google.gwt.core.ext.TreeLogger;
+
+/**
+ * Option to set the tree logger log level.
+ */
+public interface OptionLogLevel {
+
+ /**
+ * Returns the tree logger level.
+ */
+ TreeLogger.Type getLogLevel();
+
+ /**
+ * Sets the tree logger level.
+ */
+ void setLogLevel(TreeLogger.Type logLevel);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionModuleName.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionModuleName.java
new file mode 100644
index 0000000..688406e
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionModuleName.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.util.arg;
+
+/**
+ * Option to set the module name.
+ */
+public interface OptionModuleName {
+
+ /**
+ * Returns the name of the module.
+ */
+ String getModuleName();
+
+ /**
+ * Sets the name of the module.
+ */
+ void setModuleName(String moduleName);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionOutDir.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionOutDir.java
new file mode 100644
index 0000000..25b2b12
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionOutDir.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.
+ */
+public interface OptionOutDir {
+
+ /**
+ * Returns the output directory.
+ */
+ File getOutDir();
+
+ /**
+ * Sets the output directory.
+ */
+ void setOutDir(File dir);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionScriptStyle.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionScriptStyle.java
new file mode 100644
index 0000000..736f7e3
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionScriptStyle.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 com.google.gwt.dev.jjs.JsOutputOption;
+
+/**
+ * Option for setting the compiler output style.
+ */
+public interface OptionScriptStyle {
+
+ /**
+ * Returns the compiler output style.
+ */
+ JsOutputOption getOutput();
+
+ /**
+ * Sets the compiler output style.
+ */
+ void setOutput(JsOutputOption obfuscated);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionValidateOnly.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionValidateOnly.java
new file mode 100644
index 0000000..e402255
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionValidateOnly.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.util.arg;
+
+/**
+ * Option to set whether the compiler should validate and then quit.
+ */
+public interface OptionValidateOnly {
+
+ /**
+ * Returns true the compiler should only validate.
+ */
+ boolean isValidateOnly();
+
+ /**
+ * Sets whether or not the compiler should only validate.
+ */
+ void setValidateOnly(boolean validateOnly);
+}
diff --git a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
index 09c8f21..ea2625c 100644
--- a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
@@ -155,6 +155,7 @@
tempOutDir = createTempDir("gwt-out-");
genCtx = new StandardGeneratorContext(mockCompilationState, mockPropOracle,
mockPublicOracle, tempGenDir, tempOutDir, artifactSet);
+ genCtx.setCurrentGenerator(Generator.class);
}
public void testTryCreateResource_badFileName() {
@@ -355,7 +356,8 @@
protected void tearDown() throws Exception {
for (int i = toDelete.size() - 1; i >= 0; --i) {
File f = toDelete.get(i);
- assertTrue(f.delete());
+ Util.recursiveDelete(f, false);
+ assertFalse("Unable to delete " + f.getAbsolutePath(), f.exists());
}
}
diff --git a/distro-source/core/src/release_notes.html b/distro-source/core/src/release_notes.html
index 37721ff..37c804b 100644
--- a/distro-source/core/src/release_notes.html
+++ b/distro-source/core/src/release_notes.html
@@ -29,6 +29,7 @@
<h1>Google Web Toolkit Release Notes</h1>
<ul>
<li><a href="#Release_Notes_Current">@GWT_VERSION@</a></li>
+ <li><a href="#Release_Notes_1_5_2">1.5.2</a></li>
<li><a href="#Release_Notes_1_5_1">1.5.1 (RC2)</a></li>
<li><a href="#Release_Notes_1_5_0">1.5.0 (RC)</a></li>
<li><a href="#Release_Notes_1_4_60">1.4.60</a></li>
@@ -46,6 +47,25 @@
<hr/>
<a name="Release_Notes_Current"></a>
<h2>Release Notes for @GWT_VERSION@</h2>
+ <h3>Fixed Issues</h3>
+ <ul>
+ <li>RPC requests no longer fail on the embedded Android web browser</li>
+ <li>Leaf <code>TreeItems</code> now line up with their non-leaf siblings</li>
+ <li>Removing the last child node from a <code>TreeItem</code> no longer creates extra margins on the left</li>
+ <li><code>HTTPRequest</code> no longer uses POST instead of GET on some IE installs because of incorrect XHR selection</li>
+ <li>Compiler now uses a more reliable check to prevent methods with local variables from being inlined</li>
+ <li><code>getAbsoluteTop()/Left()</code> can no longer return non-integral values</li>
+ <li><code>Time.valueOf()</code> no longer fails to parse <code>"08:00:00"</code> or incorrectly accepts <code>"0xC:0xB:0xA"</code>.</li>
+ </ul>
+ <p>
+ See the GWT issue tracker for
+ <a href="http://code.google.com/p/google-web-toolkit/issues/list?can=1&q=status%3AFixed%2CFixedNotReleased%20milestone%3A1_5_3&num=1000">
+ the complete list of bug fixes and enhancements</a> in this release.
+ </p>
+
+ <hr/>
+ <a name="Release_Notes_1_5_2"></a>
+ <h2>Release Notes for 1.5.2</h2>
<h3>Potentially breaking changes and fixes</h3>
<ul>
<li><code>History.onHistoryChanged()</code> has been added back (it was missing from 1.5 RC2) but is now deprecated. Application startup should be handled by calling the new <code>History.fireCurrentHistoryState()</code>.</li>
diff --git a/eclipse/samples/DynaTable2/.checkstyle b/eclipse/samples/DynaTable2/.checkstyle
new file mode 100644
index 0000000..0f1cbd9
--- /dev/null
+++ b/eclipse/samples/DynaTable2/.checkstyle
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fileset-config file-format-version="1.2.0" simple-config="true">
+ <fileset name="all" enabled="true" check-config-name="GWT Checks" local="false">
+ <file-match-pattern match-pattern="." include-pattern="true"/>
+ </fileset>
+ <filter name="NonSrcDirs" enabled="true"/>
+</fileset-config>
diff --git a/eclipse/samples/DynaTable2/.classpath b/eclipse/samples/DynaTable2/.classpath
new file mode 100644
index 0000000..447a770
--- /dev/null
+++ b/eclipse/samples/DynaTable2/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="core/src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/gwt-user"/>
+ <classpathentry kind="output" path="war/WEB-INF/classes"/>
+</classpath>
diff --git a/eclipse/samples/DynaTable2/.project b/eclipse/samples/DynaTable2/.project
new file mode 100644
index 0000000..5ece582
--- /dev/null
+++ b/eclipse/samples/DynaTable2/.project
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>DynaTable2</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.atlassw.tools.eclipse.checkstyle.CheckstyleBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>com.atlassw.tools.eclipse.checkstyle.CheckstyleNature</nature>
+ </natures>
+ <linkedResources>
+ <link>
+ <name>core</name>
+ <type>2</type>
+ <locationURI>GWT_ROOT/samples/dynatable</locationURI>
+ </link>
+ </linkedResources>
+</projectDescription>
diff --git a/eclipse/samples/DynaTable2/DynaTable2 compile.launch b/eclipse/samples/DynaTable2/DynaTable2 compile.launch
new file mode 100644
index 0000000..9d1d153
--- /dev/null
+++ b/eclipse/samples/DynaTable2/DynaTable2 compile.launch
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/DynaTable2"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<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"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="DynaTable2" path="1" type="4"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/DynaTable2/core/src" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/src" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/super" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-dev-windows/core/super" path="3" type="2"/> "/>
+<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.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.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
new file mode 100644
index 0000000..4029b62
--- /dev/null
+++ b/eclipse/samples/DynaTable2/DynaTable2 server.launch
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/DynaTable2"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<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"/> "/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.mortbay.jetty.Main"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="8888 -webapp war"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="DynaTable2"/>
+</launchConfiguration>
diff --git a/eclipse/samples/DynaTable2/DynaTable2 shell.launch b/eclipse/samples/DynaTable2/DynaTable2 shell.launch
new file mode 100644
index 0000000..cca8023
--- /dev/null
+++ b/eclipse/samples/DynaTable2/DynaTable2 shell.launch
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/DynaTable2"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<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"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="DynaTable2" path="1" type="4"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/DynaTable2/core/src" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/src" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/super" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-dev-windows/core/super" path="3" type="2"/> "/>
+<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.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/build.xml b/eclipse/samples/DynaTable2/build.xml
new file mode 100644
index 0000000..d810bd9
--- /dev/null
+++ b/eclipse/samples/DynaTable2/build.xml
@@ -0,0 +1,82 @@
+<project name="dynatable2" default="build" basedir=".">
+ <property name="gwt.install" location="../../../build/lib" />
+ <property name="wardir" location="war" />
+
+ <target name="javac" description="Compile project to WEB-INF/classes">
+ <mkdir dir="${wardir}/WEB-INF/classes" />
+ <javac srcdir="../../../samples/dynatable/src"
+ destdir="${wardir}/WEB-INF/classes"
+ debug="true"
+ debuglevel="lines,vars,source"
+ source="1.5"
+ target="1.5"
+ nowarn="true"
+ encoding="utf-8">
+ <classpath>
+ <pathelement location="${gwt.install}/gwt-user.jar" />
+ <pathelement location="${gwt.install}/gwt-dev-windows.jar" />
+ </classpath>
+ </javac>
+ </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" />
+ </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" />
+ <classpath>
+ <pathelement location="../../../samples/dynatable/src" />
+ <pathelement location="${wardir}/WEB-INF/classes" />
+ <pathelement location="${gwt.install}/gwt-user.jar" />
+ <pathelement location="${gwt.install}/gwt-dev-windows.jar" />
+ </classpath>
+ </java>
+ </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"/>
+ <java classname="org.mortbay.jetty.Main" fork="yes">
+ <arg value="8888" />
+ <arg value="-webapp" />
+ <arg file="war" />
+ <classpath>
+ <pathelement location="${gwt.install}/gwt-dev-windows.jar" />
+ </classpath>
+ </java>
+ </target>
+
+ <target name="shell" depends="javac" description="Run the deployed app in GWT hosted mode">
+ <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" />
+ <classpath>
+ <pathelement location="../../../samples/dynatable/src" />
+ <pathelement location="${wardir}/WEB-INF/classes" />
+ <pathelement location="${gwt.install}/gwt-user.jar" />
+ <pathelement location="${gwt.install}/gwt-dev-windows.jar" />
+ </classpath>
+ </java>
+ </target>
+
+ <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" />
+ </target>
+</project>
diff --git a/eclipse/samples/DynaTable2/war/WEB-INF/web.xml b/eclipse/samples/DynaTable2/war/WEB-INF/web.xml
new file mode 100644
index 0000000..983aac0
--- /dev/null
+++ b/eclipse/samples/DynaTable2/war/WEB-INF/web.xml
@@ -0,0 +1,16 @@
+<?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 -->
+
+</web-app>
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
index 1fa5461..0d1d36b 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
@@ -26,9 +26,10 @@
// so we use getBoundingClientRect() whenever possible (but it's not
// supported on older versions). If changing this code, make sure to check
// the museum entry for issue 1932.
+ // (x) | 0 is used to coerce the value to an integer
if (Element.prototype.getBoundingClientRect) {
- return elem.getBoundingClientRect().left +
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollLeft;
+ return (elem.getBoundingClientRect().left +
+ @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollLeft) | 0;
} else {
// We cannot use DOMImpl here because offsetLeft/Top return erroneous
// values when overflow is not visible. We have to difference screenX
@@ -46,9 +47,10 @@
// so we use getBoundingClientRect() whenever possible (but it's not
// supported on older versions). If changing this code, make sure to check
// the museum entry for issue 1932.
+ // (x) | 0 is used to coerce the value to an integer
if (Element.prototype.getBoundingClientRect) {
- return elem.getBoundingClientRect().top +
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop;
+ return (elem.getBoundingClientRect().top +
+ @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop) | 0;
} else {
// We cannot use DOMImpl here because offsetLeft/Top return erroneous
// values when overflow is not visible. We have to difference screenX
diff --git a/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java b/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java
index 71b44e2..8852eb9 100644
--- a/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.i18n.rebind;
+import static com.google.gwt.i18n.rebind.AnnotationUtil.getClassAnnotation;
+
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
@@ -139,7 +141,7 @@
context.commit(logger, pw);
}
// Generate a translatable output file if requested.
- Generate generate = targetClass.getAnnotation(Generate.class);
+ Generate generate = getClassAnnotation(targetClass, Generate.class);
if (generate != null) {
String path = generate.fileName();
if (Generate.DEFAULT.equals(path)) {
diff --git a/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableInterfaceCreator.java b/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableInterfaceCreator.java
index 7a98120..8d1d141 100644
--- a/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableInterfaceCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableInterfaceCreator.java
@@ -33,12 +33,10 @@
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Set;
-import java.util.Map.Entry;
-import java.util.regex.Pattern;
/**
* Abstract base functionality for <code>MessagesInterfaceCreator</code> and
@@ -50,20 +48,32 @@
@Override
public String format(String key) {
- if (methodNames.contains(key)) {
+ while (methodNames.contains(key)) {
key += "_dup";
- return format(key);
- } else {
- methodNames.add(key);
- return key;
}
+ methodNames.add(key);
+ return key;
}
}
private static class ReplaceBadChars extends ResourceKeyFormatter {
@Override
public String format(String key) {
- return DEFAULT_CHARS.matcher(key).replaceAll("_");
+ StringBuilder buf = new StringBuilder();
+ int keyLen = key == null ? 0 : key.length();
+ for (int i = 0; i < keyLen; i = key.offsetByCodePoints(i, 1)) {
+ int codePoint = key.codePointAt(i);
+ if (i == 0 ? Character.isJavaIdentifierStart(codePoint)
+ : Character.isJavaIdentifierPart(codePoint)) {
+ buf.appendCodePoint(codePoint);
+ } else {
+ buf.append('_');
+ }
+ }
+ if (buf.length() == 0) {
+ buf.append('_');
+ }
+ return buf.toString();
}
}
@@ -71,15 +81,53 @@
public abstract String format(String key);
}
- private static Pattern DEFAULT_CHARS = Pattern.compile("[.-]");
+ /**
+ * Index into this array using a nibble, 4 bits, to get the corresponding
+ * hexadecimal character representation.
+ */
+ private static final char NIBBLE_TO_HEX_CHAR[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
+ 'E', 'F'};
+
+ private static boolean needsUnicodeEscape(char ch) {
+ if (ch == ' ') {
+ return false;
+ }
+ switch (Character.getType(ch)) {
+ case Character.COMBINING_SPACING_MARK:
+ case Character.ENCLOSING_MARK:
+ case Character.NON_SPACING_MARK:
+ case Character.UNASSIGNED:
+ case Character.PRIVATE_USE:
+ case Character.SPACE_SEPARATOR:
+ case Character.CONTROL:
+ case Character.LINE_SEPARATOR:
+ case Character.FORMAT:
+ case Character.PARAGRAPH_SEPARATOR:
+ case Character.SURROGATE:
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+ }
+
+ private static void unicodeEscape(char ch, StringBuilder buf) {
+ buf.append('\\');
+ buf.append('u');
+ buf.append(NIBBLE_TO_HEX_CHAR[(ch >> 12) & 0x0F]);
+ buf.append(NIBBLE_TO_HEX_CHAR[(ch >> 8) & 0x0F]);
+ buf.append(NIBBLE_TO_HEX_CHAR[(ch >> 4) & 0x0F]);
+ buf.append(NIBBLE_TO_HEX_CHAR[ch & 0x0F]);
+ }
/**
* Composer for the current Constant.
*/
protected SourceWriter composer;
- private List<ResourceKeyFormatter> formatters =
- new ArrayList<ResourceKeyFormatter>();
+ private List<ResourceKeyFormatter> formatters = new ArrayList<ResourceKeyFormatter>();
private File resourceFile;
@@ -147,7 +195,7 @@
* Create an annotation to hold the default value.
*/
protected abstract void genValueAnnotation(String defaultValue);
-
+
/**
* Returns the javaDocComment for the class.
*
@@ -156,24 +204,55 @@
*/
protected abstract String javaDocComment(String path);
- @SuppressWarnings("unchecked") // use of raw type from LocalizedProperties
+ protected String makeJavaString(String value) {
+ StringBuilder buf = new StringBuilder();
+ buf.append('\"');
+ for (int i = 0; i < value.length(); ++i) {
+ char c = value.charAt(i);
+ switch (c) {
+ case '\r':
+ buf.append("\\r");
+ break;
+ case '\n':
+ buf.append("\\n");
+ break;
+ case '\"':
+ buf.append("\\\"");
+ break;
+ default:
+ if (needsUnicodeEscape(c)) {
+ unicodeEscape(c, buf);
+ } else {
+ buf.append(c);
+ }
+ break;
+ }
+ }
+ buf.append('\"');
+ return buf.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ // use of raw type from LocalizedProperties
void generateFromPropertiesFile() throws IOException {
InputStream propStream = new FileInputStream(resourceFile);
LocalizedProperties p = new LocalizedProperties();
p.load(propStream, Util.DEFAULT_ENCODING);
addFormatters();
// TODO: Look for a generic version of Tapestry's LocalizedProperties class
- Iterator<Entry<String, String>> elements =
- p.getPropertyMap().entrySet().iterator(); // suppress warnings
- if (elements.hasNext() == false) {
+ Set<String> keySet = p.getPropertyMap().keySet();
+ // sort keys for deterministic results
+ String[] keys = keySet.toArray(new String[keySet.size()]);
+ Arrays.sort(keys);
+ if (keys.length == 0) {
throw new IllegalStateException(
"File '"
+ resourceFile
+ "' cannot be used to generate message classes, as it has no key/value pairs defined.");
}
- while (elements.hasNext()) {
- Entry<String, String> s = elements.next();
- genSimpleMethodDecl(s.getKey(), s.getValue());
+ for (String key : keys) {
+ String value = p.getProperty(key);
+ genSimpleMethodDecl(key, value);
}
composer.commit(new PrintWriterTreeLogger());
}
@@ -190,23 +269,19 @@
for (ResourceKeyFormatter formatter : formatters) {
key = formatter.format(key);
}
- if (Util.isValidJavaIdent(key) == false) {
- // TODO(jat): we could synthesize legal method names and add an
- // @Key annotation to keep the matching key name.
- throw new IllegalArgumentException(key
- + " is not a legitimate method name.");
- }
return key;
}
private void genMethodDecl(String type, String defaultValue, String key) {
composer.beginJavaDocComment();
- composer.println("Translated \"" + defaultValue + "\".\n");
- composer.println("@return translated \"" + defaultValue + "\"");
+ String escaped = makeJavaString(defaultValue);
+ composer.println("Translated " + escaped + ".\n");
+ composer.print("@return translated " + escaped);
composer.endJavaDocComment();
genValueAnnotation(defaultValue);
- key = formatKey(key);
- composer.print(type + " " + key);
+ composer.println("@Key(" + makeJavaString(key) + ")");
+ String methodName = formatKey(key);
+ composer.print(type + " " + methodName);
composer.print("(");
genMethodArgs(defaultValue);
composer.print(");\n");
diff --git a/user/src/com/google/gwt/i18n/rebind/AnnotationUtil.java b/user/src/com/google/gwt/i18n/rebind/AnnotationUtil.java
new file mode 100644
index 0000000..21fbbd6
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/rebind/AnnotationUtil.java
@@ -0,0 +1,66 @@
+/*
+ * 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.i18n.rebind;
+
+import com.google.gwt.core.ext.typeinfo.JClassType;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Utility class for i18n-related annotation manipulation routines.
+ */
+public class AnnotationUtil {
+
+ /**
+ * Find an instance of the specified annotation, walking up the inheritance
+ * tree if necessary.
+ *
+ * <p>Note that i18n annotations may appear on classes as well as interfaces
+ * (a concrete implementation can be supplied rather than just an interface
+ * and this is the normal way of using generic Localizable interfaces), so
+ * we have to search the super chain as well as other interfaces.
+ *
+ * <p>The super chain is walked first, so if an ancestor superclass has the
+ * requested annotation, it will be preferred over a directly implemented
+ * interface.
+ *
+ * @param <T> Annotation type to search for
+ * @param clazz root class to search, may be null
+ * @param annotationClass class object of Annotation subclass to search for
+ * @return the requested annotation or null if none
+ */
+ static <T extends Annotation> T getClassAnnotation(JClassType clazz,
+ Class<T> annotationClass) {
+ if (clazz == null) {
+ return null;
+ }
+ T annot = clazz.getAnnotation(annotationClass);
+ if (annot == null) {
+ annot = getClassAnnotation(clazz.getSuperclass(), annotationClass);
+ if (annot != null) {
+ return annot;
+ }
+ for (JClassType intf : clazz.getImplementedInterfaces()) {
+ annot = getClassAnnotation(intf, annotationClass);
+ if (annot != null) {
+ return annot;
+ }
+ }
+ }
+ return annot;
+ }
+
+}
diff --git a/user/src/com/google/gwt/i18n/rebind/AnnotationsResource.java b/user/src/com/google/gwt/i18n/rebind/AnnotationsResource.java
index 87b9d05..9e5cc4e 100644
--- a/user/src/com/google/gwt/i18n/rebind/AnnotationsResource.java
+++ b/user/src/com/google/gwt/i18n/rebind/AnnotationsResource.java
@@ -13,9 +13,10 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-
package com.google.gwt.i18n.rebind;
+import static com.google.gwt.i18n.rebind.AnnotationUtil.getClassAnnotation;
+
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
@@ -167,7 +168,7 @@
*/
public static KeyGenerator getKeyGenerator(JClassType targetClass)
throws AnnotationsError {
- GenerateKeys generator = targetClass.getAnnotation(GenerateKeys.class);
+ GenerateKeys generator = getClassAnnotation(targetClass, GenerateKeys.class);
if (generator != null) {
String className = generator.value();
try {
@@ -377,7 +378,7 @@
KeyGenerator keyGenerator = getKeyGenerator(clazz);
map = new HashMap<String, MethodEntry>();
setPath(clazz.getQualifiedSourceName());
- DefaultLocale defLocale = clazz.getAnnotation(DefaultLocale.class);
+ DefaultLocale defLocale = getClassAnnotation(clazz, DefaultLocale.class);
if (defLocale != null && !ResourceFactory.DEFAULT_TOKEN.equals(locale)
&& !locale.equalsIgnoreCase(defLocale.value())) {
logger.log(TreeLogger.WARN, "@DefaultLocale on "
diff --git a/user/src/com/google/gwt/i18n/rebind/ConstantsInterfaceCreator.java b/user/src/com/google/gwt/i18n/rebind/ConstantsInterfaceCreator.java
index ef7bcd9..de7685b 100644
--- a/user/src/com/google/gwt/i18n/rebind/ConstantsInterfaceCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/ConstantsInterfaceCreator.java
@@ -50,13 +50,13 @@
@Override
protected void genValueAnnotation(String defaultValue) {
- composer.println("@DefaultStringValue(\"" + defaultValue.replace("\"", "\\\"")
- + "\")");
+ composer.println("@DefaultStringValue(" + makeJavaString(defaultValue)
+ + ")");
}
@Override
protected String javaDocComment(String path) {
- return "Interface to represent the constants contained in resource bundle:\n\t'"
+ return "Interface to represent the constants contained in resource bundle:\n\t'"
+ path + "'.";
}
}
diff --git a/user/src/com/google/gwt/i18n/rebind/MessagesInterfaceCreator.java b/user/src/com/google/gwt/i18n/rebind/MessagesInterfaceCreator.java
index 84ee86a..9c84209 100644
--- a/user/src/com/google/gwt/i18n/rebind/MessagesInterfaceCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/MessagesInterfaceCreator.java
@@ -92,8 +92,7 @@
@Override
protected void genValueAnnotation(String defaultValue) {
- composer.println("@DefaultMessage(\"" + defaultValue.replace("\"", "\\\"")
- + "\")");
+ composer.println("@DefaultMessage(" + makeJavaString(defaultValue) + ")");
}
@Override
diff --git a/user/src/com/google/gwt/i18n/rebind/ResourceFactory.java b/user/src/com/google/gwt/i18n/rebind/ResourceFactory.java
index ee5f501..f404f24 100644
--- a/user/src/com/google/gwt/i18n/rebind/ResourceFactory.java
+++ b/user/src/com/google/gwt/i18n/rebind/ResourceFactory.java
@@ -304,8 +304,15 @@
String partialPath = localizedPath.replace('.', '/');
for (int i = 0; i < loaders.size(); i++) {
ResourceFactory element = loaders.get(i);
- String path = partialPath + "." + element.getExt();
+ String ext = "." + element.getExt();
+ String path = partialPath + ext;
InputStream m = loader.getResourceAsStream(path);
+ if (m == null && partialPath.contains("$")) {
+ // Also look for A_B for inner classes, as $ in path names
+ // can cause issues for some build tools.
+ path = partialPath.replace('$', '_') + ext;
+ m = loader.getResourceAsStream(path);
+ }
if (m != null) {
AbstractResource found = element.load(m);
found.setPath(path);
diff --git a/user/src/com/google/gwt/i18n/tools/I18NSync.java b/user/src/com/google/gwt/i18n/tools/I18NSync.java
index 18da760..06bed9a 100644
--- a/user/src/com/google/gwt/i18n/tools/I18NSync.java
+++ b/user/src/com/google/gwt/i18n/tools/I18NSync.java
@@ -337,7 +337,11 @@
+ "'should not contain an extension. \"com.google.gwt.SomeClass\" is an example of a correctly formed class string");
}
String resourcePath = className.replace('.', '/') + ".properties";
- URL r = ClassLoader.getSystemResource(resourcePath);
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ if (cl == null) {
+ cl = ClassLoader.getSystemClassLoader();
+ }
+ URL r = cl.getResource(resourcePath);
if (r == null) {
throw new FileNotFoundException("Could not find the resource '"
+ resourcePath + " matching '" + className
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index d485cc5..b2ed7605 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -511,7 +511,7 @@
protected void initializeLogger() {
if (isHeadless()) {
consoleLogger = new PrintWriterTreeLogger();
- consoleLogger.setMaxDetail(getLogLevel());
+ consoleLogger.setMaxDetail(getCompilerOptions().getLogLevel());
} else {
super.initializeLogger();
}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/util/TreeMap_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/util/TreeMap_CustomFieldSerializer.java
new file mode 100644
index 0000000..ddc24f2
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/util/TreeMap_CustomFieldSerializer.java
@@ -0,0 +1,47 @@
+/*
+ * 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.rpc.core.java.util;
+
+import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+
+import java.util.Comparator;
+import java.util.TreeMap;
+
+/**
+ * Custom field serializer for {@link java.util.TreeMap}.
+ */
+@SuppressWarnings("unchecked")
+public class TreeMap_CustomFieldSerializer {
+
+ /* for now, build it entry by entry. Can optimize later via bulk loading */
+ public static void deserialize(SerializationStreamReader streamReader,
+ TreeMap instance) throws SerializationException {
+ Map_CustomFieldSerializerBase.deserialize(streamReader, instance);
+ }
+
+ public static TreeMap instantiate(SerializationStreamReader streamReader)
+ throws SerializationException {
+ return new TreeMap((Comparator) streamReader.readObject());
+ }
+
+ public static void serialize(SerializationStreamWriter streamWriter,
+ TreeMap instance) throws SerializationException {
+ streamWriter.writeObject(instance.comparator());
+ Map_CustomFieldSerializerBase.serialize(streamWriter, instance);
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/util/TreeSet_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/util/TreeSet_CustomFieldSerializer.java
new file mode 100644
index 0000000..f48f95e
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/util/TreeSet_CustomFieldSerializer.java
@@ -0,0 +1,47 @@
+/*
+ * 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.rpc.core.java.util;
+
+import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+
+import java.util.Comparator;
+import java.util.TreeSet;
+
+/**
+ * Custom field serializer for {@link java.util.TreeMap}.
+ */
+@SuppressWarnings("unchecked")
+public class TreeSet_CustomFieldSerializer {
+
+ /* for now, build it entry by entry. Can optimize later via bulk loading */
+ public static void deserialize(SerializationStreamReader streamReader,
+ TreeSet instance) throws SerializationException {
+ Collection_CustomFieldSerializerBase.deserialize(streamReader, instance);
+ }
+
+ public static TreeSet instantiate(SerializationStreamReader streamReader)
+ throws SerializationException {
+ return new TreeSet((Comparator) streamReader.readObject());
+ }
+
+ public static void serialize(SerializationStreamWriter streamWriter,
+ TreeSet instance) throws SerializationException {
+ streamWriter.writeObject(instance.comparator());
+ Collection_CustomFieldSerializerBase.serialize(streamWriter, instance);
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStream.java b/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStream.java
index 51c4483..2177020 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStream.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStream.java
@@ -23,9 +23,21 @@
public abstract class AbstractSerializationStream {
/**
+ * The character used to separate fields in client->server RPC messages.
+ *
+ * Note that this character is referenced in the following places not using
+ * this constant, and they must be changed if this is:
+ * <ul>
+ * <li>{@link ServerSerializationStreamWriter}.deserializeStringTable
+ * <li>{@link ClientSerializationStreamReader}.getQuotingRegex
+ * </ul>
+ */
+ public static final char RPC_SEPARATOR_CHAR = '|';
+
+ /**
* This is the only supported RPC protocol version.
*/
- public static final int SERIALIZATION_STREAM_VERSION = 4;
+ public static final int SERIALIZATION_STREAM_VERSION = 5;
private int flags = 0;
private int version = SERIALIZATION_STREAM_VERSION;
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java b/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java
index f44d1ec..f760109 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java
@@ -16,6 +16,7 @@
package com.google.gwt.user.client.rpc.impl;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.UnsafeNativeLong;
import com.google.gwt.user.client.rpc.SerializationException;
@@ -27,18 +28,97 @@
public final class ClientSerializationStreamWriter extends
AbstractSerializationStreamWriter {
+ /**
+ * Used by JSNI, see {@link #quoteString(String)}.
+ */
+ @SuppressWarnings("unused")
+ private static JavaScriptObject regex = getQuotingRegex();
+
private static void append(StringBuffer sb, String token) {
assert (token != null);
sb.append(token);
- sb.append('\uffff');
+ sb.append(RPC_SEPARATOR_CHAR);
}
+ /**
+ * Create the RegExp instance used for quoting dangerous characters in user
+ * payload strings.
+ *
+ * Note that {@link AbstractSerializationStream#RPC_SEPARATOR_CHAR} is used in
+ * this expression, which must be updated if the separator character is
+ * changed.
+ *
+ * For Android WebKit, we quote many more characters to keep them from being
+ * mangled.
+ *
+ * @return RegExp object
+ */
+ private static native JavaScriptObject getQuotingRegex() /*-{
+ // "|" = AbstractSerializationStream.RPC_SEPARATOR_CHAR
+ var ua = navigator.userAgent.toLowerCase();
+ var webkitregex = /webkit\/([\d]+)/;
+ var webkit = 0;
+ var result = webkitregex.exec(ua);
+ if (result) {
+ webkit = parseInt(result[1]);
+ }
+ if (ua.indexOf("android") != -1) {
+ // initial version of Android WebKit has a double-encoding bug for UTF8,
+ // so we have to encode every non-ASCII character.
+ // TODO(jat): revisit when this bug is fixed in Android
+ return /[\u0000\|\\\u0080-\uFFFF]/g;
+ } else if (webkit < 522) {
+ // Safari 2 doesn't handle \\uXXXX in regexes
+ // TODO(jat): should iPhone be treated specially?
+ return /[\x00\|\\]/g;
+ } else if (webkit > 0) {
+ // other WebKit-based browsers need some additional quoting
+ return /[\u0000\|\\\u0300-\u036F\u0590-\u05FF\uD800-\uFFFF]/g;
+ } else {
+ return /[\u0000\|\\\uD800-\uFFFF]/g;
+ }
+ }-*/;
+
@UnsafeNativeLong
// Keep synchronized with LongLib
private static native double[] makeLongComponents0(long value) /*-{
return value;
}-*/;
+ /**
+ * Quote characters in a user-supplied string to make sure they are safe to
+ * send to the server.
+ *
+ * See {@link ServerSerializationStreamReader#deserializeStringTable} for the
+ * corresponding dequoting.
+ *
+ * @param str string to quote
+ * @return quoted string
+ */
+ private static native String quoteString(String str) /*-{
+ var regex = @com.google.gwt.user.client.rpc.impl.ClientSerializationStreamWriter::regex;
+ var idx = 0;
+ var out = "";
+ var result;
+ while ((result = regex.exec(str)) != null) {
+ out += str.substring(idx, result.index);
+ idx = result.index + 1;
+ var ch = result[0].charCodeAt(0);
+ if (ch == 0) {
+ out += "\\0";
+ } else if (ch == 92) { // backslash
+ out += "\\\\";
+ } else if (ch == 124) { // vertical bar
+ // 124 = "|" = AbstractSerializationStream.RPC_SEPARATOR_CHAR
+ out += "\\!";
+ } else {
+ var hex = ch.toString(16);
+ out += "\\u0000".substring(0, 6 - hex.length) + hex;
+ }
+ }
+ return out + str.substring(idx);
+ }-*/;
+
private StringBuffer encodeBuffer;
private final String moduleBaseURL;
@@ -67,6 +147,7 @@
* Call this method before attempting to append any tokens. This method
* implementation <b>must</b> be called by any overridden version.
*/
+ @Override
public void prepareToWrite() {
super.prepareToWrite();
encodeBuffer = new StringBuffer();
@@ -148,7 +229,7 @@
List<String> stringTable = getStringTable();
append(buffer, String.valueOf(stringTable.size()));
for (String s : stringTable) {
- append(buffer, s);
+ append(buffer, quoteString(s));
}
return buffer;
}
diff --git a/user/src/com/google/gwt/user/client/ui/SuggestBox.java b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
index 179f4ec..e4ba0ee 100644
--- a/user/src/com/google/gwt/user/client/ui/SuggestBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;
@@ -23,7 +24,6 @@
import com.google.gwt.user.client.ui.SuggestOracle.Request;
import com.google.gwt.user.client.ui.SuggestOracle.Response;
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
-import com.google.gwt.i18n.client.LocaleInfo;
import java.util.ArrayList;
import java.util.Collection;
@@ -370,6 +370,7 @@
private static final String STYLENAME_DEFAULT = "gwt-SuggestBox";
private int limit = 20;
+ private boolean selectsFirstItem = false;
private SuggestOracle oracle;
private String currentText;
private final SuggestionMenu suggestionMenu;
@@ -500,6 +501,16 @@
}
/**
+ * Returns whether or not the first suggestion will be automatically
+ * selected. This behavior is off by default.
+ *
+ * @return true if the first suggestion will be automatically selected
+ */
+ public boolean getSelectsFirstItem() {
+ return selectsFirstItem;
+ }
+
+ /**
* Gets the suggest box's {@link com.google.gwt.user.client.ui.SuggestOracle}.
*
* @return the {@link SuggestOracle}
@@ -582,7 +593,18 @@
public void setPopupStyleName(String style) {
suggestionPopup.setStyleName(style);
}
-
+
+ /**
+ * Turns on or off the behavior that automatically selects the first suggested
+ * item. It defaults to off.
+ *
+ * @param selectsFirstItem Whether or not to automatically select the first
+ * suggested
+ */
+ public void setSelectsFirstItem(boolean selectsFirstItem) {
+ this.selectsFirstItem = selectsFirstItem;
+ }
+
public void setTabIndex(int index) {
box.setTabIndex(index);
}
@@ -638,8 +660,10 @@
suggestionMenu.addItem(menuItem);
}
- // Select the first item in the suggestion menu.
- suggestionMenu.selectItem(0);
+ if (selectsFirstItem) {
+ // Select the first item in the suggestion menu.
+ suggestionMenu.selectItem(0);
+ }
suggestionPopup.showAlignedPopup();
suggestionPopup.setAnimationEnabled(isAnimationEnabled);
@@ -665,7 +689,11 @@
break;
case KeyboardListener.KEY_ENTER:
case KeyboardListener.KEY_TAB:
- suggestionMenu.doSelectedItemAction();
+ if (suggestionMenu.getSelectedItemIndex() < 0) {
+ suggestionPopup.hide();
+ } else {
+ suggestionMenu.doSelectedItemAction();
+ }
break;
}
}
diff --git a/user/src/com/google/gwt/user/rebind/ClassSourceFileComposer.java b/user/src/com/google/gwt/user/rebind/ClassSourceFileComposer.java
index 658c1a6..034949c 100644
--- a/user/src/com/google/gwt/user/rebind/ClassSourceFileComposer.java
+++ b/user/src/com/google/gwt/user/rebind/ClassSourceFileComposer.java
@@ -57,22 +57,24 @@
throw new IllegalArgumentException("Cannot supply a null package name to"
+ targetClassShortName);
}
- // Inlined header to only have one method with a huge number of methods.
+ // TODO: support a user-specified file header
if (targetPackageName.length() > 0) {
println("package " + targetPackageName + ";");
}
- println();
if (imports != null && imports.length > 0) {
+ println();
for (int i = 0, n = imports.length; i < n; ++i) {
println("import " + imports[i] + ";");
}
- println();
}
if (classJavaDocComment != null) {
beginJavaDocComment();
print(classJavaDocComment);
endJavaDocComment();
+ } else {
+ // beginJavaDocComment adds its own leading newline, make up for it here.
+ println();
}
if (category == JavaSourceCategory.CLASS) {
emitClassDecl(targetClassShortName, superClassName, interfaceNames);
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
index 3e1d87e..92e1cd3 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
@@ -77,43 +77,50 @@
private enum ValueReader {
BOOLEAN {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readBoolean();
}
},
BYTE {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readByte();
}
},
CHAR {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readChar();
}
},
DOUBLE {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readDouble();
}
},
FLOAT {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readFloat();
}
},
INT {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readInt();
}
},
LONG {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readLong();
}
},
@@ -126,13 +133,15 @@
},
SHORT {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readShort();
}
},
STRING {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readString();
}
};
@@ -323,6 +332,7 @@
private final ArrayList<String> tokenList = new ArrayList<String>();
private int tokenListIndex;
+
{
CLASS_TO_VECTOR_READER.put(boolean[].class, VectorReader.BOOLEAN_VECTOR);
CLASS_TO_VECTOR_READER.put(byte[].class, VectorReader.BYTE_VECTOR);
@@ -374,11 +384,30 @@
stringTable = null;
int idx = 0, nextIdx;
- while (-1 != (nextIdx = encodedTokens.indexOf('\uffff', idx))) {
+ while (-1 != (nextIdx = encodedTokens.indexOf(RPC_SEPARATOR_CHAR, idx))) {
String current = encodedTokens.substring(idx, nextIdx);
tokenList.add(current);
idx = nextIdx + 1;
}
+ if (idx == 0) {
+ // Didn't find any separator, assume an older version with different
+ // separators and get the version as the sequence of digits at the
+ // beginning of the encoded string.
+ while (idx < encodedTokens.length()
+ && Character.isDigit(encodedTokens.charAt(idx))) {
+ ++idx;
+ }
+ if (idx == 0) {
+ throw new IncompatibleRemoteServiceException(
+ "Malformed or old RPC message received - expecting version "
+ + SERIALIZATION_STREAM_VERSION);
+ } else {
+ int version = Integer.valueOf(encodedTokens.substring(0, idx));
+ throw new IncompatibleRemoteServiceException("Expecting version "
+ + SERIALIZATION_STREAM_VERSION + " from client, got " + version
+ + ".");
+ }
+ }
super.prepareToRead(encodedTokens);
@@ -407,42 +436,42 @@
}
}
- public boolean readBoolean() {
+ public boolean readBoolean() throws SerializationException {
return !extract().equals("0");
}
- public byte readByte() {
+ public byte readByte() throws SerializationException {
return Byte.parseByte(extract());
}
- public char readChar() {
+ public char readChar() throws SerializationException {
// just use an int, it's more foolproof
return (char) Integer.parseInt(extract());
}
- public double readDouble() {
+ public double readDouble() throws SerializationException {
return Double.parseDouble(extract());
}
- public float readFloat() {
+ public float readFloat() throws SerializationException {
return (float) Double.parseDouble(extract());
}
- public int readInt() {
+ public int readInt() throws SerializationException {
return Integer.parseInt(extract());
}
- public long readLong() {
+ public long readLong() throws SerializationException {
// Keep synchronized with LongLib. The wire format are the two component
// parts of the double in the client code.
return (long) readDouble() + (long) readDouble();
}
- public short readShort() {
+ public short readShort() throws SerializationException {
return Short.parseShort(extract());
}
- public String readString() {
+ public String readString() throws SerializationException {
return getString(readInt());
}
@@ -587,7 +616,50 @@
BoundedList<String> buffer = new BoundedList<String>(String.class,
typeNameCount);
for (int typeNameIndex = 0; typeNameIndex < typeNameCount; ++typeNameIndex) {
- buffer.add(extract());
+ String str = extract();
+ // Change quoted characters back.
+ int idx = str.indexOf('\\');
+ if (idx >= 0) {
+ StringBuilder buf = new StringBuilder();
+ int pos = 0;
+ while (idx >= 0) {
+ buf.append(str.substring(pos, idx));
+ if (++idx == str.length()) {
+ throw new SerializationException("Unmatched backslash: \""
+ + str + "\"");
+ }
+ char ch = str.charAt(idx);
+ pos = idx + 1;
+ switch (ch) {
+ case '0':
+ buf.append('\u0000');
+ break;
+ case '!':
+ buf.append(RPC_SEPARATOR_CHAR);
+ break;
+ case '\\':
+ buf.append(ch);
+ break;
+ case 'u':
+ try {
+ ch = (char) Integer.parseInt(str.substring(idx + 1, idx + 5), 16);
+ } catch (NumberFormatException e) {
+ throw new SerializationException(
+ "Invalid Unicode escape sequence in \"" + str + "\"");
+ }
+ buf.append(ch);
+ pos += 4;
+ break;
+ default:
+ throw new SerializationException("Unexpected escape character "
+ + ch + " after backslash: \"" + str + "\"");
+ }
+ idx = str.indexOf('\\', pos);
+ }
+ buf.append(str.substring(pos));
+ str = buf.toString();
+ }
+ buffer.add(str);
}
if (buffer.size() != buffer.getExpectedSize()) {
@@ -613,14 +685,18 @@
throw new NoSuchMethodException("deserialize");
}
- private String extract() {
- return tokenList.get(tokenListIndex++);
+ private String extract() throws SerializationException {
+ try {
+ return tokenList.get(tokenListIndex++);
+ } catch (IndexOutOfBoundsException e) {
+ throw new SerializationException("Too few tokens in RPC request", e);
+ }
}
private Object instantiate(Class<?> customSerializer, Class<?> instanceClass)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException,
- NoSuchMethodException {
+ NoSuchMethodException, SerializationException {
if (customSerializer != null) {
for (Method method : customSerializer.getMethods()) {
if ("instantiate".equals(method.getName())) {
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java
index f355f3c..8f837cd 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java
@@ -371,11 +371,7 @@
for (int i = 0, n = input.length; i < n; ++i) {
char c = input[i];
- if (c < NUMBER_OF_JS_ESCAPED_CHARS && JS_CHARS_ESCAPED[c] != 0) {
- charVector.add(JS_ESCAPE_CHAR);
- charVector.add(JS_CHARS_ESCAPED[c]);
- } else if (needsUnicodeEscape(c)) {
- charVector.add(JS_ESCAPE_CHAR);
+ if (needsUnicodeEscape(c)) {
unicodeEscape(c, charVector);
} else {
charVector.add(c);
@@ -444,43 +440,57 @@
* </ol>
*/
private static boolean needsUnicodeEscape(char ch) {
- switch (Character.getType(ch)) {
- // Conservative
- case Character.COMBINING_SPACING_MARK:
- case Character.ENCLOSING_MARK:
- case Character.NON_SPACING_MARK:
- case Character.UNASSIGNED:
- case Character.PRIVATE_USE:
- case Character.SPACE_SEPARATOR:
- case Character.CONTROL:
-
- // Minimal
- case Character.LINE_SEPARATOR:
- case Character.FORMAT:
- case Character.PARAGRAPH_SEPARATOR:
- case Character.SURROGATE:
+ switch (ch) {
+ case ' ':
+ // ASCII space gets caught in SPACE_SEPARATOR below, but does not
+ // need to be escaped
+ return false;
+ case JS_QUOTE_CHAR:
+ case JS_ESCAPE_CHAR:
+ // these must be quoted or they will break the protocol
return true;
-
- default:
- if (ch == NON_BREAKING_HYPHEN) {
+ case NON_BREAKING_HYPHEN:
// This can be expanded into a break followed by a hyphen
return true;
+ default:
+ switch (Character.getType(ch)) {
+ // Conservative
+ case Character.COMBINING_SPACING_MARK:
+ case Character.ENCLOSING_MARK:
+ case Character.NON_SPACING_MARK:
+ case Character.UNASSIGNED:
+ case Character.PRIVATE_USE:
+ case Character.SPACE_SEPARATOR:
+ case Character.CONTROL:
+
+ // Minimal
+ case Character.LINE_SEPARATOR:
+ case Character.FORMAT:
+ case Character.PARAGRAPH_SEPARATOR:
+ case Character.SURROGATE:
+ return true;
+
+ default:
+ break;
}
break;
}
-
return false;
}
/**
- * Writes either the two or four character escape sequence for a character.
- *
+ * Writes a safe escape sequence for a character. Some characters have a
+ * short form, such as \n for U+000D, while others are represented as \\xNN
+ * or \\uNNNN.
*
* @param ch character to unicode escape
* @param charVector char vector to receive the unicode escaped representation
*/
private static void unicodeEscape(char ch, CharVector charVector) {
- if (ch < 256) {
+ charVector.add(JS_ESCAPE_CHAR);
+ if (ch < NUMBER_OF_JS_ESCAPED_CHARS && JS_CHARS_ESCAPED[ch] != 0) {
+ charVector.add(JS_CHARS_ESCAPED[ch]);
+ } else if (ch < 256) {
charVector.add('x');
charVector.add(NIBBLE_TO_HEX_CHAR[(ch >> 4) & 0x0F]);
charVector.add(NIBBLE_TO_HEX_CHAR[ch & 0x0F]);
diff --git a/user/super/com/google/gwt/emul/java/io/IOException.java b/user/super/com/google/gwt/emul/java/io/IOException.java
new file mode 100644
index 0000000..34362a6
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/io/IOException.java
@@ -0,0 +1,40 @@
+/*
+ * 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 java.io;
+
+/**
+ * See <a
+ * href="http://java.sun.com/javase/6/docs/api/java/io/IOException.html">the
+ * official Java API doc</a> for details.
+ */
+public class IOException extends Exception {
+
+ public IOException() {
+ super();
+ }
+
+ public IOException(String message) {
+ super(message);
+ }
+
+ public IOException(String message, Throwable throwable) {
+ super(message, throwable);
+ }
+
+ public IOException(Throwable throwable) {
+ super(throwable);
+ }
+}
diff --git a/user/super/com/google/gwt/emul/java/lang/Appendable.java b/user/super/com/google/gwt/emul/java/lang/Appendable.java
new file mode 100644
index 0000000..c0c4c85
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/lang/Appendable.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 java.lang;
+
+import java.io.IOException;
+
+/**
+ * See <a
+ * href="http://java.sun.com/javase/6/docs/api/java/lang/Appendable.html">the
+ * official Java API doc</a> for details.
+ */
+public interface Appendable {
+
+ Appendable append(char c) throws IOException;
+
+ Appendable append(CharSequence charSquence) throws IOException;
+
+ Appendable append(CharSequence charSquence, int start, int end)
+ throws IOException;
+}
diff --git a/user/super/com/google/gwt/emul/java/lang/StringBuffer.java b/user/super/com/google/gwt/emul/java/lang/StringBuffer.java
index f851bef..2b24557 100644
--- a/user/super/com/google/gwt/emul/java/lang/StringBuffer.java
+++ b/user/super/com/google/gwt/emul/java/lang/StringBuffer.java
@@ -30,7 +30,7 @@
* This class is an exact clone of {@link StringBuilder} except for the name.
* Any change made to one should be mirrored in the other.
*/
-public class StringBuffer implements CharSequence {
+public class StringBuffer implements CharSequence, Appendable {
private final StringBufferImpl impl = GWT.create(StringBufferImpl.class);
private final Object data = impl.createData();
diff --git a/user/super/com/google/gwt/emul/java/lang/StringBuilder.java b/user/super/com/google/gwt/emul/java/lang/StringBuilder.java
index 00f9d19..e6d495a 100644
--- a/user/super/com/google/gwt/emul/java/lang/StringBuilder.java
+++ b/user/super/com/google/gwt/emul/java/lang/StringBuilder.java
@@ -30,7 +30,7 @@
* This class is an exact clone of {@link StringBuffer} except for the name. Any
* change made to one should be mirrored in the other.
*/
-public class StringBuilder implements CharSequence {
+public class StringBuilder implements CharSequence, Appendable {
private final StringBufferImpl impl = GWT.create(StringBufferImpl.class);
private final Object data = impl.createData();
diff --git a/user/super/com/google/gwt/emul/java/sql/Time.java b/user/super/com/google/gwt/emul/java/sql/Time.java
index a3302af..81c81cd 100644
--- a/user/super/com/google/gwt/emul/java/sql/Time.java
+++ b/user/super/com/google/gwt/emul/java/sql/Time.java
@@ -27,9 +27,9 @@
}
try {
- int hh = Integer.decode(split[0]);
- int mm = Integer.decode(split[1]);
- int ss = Integer.decode(split[2]);
+ int hh = Integer.parseInt(split[0]);
+ int mm = Integer.parseInt(split[1]);
+ int ss = Integer.parseInt(split[2]);
return new Time(hh, mm, ss);
} catch (NumberFormatException e) {
diff --git a/user/super/com/google/gwt/emul/java/util/TreeMap.java b/user/super/com/google/gwt/emul/java/util/TreeMap.java
index 2edb562..1c6ffcd 100644
--- a/user/super/com/google/gwt/emul/java/util/TreeMap.java
+++ b/user/super/com/google/gwt/emul/java/util/TreeMap.java
@@ -15,6 +15,8 @@
*/
package java.util;
+import java.io.Serializable;
+
/**
* Implements a TreeMap using a red-black tree. This guarantees O(log n)
* performance on lookups, inserts, and deletes while maintaining linear
@@ -24,7 +26,8 @@
* @param <K> key type
* @param <V> value type
*/
-public class TreeMap<K, V> extends AbstractMap<K, V> implements SortedMap<K, V> {
+public class TreeMap<K, V> extends AbstractMap<K, V> implements
+ SortedMap<K, V>, Serializable {
/*
* Implementation derived from public domain C implementation as of 5
* September 2007 at:
@@ -32,8 +35,6 @@
* written by Julienne Walker.
*
* This version does not require a parent pointer kept in each node.
- *
- * TODO: should this class be serializable? What to do about the comparator?
*/
/**
@@ -494,14 +495,14 @@
private enum SubMapType {
All,
-
+
Head {
@Override
public boolean toKeyValid() {
return true;
}
},
-
+
Range {
@Override
public boolean fromKeyValid() {
@@ -513,21 +514,21 @@
return true;
}
},
-
+
Tail {
@Override
public boolean fromKeyValid() {
return true;
}
};
-
+
/**
* @return true if this submap type uses a from-key.
*/
public boolean fromKeyValid() {
return false;
}
-
+
/**
* @return true if this submap type uses a to-key.
*/
@@ -580,8 +581,17 @@
// The comparator to use.
private Comparator<? super K> cmp;
+ /*
+ * These two fields are just hints to STOB so that it generates serializers
+ * for K and V
+ */
+ @SuppressWarnings("unused")
+ private K exposeKeyType;
+ @SuppressWarnings("unused")
+ private V exposeValueType;
+
// The root of the tree.
- private Node<K, V> root;
+ private transient Node<K, V> root;
// The number of nodes in the tree.
private int size = 0;
@@ -843,14 +853,13 @@
/**
* Insert a node into a subtree, collecting state about the insertion.
*
- * If the same key already exists, the value of the node is overwritten
- * with the value from the new node instead.
+ * If the same key already exists, the value of the node is overwritten with
+ * the value from the new node instead.
*
* @param tree subtree to insert into
* @param newNode new node to insert
- * @param state result of the insertion:
- * state.found true if the key already existed in the tree
- * state.value the old value if the key existed
+ * @param state result of the insertion: state.found true if the key already
+ * existed in the tree state.value the old value if the key existed
* @return the new subtree root
*/
private Node<K, V> insert(Node<K, V> tree, Node<K, V> newNode, State<V> state) {
diff --git a/user/super/com/google/gwt/emul/java/util/TreeSet.java b/user/super/com/google/gwt/emul/java/util/TreeSet.java
index b4bce7f..496e87d 100644
--- a/user/super/com/google/gwt/emul/java/util/TreeSet.java
+++ b/user/super/com/google/gwt/emul/java/util/TreeSet.java
@@ -15,6 +15,8 @@
*/
package java.util;
+import java.io.Serializable;
+
/**
* Implements a set using a TreeMap. <a
* href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/TreeSet.html">[Sun
@@ -22,15 +24,15 @@
*
* @param <E> element type.
*/
-public class TreeSet<E> extends AbstractSet<E> implements SortedSet<E> {
+public class TreeSet<E> extends AbstractSet<E> implements SortedSet<E>, Serializable {
/**
- * TreeSet is stored as a TreeMap of the requested type to null Objects.
+ * TreeSet is stored as a TreeMap of the requested type to a constant integer.
*/
- private SortedMap<E, Object> map;
+ SortedMap<E, Boolean> map;
public TreeSet() {
- map = new TreeMap<E, Object>();
+ map = new TreeMap<E, Boolean>();
}
public TreeSet(Collection<? extends E> c) {
@@ -40,9 +42,9 @@
public TreeSet(Comparator<? super E> c) {
if (c == null) {
- map = new TreeMap<E, Object>();
+ map = new TreeMap<E, Boolean>();
} else {
- map = new TreeMap<E, Object>(c);
+ map = new TreeMap<E, Boolean>(c);
}
}
@@ -57,14 +59,14 @@
*
* @param map map to use for backing store
*/
- private TreeSet(SortedMap<E, Object> map) {
+ private TreeSet(SortedMap<E, Boolean> map) {
this.map = map;
}
@Override
public boolean add(E o) {
// Use "this" as a convenient non-null value to store in the map
- return map.put(o, this) == null;
+ return map.put(o, Boolean.FALSE) == null;
}
@Override
diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
index 4c744e7..e6e3657 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
@@ -26,9 +26,29 @@
@SuppressWarnings("unused")
public class CompilerTest extends GWTTestCase {
+ private abstract static class AbstractSuper {
+ public static String foo() {
+ if (FALSE) {
+ // prevent inlining
+ return foo();
+ }
+ return "AbstractSuper";
+ }
+ }
+
private abstract static class Apple implements Fruit {
}
+ private static class ConcreteSub extends AbstractSuper {
+ public static String foo() {
+ if (FALSE) {
+ // prevent inlining
+ return foo();
+ }
+ return "ConcreteSub";
+ }
+ }
+
private static interface Fruit {
}
@@ -174,6 +194,8 @@
return @com.google.gwt.dev.jjs.test.CompilerTest$SideEffectCauser5::causeClinitSideEffectOnRead;
}-*/;
+ private Integer boxedInteger = 0;
+
@Override
public String getModuleName() {
return "com.google.gwt.dev.jjs.CompilerSuite";
@@ -557,6 +579,16 @@
assertEquals("null true", test);
}
+ /**
+ * Issue 2886: inlining should cope with local variables that do not have an
+ * explicit declaration node.
+ */
+ public void testInliningBoxedIncrement() {
+ // should not actually inline, because it has a temp variable
+ incrementBoxedInteger();
+ assertEquals((Integer) 1, boxedInteger);
+ }
+
public void testJavaScriptReservedWords() {
boolean delete = TRUE;
for (int in = 0; in < 10; ++in) {
@@ -777,6 +809,11 @@
assertEquals(new Foo(2).i, 2);
}
+ public void testStaticMethodResolution() {
+ // Issue 2922
+ assertEquals("AbstractSuper", AbstractSuper.foo());
+ }
+
public void testStringOptimizations() {
assertEquals("Herro, AJAX", "Hello, AJAX".replace('l', 'r'));
assertEquals('J', "Hello, AJAX".charAt(8));
@@ -988,6 +1025,11 @@
}
}
+ private void incrementBoxedInteger() {
+ // the following will need a temporary variable created
+ boxedInteger++;
+ }
+
private boolean returnFalse() {
return false;
}
diff --git a/user/test/com/google/gwt/emultest/java/sql/SqlTimeTest.java b/user/test/com/google/gwt/emultest/java/sql/SqlTimeTest.java
index e3129f4..0646e3c 100644
--- a/user/test/com/google/gwt/emultest/java/sql/SqlTimeTest.java
+++ b/user/test/com/google/gwt/emultest/java/sql/SqlTimeTest.java
@@ -102,13 +102,20 @@
}
Time t = Time.valueOf("13:01:30");
- // Months are 0-based, days are 1-based
assertEquals(13, t.getHours());
assertEquals(1, t.getMinutes());
assertEquals(30, t.getSeconds());
Time d2 = Time.valueOf(t.toString());
assertEquals(t, d2);
+
+ // tests to see if the various parts are indeed decoded in base-10 (till
+ // r3728 the base was first inferred)
+ Time t2 = Time.valueOf("08:09:01");
+ assertEquals(8, t2.getHours());
+ assertEquals(9, t2.getMinutes());
+ assertEquals(1, t2.getSeconds());
+ assertEquals(t2, Time.valueOf(t2.toString()));
}
public void testToString() {
diff --git a/user/test/com/google/gwt/i18n/client/CommonInterfaceAnnotations.java b/user/test/com/google/gwt/i18n/client/CommonInterfaceAnnotations.java
new file mode 100644
index 0000000..c33704d
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/CommonInterfaceAnnotations.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.i18n.client;
+
+import com.google.gwt.i18n.client.LocalizableResource.GenerateKeys;
+
+/**
+ * Base interface to test annotation inheritance.
+ *
+ * <p>This works by setting the key generator to MD5 on this interface,
+ * then verifying that keys in the subinterface are looked up with
+ * MD5 hashes rather than method names.
+ */
+@GenerateKeys("com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator")
+public interface CommonInterfaceAnnotations extends Messages {
+
+ @DefaultMessage("foo")
+ String foo();
+}
diff --git a/user/test/com/google/gwt/i18n/client/I18N2Test.java b/user/test/com/google/gwt/i18n/client/I18N2Test.java
index 3cc843b..89568ab 100644
--- a/user/test/com/google/gwt/i18n/client/I18N2Test.java
+++ b/user/test/com/google/gwt/i18n/client/I18N2Test.java
@@ -16,6 +16,7 @@
package com.google.gwt.i18n.client;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.TestAnnotatedMessages.Nested;
import com.google.gwt.i18n.client.gen.Colors;
import com.google.gwt.i18n.client.gen.TestBadKeys;
import com.google.gwt.junit.client.GWTTestCase;
@@ -32,6 +33,7 @@
return "com.google.gwt.i18n.I18N2Test";
}
+ @SuppressWarnings("deprecation")
public void testAnnotatedMessages() {
TestAnnotatedMessages m = GWT.create(TestAnnotatedMessages.class);
assertEquals("Test me", m.basicText());
@@ -103,6 +105,10 @@
assertEquals("a_b_c", test.a_b_c());
assertEquals("a_b_c", test.getString("a_b_c"));
assertEquals("__s_dup_dup", test.__s_dup_dup());
+ assertEquals("e in b_C_d", test.getString("__dup_dup"));
+ assertEquals("e in b_C_d", test.__dup_dup());
+ assertEquals("andStar", test.getString("__"));
+ assertEquals("andStar", test.__());
}
public void testBinding() {
@@ -125,6 +131,18 @@
assertEquals("a circle", s.circle());
}
+ /**
+ * Verify that nested annotations are looked up with both A$B names
+ * and A_B names. Note that $ takes precedence and only one file for a
+ * given level in the inheritance tree will be used, so A$B_locale will
+ * be used and A_B_locale ignored.
+ */
+ public void testNestedAnnotations() {
+ Nested m = GWT.create(Nested.class);
+ assertEquals("nested dollar b_C", m.nestedDollar());
+ assertEquals("nested underscore b", m.nestedUnderscore());
+ }
+
public void testWalkUpColorTree() {
Colors colors = (Colors) GWT.create(Colors.class);
assertEquals("red_b_C_d", colors.red());
diff --git a/user/test/com/google/gwt/i18n/client/I18NTest.java b/user/test/com/google/gwt/i18n/client/I18NTest.java
index 1e5e2a7..5889825 100644
--- a/user/test/com/google/gwt/i18n/client/I18NTest.java
+++ b/user/test/com/google/gwt/i18n/client/I18NTest.java
@@ -16,6 +16,7 @@
package com.google.gwt.i18n.client;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.TestAnnotatedMessages.Nested;
import com.google.gwt.i18n.client.gen.Colors;
import com.google.gwt.i18n.client.gen.Shapes;
import com.google.gwt.i18n.client.gen.TestMessages;
@@ -51,6 +52,7 @@
return "com.google.gwt.i18n.I18NTest";
}
+ @SuppressWarnings("unchecked") // intentional test of raw map
public void testAnnotatedConstants() {
TestAnnotatedConstants c = GWT.create(TestAnnotatedConstants.class);
assertEquals(14, c.fourteen());
@@ -115,13 +117,22 @@
assertEquals("PL: Total is US$11,305.01", m.currencyFormat(11305.01));
assertEquals("PL: Default number format is 1,017.1",
m.defaultNumberFormat(1017.1));
+ @SuppressWarnings("deprecation")
+ Date date = new Date(107, 11, 1, 12, 1, 2);
assertEquals("PL: It is 12:01 PM on Saturday, December 1, 2007",
- m.getTimeDate(new Date(107, 11, 1, 12, 1, 2)));
+ m.getTimeDate(date));
assertEquals("PL: 13 widgets", m.pluralWidgetsOther(13));
assertEquals("Too many widgets to count (150) in pig-latin",
m.pluralWidgetsOther(150));
}
+ public void testAnnotationInheritance() {
+ TestAnnotationGrandchild m = GWT.create(TestAnnotationGrandchild.class);
+ assertEquals("foo", m.foo());
+ assertEquals("bar_piglatin", m.bar());
+ assertEquals("baz_piglatin", m.baz());
+ }
+
public void testBindings() {
TestBinding b = (TestBinding) GWT.create(TestBinding.class);
assertEquals("default", b.a());
@@ -519,6 +530,13 @@
assertEquals("Extend Protected Inner", extendProtectedInner);
}
+ public void testNestedAnnotations() {
+ Nested m = GWT.create(Nested.class);
+ // no translation exists in piglatin for nested dollar
+ assertEquals("nested dollar", m.nestedDollar());
+ assertEquals("estednay underscoray", m.nestedUnderscore());
+ }
+
public void testShapesFamily() {
Shapes shapes = (Shapes) GWT.create(Shapes.class);
// test overload
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages$Nested_b_C.properties b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages$Nested_b_C.properties
new file mode 100644
index 0000000..57a9bd3
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages$Nested_b_C.properties
@@ -0,0 +1 @@
+nestedDollar = nested dollar b_C
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
index 437a559..7c0d56c 100644
--- a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
@@ -26,47 +26,66 @@
* Test of Messages generation using annotations.
*/
@DefaultLocale("en-US")
-//@GenerateKeys("com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator")
-@GenerateKeys("com.google.gwt.i18n.rebind.keygen.MethodNameKeyGenerator") // default
+// @GenerateKeys("com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator")
+@GenerateKeys("com.google.gwt.i18n.rebind.keygen.MethodNameKeyGenerator")
+// default
@Generate(format = "com.google.gwt.i18n.rebind.format.PropertiesFormat")
public interface TestAnnotatedMessages extends Messages {
+ /**
+ * Test of property file lookup on nested classes.
+ *
+ * nestedDollar() is redefined in a property file with a $ in it.
+ * nestedUnderscore() is redefined in a property file with a _ in it.
+ */
+ public interface Nested extends Messages {
+
+ @DefaultMessage("nested dollar")
+ String nestedDollar();
+
+ @DefaultMessage("nested underscore")
+ String nestedUnderscore();
+ }
+
@DefaultMessage("Test me")
String basicText();
-
+
@DefaultMessage("Once more, with meaning")
@Meaning("Mangled quote")
String withMeaning();
-
+
@DefaultMessage("One argument: {0}")
String oneArgument(String value);
-
+
@DefaultMessage("One argument, which is optional")
- String optionalArgument(@Optional String value);
-
+ String optionalArgument(@Optional
+ String value);
+
@DefaultMessage("Two arguments, {1} and {0}, inverted")
String invertedArguments(String one, String two);
-
+
@DefaultMessage("Don''t tell me I can''t '{'quote things in braces'}'")
String quotedText();
-
+
@DefaultMessage("This '{0}' would be an argument if not quoted")
String quotedArg();
-
+
@DefaultMessage("Total is {0,number,currency}")
String currencyFormat(double value);
-
+
@DefaultMessage("Default number format is {0,number}")
String defaultNumberFormat(double value);
-
+
@DefaultMessage("It is {0,time,short} on {0,date,full}")
String getTimeDate(Date value);
-
+
@DefaultMessage("{0} widgets")
- @PluralText({"one", "A widget"})
- String pluralWidgetsOther(@PluralCount int count);
+ @PluralText( {"one", "A widget"})
+ String pluralWidgetsOther(@PluralCount
+ int count);
@DefaultMessage("{1} {0}")
- @PluralText({"one", "A {0}"})
- String twoParamPlural(String name, @PluralCount int count);
+ @PluralText( {"one", "A {0}"})
+ String twoParamPlural(String name, @PluralCount
+ int count);
}
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_b.properties b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_b.properties
new file mode 100644
index 0000000..50b477c
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_b.properties
@@ -0,0 +1 @@
+nestedUnderscore = nested underscore b
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_piglatin.properties b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_piglatin.properties
new file mode 100644
index 0000000..4732950
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_piglatin.properties
@@ -0,0 +1 @@
+nestedUnderscore = estednay underscoray
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotationGrandchild.java b/user/test/com/google/gwt/i18n/client/TestAnnotationGrandchild.java
new file mode 100644
index 0000000..c69b16d
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotationGrandchild.java
@@ -0,0 +1,26 @@
+/*
+ * 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.i18n.client;
+
+/**
+ * Verifies that class-level annotations on grandparent interface are still honored,
+ * to make sure multiple levels of inheritance are handled.
+ */
+public interface TestAnnotationGrandchild extends TestAnnotationInheritance {
+
+ @DefaultMessage("baz")
+ String baz();
+}
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotationGrandchild_piglatin.properties b/user/test/com/google/gwt/i18n/client/TestAnnotationGrandchild_piglatin.properties
new file mode 100644
index 0000000..6dda386
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotationGrandchild_piglatin.properties
@@ -0,0 +1,4 @@
+# MD5 hash of "bar"
+37B51D194A7513E45B56F6524F2D51F2 = bar_piglatin
+# MD5 hash of "baz"
+73FEFFA4B7F6BB68E44CF984C85F6E88 = baz_piglatin
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotationInheritance.java b/user/test/com/google/gwt/i18n/client/TestAnnotationInheritance.java
new file mode 100644
index 0000000..92ddcdc
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotationInheritance.java
@@ -0,0 +1,27 @@
+/*
+ * 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.i18n.client;
+
+/**
+ * Verifies that class-level annotations on superinterface are still used
+ * by this interface. In this case, we verify that this interface's keys
+ * are based on the MD5 hash of the default value.
+ */
+public interface TestAnnotationInheritance extends CommonInterfaceAnnotations {
+
+ @DefaultMessage("bar")
+ String bar();
+}
diff --git a/user/test/com/google/gwt/i18n/client/gen/Colors.java b/user/test/com/google/gwt/i18n/client/gen/Colors.java
index 2da193e..560836d 100644
--- a/user/test/com/google/gwt/i18n/client/gen/Colors.java
+++ b/user/test/com/google/gwt/i18n/client/gen/Colors.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -17,71 +17,79 @@
/**
* Interface to represent the constants contained in resource bundle:
- * com/google/gwt/i18n/client/gen/Colors.properties.
+ * 'com/google/gwt/i18n/client/gen/Colors.properties'.
*/
public interface Colors extends com.google.gwt.i18n.client.Constants {
/**
- * Translated "ĝrééñ".
- *
- * @return translated "ĝrééñ"
- * @gwt.key green
- */
- String green();
-
- /**
- * Translated "réd ".
- *
- * @return translated "réd "
- * @gwt.key red
- */
- String red();
-
- /**
- * Translated "ŵĥîţé".
- *
- * @return translated "ŵĥîţé"
- * @gwt.key white
- */
- String white();
-
- /**
- * Translated "ĝréý".
- *
- * @return translated "ĝréý"
- * @gwt.key grey
- */
- String grey();
-
- /**
- * Translated "bļûç".
- *
- * @return translated "bļûç"
- * @gwt.key blue
- */
- String blue();
-
- /**
- * Translated "ýéļļöŵ".
- *
- * @return translated "ýéļļöŵ"
- * @gwt.key yellow
- */
- String yellow();
-
- /**
* Translated "bļåçķ".
*
* @return translated "bļåçķ"
- * @gwt.key black
*/
+ @DefaultStringValue("bļåçķ")
+ @Key("black")
String black();
/**
+ * Translated "bļûç".
+ *
+ * @return translated "bļûç"
+ */
+ @DefaultStringValue("bļûç")
+ @Key("blue")
+ String blue();
+
+ /**
+ * Translated "ĝrééñ".
+ *
+ * @return translated "ĝrééñ"
+ */
+ @DefaultStringValue("ĝrééñ")
+ @Key("green")
+ String green();
+
+ /**
+ * Translated "ĝréý".
+ *
+ * @return translated "ĝréý"
+ */
+ @DefaultStringValue("ĝréý")
+ @Key("grey")
+ String grey();
+
+ /**
+ * Translated "réd ".
+ *
+ * @return translated "réd "
+ */
+ @DefaultStringValue("réd ")
+ @Key("red")
+ String red();
+
+ /**
* Translated "any primary color".
*
* @return translated "any primary color"
- * @gwt.key shapeColor
*/
+ @DefaultStringValue("any primary color")
+ @Key("shapeColor")
String shapeColor();
+
+ /**
+ * Translated "ŵĥîţé".
+ *
+ * @return translated "ŵĥîţé"
+ */
+ @DefaultStringValue("ŵĥîţé")
+ @Key("white")
+ String white();
+
+ /**
+ * Translated "ýéļļöŵ".
+ *
+ * @return translated "ýéļļöŵ"
+ */
+ @DefaultStringValue("ýéļļöŵ")
+ @Key("yellow")
+ String yellow();
}
diff --git a/user/test/com/google/gwt/i18n/client/gen/Shapes.java b/user/test/com/google/gwt/i18n/client/gen/Shapes.java
index 089cd74..1f2be04 100644
--- a/user/test/com/google/gwt/i18n/client/gen/Shapes.java
+++ b/user/test/com/google/gwt/i18n/client/gen/Shapes.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -17,39 +17,43 @@
/**
* Interface to represent the constants contained in resource bundle:
- * com/google/gwt/i18n/client/gen/Shapes.properties.
+ * 'com/google/gwt/i18n/client/gen/Shapes.properties'.
*/
public interface Shapes extends com.google.gwt.i18n.client.Constants {
/**
- * Translated "a triangle".
- *
- * @return translated "a triangle"
- * @gwt.key triangle
- */
- String triangle();
-
- /**
- * Translated "a square ".
- *
- * @return translated "a square "
- * @gwt.key square
- */
- String square();
-
- /**
* Translated "a circle".
*
* @return translated "a circle"
- * @gwt.key circle
*/
+ @DefaultStringValue("a circle")
+ @Key("circle")
String circle();
/**
* Translated "a color wheel".
*
* @return translated "a color wheel"
- * @gwt.key shapeColor
*/
+ @DefaultStringValue("a color wheel")
+ @Key("shapeColor")
String shapeColor();
+
+ /**
+ * Translated "a square\u0009".
+ *
+ * @return translated "a square\u0009"
+ */
+ @DefaultStringValue("a square\u0009")
+ @Key("square")
+ String square();
+
+ /**
+ * Translated "a triangle".
+ *
+ * @return translated "a triangle"
+ */
+ @DefaultStringValue("a triangle")
+ @Key("triangle")
+ String triangle();
}
diff --git a/user/test/com/google/gwt/i18n/client/gen/SingleConstant.java b/user/test/com/google/gwt/i18n/client/gen/SingleConstant.java
index 57648d9..a3cfec7 100644
--- a/user/test/com/google/gwt/i18n/client/gen/SingleConstant.java
+++ b/user/test/com/google/gwt/i18n/client/gen/SingleConstant.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -17,7 +17,7 @@
/**
* Interface to represent the constants contained in resource bundle:
- * com/google/gwt/i18n/client/gen/SingleConstant.properties.
+ * 'com/google/gwt/i18n/client/gen/SingleConstant.properties'.
*/
public interface SingleConstant extends com.google.gwt.i18n.client.Constants {
@@ -25,7 +25,8 @@
* Translated "me".
*
* @return translated "me"
- * @gwt.key justOne
*/
+ @DefaultStringValue("me")
+ @Key("justOne")
String justOne();
}
diff --git a/user/test/com/google/gwt/i18n/client/gen/SingleMessages.java b/user/test/com/google/gwt/i18n/client/gen/SingleMessages.java
index a97c277..d14e857 100644
--- a/user/test/com/google/gwt/i18n/client/gen/SingleMessages.java
+++ b/user/test/com/google/gwt/i18n/client/gen/SingleMessages.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -17,7 +17,7 @@
/**
* Interface to represent the messages contained in resource bundle:
- * com/google/gwt/i18n/client/gen/SingleMessages.properties.
+ * 'com/google/gwt/i18n/client/gen/SingleMessages.properties'.
*/
public interface SingleMessages extends com.google.gwt.i18n.client.Messages {
@@ -25,7 +25,8 @@
* Translated "me".
*
* @return translated "me"
- * @gwt.key justOne
*/
+ @DefaultMessage("me")
+ @Key("justOne")
String justOne();
}
diff --git a/user/test/com/google/gwt/i18n/client/gen/TestBadKeys.java b/user/test/com/google/gwt/i18n/client/gen/TestBadKeys.java
index 08ca867..d10bb2e 100644
--- a/user/test/com/google/gwt/i18n/client/gen/TestBadKeys.java
+++ b/user/test/com/google/gwt/i18n/client/gen/TestBadKeys.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -17,17 +17,27 @@
/**
* Interface to represent the constants contained in resource bundle:
- * com/google/gwt/i18n/client/gen/TestBadKeys.properties.
+ * 'com/google/gwt/i18n/client/gen/TestBadKeys.properties'.
*/
public interface TestBadKeys extends
com.google.gwt.i18n.client.ConstantsWithLookup {
/**
+ * Translated "andStar".
+ *
+ * @return translated "andStar"
+ */
+ @DefaultStringValue("andStar")
+ @Key("&*")
+ String __();
+
+ /**
* Translated "_".
*
* @return translated "_"
- * @gwt.key -
*/
+ @DefaultStringValue("_")
+ @Key("-")
String _();
/**
@@ -36,159 +46,188 @@
*
* @return translated
* "________________________________________________________________"
- * @gwt.key ----------------------------------------------------------------
*/
+ @DefaultStringValue("________________________________________________________________")
+ @Key("----------------------------------------------------------------")
String ________________________________________________________________();
/**
- * Translated "__dup".
- *
- * @return translated "__dup"
- * @gwt.key .
- */
- String __dup();
-
- /**
* Translated "__s".
*
* @return translated "__s"
- * @gwt.key --s
*/
+ @DefaultStringValue("__s")
+ @Key("--s")
String __s();
/**
* Translated "__s_dup".
*
* @return translated "__s_dup"
- * @gwt.key -.s
*/
+ @DefaultStringValue("__s_dup")
+ @Key("-.s")
String __s_dup();
/**
- * Translated "__s_dup_dup".
- *
- * @return translated "__s_dup_dup"
- * @gwt.key ..s
- */
- String __s_dup_dup();
-
- /**
- * Translated "_1_2_3_4".
- *
- * @return translated "_1_2_3_4"
- * @gwt.key _1.2.3.4
- */
- String _1_2_3_4();
-
- /**
* Translated "_c_____".
*
* @return translated "_c_____"
- * @gwt.key -c..-.-
*/
+ @DefaultStringValue("_c_____")
+ @Key("-c..-.-")
String _c_____();
/**
+ * Translated "__dup".
+ *
+ * @return translated "__dup"
+ */
+ @DefaultStringValue("__dup")
+ @Key(".")
+ String __dup();
+
+ /**
+ * Translated "__s_dup_dup".
+ *
+ * @return translated "__s_dup_dup"
+ */
+ @DefaultStringValue("__s_dup_dup")
+ @Key("..s")
+ String __s_dup_dup();
+
+ /**
* Translated "_level".
*
* @return translated "_level"
- * @gwt.key .level
*/
+ @DefaultStringValue("_level")
+ @Key(".level")
String _level();
/**
- * Translated "a__b".
- *
- * @return translated "a__b"
- * @gwt.key a-.b
- */
- String a__b();
-
- /**
- * Translated "a_b_c".
- *
- * @return translated "a_b_c"
- * @gwt.key a-b-c
- */
- String a_b_c();
-
- /**
* Translated "AWT_end".
*
* @return translated "AWT_end"
- * @gwt.key AWT.end
*/
+ @DefaultStringValue("AWT_end")
+ @Key("AWT.end")
String AWT_end();
/**
* Translated "AWT_f5".
*
* @return translated "AWT_f5"
- * @gwt.key AWT.f5
*/
+ @DefaultStringValue("AWT_f5")
+ @Key("AWT.f5")
String AWT_f5();
/**
- * Translated "cell_2_5".
- *
- * @return translated "cell_2_5"
- * @gwt.key cell.2.5
- */
- String cell_2_5();
-
- /**
* Translated "Cursor_MoveDrop_32x32_File".
*
* @return translated "Cursor_MoveDrop_32x32_File"
- * @gwt.key Cursor.MoveDrop.32x32.File
*/
+ @DefaultStringValue("Cursor_MoveDrop_32x32_File")
+ @Key("Cursor.MoveDrop.32x32.File")
String Cursor_MoveDrop_32x32_File();
/**
+ * Translated "_1_2_3_4".
+ *
+ * @return translated "_1_2_3_4"
+ */
+ @DefaultStringValue("_1_2_3_4")
+ @Key("_1.2.3.4")
+ String _1_2_3_4();
+
+ /**
+ * Translated "a__b".
+ *
+ * @return translated "a__b"
+ */
+ @DefaultStringValue("a__b")
+ @Key("a-.b")
+ String a__b();
+
+ /**
+ * Translated "a_b_c".
+ *
+ * @return translated "a_b_c"
+ */
+ @DefaultStringValue("a_b_c")
+ @Key("a-b-c")
+ String a_b_c();
+
+ /**
+ * Translated "cell_2_5".
+ *
+ * @return translated "cell_2_5"
+ */
+ @DefaultStringValue("cell_2_5")
+ @Key("cell.2.5")
+ String cell_2_5();
+
+ /**
* Translated "entity_160".
*
* @return translated "entity_160"
- * @gwt.key entity.160
*/
+ @DefaultStringValue("entity_160")
+ @Key("entity.160")
String entity_160();
/**
* Translated "logger_org_hibernate_jdbc".
*
* @return translated "logger_org_hibernate_jdbc"
- * @gwt.key logger.org.hibernate.jdbc
*/
+ @DefaultStringValue("logger_org_hibernate_jdbc")
+ @Key("logger.org.hibernate.jdbc")
String logger_org_hibernate_jdbc();
/**
* Translated "maven_checkstyle_properties".
*
* @return translated "maven_checkstyle_properties"
- * @gwt.key maven.checkstyle.properties
*/
+ @DefaultStringValue("maven_checkstyle_properties")
+ @Key("maven.checkstyle.properties")
String maven_checkstyle_properties();
/**
* Translated "maven_jdiff_old_tag".
*
* @return translated "maven_jdiff_old_tag"
- * @gwt.key maven.jdiff.old.tag
*/
+ @DefaultStringValue("maven_jdiff_old_tag")
+ @Key("maven.jdiff.old.tag")
String maven_jdiff_old_tag();
/**
* Translated "permissions_755".
*
* @return translated "permissions_755"
- * @gwt.key permissions.755
*/
+ @DefaultStringValue("permissions_755")
+ @Key("permissions.755")
String permissions_755();
/**
* Translated "zh_spacer".
*
* @return translated "zh_spacer"
- * @gwt.key zh.spacer
*/
+ @DefaultStringValue("zh_spacer")
+ @Key("zh.spacer")
String zh_spacer();
+
+ /**
+ * Translated "e".
+ *
+ * @return translated "e"
+ */
+ @DefaultStringValue("e")
+ @Key("�")
+ String __dup_dup();
}
diff --git a/user/test/com/google/gwt/i18n/client/gen/TestBadKeys.properties b/user/test/com/google/gwt/i18n/client/gen/TestBadKeys.properties
index 46ab4d5..4761eff 100644
--- a/user/test/com/google/gwt/i18n/client/gen/TestBadKeys.properties
+++ b/user/test/com/google/gwt/i18n/client/gen/TestBadKeys.properties
@@ -19,4 +19,5 @@
-c..-.- = _c_____
---------------------------------------------------------------- = ________________________________________________________________
_1.2.3.4 = _1_2_3_4
-
+&* = andStar
+é = e
diff --git a/user/test/com/google/gwt/i18n/client/gen/TestBadKeys_b_C_d.properties b/user/test/com/google/gwt/i18n/client/gen/TestBadKeys_b_C_d.properties
new file mode 100644
index 0000000..a036225
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/gen/TestBadKeys_b_C_d.properties
@@ -0,0 +1 @@
+é = e in b_C_d
diff --git a/user/test/com/google/gwt/i18n/client/gen/TestConstantsQuoting.java b/user/test/com/google/gwt/i18n/client/gen/TestConstantsQuoting.java
new file mode 100644
index 0000000..a2a50af
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/gen/TestConstantsQuoting.java
@@ -0,0 +1,60 @@
+/*
+ * 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.i18n.client.gen;
+
+/**
+ * Interface to represent the constants contained in resource bundle:
+ * 'com/google/gwt/i18n/client/gen/TestConstantsQuoting.properties'.
+ */
+public interface TestConstantsQuoting extends
+ com.google.gwt.i18n.client.Constants {
+
+ /**
+ * Translated "Doesn''t work this way here".
+ *
+ * @return translated "Doesn''t work this way here"
+ */
+ @DefaultStringValue("Doesn''t work this way here")
+ @Key("doubledQuote")
+ String doubledQuote();
+
+ /**
+ * Translated "Embedded\r\ncr-nl.".
+ *
+ * @return translated "Embedded\r\ncr-nl."
+ */
+ @DefaultStringValue("Embedded\r\ncr-nl.")
+ @Key("embeddedCRNL")
+ String embeddedCRNL();
+
+ /**
+ * Translated "This line has an\nembedded newline".
+ *
+ * @return translated "This line has an\nembedded newline"
+ */
+ @DefaultStringValue("This line has an\nembedded newline")
+ @Key("embeddedNL")
+ String embeddedNL();
+
+ /**
+ * Translated "\"Don't worry, be happy\" he said.".
+ *
+ * @return translated "\"Don't worry, be happy\" he said."
+ */
+ @DefaultStringValue("\"Don't worry, be happy\" he said.")
+ @Key("embeddedQuote")
+ String embeddedQuote();
+}
diff --git a/user/test/com/google/gwt/i18n/client/gen/TestConstantsQuoting.properties b/user/test/com/google/gwt/i18n/client/gen/TestConstantsQuoting.properties
new file mode 100644
index 0000000..97baf73
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/gen/TestConstantsQuoting.properties
@@ -0,0 +1,4 @@
+embeddedNL=This line has an\nembedded newline
+embeddedCRNL=Embedded\r\ncr-nl.
+embeddedQuote="Don't worry, be happy" he said.
+doubledQuote=Doesn''t work this way here
diff --git a/user/test/com/google/gwt/i18n/client/gen/TestMessages.java b/user/test/com/google/gwt/i18n/client/gen/TestMessages.java
index 136c8cd..022ebeb 100644
--- a/user/test/com/google/gwt/i18n/client/gen/TestMessages.java
+++ b/user/test/com/google/gwt/i18n/client/gen/TestMessages.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -16,107 +16,120 @@
package com.google.gwt.i18n.client.gen;
/**
- * Interface to represent the messages contained in resource bundle
- * com/google/gwt/i18n/client/gen/TestMessages.properties.
+ * Interface to represent the messages contained in resource bundle:
+ * 'com/google/gwt/i18n/client/gen/TestMessages.properties'.
*/
public interface TestMessages extends com.google.gwt.i18n.client.Messages {
/**
- * Translated "{0},{1}, "a","b", "{0}", "{1}", ''a'', 'b', '{0}', ''{1}''".
- *
- * @return translated "{0},{1}, "a","b", "{0}", "{1}", ''a'', 'b', '{0}',
- * ''{1}''"
- * @gwt.key argsWithQuotes
- */
- String argsWithQuotes(String arg0, String arg1);
-
- /**
- * Translated "{1} is the second arg, {0} is the first".
- *
- * @return translated "{1} is the second arg, {0} is the first"
- * @gwt.key args2
- */
- String args2(String arg0, String arg1);
-
- /**
* Translated "no args".
*
* @return translated "no args"
- * @gwt.key args0
*/
+ @DefaultMessage("no args")
+ @Key("args0")
String args0();
/**
- * Translated "{0}".
- *
- * @return translated "{0}"
- * @gwt.key simpleMessageTest
- */
- String simpleMessageTest(String arg0);
-
- /**
- * Translated ""~" ~~ "~~~~ """.
- *
- * @return translated ""~" ~~ "~~~~ """
- * @gwt.key testWithXs
- */
- String testWithXs();
-
- /**
- * Translated "arg0arg1 arg0,arg1 {0}arg4".
- *
- * @return translated "arg0arg1 arg0,arg1 {0}arg4"
- * @gwt.key argsTest
- */
- String argsTest(String arg0);
-
- /**
- * Translated "repeatedArgs: {0}, {1}, {0}, {1}, {0}, {1}, {0}, {1}".
- *
- * @return translated "repeatedArgs: {0}, {1}, {0}, {1}, {0}, {1}, {0}, {1}"
- * @gwt.key testLotsOfUsageOfArgs
- */
- String testLotsOfUsageOfArgs(String arg0, String arg1);
-
- /**
- * Translated "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}".
- *
- * @return translated "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}"
- * @gwt.key args10
- */
- String args10(String arg0, String arg1, String arg2, String arg3,
- String arg4, String arg5, String arg6, String arg7, String arg8,
- String arg9);
-
- /**
- * Translated "お{0}你{1}好".
- *
- * @return translated "お{0}你{1}好"
- * @gwt.key unicode
- */
- String unicode(String arg0, String arg1);
-
- /**
* Translated "{0} is a arg".
*
* @return translated "{0} is a arg"
- * @gwt.key args1
*/
+ @DefaultMessage("{0} is a arg")
+ @Key("args1")
String args1(String arg0);
/**
- * Translated "{quoted}".
+ * Translated "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}".
*
- * @return translated "{quoted}"
- * @gwt.key quotedBraces
+ * @return translated "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}"
*/
- String quotedBraces();
+ @DefaultMessage("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}")
+ @Key("args10")
+ String args10(String arg0, String arg1, String arg2, String arg3,
+ String arg4, String arg5, String arg6, String arg7, String arg8,
+ String arg9);
+
+ /**
+ * Translated "{1} is the second arg, {0} is the first".
+ *
+ * @return translated "{1} is the second arg, {0} is the first"
+ */
+ @DefaultMessage("{1} is the second arg, {0} is the first")
+ @Key("args2")
+ String args2(String arg0, String arg1);
+
+ /**
+ * Translated "arg0arg1 arg0,arg1 {0}arg4".
+ *
+ * @return translated "arg0arg1 arg0,arg1 {0}arg4"
+ */
+ @DefaultMessage("arg0arg1 arg0,arg1 {0}arg4")
+ @Key("argsTest")
+ String argsTest(String arg0);
+
+ /**
+ * Translated "{0},{1}, \"a\",\"b\", \"{0}\", \"{1}\", ''a'', 'b', '{0}',
+ * ''{1}''".
+ *
+ * @return translated "{0},{1}, \"a\",\"b\", \"{0}\", \"{1}\", ''a'', 'b',
+ * '{0}', ''{1}''"
+ */
+ @DefaultMessage("{0},{1}, \"a\",\"b\", \"{0}\", \"{1}\", ''a'', 'b', '{0}', ''{1}''")
+ @Key("argsWithQuotes")
+ String argsWithQuotes(String arg0, String arg1);
/**
* Translated "".
*
* @return translated ""
- * @gwt.key empty
*/
+ @DefaultMessage("")
+ @Key("empty")
String empty();
+
+ /**
+ * Translated "'{'quoted'}'".
+ *
+ * @return translated "'{'quoted'}'"
+ */
+ @DefaultMessage("'{'quoted'}'")
+ @Key("quotedBraces")
+ String quotedBraces();
+
+ /**
+ * Translated "{0}".
+ *
+ * @return translated "{0}"
+ */
+ @DefaultMessage("{0}")
+ @Key("simpleMessageTest")
+ String simpleMessageTest(String arg0);
+
+ /**
+ * Translated "repeatedArgs: {0}, {1}, {0}, {1}, {0}, {1}, {0}, {1}".
+ *
+ * @return translated "repeatedArgs: {0}, {1}, {0}, {1}, {0}, {1}, {0}, {1}"
+ */
+ @DefaultMessage("repeatedArgs: {0}, {1}, {0}, {1}, {0}, {1}, {0}, {1}")
+ @Key("testLotsOfUsageOfArgs")
+ String testLotsOfUsageOfArgs(String arg0, String arg1);
+
+ /**
+ * Translated "\"~\" ~~ \"~~~~ \"\"".
+ *
+ * @return translated "\"~\" ~~ \"~~~~ \"\""
+ */
+ @DefaultMessage("\"~\" ~~ \"~~~~ \"\"")
+ @Key("testWithXs")
+ String testWithXs();
+
+ /**
+ * Translated "お{0}你{1}好".
+ *
+ * @return translated "お{0}你{1}好"
+ */
+ @DefaultMessage("お{0}你{1}好")
+ @Key("unicode")
+ String unicode(String arg0, String arg1);
}
diff --git a/user/test/com/google/gwt/i18n/client/gen/TestMessagesQuoting.java b/user/test/com/google/gwt/i18n/client/gen/TestMessagesQuoting.java
new file mode 100644
index 0000000..b20efdc
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/gen/TestMessagesQuoting.java
@@ -0,0 +1,51 @@
+/*
+ * 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.i18n.client.gen;
+
+/**
+ * Interface to represent the messages contained in resource bundle:
+ * 'com/google/gwt/i18n/client/gen/TestMessagesQuoting.properties'.
+ */
+public interface TestMessagesQuoting extends
+ com.google.gwt.i18n.client.Messages {
+
+ /**
+ * Translated "Embedded\r\ncr-nl.".
+ *
+ * @return translated "Embedded\r\ncr-nl."
+ */
+ @DefaultMessage("Embedded\r\ncr-nl.")
+ @Key("embeddedCRNL")
+ String embeddedCRNL();
+
+ /**
+ * Translated "This line has an\nembedded newline".
+ *
+ * @return translated "This line has an\nembedded newline"
+ */
+ @DefaultMessage("This line has an\nembedded newline")
+ @Key("embeddedNL")
+ String embeddedNL();
+
+ /**
+ * Translated "\"Don''t worry, be happy\" he said.".
+ *
+ * @return translated "\"Don''t worry, be happy\" he said."
+ */
+ @DefaultMessage("\"Don''t worry, be happy\" he said.")
+ @Key("embeddedQuote")
+ String embeddedQuote();
+}
diff --git a/user/test/com/google/gwt/i18n/client/gen/TestMessagesQuoting.properties b/user/test/com/google/gwt/i18n/client/gen/TestMessagesQuoting.properties
new file mode 100644
index 0000000..35263b8
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/gen/TestMessagesQuoting.properties
@@ -0,0 +1,3 @@
+embeddedNL=This line has an\nembedded newline
+embeddedCRNL=Embedded\r\ncr-nl.
+embeddedQuote="Don''t worry, be happy" he said.
diff --git a/user/test/com/google/gwt/i18n/tools/I18NSyncTest_.java b/user/test/com/google/gwt/i18n/tools/I18NSyncTest_.java
index 30d0024..389359d 100644
--- a/user/test/com/google/gwt/i18n/tools/I18NSyncTest_.java
+++ b/user/test/com/google/gwt/i18n/tools/I18NSyncTest_.java
@@ -50,7 +50,12 @@
// Should be caught
}
}
-
+
+ public void testConstantsQuoting() throws IOException {
+ String className = CLIENT_SOURCE_PACKAGE + "TestConstantsQuoting";
+ I18NSync.createConstantsInterfaceFromClassName(className, CLIENT_SOURCE_DIR);
+ }
+
public void testFileIsDirCase() {
try {
I18NSync.createMessagesInterfaceFromClassName(CLIENT_SOURCE_PACKAGE, null);
@@ -77,15 +82,14 @@
I18NSync.createMessagesInterfaceFromClassName(className, CLIENT_SOURCE_DIR);
}
+ public void testMessagesQuoting() throws IOException {
+ String className = CLIENT_SOURCE_PACKAGE + "TestMessagesQuoting";
+ I18NSync.createMessagesInterfaceFromClassName(className, CLIENT_SOURCE_DIR);
+ }
+
public void testMethodRenaming() throws IOException {
String className = CLIENT_SOURCE_PACKAGE + "TestBadKeys";
I18NSync.createConstantsWithLookupInterfaceFromClassName(className,
CLIENT_SOURCE_DIR);
}
-
- public void testWarning() throws IOException {
- String className = CLIENT_SOURCE_PACKAGE + "TestReallyBadKeys";
- I18NSync.createConstantsWithLookupInterfaceFromClassName(className);
- }
-
}
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
index 78eac3f..db7c871 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
@@ -22,6 +22,8 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
import java.sql.Time;
@@ -32,6 +34,8 @@
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.Vector;
/**
@@ -591,6 +595,48 @@
});
}
+ public void testTreeMap() {
+ delayTestFinish(TEST_DELAY);
+
+ CollectionsTestServiceAsync service = getServiceAsync();
+ for (boolean option : new boolean[] {true, false}) {
+ final TreeMap<String, MarkerTypeTreeMap> expected = TestSetFactory.createTreeMap(option);
+ service.echo(expected, option,
+ new AsyncCallback<TreeMap<String, MarkerTypeTreeMap>>() {
+ public void onFailure(Throwable caught) {
+ TestSetValidator.rethrowException(caught);
+ }
+
+ public void onSuccess(TreeMap<String, MarkerTypeTreeMap> result) {
+ assertNotNull(result);
+ assertTrue(TestSetValidator.isValid(expected, result));
+ finishTest();
+ }
+ });
+ }
+ }
+
+ public void testTreeSet() {
+ delayTestFinish(TEST_DELAY);
+
+ CollectionsTestServiceAsync service = getServiceAsync();
+ for (boolean option : new boolean[] {true, false}) {
+ final TreeSet<MarkerTypeTreeSet> expected = TestSetFactory.createTreeSet(option);
+ service.echo(expected, option,
+ new AsyncCallback<TreeSet<MarkerTypeTreeSet>>() {
+ public void onFailure(Throwable caught) {
+ TestSetValidator.rethrowException(caught);
+ }
+
+ public void onSuccess(TreeSet<MarkerTypeTreeSet> result) {
+ assertNotNull(result);
+ assertTrue(TestSetValidator.isValid(expected, result));
+ finishTest();
+ }
+ });
+ }
+ }
+
public void testVector() {
delayTestFinish(TEST_DELAY);
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
index 38590f9..6560d31 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
@@ -21,6 +21,8 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
import java.sql.Time;
@@ -32,6 +34,8 @@
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.Vector;
/**
@@ -50,6 +54,7 @@
super(msg);
}
}
+
ArrayList<MarkerTypeArrayList> echo(ArrayList<MarkerTypeArrayList> value)
throws CollectionsTestServiceException;
@@ -113,6 +118,13 @@
Timestamp[] echo(Timestamp[] value) throws CollectionsTestServiceException;
+ TreeMap<String, MarkerTypeTreeMap> echo(
+ TreeMap<String, MarkerTypeTreeMap> value, boolean option)
+ throws CollectionsTestServiceException;
+
+ TreeSet<MarkerTypeTreeSet> echo(TreeSet<MarkerTypeTreeSet> value,
+ boolean option) throws CollectionsTestServiceException;
+
Vector<MarkerTypeVector> echo(Vector<MarkerTypeVector> value)
throws CollectionsTestServiceException;
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
index 5423060..66fe565 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
@@ -21,6 +21,8 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
import java.sql.Time;
@@ -32,6 +34,8 @@
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.Vector;
/**
@@ -94,7 +98,13 @@
void echo(String[][] value, AsyncCallback<String[][]> callback);
void echo(Time[] value, AsyncCallback<Time[]> callback);
+
+ void echo(TreeMap<String, MarkerTypeTreeMap> value, boolean option,
+ AsyncCallback<TreeMap<String, MarkerTypeTreeMap>> callback);
+ void echo(TreeSet<MarkerTypeTreeSet> value, boolean option,
+ AsyncCallback<TreeSet<MarkerTypeTreeSet>> callback);
+
void echo(Timestamp[] value, AsyncCallback<Timestamp[]> callback);
void echo(Vector<MarkerTypeVector> value,
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
index 8bb6dd9..a9fdeff 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
@@ -15,16 +15,20 @@
*/
package com.google.gwt.user.client.rpc;
+import java.io.Serializable;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.Vector;
/**
@@ -37,7 +41,7 @@
* exposure in various collections.
*/
public static class MarkerBase implements IsSerializable {
- public String value;
+ private String value;
public MarkerBase(String value) {
this.value = value;
@@ -53,6 +57,10 @@
return false;
}
+ public String getValue() {
+ return value;
+ }
+
@Override
public int hashCode() {
return value.hashCode();
@@ -157,6 +165,43 @@
* A single-use marker type to independently check type parameter exposure in
* various collections.
*/
+ public static final class MarkerTypeTreeMap extends MarkerBase {
+
+ public MarkerTypeTreeMap(String value) {
+ super(value);
+ }
+
+ MarkerTypeTreeMap() {
+ super(null);
+ }
+ }
+
+ /**
+ * A single-use marker type to independently check type parameter exposure in
+ * various collections.
+ */
+ public static final class MarkerTypeTreeSet extends MarkerBase implements
+ Comparable<MarkerTypeTreeSet> {
+
+ public MarkerTypeTreeSet(String value) {
+ super(value);
+ }
+
+ MarkerTypeTreeSet() {
+ super(null);
+ }
+
+ // if getValue() returns null, a null-pointer expection will be thrown,
+ // which is the intended effect
+ public int compareTo(MarkerTypeTreeSet arg0) {
+ return getValue().compareTo(arg0.getValue());
+ }
+ }
+
+ /**
+ * A single-use marker type to independently check type parameter exposure in
+ * various collections.
+ */
public static final class MarkerTypeVector extends MarkerBase {
public MarkerTypeVector(String value) {
@@ -236,6 +281,35 @@
public static class UnserializableNode {
}
+ static class ReverseSorter<T extends Comparable<T>> implements Comparator<T>,
+ Serializable {
+
+ // for gwt-serialization
+ ReverseSorter() {
+ }
+
+ public int compare(T a, T b) {
+ // Explicit null check to match JRE specs
+ if (a == null || b == null) {
+ throw new NullPointerException();
+ }
+ return b.compareTo(a);
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object ob) {
+ if (!(ob instanceof ReverseSorter)) {
+ return false;
+ }
+ return true;
+ }
+ }
+
public static ArrayList<MarkerTypeArrayList> createArrayList() {
ArrayList<MarkerTypeArrayList> list = new ArrayList<MarkerTypeArrayList>();
list.add(new MarkerTypeArrayList("foo"));
@@ -425,6 +499,38 @@
"valueOf", "constructor", "__proto__"};
}
+ public static TreeMap<String, MarkerTypeTreeMap> createTreeMap(
+ boolean defaultComparator) {
+ TreeMap<String, MarkerTypeTreeMap> map;
+ if (defaultComparator) {
+ map = new TreeMap<String, MarkerTypeTreeMap>();
+ } else {
+ map = new TreeMap<String, MarkerTypeTreeMap>(new ReverseSorter<String>());
+ }
+ map.put("foo", new MarkerTypeTreeMap("foo"));
+ map.put("bar", new MarkerTypeTreeMap("bar"));
+ map.put("baz", new MarkerTypeTreeMap("baz"));
+ map.put("bal", new MarkerTypeTreeMap("bal"));
+ map.put("w00t", new MarkerTypeTreeMap("w00t"));
+ return map;
+ }
+
+ public static TreeSet<MarkerTypeTreeSet> createTreeSet(
+ boolean defaultComparator) {
+ TreeSet<MarkerTypeTreeSet> set;
+ if (defaultComparator) {
+ set = new TreeSet<MarkerTypeTreeSet>();
+ } else {
+ set = new TreeSet<MarkerTypeTreeSet>(new ReverseSorter<MarkerTypeTreeSet>());
+ }
+ set.add(new MarkerTypeTreeSet("foo"));
+ set.add(new MarkerTypeTreeSet("bar"));
+ set.add(new MarkerTypeTreeSet("baz"));
+ set.add(new MarkerTypeTreeSet("bal"));
+ set.add(new MarkerTypeTreeSet("w00t"));
+ return set;
+ }
+
public static Vector<MarkerTypeVector> createVector() {
Vector<MarkerTypeVector> vector = new Vector<MarkerTypeVector>();
vector.add(new MarkerTypeVector("foo"));
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
index da95a6d..a0b21f8 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.user.client.rpc;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.SerializableDoublyLinkedNode;
import com.google.gwt.user.client.rpc.TestSetFactory.SerializablePrivateNoArg;
import com.google.gwt.user.client.rpc.TestSetFactory.SerializableWithTwoArrays;
@@ -26,7 +28,10 @@
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.Vector;
import java.util.Map.Entry;
@@ -318,6 +323,60 @@
return node.one == node.two;
}
+ // also checks whether the sorting of entries is maintained or not.
+ public static boolean isValid(TreeMap<String, MarkerTypeTreeMap> expected,
+ TreeMap<String, MarkerTypeTreeMap> map) {
+ if (map == null) {
+ return false;
+ }
+ if (!equalsWithNullCheck(map.comparator(), expected.comparator())) {
+ return false;
+ }
+ int size = 0;
+ if ((size = expected.size()) != map.size()) {
+ return false;
+ }
+ // entrySet returns entries in the sorted order
+ List<Map.Entry<String, MarkerTypeTreeMap>> actualList = new ArrayList<Map.Entry<String, MarkerTypeTreeMap>>(
+ map.entrySet());
+ List<Map.Entry<String, MarkerTypeTreeMap>> expectedList = new ArrayList<Map.Entry<String, MarkerTypeTreeMap>>(
+ expected.entrySet());
+ for (int index = 0; index < size; index++) {
+ Entry<String, MarkerTypeTreeMap> expectedEntry = expectedList.get(index);
+ Entry<String, MarkerTypeTreeMap> actualEntry = actualList.get(index);
+ if (!equalsWithNullCheck(expectedEntry.getKey(), actualEntry.getKey())
+ || !equalsWithNullCheck(expectedEntry.getValue(),
+ actualEntry.getValue())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // also checks whether the sorting of entries is maintained or not.
+ public static boolean isValid(TreeSet<MarkerTypeTreeSet> expected,
+ TreeSet<MarkerTypeTreeSet> set) {
+ if (set == null) {
+ return false;
+ }
+ if (!equalsWithNullCheck(set.comparator(), expected.comparator())) {
+ return false;
+ }
+ int size = 0;
+ if ((size = expected.size()) != set.size()) {
+ return false;
+ }
+ // entrySet returns entries in the sorted order
+ List<MarkerTypeTreeSet> actualList = new ArrayList<MarkerTypeTreeSet>(set);
+ List<MarkerTypeTreeSet> expectedList = new ArrayList<MarkerTypeTreeSet>(expected);
+ for (int index = 0; index < size; index++) {
+ if (!equalsWithNullCheck(expectedList.get(index), actualList.get(index))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static boolean isValid(Vector expected, Vector actual) {
if (actual == null) {
return false;
@@ -446,6 +505,12 @@
return true;
}
+ /**
+ * Wrap an exception in RuntimeException if necessary so it doesn't have to be listed in
+ * throws clauses.
+ *
+ * @param caught exception to wrap
+ */
public static void rethrowException(Throwable caught) {
if (caught instanceof RuntimeException) {
throw (RuntimeException) caught;
@@ -453,5 +518,8 @@
throw new RuntimeException(caught);
}
}
+ private static boolean equalsWithNullCheck(Object a, Object b) {
+ return a == b || (a != null && a.equals(b));
+ }
}
diff --git a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingService.java b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingService.java
index 7edbbfa..d31416f 100644
--- a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingService.java
+++ b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingService.java
@@ -19,12 +19,69 @@
* Service used to test unicode escaping.
*/
public interface UnicodeEscapingService extends RemoteService {
+
+ /**
+ * Exception for escaping errors.
+ */
+ public static class InvalidCharacterException extends Exception {
+
+ private static String toHex(int val) {
+ String hex = Integer.toHexString(val);
+ return "00000".substring(hex.length()) + hex;
+ }
+
+ private int index;
+ private int expected;
+ private int actual;
+
+ protected InvalidCharacterException() { }
+
+ public InvalidCharacterException(int index, int expected, int actual) {
+ super(index < 0 ? "String length mismatch: expected = " + expected + ", actual = " + actual
+ : "At index " + index + ", expected = U+" + toHex(expected) + ", actual = U+"
+ + toHex(actual));
+ this.index = index;
+ this.expected = expected;
+ this.actual = actual;
+ }
+
+ public int getActual() {
+ return actual;
+ }
+
+ public int getExpected() {
+ return expected;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+ }
+
/**
* Returns a string containing the characters from start to end.
*
- * @param start start character value, inclusive
- * @param end end character value, exclusive
+ * Used to verify server->client escaping.
+ *
+ * @param start start character value, inclusive -- note if greater
+ * than {@link Character#MIN_SUPPLEMENTARY_CODE_POINT} it will
+ * be included as surrogate pairs in the returned string.
+ * @param end end character value, exclusive (see above comment)
* @return a string containing the characters from start to end
*/
String getStringContainingCharacterRange(int start, int end);
+
+ /**
+ * Verifies that the string contains the specified characters.
+ *
+ * Used to verify client->server escaping.
+ *
+ * @param start start code point value included
+ * @param end first code point not included
+ * @param str string to verify
+ * @throws InvalidCharacterException if the string does not contain the specified characters
+ * @return true if the verification succeeded
+ */
+ boolean verifyStringContainingCharacterRange(int start, int end, String str)
+ throws InvalidCharacterException;
}
diff --git a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingServiceAsync.java b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingServiceAsync.java
index f563218..6ae9fd4 100644
--- a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingServiceAsync.java
+++ b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingServiceAsync.java
@@ -15,10 +15,14 @@
*/
package com.google.gwt.user.client.rpc;
+import com.google.gwt.user.client.rpc.UnicodeEscapingService.InvalidCharacterException;
+
/**
* Async version of the {@link UnicodeEscapingService} interface.
*/
public interface UnicodeEscapingServiceAsync {
void getStringContainingCharacterRange(int start, int end,
- AsyncCallback callback);
+ AsyncCallback<String> callback);
+ void verifyStringContainingCharacterRange(int start, int end, String str,
+ AsyncCallback<Boolean> callback) throws InvalidCharacterException;
}
diff --git a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java
index 1c5f989..f45777e 100644
--- a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java
@@ -17,68 +17,256 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.rpc.UnicodeEscapingService.InvalidCharacterException;
/**
- * Test which verifies that we properly escape JSON strings sent back from the
- * server.
+ * Test that any valid string can be sent via RPC in both directions.
+ *
+ * TODO(jat): make unpaired surrogates work properly if it is possible to do
+ * so on all browsers, then add them to this test.
*/
public class UnicodeEscapingTest extends GWTTestCase {
- private static final int DEFAULT_TEST_FINISH_DELAY_MS = 5000;
- private static final int CHARACTER_RANGE_SIZE = 1024;
- private static final int LAST_CHARACTER = 0x10000;
+ /** the size of a block of characters to test */
+ private static final int CHARACTER_BLOCK_SIZE = 64;
- private int start = 0;
+ /**
+ * When doing the non-BMP test, we don't test every block of characters
+ * because it takes too long - this is the increment to use. It is not a
+ * power of two so we alter the alignment of the block of characters we skip.
+ */
+ private static final int NON_BMP_TEST_INCREMENT = 8192 + 64;
+ /** the time to wait for the test of a block of characters */
+ private static final int TEST_FINISH_DELAY_MS = 500000;
+
+ /**
+ * Generates a string containing a sequence of code points.
+ *
+ * @param start first code point to include in the string
+ * @param end one past the last code point to include in the string
+ * @return a string containing all the requested code points
+ */
+ public static String getStringContainingCharacterRange(int start, int end) {
+ StringBuffer buf = new StringBuffer();
+ for (int codePoint = start; codePoint < end; ++codePoint) {
+ if (Character.isSupplementaryCodePoint(codePoint)) {
+ buf.append(Character.toChars(codePoint));
+ } else {
+ buf.append((char) codePoint);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ /*
+ * Copied from HistoryTest.
+ */
+ private static native boolean isSafari2() /*-{
+ var exp = / AppleWebKit\/([\d]+)/;
+ var result = exp.exec(navigator.userAgent);
+ if (result) {
+ // The standard history implementation works fine on WebKit >= 522
+ // (Safari 3 beta).
+ if (parseInt(result[1]) >= 522) {
+ return false;
+ }
+ }
+
+ // The standard history implementation works just fine on the iPhone, which
+ // unfortunately reports itself as WebKit/420+.
+ if (navigator.userAgent.indexOf('iPhone') != -1) {
+ return false;
+ }
+
+ return true;
+ }-*/;
+ /**
+ * Verifies that the supplied string includes the requested code points.
+ *
+ * @param start first code point to include in the string
+ * @param end one past the last code point to include in the string
+ * @param str the string to test
+ * @throws InvalidCharacterException if a character doesn't match
+ * @throws RuntimeException if the string is too long
+ */
+ public static void verifyStringContainingCharacterRange(int start, int end,
+ String str) throws InvalidCharacterException {
+ if (str == null) {
+ throw new NullPointerException("String is null");
+ }
+ int expectedLen = end - start;
+ int strLen = str.codePointCount(0, str.length());
+ for (int i = 0, codePoint = start; i < strLen;
+ i = Character.offsetByCodePoints(str, i, 1)) {
+ int strCodePoint = str.codePointAt(i);
+ if (strCodePoint != codePoint) {
+ throw new InvalidCharacterException(i, codePoint, strCodePoint);
+ }
+ ++codePoint;
+ }
+ if (strLen < expectedLen) {
+ throw new InvalidCharacterException(strLen, start + strLen, -1);
+ } else if (expectedLen != strLen) {
+ throw new RuntimeException("Too many characters returned on block from U+"
+ + Integer.toHexString(start) + " to U+" + Integer.toHexString(end)
+ + ": expected=" + expectedLen + ", actual=" + strLen);
+ }
+ }
private static UnicodeEscapingServiceAsync getService() {
- UnicodeEscapingServiceAsync service = (UnicodeEscapingServiceAsync) GWT.create(UnicodeEscapingService.class);
+ UnicodeEscapingServiceAsync service = GWT.create(
+ UnicodeEscapingService.class);
ServiceDefTarget target = (ServiceDefTarget) service;
target.setServiceEntryPoint(GWT.getModuleBaseURL() + "unicodeEscape");
return service;
}
+ /** start of current block being tested */
+ private int current;
+
+ @Override
public String getModuleName() {
return "com.google.gwt.user.RPCSuite";
}
/**
+ * Generate strings containing ranges of characters and sends them to the
+ * server for verification. This ensures that client->server string escaping
+ * properly handles all BMP characters.
+ *
+ * Unpaired or improperly paired surrogates are not tested here, as some
+ * browsers refuse to accept them. Properly paired surrogates are tested
+ * in the non-BMP test.
+ *
+ * Note that this does not test all possible combinations, which might be an
+ * issue, particularly with combining marks, though they should be logically
+ * equivalent in that case.
+ *
+ * @throws InvalidCharacterException
+ */
+ public void testClientToServerBMP() throws InvalidCharacterException {
+ delayTestFinish(TEST_FINISH_DELAY_MS);
+ if (isSafari2()) {
+ // Safari2 can't be fixed for many characters, including null
+ // We only guarantee that basic ISO-Latin characters are unmolested.
+ clientToServerVerifyRange(0x0001, 0x0300, CHARACTER_BLOCK_SIZE,
+ CHARACTER_BLOCK_SIZE);
+ } else {
+ clientToServerVerifyRange(Character.MIN_CODE_POINT,
+ Character.MIN_SURROGATE, CHARACTER_BLOCK_SIZE,
+ CHARACTER_BLOCK_SIZE);
+ clientToServerVerifyRange(Character.MAX_SURROGATE + 1,
+ Character.MIN_SUPPLEMENTARY_CODE_POINT, CHARACTER_BLOCK_SIZE,
+ CHARACTER_BLOCK_SIZE);
+ }
+ }
+
+ /**
+ * Generate strings containing ranges of characters and sends them to the
+ * server for verification. This ensures that client->server string escaping
+ * properly handles all non-BMP characters.
+ *
+ * Note that this does not test all possible combinations, which might be an
+ * issue, particularly with combining marks, though they should be logically
+ * equivalent in that case.
+ *
+ * @throws InvalidCharacterException
+ */
+ public void testClientToServerNonBMP() throws InvalidCharacterException {
+ delayTestFinish(TEST_FINISH_DELAY_MS);
+ clientToServerVerifyRange(Character.MIN_SUPPLEMENTARY_CODE_POINT,
+ Character.MAX_CODE_POINT + 1, CHARACTER_BLOCK_SIZE,
+ NON_BMP_TEST_INCREMENT);
+ }
+
+ /**
+ * Requests strings of CHARACTER_RANGE_SIZE from the server and validates
+ * that the returned string length matches CHARACTER_RANGE_SIZE and that all
+ * of the characters remain intact.
+ *
+ * Note that this does not test all possible combinations, which might be an
+ * issue, particularly with combining marks, though they should be logically
+ * equivalent in that case.
+ */
+ public void testServerToClientBMP() {
+ delayTestFinish(TEST_FINISH_DELAY_MS);
+ serverToClientVerify(Character.MIN_CODE_POINT,
+ Character.MIN_SUPPLEMENTARY_CODE_POINT, CHARACTER_BLOCK_SIZE,
+ CHARACTER_BLOCK_SIZE);
+ }
+
+ /**
* Requests strings of CHARACTER_RANGE_SIZE from the server and validates that
* the returned string length matches CHARACTER_RANGE_SIZE and that all of the
- * characters remain intact.
+ * characters remain intact. Note that this test verifies non-BMP characters
+ * (ie, those which are represented as pairs of surrogates).
+ *
+ * Note that this does not test all possible combinations, which might be an
+ * issue, particularly with combining marks, though they should be logically
+ * equivalent in that case.
*/
- public void testUnicodeEscaping() {
- delayTestFinish(DEFAULT_TEST_FINISH_DELAY_MS);
+ public void testServerToClientNonBMP() {
+ delayTestFinish(TEST_FINISH_DELAY_MS);
+ serverToClientVerify(Character.MIN_SUPPLEMENTARY_CODE_POINT,
+ Character.MAX_CODE_POINT + 1, CHARACTER_BLOCK_SIZE,
+ NON_BMP_TEST_INCREMENT);
+ }
- getService().getStringContainingCharacterRange(0, CHARACTER_RANGE_SIZE,
- new AsyncCallback() {
- public void onFailure(Throwable caught) {
- TestSetValidator.rethrowException(caught);
+ private void clientToServerVerifyRange(final int start, final int end,
+ final int size, final int step) throws InvalidCharacterException {
+ current = start;
+ int blockEnd = Math.min(end, current + size);
+ getService().verifyStringContainingCharacterRange(current, blockEnd,
+ getStringContainingCharacterRange(start, blockEnd),
+ new AsyncCallback<Boolean>() {
+ public void onFailure(Throwable caught) {
+ TestSetValidator.rethrowException(caught);
+ }
+
+ public void onSuccess(Boolean ignored) {
+ current += step;
+ if (current < end) {
+ delayTestFinish(TEST_FINISH_DELAY_MS);
+ int blockEnd = Math.min(end, current + size);
+ try {
+ getService().verifyStringContainingCharacterRange(current, blockEnd,
+ getStringContainingCharacterRange(current, blockEnd), this);
+ } catch (InvalidCharacterException e) {
+ TestSetValidator.rethrowException(e);
}
+ } else {
+ finishTest();
+ }
+ }
+ });
+ }
- public void onSuccess(Object result) {
- String str = (String) result;
+ private void serverToClientVerify(final int start, final int end,
+ final int size, final int step) {
+ current = start;
+ getService().getStringContainingCharacterRange(start, Math.min(end,
+ current + size), new AsyncCallback<String>() {
+ public void onFailure(Throwable caught) {
+ TestSetValidator.rethrowException(caught);
+ }
- assertTrue("expected: " + Integer.toString(CHARACTER_RANGE_SIZE)
- + " actual: " + str.length() + " for character range ["
- + Integer.toString(start) + ", "
- + Integer.toString(start + CHARACTER_RANGE_SIZE) + ")",
- CHARACTER_RANGE_SIZE == str.length());
-
- char[] chars = str.toCharArray();
- for (int i = 0; i < CHARACTER_RANGE_SIZE; ++i) {
- assertEquals(i + start, chars[i]);
- }
-
- start += CHARACTER_RANGE_SIZE;
- if (start < LAST_CHARACTER) {
- delayTestFinish(DEFAULT_TEST_FINISH_DELAY_MS);
-
- getService().getStringContainingCharacterRange(start,
- start + CHARACTER_RANGE_SIZE, this);
- } else {
- finishTest();
- }
- }
- });
+ public void onSuccess(String str) {
+ try {
+ verifyStringContainingCharacterRange(current, Math.min(end,
+ current + size), str);
+ } catch (InvalidCharacterException e) {
+ TestSetValidator.rethrowException(e);
+ }
+ current += step;
+ if (current < end) {
+ delayTestFinish(TEST_FINISH_DELAY_MS);
+ getService().getStringContainingCharacterRange(current,
+ Math.min(end, current + size), this);
+ } else {
+ finishTest();
+ }
+ }
+ });
}
}
diff --git a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
index 12bd35b..d02c6e1 100644
--- a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
@@ -24,6 +24,8 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
import java.sql.Time;
@@ -36,6 +38,8 @@
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.Vector;
/**
@@ -328,6 +332,29 @@
return actual;
}
+ public TreeMap<String, MarkerTypeTreeMap> echo(
+ TreeMap<String, MarkerTypeTreeMap> actual, boolean option)
+ throws CollectionsTestServiceException {
+ TreeMap<String, MarkerTypeTreeMap> expected = TestSetFactory.createTreeMap(option);
+ if (!TestSetValidator.isValid(expected, actual)) {
+ throw new CollectionsTestServiceException("expected: "
+ + expected.toString() + " actual: " + actual.toString());
+ }
+
+ return actual;
+ }
+
+ public TreeSet<MarkerTypeTreeSet> echo(TreeSet<MarkerTypeTreeSet> actual,
+ boolean option) throws CollectionsTestServiceException {
+ TreeSet<MarkerTypeTreeSet> expected = TestSetFactory.createTreeSet(option);
+ if (!TestSetValidator.isValid(expected, actual)) {
+ throw new CollectionsTestServiceException("expected: "
+ + expected.toString() + " actual: " + actual.toString());
+ }
+
+ return actual;
+ }
+
public Vector<MarkerTypeVector> echo(Vector<MarkerTypeVector> actual)
throws CollectionsTestServiceException {
Vector<MarkerTypeVector> expected = TestSetFactory.createVector();
@@ -348,4 +375,5 @@
return value;
}
+
}
diff --git a/user/test/com/google/gwt/user/server/rpc/RPCTest.java b/user/test/com/google/gwt/user/server/rpc/RPCTest.java
index 8eb1bb3..20dd1b9 100644
--- a/user/test/com/google/gwt/user/server/rpc/RPCTest.java
+++ b/user/test/com/google/gwt/user/server/rpc/RPCTest.java
@@ -15,10 +15,14 @@
*/
package com.google.gwt.user.server.rpc;
+import static com.google.gwt.user.client.rpc.impl.AbstractSerializationStream.RPC_SEPARATOR_CHAR;
+
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializableException;
import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.impl.AbstractSerializationStream;
+import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader;
import junit.framework.TestCase;
@@ -27,6 +31,7 @@
/**
* Tests for the {@link com.google.gwt.user.server.rpc.RPC RPC} class.
*/
+@SuppressWarnings("deprecation")
public class RPCTest extends TestCase {
private static interface A extends RemoteService {
@@ -41,50 +46,74 @@
void method1();
}
- private static final String VALID_ENCODED_REQUEST = "4\uffff" + // version
- "0\uffff" + // flags
- "4\uffff" + // string table entry count
- A.class.getName() + "\uffff" + // string table entry #0
- "method2" + "\uffff" + // string table entry #1
- "moduleBaseURL" + "\uffff" + // string table entry #2
- "whitelistHashcode" + "\uffff" + // string table entry #4
- "3\uffff" + // module base URL
- "4\uffff" + // whitelist hashcode
- "1\uffff" + // interface name
- "2\uffff" + // method name
- "0\uffff"; // param count
+ private static final String VALID_ENCODED_REQUEST = "" +
+ AbstractSerializationStream.SERIALIZATION_STREAM_VERSION +
+ RPC_SEPARATOR_CHAR + // version
+ "0" + RPC_SEPARATOR_CHAR + // flags
+ "4" + RPC_SEPARATOR_CHAR + // string table entry count
+ A.class.getName() + RPC_SEPARATOR_CHAR + // string table entry #1
+ "method2" + RPC_SEPARATOR_CHAR + // string table entry #2
+ "moduleBaseURL" + RPC_SEPARATOR_CHAR + // string table entry #3
+ "whitelistHashcode" + RPC_SEPARATOR_CHAR + // string table entry #4
+ "3" + RPC_SEPARATOR_CHAR + // module base URL
+ "4" + RPC_SEPARATOR_CHAR + // whitelist hashcode
+ "1" + RPC_SEPARATOR_CHAR + // interface name
+ "2" + RPC_SEPARATOR_CHAR + // method name
+ "0" + RPC_SEPARATOR_CHAR; // param count
- private static final String INVALID_METHOD_REQUEST = "4\uffff" + // version
- "0\uffff" + // flags
- "4\uffff" + // string table entry count
- A.class.getName() + "\uffff" + // string table entry #0
- "method3" + "\uffff" + // string table entry #1
- "moduleBaseURL" + "\uffff" + // string table entry #2
- "whitelistHashcode" + "\uffff" + // string table entry #4
- "3\uffff" + // module base URL
- "4\uffff" + // whitelist hashcode
- "1\uffff" + // interface name
- "2\uffff" + // method name
- "0\uffff"; // param count
+ private static final String INVALID_METHOD_REQUEST = "" +
+ AbstractSerializationStream.SERIALIZATION_STREAM_VERSION +
+ RPC_SEPARATOR_CHAR + // version
+ "0" + RPC_SEPARATOR_CHAR + // flags
+ "4" + RPC_SEPARATOR_CHAR + // string table entry count
+ A.class.getName() + RPC_SEPARATOR_CHAR + // string table entry #1
+ "method3" + RPC_SEPARATOR_CHAR + // string table entry #2
+ "moduleBaseURL" + RPC_SEPARATOR_CHAR + // string table entry #3
+ "whitelistHashcode" + RPC_SEPARATOR_CHAR + // string table entry #4
+ "3" + RPC_SEPARATOR_CHAR + // module base URL
+ "4" + RPC_SEPARATOR_CHAR + // whitelist hashcode
+ "1" + RPC_SEPARATOR_CHAR + // interface name
+ "2" + RPC_SEPARATOR_CHAR + // method name
+ "0" + RPC_SEPARATOR_CHAR; // param count
- private static final String INVALID_INTERFACE_REQUEST = "4\uffff" + // version
- "0\uffff" + // flags
- "4\uffff" + // string table entry count
- B.class.getName() + "\uffff" + // string table entry #0
- "method1" + "\uffff" + // string table entry #1
- "moduleBaseURL" + "\uffff" + // string table entry #2
- "whitelistHashcode" + "\uffff" + // string table entry #4
- "3\uffff" + // module base URL
- "4\uffff" + // whitelist hashcode
- "1\uffff" + // interface name
- "2\uffff" + // method name
- "0\uffff"; // param count
+ private static final String INVALID_INTERFACE_REQUEST = "" +
+ AbstractSerializationStream.SERIALIZATION_STREAM_VERSION +
+ RPC_SEPARATOR_CHAR + // version
+ "0" + RPC_SEPARATOR_CHAR + // flags
+ "4" + RPC_SEPARATOR_CHAR + // string table entry count
+ B.class.getName() + RPC_SEPARATOR_CHAR + // string table entry #1
+ "method1" + RPC_SEPARATOR_CHAR + // string table entry #2
+ "moduleBaseURL" + RPC_SEPARATOR_CHAR + // string table entry #3
+ "whitelistHashcode" + RPC_SEPARATOR_CHAR + // string table entry #4
+ "3" + RPC_SEPARATOR_CHAR + // module base URL
+ "4" + RPC_SEPARATOR_CHAR + // whitelist hashcode
+ "1" + RPC_SEPARATOR_CHAR + // interface name
+ "2" + RPC_SEPARATOR_CHAR + // method name
+ "0" + RPC_SEPARATOR_CHAR; // param count
+
+ private static final String STRING_QUOTE_REQUEST = "" +
+ AbstractSerializationStream.SERIALIZATION_STREAM_VERSION +
+ RPC_SEPARATOR_CHAR + // version
+ "0" + RPC_SEPARATOR_CHAR + // flags
+ "7" + RPC_SEPARATOR_CHAR + // string table entry count
+ A.class.getName() + RPC_SEPARATOR_CHAR + // string table entry #1
+ "method2" + RPC_SEPARATOR_CHAR + // string table entry #2
+ "moduleBaseURL" + RPC_SEPARATOR_CHAR + // string table entry #3
+ "whitelistHashcode" + RPC_SEPARATOR_CHAR + // string table entry #4
+ "Raw backslash \\\\" + RPC_SEPARATOR_CHAR + // string table entry #5
+ "Quoted separator \\!" + RPC_SEPARATOR_CHAR + // string table entry #6
+ "\\uffff\\\\!\\\\0\\0" + RPC_SEPARATOR_CHAR + // string table entry #7
+ "3" + RPC_SEPARATOR_CHAR + // module base URL
+ "4" + RPC_SEPARATOR_CHAR + // whitelist hashcode
+ "5" + RPC_SEPARATOR_CHAR + // begin test data
+ "6" + RPC_SEPARATOR_CHAR +
+ "7" + RPC_SEPARATOR_CHAR;
private static final String VALID_V2_ENCODED_REQUEST = "2\uffff" + // version
"0\uffff" + // flags
"2\uffff" + // string table entry count
- A.class.getName() + "\uffff" + // string table entry #0
- "method2" + "\uffff" + // string table entry #1
+ A.class.getName() + "\uffff" + // string table entry #1
+ "method2\uffff" + // string table entry #2
"1\uffff" + // interface name
"2\uffff" + // method name
"0\uffff"; // param count
@@ -92,9 +121,22 @@
private static final String VALID_V3_ENCODED_REQUEST = "3\uffff" + // version
"0\uffff" + // flags
"4\uffff" + // string table entry count
- A.class.getName() + "\uffff" + // string table entry #0
- "method2" + "\uffff" + // string table entry #1
- "moduleBaseURL" + "\uffff" + // string table entry #2
+ A.class.getName() + "\uffff" + // string table entry #1
+ "method2\uffff" + // string table entry #2
+ "moduleBaseURL\uffff" + // string table entry #3
+ "whitelistHashcode\uffff" + // string table entry #4
+ "3\uffff" + // module base URL
+ "4\uffff" + // whitelist hashcode
+ "1\uffff" + // interface name
+ "2\uffff" + // method name
+ "0\uffff"; // param count
+
+ private static final String VALID_V4_ENCODED_REQUEST = "4\uffff" + // version
+ "0\uffff" + // flags
+ "4\uffff" + // string table entry count
+ A.class.getName() + "\uffff" + // string table entry #1
+ "method2" + "\uffff" + // string table entry #2
+ "moduleBaseURL" + "\uffff" + // string table entry #3
"whitelistHashcode" + "\uffff" + // string table entry #4
"3\uffff" + // module base URL
"4\uffff" + // whitelist hashcode
@@ -120,6 +162,13 @@
} catch (IncompatibleRemoteServiceException e) {
// Expected
}
+
+ try {
+ RPC.decodeRequest(VALID_V4_ENCODED_REQUEST, A.class, null);
+ fail("Should have thrown an IncompatibleRemoteServiceException");
+ } catch (IncompatibleRemoteServiceException e) {
+ // Expected
+ }
}
/**
@@ -402,4 +451,12 @@
}
}, A_method1, null);
}
+
+ public void testSerializationStreamDequote() throws SerializationException {
+ ServerSerializationStreamReader reader = new ServerSerializationStreamReader(null, null);
+ reader.prepareToRead(STRING_QUOTE_REQUEST);
+ assertEquals("Raw backslash \\", reader.readString());
+ assertEquals("Quoted separator " + RPC_SEPARATOR_CHAR, reader.readString());
+ assertEquals("\uffff\\!\\0\u0000", reader.readString());
+ }
}
diff --git a/user/test/com/google/gwt/user/server/rpc/UnicodeEscapingServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/UnicodeEscapingServiceImpl.java
index 76bd2e7..7d4e99f 100644
--- a/user/test/com/google/gwt/user/server/rpc/UnicodeEscapingServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/UnicodeEscapingServiceImpl.java
@@ -16,6 +16,7 @@
package com.google.gwt.user.server.rpc;
import com.google.gwt.user.client.rpc.UnicodeEscapingService;
+import com.google.gwt.user.client.rpc.UnicodeEscapingTest;
/**
* Implementation of the {@link UnicodeEscapingService} interface.
@@ -24,18 +25,18 @@
UnicodeEscapingService {
/**
- * @see com.google.gwt.user.client.rpc.UnicodeEscapingService#getStringContainingCharacterRange(int,
- * int)
+ * @see UnicodeEscapingService#getStringContainingCharacterRange(int, int)
*/
public String getStringContainingCharacterRange(int start, int end) {
- int nChars = end - start;
-
- char[] chars = new char[nChars];
- for (int i = 0; i < nChars; ++i) {
- char ch = (char) (start + i);
- chars[i] = ch;
- }
+ return UnicodeEscapingTest.getStringContainingCharacterRange(start, end);
+ }
- return new String(chars);
+ /**
+ * @see UnicodeEscapingService#verifyStringContainingCharacterRange(int, int, String)
+ */
+ public boolean verifyStringContainingCharacterRange(int start, int end,
+ String str) throws InvalidCharacterException {
+ UnicodeEscapingTest.verifyStringContainingCharacterRange(start, end, str);
+ return true;
}
}
diff --git a/user/test/com/google/gwt/xml/client/XMLTest.java b/user/test/com/google/gwt/xml/client/XMLTest.java
index a34f366..180bad7 100644
--- a/user/test/com/google/gwt/xml/client/XMLTest.java
+++ b/user/test/com/google/gwt/xml/client/XMLTest.java
@@ -312,7 +312,13 @@
assertEquals(top.getChildNodes().getLength(), 1);
}
- public void testParse() {
+ /**
+ * This test is failing on one Safari configuration in web mode in the 1.5
+ * release branch, but it passes in all other configurations and in the trunk.
+ * The files in the xml package are identical between the trunk and the 1.5
+ * branch.
+ */
+ public void disabledTestParse() {
Document docA = XMLParser.parse("<!--hello--> <a spam=\"ham\">\n <?pi hello ?>dfgdfg <b/>\t</a>");
Document docB = XMLParser.createDocument();