Merging releases/1.6@4669:4911 into trunk.
These are the specific merges I performed, skipping c4695, c4875, c4878, c4892:
svn merge -r4669:4694 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
svn merge -r4695:4874 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
svn merge -r4875:4877 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
svn merge -r4878:4891 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
svn merge -r4892:4911 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4919 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/branch-info.txt b/branch-info.txt
deleted file mode 100644
index 6b0149f..0000000
--- a/branch-info.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-branch-info.txt for GWT 1.6 release:
-Tracks interactions between this branch and other branches.
-See: http://code.google.com/p/google-web-toolkit/wiki/ManagingMerges
-
-Copies:
-/releases/1.6/ was created (r3732) as a straight copy from /trunk/@r3683
-
-Merges:
-/trunk revisions c3688,c3703,c3700,c3704,c3707,c3715,c3717,c3724,c3725 were merged (r3739) into this branch
-/trunk revision c4859 was merged (r4870) into this branch
-/trunk revision c4867 was merged (r4871) into this branch
-/releases/1.5/@r3630:3863 was merged (r3864) into this branch
-/releases/1.6/@r3739:3876 was merged (r3877) into trunk
-/releases/1.6/@r3878:3944 was merged (r3945) into trunk, skipping c3878
-/releases/1.6/@r3944:4025 was merged (r4032) into trunk
-/branches/1_6_clean_events@3936:4088 was merged (r4092) into this branch
-/releases/1.5/@r3863:4093 was merged (r4134) into this branch
-/releases/1.6/@r4025:4130 was merged (r4142) into trunk, superceding trunk:c4118
-/releases/1.6/@r4130:4147 was merged (r4148) into trunk
-/releases/1.6/@r4147:4198 was merged (r4202) into trunk
-/releases/1.6/@c4269, c4298, and c4299 were merged (r4314) into trunk; note this is a cherrypick
-/trunk revision c4266 was merged (r4321) into this branch
-/releases/1.6/@r4198:4268 was merged (r4367,r4368) into trunk
-/releases/1.6/@r4269:4297 was merged (r4367,r4368) into trunk, skipping c4269 (already merged, c4314)
-/releases/1.6/@r4299:4320 was merged (r4367,r4368) into trunk, skipping c4298, c4299 (already merged, c4314)
-/releases/1.6/@r4321:4366 was merged (r4367,r4368) into trunk, skipping c4321 (was a backmerge from trunk)
-/releases/1.6/@r4366:4385 was merged (r4386) into trunk
-/releases/1.6/@r4385:4459 was merged (r4488) into trunk
-/releases/1.6/@r4359:4490 was merged (r4491) into trunk
-/releases/1.6/@c4498 was merged (r4499) into trunk
-/releases/1.6/@r4490:4497,4498:4511 was merged (r4512) into trunk, skipping c4498 (cherry picked above)
-/trunk@c4603 was merged (r4605) into /releases/1.6
-/releases/1.6/@r4511:4604,4605:4657 was merged (r4659) into trunk, skipping c4605 (cherry picked above)
-/releases/1.6/@r4657:4658 was merged (r4662) into trunk
-/releases/1.6/@r4658:4669 was merged (r4670) into trunk
-/trunk@c4873 was merged (r4878) into /releases/1.6
-/trunk revision c4889 was merged (r4892) into this branch
-
-The next merge into trunk will be:
-svn merge -r4669:4694 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
-svn merge -r4695:4877 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
-svn merge -r4878:???? https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
diff --git a/build-tools/ant-gwt/src/com/google/gwt/ant/taskdefs/SvnInfo.java b/build-tools/ant-gwt/src/com/google/gwt/ant/taskdefs/SvnInfo.java
index 1b3ed08..f326367 100644
--- a/build-tools/ant-gwt/src/com/google/gwt/ant/taskdefs/SvnInfo.java
+++ b/build-tools/ant-gwt/src/com/google/gwt/ant/taskdefs/SvnInfo.java
@@ -59,9 +59,20 @@
if (!workDirFile.isDirectory()) {
throw new BuildException(workdir + " is not a directory");
}
+
+ String branch;
+ String revision;
- String branch = getSvnBranch(workDirFile);
- String revision = getSvnVersion(workDirFile);
+ File svnDirFile = new File(workdir, ".svn");
+ if (!svnDirFile.exists()) {
+ // This is not svn workdir. We can't guess the version...
+ branch = "unknown";
+ revision = "unknown";
+ } else {
+ branch = getSvnBranch(workDirFile);
+ revision = getSvnVersion(workDirFile);
+ }
+
getProject().setNewProperty(outprop, branch + "@" + revision);
if (fileprop != null) {
getProject().setNewProperty(fileprop,
diff --git a/build-tools/drtool/BuildGlobalTOC.py b/build-tools/drtool/BuildGlobalTOC.py
new file mode 100644
index 0000000..6600c1e
--- /dev/null
+++ b/build-tools/drtool/BuildGlobalTOC.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may 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.
+#
+
+"""
+Routines for constructing a TOCNode from a file on disk.
+"""
+
+from TOCNode import TOCNode
+import re
+
+def BuildTOC(toc_filename, displayname):
+ """This will return a list of toplevel TOCNodes, each of which may have
+ nested children."""
+
+ infile = open(toc_filename)
+ bytes = infile.read()
+ lines = bytes.split("\n")
+
+ out = TOCNode(displayname)
+ parentstack = [(out, -1)]
+ previndent = 0
+ prevnode = None
+
+ for line in lines:
+ if line.startswith("#"): continue
+
+ indentlevel = line.find("*")
+ if -1 == indentlevel: continue
+
+ postindent = line[indentlevel:]
+ poststar = postindent[2:]
+
+ if poststar.startswith('['):
+ splitted = re.split("[\[\] ]", poststar)
+ wikiWord = splitted[1]
+ caption = " ".join(splitted[2:])
+ caption = caption.replace("&", "and")
+ caption = caption.strip()
+
+ tocnode = TOCNode(caption, wikiWord)
+ else:
+ caption = poststar
+ caption = caption.replace("&", "and")
+ caption = caption.strip()
+
+ tocnode = TOCNode(caption)
+
+ if indentlevel > previndent:
+ if prevnode:
+ parentstack.append((prevnode, previndent))
+ elif indentlevel < previndent:
+ while (parentstack and parentstack[-1][1] >= indentlevel ):
+ parentstack.pop()
+
+ parentstack[-1][0].addChild(tocnode)
+
+ prevnode = tocnode
+ previndent = indentlevel
+ return out.AsTree()
diff --git a/build-tools/drtool/TOCNode.py b/build-tools/drtool/TOCNode.py
new file mode 100644
index 0000000..891c83b
--- /dev/null
+++ b/build-tools/drtool/TOCNode.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may 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.
+#
+
+"""Routines and a class for describing and manipulating data from a
+TableOfContents wiki page.
+"""
+
+nodes = {}
+def lookup(wikiWord):
+ if nodes.has_key(wikiWord):
+ return nodes[wikiWord]
+ else:
+ return None
+
+class TOCNode:
+ def __init__(self, caption, wikiWord=None):
+ self.caption = caption
+ self.wikiWord = wikiWord
+ self.children = []
+
+ if(wikiWord):
+ nodes[wikiWord] = self
+
+ def addChild(self, child):
+ self.children.append(child)
+
+ def AsTree(self):
+ out = {"caption":self.caption, "wikiword":self.wikiWord}
+
+ if(not self.children):
+ out["children"] = None
+ else:
+ out["children"] = map(TOCNode.AsTree, self.children)
+
+ return out
+
+ def __repr__(self):
+ return str(self)
+
+ def __str__(self):
+ return "(((%s)))" % self.caption
diff --git a/build-tools/drtool/drtool.py b/build-tools/drtool/drtool.py
new file mode 100755
index 0000000..7feb72e
--- /dev/null
+++ b/build-tools/drtool/drtool.py
@@ -0,0 +1,270 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+"""drtool is for moving your wiki documents between googlecode projects.
+
+drtool actually does three things:
+ - copy all of your wiki documentation between googlecode projects. This is
+ done via the "copy" command. References to a project will be changed during
+ the move.
+
+ - tell you what wiki pages are not referenced by your docreader-enabled
+ TableOfContents page. Use "nothave" or "orphans" or "list-orphans" for
+ this.
+
+ - find all of the http references to your subversion repository in your wiki
+ docs. "references" or "refs".
+
+It's assumed that you have svn checkouts of both projects.
+"""
+
+import sys
+import shutil
+import re
+import os.path
+import glob
+import TOCNode
+from BuildGlobalTOC import BuildTOC
+
+NOTHAVE = ["nothave", "orphans", "list-orphans"]
+REFERENCES = ["references", "refs"]
+COPY = ["copy"]
+
+wikipatterns = {}
+svnpatterns = {}
+
+def getpattern(table, template, projectname):
+ if table.has_key(projectname):
+ return table[projectname]
+ else:
+ pattern = (template % projectname)
+ compiled = re.compile(pattern)
+ table[projectname] = compiled
+ return compiled
+
+def wikipattern(projectname):
+ return getpattern(wikipatterns,
+ "http://code.google.com/p/(%s)/wiki/([^\s\]]+)",
+ projectname)
+
+def svnpattern(projectname):
+ return getpattern(svnpatterns,
+ "http://(%s).googlecode.com([^\s\]]+)",
+ projectname)
+
+def change_ref(link, oldproject, newproject):
+ return link.replace(oldproject, newproject)
+
+def change_references(bytes, oldprojectname, newprojectname):
+ """Returns the string that is the new text for the wiki page, with all
+ of the references changed to point to the new project."""
+
+ svn = svnpattern(oldprojectname)
+ wiki = wikipattern(oldprojectname)
+
+ postsvn = ""
+ postwiki = ""
+ ## step one, do all the svn references.
+ svnreferences = re.finditer(svn, bytes)
+ append_start = 0
+
+ for match in svnreferences:
+ matchstart, matchend = match.span()
+
+ ## take all of the stuff from the end of the last match to the beginning
+ ## of this one and append it to the output.
+ postsvn += bytes[append_start:matchstart]
+
+ ## append the version of this match with the project names replaced
+ postsvn += change_ref(match.group(0), oldprojectname, newprojectname)
+ append_start = matchend
+ postsvn += bytes[append_start:]
+
+ ## step two, do all the wiki references (should be rarer?)
+ wikireferences = re.finditer(wiki, postsvn)
+ append_start = 0
+
+ for match in wikireferences:
+ matchstart, matchend = match.span()
+
+ ## take all of the stuff from the end of the last match to the beginning
+ ## of this one and append it to the output.
+ postwiki += postsvn[append_start:matchstart]
+
+ ## append the version of this match with the project names replaced
+ postwiki += change_ref(match.group(0),
+ oldprojectname,
+ newprojectname)
+ append_start = matchend
+ postwiki += postsvn[append_start:]
+
+ return postwiki
+
+def find_references(bytes, projectname, fn):
+ """Return a list of all the references to a given project in this string"""
+ def find_refs(pattern):
+ compiled = re.compile(pattern)
+ refs = re.findall(compiled, bytes)
+ return refs
+
+ svn = svnpattern(projectname)
+ wiki = wikipattern(projectname)
+
+ return find_refs(svn) + find_refs(wiki)
+
+def print_references(bytes, projectname, fn):
+ refs = find_references(bytes, projectname, fn)
+ if refs:
+ print ("** %s" % fn)
+ for ref in refs:
+ print ":::", ref
+
+def usage():
+ commands = (", ").join(NOTHAVE + REFERENCES + COPY)
+ print ("usage: %s <cmd> prj1 [prj2]" % sys.argv[0])
+ print "\tcmd is one of: ", commands
+ print "\tprj2 is required for 'copy' command"
+
+def copy_into_target(source_project, target_project, source_path,
+ relative_filename, target_dir):
+ """Copy one file into the target directory."""
+ target_path = os.path.join(target_dir, relative_filename)
+
+ if relative_filename.endswith(".wiki"):
+ infile = open(source_path)
+ bytes = infile.read()
+ changed = change_references(bytes, source_project, target_project)
+
+ head,tail = os.path.split(target_path)
+ if not os.path.isdir(head):
+ os.makedirs(head)
+
+ outfile = open(target_path, "w")
+ outfile.write(changed)
+ outfile.close()
+
+ # print ("%s: changed references, wrote into %s." %
+ # (relative_filename, target_project) )
+ else:
+ shutil.copyfile(source_path, target_path)
+ # print ("%s: not a wiki file, copied into the new %s" %
+ # (relative_filename, target_project))
+
+ pass
+
+def find_wikipath(target):
+ normalized = os.path.normpath(target)
+
+ if not normalized.endswith("/wiki"):
+ normalized += "/wiki"
+ return normalized
+
+def all_wiki_docs(wikipath):
+ """All of the .wiki files in our wiki directory, with paths, recursively."""
+ out = []
+ for root, dirs, fileshere in os.walk(wikipath):
+ path_elements = root.split(os.sep)
+ if ".svn" in path_elements:
+ continue
+
+ for fn in fileshere:
+ if fn.endswith(".wiki"):
+ whole_pathname = os.path.join(root, fn)
+ out.append(whole_pathname)
+ return out
+
+def nothave(wikipath, projectname):
+ toc_path = wikipath + os.path.sep + "TableOfContents.wiki"
+ if not os.path.exists(toc_path):
+ print "Could not find TableOfContents.wiki for that project."
+ return
+
+ listed = BuildTOC(toc_path, projectname)
+ all_wiki_pages = all_wiki_docs(wikipath)
+
+ ## run through every .wiki file (recursively under the wiki directory, and if
+ ## it's not mentioned in the TOC, print it out.
+
+ for wikipage in all_wiki_pages:
+ basename = os.path.basename(wikipage)
+ wikiword = basename[:-5]
+ node = TOCNode.lookup(wikiword)
+
+ if not node:
+ print " ", wikipage
+
+def file_references(fn, projectname):
+ infile = open(fn)
+ bytes = infile.read()
+ print_references(bytes, projectname, fn)
+
+def references(wikipath, projectname):
+ wikipaths = all_wiki_docs(wikipath)
+
+ for wikipath in wikipaths:
+ file_references(wikipath, projectname)
+
+def wikicopy(source_dir, source_project, target_dir, target_project):
+ print "Copying from", source_project,
+ print "to", target_project, "and changing references...",
+
+ ## Walk every file in source_dir. Skip .svn directories.
+ for root, dirs, fileshere in os.walk(source_dir):
+ path_elements = root.split(os.sep)
+ if ".svn" in path_elements:
+ continue
+
+ for filename in fileshere:
+ ## Find the part of the path after source_dir
+ whole_pathname = os.path.join(root, filename)
+ after_source_dir = whole_pathname[len(source_dir):]
+ if after_source_dir.startswith("/"):
+ after_source_dir = after_source_dir[1:]
+
+ copy_into_target(source_project, target_project, whole_pathname,
+ after_source_dir, target_dir)
+
+ print "OK!"
+ ## Warn about wiki pages that are not referenced by TOC.
+ print "Careful: these wiki pages aren't referenced in your TableOfContents:"
+ nothave(source_dir, source_project)
+ print "Done."
+
+def main(argv):
+ if len(argv) < 3:
+ usage()
+ return
+
+ source_dir = find_wikipath(argv[2])
+ source_projectname = source_dir.split(os.path.sep)[-2]
+
+ if len(argv) > 3:
+ target_dir = find_wikipath(argv[3])
+ target_projectname = target_dir.split(os.path.sep)[-2]
+
+ if argv[1] in NOTHAVE:
+ nothave(source_dir, source_projectname)
+ elif argv[1] in REFERENCES:
+ references(source_dir, source_projectname)
+ elif argv[1] in COPY:
+ if not target_dir:
+ usage()
+ return
+ wikicopy(source_dir, source_projectname, target_dir, target_projectname)
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/build.xml b/build.xml
index b42149b..15ea822 100755
--- a/build.xml
+++ b/build.xml
@@ -11,6 +11,10 @@
<property name="gwt.apicheck.oldroot"
value="../gwt-1.5"/>
+ <target name="buildonly" depends="dev, user, servlet, jni" description="Build without docs/samples">
+ <gwt.ant dir="distro-source" />
+ </target>
+
<target name="dist" depends="dev, user, servlet, tools, jni, doc, samples" description="Run the distributions">
<gwt.ant dir="distro-source" />
</target>
diff --git a/common.ant.xml b/common.ant.xml
index 1bbd0e1..2e2c78a 100755
--- a/common.ant.xml
+++ b/common.ant.xml
@@ -37,6 +37,7 @@
<property name="gwt.build.jni" location="${gwt.build}/jni" />
<property name="gwt.build.staging" location="${gwt.build}/staging" />
<property name="gwt.build.dist" location="${gwt.build}/dist" />
+ <property name="gwt.threadsPerProcessor" value="1" />
<property name="project.build" location="${gwt.build.out}/${project.tail}" />
<property name="project.lib" location="${gwt.build.lib}/gwt-${ant.project.name}.jar" />
<property name="project.jni" location="${gwt.build}/${project.tail}" />
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/AbstractLinker.java b/dev/core/src/com/google/gwt/core/ext/linker/AbstractLinker.java
index 9f009e4..06b9549 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/AbstractLinker.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/AbstractLinker.java
@@ -36,10 +36,9 @@
* @return an artifact that contains the given data
* @throws UnableToCompleteException
*/
- @SuppressWarnings("unused")
protected final SyntheticArtifact emitBytes(TreeLogger logger, byte[] what,
String partialPath) throws UnableToCompleteException {
- return new SyntheticArtifact(getClass(), partialPath, what);
+ return new SyntheticArtifact(logger, getClass(), partialPath, what);
}
/**
@@ -52,10 +51,9 @@
* @param lastModified the last modified time of the new artifact
* @throws UnableToCompleteException
*/
- @SuppressWarnings("unused")
protected final SyntheticArtifact emitBytes(TreeLogger logger, byte[] what,
String partialPath, long lastModified) throws UnableToCompleteException {
- return new SyntheticArtifact(getClass(), partialPath, what, lastModified);
+ return new SyntheticArtifact(logger, getClass(), partialPath, what, lastModified);
}
/**
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/CompilationAnalysis.java b/dev/core/src/com/google/gwt/core/ext/linker/CompilationAnalysis.java
new file mode 100644
index 0000000..fc7b985
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/linker/CompilationAnalysis.java
@@ -0,0 +1,114 @@
+/*
+ * 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.core.ext.linker;
+
+import com.google.gwt.core.ext.Linker;
+import com.google.gwt.core.ext.soyc.ClassMember;
+import com.google.gwt.core.ext.soyc.FunctionMember;
+import com.google.gwt.core.ext.soyc.Range;
+import com.google.gwt.core.ext.soyc.Story;
+
+import java.util.Map;
+import java.util.SortedSet;
+
+/**
+ * Represents analysis data for a CompilationResult.
+ */
+public abstract class CompilationAnalysis extends Artifact<CompilationAnalysis> {
+
+ /**
+ * Associates a Story and a Range of the output. Instances of this interface
+ * are obtained from {@link CompilationAnalysis#getSnippets()}.
+ */
+ public interface Snippet {
+ Range getRange();
+
+ Story getStory();
+ }
+
+ protected CompilationAnalysis(Class<? extends Linker> linkerType) {
+ super(linkerType);
+ }
+
+ /**
+ * Returns all ClassMembers present in the CompilationResult. This method
+ * would typically be used by consumers that are interested in the type
+ * hierarchy of the compilation.
+ */
+ public abstract SortedSet<ClassMember> getClasses();
+
+ /**
+ * Returns the CompilationResult upon which the analysis was performed.
+ */
+ public abstract CompilationResult getCompilationResult();
+
+ /**
+ * Returns all JavaScript FunctionMembers in the output.
+ */
+ public abstract SortedSet<FunctionMember> getFunctions();
+
+ /**
+ * Provides access to the assignments of Stories to Ranges for a fragment of
+ * the output. The Ranges are guaranteed not to overlap, and may be used for
+ * exact accounting of bytes. Due to the potential for very large data-sets to
+ * be accessible through this method, it is recommended that Snippets should
+ * be processed in an incremental fashion that does not require all instances
+ * to be retained at once.
+ */
+ /*
+ * NB: The reason that this returns an Iterable, and not a Map, is that we
+ * want to delay the construction of Range objects for as long as possible. If
+ * we were to return a Map for an analysis of N stories, we would also need N
+ * Ranges, plus the overhead of constructing an ordered Map.
+ */
+ public abstract Iterable<Snippet> getSnippets(int fragmentNumber);
+
+ /**
+ * Returns splitPointMap.
+ */
+ public abstract Map<Integer, String> getSplitPointMap();
+
+ /**
+ * Returns all Stories.
+ */
+ public abstract SortedSet<Story> getStories();
+
+ @Override
+ public final int hashCode() {
+ // NB: Identity is keyed to the CompilationResult
+ return getCompilationResult().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Compilation analysis for " + getCompilationResult().toString();
+ }
+
+ @Override
+ protected final int compareToComparableArtifact(CompilationAnalysis o) {
+ /*
+ * The identity of a CompilationAnalysis is based on the identity of its
+ * associated CompilationResult.
+ */
+ return getCompilationResult().compareToComparableArtifact(
+ o.getCompilationResult());
+ }
+
+ @Override
+ protected final Class<CompilationAnalysis> getComparableArtifactType() {
+ return CompilationAnalysis.class;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/CompilationResult.java b/dev/core/src/com/google/gwt/core/ext/linker/CompilationResult.java
index 9760804..e194f59 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/CompilationResult.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/CompilationResult.java
@@ -26,16 +26,20 @@
* result in identical JavaScript.
*/
public abstract class CompilationResult extends Artifact<CompilationResult> {
-
protected CompilationResult(Class<? extends Linker> linkerType) {
super(linkerType);
}
/**
- * Returns the JavaScript compilation. The exact form and function of the
- * JavaScript should be considered opaque.
+ * Returns the JavaScript compilation. The first element of the array contains
+ * the code that should be run when the application starts up. The remaining
+ * elements are loaded via
+ * {@link com.google.gwt.core.client.GWT#runAsync(com.google.gwt.core.client.RunAsyncCallback)
+ * GWT.runAsync}. See {@link com.google.gwt.core.client.AsyncFragmentLoader
+ * AsyncFragmentLoader} for details on the necessary linker support for
+ * runAsync.
*/
- public abstract String getJavaScript();
+ public abstract String[] getJavaScript();
/**
* Provides values for {@link SelectionProperty} instances that are not
@@ -45,9 +49,27 @@
*/
public abstract SortedSet<SortedMap<SelectionProperty, String>> getPropertyMap();
+ /**
+ * Return a string that uniquely identifies this compilation result. Typically
+ * this is a cryptographic hash of the compiled data.
+ */
+ public abstract String getStrongName();
+
+ /**
+ * Returns a map of obfuscated symbol names in the compilation to JSNI-style
+ * identifiers. This data can allow for on-the-fly deobfuscation of stack
+ * trace information or to allow server components to have in-depth knowledge
+ * of the runtime structure of compiled objects.
+ */
+ public abstract SortedMap<String, String> getSymbolMap();
+
@Override
public final int hashCode() {
- return getJavaScript().hashCode();
+ int hash = 17;
+ for (String js : getJavaScript()) {
+ hash = hash * 37 + js.hashCode();
+ }
+ return hash;
}
@Override
@@ -69,11 +91,11 @@
@Override
protected final int compareToComparableArtifact(CompilationResult o) {
- return getJavaScript().compareTo(o.getJavaScript());
+ return getStrongName().compareTo(o.getStrongName());
}
@Override
protected final Class<CompilationResult> getComparableArtifactType() {
return CompilationResult.class;
}
-}
\ No newline at end of file
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/SyntheticArtifact.java b/dev/core/src/com/google/gwt/core/ext/linker/SyntheticArtifact.java
index d9283d0..f46c7c2 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/SyntheticArtifact.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/SyntheticArtifact.java
@@ -18,34 +18,52 @@
import com.google.gwt.core.ext.Linker;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.util.Util;
-import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.io.InputStream;
/**
* Artifacts created by {@link AbstractLinker}.
*/
public class SyntheticArtifact extends EmittedArtifact {
- private final byte[] data;
+ private final File backing;
private final long lastModified;
- SyntheticArtifact(Class<? extends Linker> linkerType, String partialPath,
- byte[] data) {
- this(linkerType, partialPath, data, System.currentTimeMillis());
+ SyntheticArtifact(TreeLogger logger, Class<? extends Linker> linkerType,
+ String partialPath, byte[] data) throws UnableToCompleteException {
+ this(logger, linkerType, partialPath, data, System.currentTimeMillis());
}
- SyntheticArtifact(Class<? extends Linker> linkerType, String partialPath,
- byte[] data, long lastModified) {
+ SyntheticArtifact(TreeLogger logger, Class<? extends Linker> linkerType, String partialPath,
+ byte[] data, long lastModified) throws UnableToCompleteException {
super(linkerType, partialPath);
assert data != null;
- this.data = data;
+
+ try {
+ backing = File.createTempFile("synthetic", ".artifact");
+ backing.deleteOnExit();
+ Util.writeBytesToFile(TreeLogger.NULL, backing, data);
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to write backing file for artifact "
+ + partialPath, e);
+ throw new UnableToCompleteException();
+ }
this.lastModified = lastModified;
}
@Override
public InputStream getContents(TreeLogger logger)
throws UnableToCompleteException {
- return new ByteArrayInputStream(data);
+ try {
+ return new FileInputStream(backing);
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to read backing file for artifact "
+ + getPartialPath(), e);
+ throw new UnableToCompleteException();
+ }
}
@Override
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeLinker.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeLinker.java
index ea3cf05..d3e8f22 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeLinker.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeLinker.java
@@ -44,6 +44,7 @@
return super.generateSelectionScript(logger, context, artifacts);
}
+ @Override
public String getDescription() {
return "Hosted Mode";
}
@@ -61,8 +62,8 @@
}
@Override
- protected String getModulePrefix(TreeLogger logger, LinkerContext context)
- throws UnableToCompleteException {
+ protected String getModulePrefix(TreeLogger logger, LinkerContext context,
+ String strongName) throws UnableToCompleteException {
return unsupported(logger);
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeTemplate.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeTemplate.js
index 07d00a9..488a56b 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeTemplate.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeTemplate.js
@@ -70,8 +70,10 @@
function isHostedMode() {
try {
- return ($wnd.external && $wnd.external.gwtOnLoad &&
- ($wnd.location.search.indexOf('gwt.hybrid') == -1));
+ var query = $wnd.location.search;
+ return (query.indexOf('gwt.hosted=') != -1
+ || ($wnd.external && $wnd.external.gwtOnLoad)) &&
+ (query.indexOf('gwt.hybrid') == -1);
} catch (e) {
// Defensive: some versions of IE7 reportedly can throw an exception
// evaluating "external.gwtOnLoad".
@@ -389,7 +391,7 @@
if (isHostedMode()) {
strongName = "hosted.html?__MODULE_FUNC__";
// Hang an expando for hosted.html to be able to grab the module name early.
- __MODULE_FUNC__.moduleName = '__MODULE_NAME__';
+ __MODULE_FUNC__.moduleName = '__MODULE_NAME__';
} else {
try {
// __PERMUTATIONS_BEGIN__
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java
index 648ba05..6485c5d 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java
@@ -28,9 +28,12 @@
import com.google.gwt.dev.util.Util;
import com.google.gwt.util.tools.Utility;
+import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
@@ -38,7 +41,7 @@
/**
* A base class for Linkers that use an external script to boostrap the GWT
- * module. This implementation injects JavaScript snippits into a JS program
+ * module. This implementation injects JavaScript Snippets into a JS program
* defined in an external file.
*/
public abstract class SelectionScriptLinker extends AbstractLinker {
@@ -48,11 +51,20 @@
*/
/**
+ * The extension added to demand-loaded fragment files.
+ */
+ protected static final String FRAGMENT_EXTENSION = ".cache.js";
+
+ /**
+ * A subdirectory to hold all the generated fragments.
+ */
+ protected static final String FRAGMENT_SUBDIR = "deferredjs";
+
+ /**
* Determines whether or not the URL is relative.
*
* @param src the test url
- * @return <code>true</code> if the URL is relative, <code>false</code> if
- * not
+ * @return <code>true</code> if the URL is relative, <code>false</code> if not
*/
@SuppressWarnings("unused")
protected static boolean isRelativeURL(String src) {
@@ -84,7 +96,7 @@
}
}
- private final Map<CompilationResult, String> compilationPartialPaths = new IdentityHashMap<CompilationResult, String>();
+ private final Map<CompilationResult, String> compilationStrongNames = new IdentityHashMap<CompilationResult, String>();
@Override
public ArtifactSet link(TreeLogger logger, LinkerContext context,
@@ -92,24 +104,34 @@
ArtifactSet toReturn = new ArtifactSet(artifacts);
for (CompilationResult compilation : toReturn.find(CompilationResult.class)) {
- toReturn.add(doEmitCompilation(logger, context, compilation));
+ toReturn.addAll(doEmitCompilation(logger, context, compilation));
}
toReturn.add(emitSelectionScript(logger, context, artifacts));
return toReturn;
}
- protected EmittedArtifact doEmitCompilation(TreeLogger logger,
+ protected Collection<EmittedArtifact> doEmitCompilation(TreeLogger logger,
LinkerContext context, CompilationResult result)
throws UnableToCompleteException {
- StringBuffer b = new StringBuffer();
- b.append(getModulePrefix(logger, context));
- b.append(result.getJavaScript());
- b.append(getModuleSuffix(logger, context));
- EmittedArtifact toReturn = emitWithStrongName(logger,
- Util.getBytes(b.toString()), "", getCompilationExtension(logger,
- context));
- compilationPartialPaths.put(result, toReturn.getPartialPath());
+ String[] js = result.getJavaScript();
+ byte[][] bytes = new byte[js.length][];
+ bytes[0] = generatePrimaryFragment(logger, context, js[0],
+ result.getStrongName(), js.length);
+ for (int i = 1; i < js.length; i++) {
+ bytes[i] = Util.getBytes(js[i]);
+ }
+
+ Collection<EmittedArtifact> toReturn = new ArrayList<EmittedArtifact>();
+ toReturn.add(emitBytes(logger, bytes[0], result.getStrongName()
+ + getCompilationExtension(logger, context)));
+ for (int i = 1; i < js.length; i++) {
+ toReturn.add(emitBytes(logger, bytes[i], FRAGMENT_SUBDIR + File.separator
+ + result.getStrongName() + File.separator + i + FRAGMENT_EXTENSION));
+ }
+
+ compilationStrongNames.put(result, result.getStrongName());
+
return toReturn;
}
@@ -247,9 +269,8 @@
// Just one distinct compilation; no need to evaluate properties
Iterator<CompilationResult> iter = compilations.iterator();
CompilationResult result = iter.next();
- text.append("strongName = '" + compilationPartialPaths.get(result)
+ text.append("strongName = '" + compilationStrongNames.get(result)
+ "';");
-
} else {
for (CompilationResult r : compilations) {
for (Map<SelectionProperty, String> propertyMap : r.getPropertyMap()) {
@@ -268,7 +289,7 @@
}
text.append("'" + propertyMap.get(p) + "'");
}
- text.append("], '").append(compilationPartialPaths.get(r)).append(
+ text.append("], '").append(compilationStrongNames.get(r)).append(
"');\n");
}
}
@@ -296,7 +317,7 @@
}
/**
- * Generate a snippit of JavaScript to inject an external stylesheet.
+ * Generate a Snippet of JavaScript to inject an external stylesheet.
*
* <pre>
* if (!__gwt_stylesLoaded['URL']) {
@@ -329,19 +350,48 @@
/**
* Get the partial path on which a CompilationResult has been emitted.
*
- * @return the partial path, or <code>null</code> if the CompilationResult
- * has not been emitted.
+ * @return the partial path, or <code>null</code> if the CompilationResult has
+ * not been emitted.
*/
- protected String getCompilationPartialPath(CompilationResult result) {
- return compilationPartialPaths.get(result);
+ protected String getCompilationStrongName(CompilationResult result) {
+ return compilationStrongNames.get(result);
}
+ /**
+ * Compute the beginning of a JavaScript file that will hold the main module
+ * implementation.
+ */
protected abstract String getModulePrefix(TreeLogger logger,
- LinkerContext context) throws UnableToCompleteException;
+ LinkerContext context, String strongName)
+ throws UnableToCompleteException;
+
+ /**
+ * Compute the beginning of a JavaScript file that will hold the main module
+ * implementation. By default, calls
+ * {@link #getModulePrefix(TreeLogger, LinkerContext, String)}.
+ *
+ * @param strongName strong name of the module being emitted
+ * @param numFragments the number of fragments for this module, including the
+ * main fragment (fragment 0)
+ */
+ protected String getModulePrefix(TreeLogger logger, LinkerContext context,
+ String strongName, int numFragments) throws UnableToCompleteException {
+ return getModulePrefix(logger, context, strongName);
+ }
protected abstract String getModuleSuffix(TreeLogger logger,
LinkerContext context) throws UnableToCompleteException;
protected abstract String getSelectionScriptTemplate(TreeLogger logger,
LinkerContext context) throws UnableToCompleteException;
+
+ private byte[] generatePrimaryFragment(TreeLogger logger,
+ LinkerContext context, String js, String strongName, int numFragments)
+ throws UnableToCompleteException {
+ StringBuffer b = new StringBuffer();
+ b.append(getModulePrefix(logger, context, strongName, numFragments));
+ b.append(js);
+ b.append(getModuleSuffix(logger, context));
+ return Util.getBytes(b.toString());
+ }
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationAnalysis.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationAnalysis.java
new file mode 100644
index 0000000..522094a
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationAnalysis.java
@@ -0,0 +1,434 @@
+/*
+ * 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.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.CompilationAnalysis;
+import com.google.gwt.core.ext.linker.CompilationResult;
+import com.google.gwt.core.ext.soyc.ClassMember;
+import com.google.gwt.core.ext.soyc.FunctionMember;
+import com.google.gwt.core.ext.soyc.Member;
+import com.google.gwt.core.ext.soyc.Range;
+import com.google.gwt.core.ext.soyc.Story;
+import com.google.gwt.core.ext.soyc.Story.Origin;
+import com.google.gwt.core.ext.soyc.impl.AbstractMemberWithDependencies;
+import com.google.gwt.core.ext.soyc.impl.MemberFactory;
+import com.google.gwt.core.ext.soyc.impl.OriginImpl;
+import com.google.gwt.core.ext.soyc.impl.SnippetIterator;
+import com.google.gwt.core.ext.soyc.impl.StandardClassMember;
+import com.google.gwt.core.ext.soyc.impl.StandardFieldMember;
+import com.google.gwt.core.ext.soyc.impl.StandardFunctionMember;
+import com.google.gwt.core.ext.soyc.impl.StandardMethodMember;
+import com.google.gwt.core.ext.soyc.impl.StoryImpl;
+import com.google.gwt.dev.jjs.Correlation;
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.Correlation.Axis;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.js.ast.JsFunction;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.Stack;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * An implementation of CompilationAnalysis. This class transforms SourceInfos
+ * and related data into an API suitable for public consumption via the Linker
+ * API.
+ */
+public class StandardCompilationAnalysis extends CompilationAnalysis {
+ /**
+ * A roll-up struct for all the data produced by the analysis to make
+ * serialization simpler.
+ */
+ private static class Data implements Serializable {
+ SortedSet<ClassMember> classes;
+ SortedSet<FunctionMember> functions;
+
+ /**
+ * These are the Stories in the order in which they should be presented to
+ * the user via {@link CompilationAnalysis#getSnippets()}.
+ */
+ Map<Integer, List<StoryImpl>> orderedStories = new HashMap<Integer, List<StoryImpl>>();
+
+ SortedSet<Story> stories;
+ }
+
+ /**
+ * Associates a SourceInfo with a Range.
+ */
+ private static class RangeInfo {
+ public final SourceInfo info;
+ public final Range range;
+
+ public RangeInfo(Range range, SourceInfo info) {
+ this.range = range;
+ this.info = info;
+ }
+ }
+
+ private Data data;
+
+ /**
+ * Used by {@link #popAndRecord(Stack)} to determine start and end ranges.
+ */
+ private int lastEnd = 0;
+
+ private CompilationResult result;
+
+ /**
+ * This is a class field for convenience, but it should be deleted at the end
+ * of the constructor.
+ */
+ private transient Map<SourceInfo, StoryImpl> storyCache = new IdentityHashMap<SourceInfo, StoryImpl>();
+
+ /**
+ * This is a class field for convenience, but it should be deleted at the end
+ * of the constructor.
+ */
+ private transient Map<Correlation, Member> membersByCorrelation = new IdentityHashMap<Correlation, Member>();
+
+ /**
+ * Map from split point numbers to the method where they were set.
+ */
+ private Map<Integer, String> splitPointMap = new TreeMap<Integer, String>();
+
+ /**
+ * Constructed by PermutationCompiler.
+ */
+ public StandardCompilationAnalysis(TreeLogger logger,
+ List<Map<Range, SourceInfo>> sourceInfoMaps,
+ Map<Integer, String> splitPointMap)
+ throws UnableToCompleteException {
+ super(StandardLinkerContext.class);
+ logger = logger.branch(TreeLogger.INFO,
+ "Creating CompilationAnalysis (this may take some time)");
+
+ data = new Data();
+
+ this.splitPointMap = splitPointMap;
+
+ /*
+ * Don't retain beyond the constructor to avoid lingering references to AST
+ * nodes.
+ */
+ MemberFactory memberFactory = new MemberFactory();
+
+ // Record what we've seen so far
+ TreeSet<ClassMember> classesMutable = new TreeSet<ClassMember>(
+ Member.SOURCE_NAME_COMPARATOR);
+ TreeSet<FunctionMember> functionsMutable = new TreeSet<FunctionMember>(
+ Member.SOURCE_NAME_COMPARATOR);
+ Set<SourceInfo> sourceInfoSeen = new HashSet<SourceInfo>();
+
+ int fragment = 0;
+ for (Map<Range, SourceInfo> sourceInfoMap : sourceInfoMaps) {
+ lastEnd = 0;
+ analyzeFragment(memberFactory, classesMutable, functionsMutable,
+ sourceInfoMap, sourceInfoSeen, fragment++);
+ }
+
+ data.classes = Collections.unmodifiableSortedSet(classesMutable);
+ data.functions = Collections.unmodifiableSortedSet(functionsMutable);
+
+ // Deduplicate the ordered stories into an ordered set
+ SortedSet<Story> mutableStories = new TreeSet<Story>(
+ StoryImpl.ID_COMPARATOR);
+ for (List<StoryImpl> stories : data.orderedStories.values()) {
+ mutableStories.addAll(stories);
+ }
+ data.stories = Collections.unmodifiableSortedSet(mutableStories);
+
+ /*
+ * Clear the member fields that we don't need anymore to allow GC of the
+ * SourceInfo objects
+ */
+ membersByCorrelation = null;
+ storyCache = null;
+
+ logger.log(TreeLogger.INFO, "Done");
+ }
+
+ @Override
+ public SortedSet<ClassMember> getClasses() {
+ return data.classes;
+ }
+
+ @Override
+ public CompilationResult getCompilationResult() {
+ return result;
+ }
+
+ @Override
+ public SortedSet<FunctionMember> getFunctions() {
+ return data.functions;
+ }
+
+ @Override
+ public Iterable<Snippet> getSnippets(int fragment) {
+ final List<StoryImpl> stories = data.orderedStories.get(fragment);
+ if (stories == null) {
+ throw new IllegalArgumentException("Unknown fragment id " + fragment);
+ }
+
+ return new Iterable<Snippet>() {
+ public Iterator<Snippet> iterator() {
+ return new SnippetIterator(stories);
+ }
+ };
+ }
+
+ @Override
+ public Map<Integer, String> getSplitPointMap() {
+ return splitPointMap;
+ }
+
+ @Override
+ public SortedSet<Story> getStories() {
+ return data.stories;
+ }
+
+ /**
+ * Back-channel setter used by PermutationCompiler.
+ */
+ public void setCompilationResult(CompilationResult result) {
+ this.result = result;
+ }
+
+ private void analyzeFragment(MemberFactory memberFactory,
+ TreeSet<ClassMember> classesMutable,
+ TreeSet<FunctionMember> functionsMutable,
+ Map<Range, SourceInfo> sourceInfoMap, Set<SourceInfo> sourceInfoSeen,
+ int fragment) {
+ /*
+ * We want to iterate over the Ranges so that enclosing Ranges come before
+ * their enclosed Ranges...
+ */
+ Range[] dependencyOrder = sourceInfoMap.keySet().toArray(
+ new Range[sourceInfoMap.size()]);
+ Arrays.sort(dependencyOrder, Range.DEPENDENCY_ORDER_COMPARATOR);
+
+ Stack<RangeInfo> dependencyScope = new Stack<RangeInfo>();
+ for (Range range : dependencyOrder) {
+ SourceInfo info = sourceInfoMap.get(range);
+ assert info != null;
+
+ // Infer dependency information
+ if (!dependencyScope.isEmpty()) {
+
+ /*
+ * Pop frames until we get back to a container, using this as a chance
+ * to build up our list of non-overlapping Ranges to report back to the
+ * user.
+ */
+ while (!dependencyScope.peek().range.contains(range)) {
+ popAndRecord(dependencyScope, fragment);
+ }
+ }
+
+ // Possibly create and record Members
+ if (!sourceInfoSeen.contains(info)) {
+ sourceInfoSeen.add(info);
+ for (Correlation c : info.getPrimaryCorrelations()) {
+ if (membersByCorrelation.containsKey(c)) {
+ continue;
+ }
+
+ switch (c.getAxis()) {
+ case CLASS: {
+ JReferenceType type = c.getType();
+ StandardClassMember member = memberFactory.get(type);
+ membersByCorrelation.put(c, member);
+ classesMutable.add(member);
+ break;
+ }
+ case FIELD: {
+ JField field = c.getField();
+ JReferenceType type = c.getType();
+ StandardFieldMember member = memberFactory.get(field);
+ memberFactory.get(type).addField(member);
+ membersByCorrelation.put(c, member);
+ break;
+ }
+ case FUNCTION: {
+ JsFunction function = c.getFunction();
+ StandardFunctionMember member = memberFactory.get(function);
+ membersByCorrelation.put(c, member);
+ functionsMutable.add(member);
+ break;
+ }
+ case METHOD: {
+ JMethod method = c.getMethod();
+ JReferenceType type = c.getType();
+ StandardMethodMember member = memberFactory.get(method);
+ memberFactory.get(type).addMethod(member);
+ membersByCorrelation.put(c, member);
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * Record dependencies as observed in the structure of the JS output. This
+ * an an ad-hoc approach that just looks at which SourceInfos are used
+ * within the Range of another SourceInfo.
+ */
+ Set<Correlation> correlationsInScope = new HashSet<Correlation>();
+ for (RangeInfo outer : dependencyScope) {
+ SourceInfo outerInfo = outer.info;
+ correlationsInScope.addAll(outerInfo.getPrimaryCorrelations());
+
+ for (Correlation outerCorrelation : outerInfo.getPrimaryCorrelations()) {
+ Member outerMember = membersByCorrelation.get(outerCorrelation);
+
+ if (outerMember instanceof AbstractMemberWithDependencies) {
+ for (Correlation innerCorrelation : info.getAllCorrelations()) {
+ /*
+ * This check prevents an inlined method from depending on the
+ * method or function into which is was inlined.
+ */
+ if (correlationsInScope.contains(innerCorrelation)) {
+ continue;
+ }
+
+ Member innerMember = membersByCorrelation.get(innerCorrelation);
+
+ /*
+ * The null check is because we may not create Members for all
+ * types of Correlations.
+ */
+ if (innerMember != null) {
+ if (((AbstractMemberWithDependencies) outerMember).addDependency(innerMember)) {
+ // System.out.println(outerMember + " -> " + innerMember);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ dependencyScope.push(new RangeInfo(range, info));
+ }
+
+ // Unwind the rest of the stack to finish out the ranges
+ while (!dependencyScope.isEmpty()) {
+ popAndRecord(dependencyScope, fragment);
+ }
+
+ /*
+ * Because the first Range corresponds to the SourceInfo of the whole
+ * program, we'll know that we got all of the data if the ends match up. If
+ * this assert passes, we know that we've correctly generated a sequence of
+ * non-overlapping Ranges that encompass the whole program.
+ */
+ assert dependencyOrder[0].getEnd() == lastEnd;
+ }
+
+ /**
+ * Remove an element from the RangeInfo stack and stare a new StoryImpl with
+ * the right length, possibly sub-dividing the super-enclosing Range in the
+ * process.
+ */
+ private void popAndRecord(Stack<RangeInfo> dependencyScope, int fragment) {
+ RangeInfo rangeInfo = dependencyScope.pop();
+ Range toStore = rangeInfo.range;
+
+ /*
+ * Make a new Range for the gap between the popped Range and whatever we
+ * last stored.
+ */
+ if (lastEnd < toStore.getStart()) {
+ Range newRange = new Range(lastEnd, toStore.getStart());
+ assert !dependencyScope.isEmpty();
+
+ SourceInfo gapInfo = dependencyScope.peek().info;
+ recordStory(gapInfo, fragment, newRange.length());
+ lastEnd += newRange.length();
+ }
+
+ /*
+ * Store as much of the current Range as we haven't previously stored. The
+ * Max.max() is there to take care of the tail end of Ranges that have had a
+ * sub-range previously stored.
+ */
+ if (lastEnd < toStore.getEnd()) {
+ Range newRange = new Range(Math.max(lastEnd, toStore.getStart()),
+ toStore.getEnd());
+ recordStory(rangeInfo.info, fragment, newRange.length());
+ lastEnd += newRange.length();
+ }
+ }
+
+ private void recordStory(SourceInfo info, int fragment, int length) {
+ assert storyCache != null;
+
+ StoryImpl theStory;
+ if (!storyCache.containsKey(info)) {
+
+ SortedSet<Member> members = new TreeSet<Member>(
+ Member.TYPE_AND_SOURCE_NAME_COMPARATOR);
+
+ if (info != null) {
+ for (Correlation c : info.getAllCorrelations()) {
+ Member m = membersByCorrelation.get(c);
+ if (m != null) {
+ members.add(m);
+ }
+ }
+ }
+
+ SortedSet<Origin> origins = new TreeSet<Origin>();
+ for (Correlation c : info.getAllCorrelations(Axis.ORIGIN)) {
+ origins.add(new OriginImpl(c.getOrigin()));
+ }
+
+ String literalType = null;
+ Correlation literalCorrelation = info.getPrimaryCorrelation(Axis.LITERAL);
+ if (literalCorrelation != null) {
+ literalType = literalCorrelation.getLiteral().getDescription();
+ }
+
+ theStory = new StoryImpl(storyCache.size(), members, info.getMutations(),
+ origins, literalType, fragment, length);
+ storyCache.put(info, theStory);
+ } else {
+ // Use a copy-constructed instance
+ theStory = new StoryImpl(storyCache.get(info), length);
+ }
+
+ List<StoryImpl> stories = data.orderedStories.get(fragment);
+ if (stories == null) {
+ stories = new ArrayList<StoryImpl>();
+ data.orderedStories.put(fragment, stories);
+ }
+ stories.add(theStory);
+ }
+}
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 743e8cc..62be9ce 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,12 +15,13 @@
*/
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.PermutationResult;
-import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.FileBackedObject;
-import java.io.File;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.util.Collections;
@@ -69,15 +70,20 @@
*/
public static final Comparator<SortedMap<SelectionProperty, String>> MAP_COMPARATOR = new MapComparator();
- private final File resultFile;
- private transient SoftReference<String> js;
+ private transient SoftReference<String[]> js;
+
+ private final FileBackedObject<PermutationResult> resultFile;
+
+ private transient SoftReference<SortedMap<String, String>> symbolMap;
+
private final SortedSet<SortedMap<SelectionProperty, String>> propertyValues = new TreeSet<SortedMap<SelectionProperty, String>>(
MAP_COMPARATOR);
private final String strongName;
- public StandardCompilationResult(String js, String strongName, File resultFile) {
+ public StandardCompilationResult(String[] js, String strongName,
+ FileBackedObject<PermutationResult> resultFile) {
super(StandardLinkerContext.class);
- this.js = new SoftReference<String>(js);
+ this.js = new SoftReference<String[]>(js);
this.strongName = strongName;
this.resultFile = resultFile;
}
@@ -93,36 +99,54 @@
propertyValues.add(Collections.unmodifiableSortedMap(map));
}
- public String getJavaScript() {
- String toReturn = null;
+ @Override
+ public String[] getJavaScript() {
+ String[] toReturn = null;
if (js != null) {
toReturn = js.get();
}
+
if (toReturn == null) {
- PermutationResult result;
- try {
- result = Util.readFileAsObject(resultFile, PermutationResult.class);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(
- "Unexpectedly unable to read PermutationResult '"
- + resultFile.getAbsolutePath() + "'", e);
- }
- if (result == null) {
- throw new RuntimeException(
- "Unexpectedly unable to read PermutationResult '"
- + resultFile.getAbsolutePath() + "'");
- }
+ PermutationResult result = loadPermutationResult();
toReturn = result.getJs();
- js = new SoftReference<String>(toReturn);
+ js = new SoftReference<String[]>(toReturn);
}
+
return toReturn;
}
+ @Override
public SortedSet<SortedMap<SelectionProperty, String>> getPropertyMap() {
return Collections.unmodifiableSortedSet(propertyValues);
}
+ @Override
public String getStrongName() {
return strongName;
}
+
+ @Override
+ public SortedMap<String, String> getSymbolMap() {
+ SortedMap<String, String> toReturn = null;
+ if (symbolMap != null) {
+ toReturn = symbolMap.get();
+ }
+
+ if (toReturn == null) {
+ PermutationResult result = loadPermutationResult();
+ toReturn = result.getSymbolMap();
+ symbolMap = new SoftReference<SortedMap<String, String>>(toReturn);
+ }
+
+ return toReturn;
+ }
+
+ private PermutationResult loadPermutationResult() {
+ try {
+ return resultFile.newInstance(TreeLogger.NULL);
+ } catch (UnableToCompleteException e) {
+ throw new RuntimeException(
+ "Unexpectedly unable to read PermutationResult");
+ }
+ }
}
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 df24b42..bbc8d3a 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
@@ -33,6 +33,7 @@
import com.google.gwt.dev.cfg.Script;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.JJSOptions;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.js.JsObfuscateNamer;
import com.google.gwt.dev.js.JsParser;
import com.google.gwt.dev.js.JsParserException;
@@ -50,6 +51,7 @@
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.js.ast.JsScope;
import com.google.gwt.dev.util.DefaultTextOutput;
+import com.google.gwt.dev.util.FileBackedObject;
import com.google.gwt.dev.util.Util;
import java.io.File;
@@ -78,14 +80,20 @@
private static class TopFunctionStringInterner extends JsModVisitor {
public static boolean exec(JsProgram program) {
- TopFunctionStringInterner v = new TopFunctionStringInterner();
+ TopFunctionStringInterner v = new TopFunctionStringInterner(program);
v.accept(program);
return v.didChange();
}
+ private final JsProgram program;
+
+ public TopFunctionStringInterner(JsProgram program) {
+ this.program = program;
+ }
+
@Override
public boolean visit(JsFunction x, JsContext<JsExpression> ctx) {
- didChange |= JsStringInterner.exec(x.getBody(), x.getScope());
+ didChange |= JsStringInterner.exec(program, x.getBody(), x.getScope());
return false;
}
}
@@ -258,28 +266,26 @@
* Gets or creates a CompilationResult for the given JavaScript program.
*/
public StandardCompilationResult getCompilation(TreeLogger logger,
- File resultFile) throws UnableToCompleteException {
- PermutationResult permutationResult;
- try {
- permutationResult = Util.readFileAsObject(resultFile,
- PermutationResult.class);
- } catch (ClassNotFoundException e) {
- logger.log(TreeLogger.ERROR, "Unable to instantiate PermutationResult", e);
- throw new UnableToCompleteException();
- }
-
- if (permutationResult == null) {
- logger.log(TreeLogger.ERROR, "Unable to read PermutationResult");
- throw new UnableToCompleteException();
- }
+ FileBackedObject<PermutationResult> resultFile)
+ throws UnableToCompleteException {
+ PermutationResult permutationResult = resultFile.newInstance(logger);
String strongName = Util.computeStrongName(Util.getBytes(permutationResult.getJs()));
StandardCompilationResult result = resultsByStrongName.get(strongName);
if (result == null) {
- result = new StandardCompilationResult(permutationResult.getJs(),
- strongName, resultFile);
+ result = new StandardCompilationResult(null, strongName, resultFile);
resultsByStrongName.put(result.getStrongName(), result);
artifacts.add(result);
+
+ // Add any other Permutations
+ ArtifactSet otherArtifacts = permutationResult.getArtifacts();
+ if (otherArtifacts != null) {
+ // Fixups for StandardCompilationAnalysis objects
+ for (StandardCompilationAnalysis a : otherArtifacts.find(StandardCompilationAnalysis.class)) {
+ a.setCompilationResult(result);
+ }
+ artifacts.addAll(otherArtifacts);
+ }
}
return result;
}
@@ -373,6 +379,9 @@
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);
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
index aeec95e..0f45480 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
@@ -4,37 +4,243 @@
var $doc = $wnd.document;
var $moduleName, $moduleBase
,$stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null;
+// Lightweight metrics
if ($stats) {
var moduleFuncName = location.search.substr(1);
var moduleFunc = $wnd[moduleFuncName];
var moduleName = moduleFunc ? moduleFunc.moduleName : "unknown";
$stats({moduleName:moduleName,subSystem:'startup',evtGroup:'moduleStartup',millis:(new Date()).getTime(),type:'moduleEvalStart'});
}
-</script></head>
-<body>
-<font face='arial' size='-1'>This html file is for hosted mode support.</font>
-<script><!--
-function gwtOnLoad(errFn, modName, modBase){
- $moduleName = modName;
- $moduleBase = modBase;
- if (!external.gwtOnLoad(window, modName, "1.6")) {
- if (errFn) {
- errFn(modName);
+
+var gwtOnLoad;
+var $hosted = "localhost:9997";
+var $legacyHosted = false;
+try {
+ // try/catch perhaps unnecessary, but I recall issues on IE if it isn't
+ // present
+ if (external.gwtOnLoad) {
+ $legacyHosted = true;
+ }
+} catch(e) {
+}
+if ($legacyHosted) {
+ gwtOnLoad = function(errFn, modName, modBase) {
+ $moduleName = modName;
+ $moduleBase = modBase;
+ if (!external.gwtOnLoad(window, modName, "1.6")) {
+ if (errFn) {
+ errFn(modName);
+ }
}
}
+
+ window.onunload = function() {
+ external.gwtOnLoad(window, null, "1.6");
+ };
+} else {
+ // install eval wrapper on FF to avoid EvalError problem
+ if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) {
+ var __eval = window.eval;
+ window.eval = function(s) {
+ return __eval(s);
+ }
+ }
+
+ // wrapper to call JS methods, which we need both to be able to supply a
+ // different this for method lookup and to get the exception back
+ function __gwt_jsInvoke(thisObj, methodName) {
+ try {
+ var args = Array.prototype.slice.call(arguments, 2);
+ return [0, window[methodName].apply(thisObj, args)];
+ } catch (e) {
+ return [1, e];
+ }
+ }
+
+ var __gwt_javaInvokes = [];
+ function __gwt_makeJavaInvoke(argCount) {
+ return __gwt_javaInvokes[argCount] || __gwt_doMakeJavaInvoke(argCount);
+ }
+
+ function __gwt_doMakeJavaInvoke(argCount) {
+ // IE6 won't eval() anonymous functions except as r-values
+ var argList = "";
+ for (var i = 0; i < argCount; i++) {
+ argList += ",p" + i;
+ }
+ var argListNoComma = argList.substring(1);
+
+ return eval(
+ "__gwt_javaInvokes[" + argCount + "] =\n" +
+ " function(thisObj, dispId" + argList + ") {\n" +
+ " var result = __static(dispId, thisObj" + argList + ");\n" +
+ " if (result[0]) {\n" +
+ " throw result[1];\n" +
+ " } else {\n" +
+ " return result[1];\n" +
+ " }\n" +
+ " }\n"
+ );
+ }
+
+ /*
+ * This is used to create tear-offs of Java methods. Each function corresponds
+ * to exactly one dispId, and also embeds the argument count. We get the "this"
+ * value from the context in which the function is being executed.
+ * Function-object identity is preserved by caching in a sparse array.
+ */
+ var __gwt_tearOffs = [];
+ var __gwt_tearOffGenerators = [];
+ function __gwt_makeTearOff(proxy, dispId, argCount) {
+ return __gwt_tearOffs[dispId] || __gwt_doMakeTearOff(dispId, argCount);
+ }
+
+ function __gwt_doMakeTearOff(dispId, argCount) {
+ return __gwt_tearOffs[dispId] =
+ (__gwt_tearOffGenerators[argCount] || __gwt_doMakeTearOffGenerator(argCount))(dispId);
+ }
+
+ function __gwt_doMakeTearOffGenerator(argCount) {
+ // IE6 won't eval() anonymous functions except as r-values
+ var argList = "";
+ for (var i = 0; i < argCount; i++) {
+ argList += ",p" + i;
+ }
+ var argListNoComma = argList.substring(1);
+
+ return eval(
+ "__gwt_tearOffGenerators[" + argCount + "] =\n" +
+ " function(dispId) {\n" +
+ " return function(" + argListNoComma + ") {\n" +
+ " var result = __static(dispId, this" + argList + ");\n" +
+ " if (result[0]) {\n" +
+ " throw result[1];\n" +
+ " } else {\n" +
+ " return result[1];\n" +
+ " }\n" +
+ " }\n" +
+ " }\n"
+ );
+ }
+
+ function __gwt_makeResult(isException, result) {
+ return [isException, result];
+ }
+
+ function findPluginObject() {
+ try {
+ return document.getElementById('pluginObject');
+ } catch (e) {
+ return null;
+ }
+ }
+
+ function findPluginEmbed() {
+ try {
+ return document.getElementById('pluginEmbed')
+ } catch (e) {
+ return null;
+ }
+ }
+
+ function findPluginXPCOM() {
+ try {
+ return __gwt_HostedModePlugin;
+ } catch (e) {
+ return null;
+ }
+ }
+
+ gwtOnLoad = function(errFn, modName, modBase){
+ $moduleName = modName;
+ $moduleBase = modBase;
+
+ /*
+ * NOTE: this presently sucks and is the only formulation I can find that will
+ * work across browsers. On a Windows box where both plugins are registered,
+ * FF will instantiate the (non-working) IE plugin. But plugins have problems
+ * that prevent making this easy.
+ *
+ * The IE plugin will throw an exception in FF if you try to resolve
+ * "pluginObject.connect" as a value. Thus the try/catch below.
+ *
+ * The FF plugin will actually do illegal crashy things in IE if you try to
+ * resolve "pluginEmbed.connect" as a value. Thus we have to try the IE
+ * plugin first.
+ *
+ * Both plugins need some work to make them truly safe.
+ */
+ var pluginFinders = [
+ findPluginXPCOM,
+ findPluginObject,
+ findPluginEmbed,
+ ];
+ var found = false;
+ for (var i = 0; i < pluginFinders.length; ++i) {
+ try {
+ var plugin = pluginFinders[i]();
+ if (plugin != null) {
+ // TODO: split connect into init/connect so we can tell plugin
+ // failures from connection failures.
+ if (plugin.connect($hosted, $moduleName, window)) {
+ found = true;
+ break;
+ } else {
+ if (errFn) {
+ errFn(modName);
+ } else {
+ alert("failed to connect to hosted mode server at " + $hosted);
+ }
+ }
+ }
+ } catch (e) {
+ }
+ }
+ if (!found) {
+ alert("No GWT plugin found or hosted-mode connection failed");
+ }
+ }
+
+ window.onunload = function() {
+ // TODO: do we need to do anything here or just rely on the plugins
+ // unload call?
+ };
}
+// Lightweight metrics
window.fireOnModuleLoadStart = function(className) {
$stats && $stats({moduleName:$moduleName, subSystem:'startup', evtGroup:'moduleStartup', millis:(new Date()).getTime(), type:'onModuleLoadStart', className:className});
};
-window.onunload = function() {
- external.gwtOnLoad(window, null, "1.6");
-};
-
window.__gwt_module_id = 0;
-
-var query = window.location.search.substr(1);
+</script></head>
+<body>
+<font face='arial' size='-1'>This html file is for hosted mode support.</font>
+<script><!--
+// Lightweight metrics
$stats && $stats({moduleName:$moduleName,subSystem:'startup',evtGroup:'moduleStartup',millis:(new Date()).getTime(),type:'moduleEvalEnd'});
-if (query && $wnd[query]) $wnd[query].onScriptLoad();
+
+// OOPHM currently only supports IFrameLinker
+var query = parent.location.search;
+if (!$legacyHosted) {
+ if (!findPluginXPCOM()) {
+ document.write('<embed id="pluginEmbed" type="application/x-gwt-hosted-mode" width="10" height="10">');
+ document.write('</embed>');
+ document.write('<object id="pluginObject" CLASSID="CLSID:1D6156B6-002B-49E7-B5CA-C138FB843B4E">');
+ document.write('</object>');
+ }
+
+ var idx = query.indexOf("gwt.hosted=");
+ if (idx >= 0) {
+ var amp = query.indexOf("&", idx);
+ if (amp >= 0) {
+ $hosted = query.substring(idx + 11, amp);
+ } else {
+ $hosted = query.substring(idx + 11);
+ }
+ }
+}
+
+query = window.location.search.substring(1);
+if (query && $wnd[query]) setTimeout($wnd[query].onScriptLoad, 1);
--></script></body></html>
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/ClassMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/ClassMember.java
new file mode 100644
index 0000000..e8e84b8
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/ClassMember.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.soyc;
+
+import java.util.SortedSet;
+
+/**
+ * Represents a reference type, such as a class or interface, in the compiled
+ * output. Methods and fields of the original Java type will have been pruned by
+ * the compiler, so the values returned by {@link #getFields()} and
+ * {@link #getMethods()} may be incomplete when compared to the original Java
+ * type.
+ */
+public interface ClassMember extends HasDependencies,
+ HasOverrides<ClassMember>, Member {
+ /**
+ * Returns the fields of the ClassMember that have been retained in the
+ * compiled output.
+ */
+ SortedSet<FieldMember> getFields();
+
+ /**
+ * Returns the methods of the ClassMember that have been retained in the
+ * compiled output.
+ */
+ SortedSet<MethodMember> getMethods();
+
+ /**
+ * Returns the Java package from which the ClassMember originated.
+ */
+ String getPackage();
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/FieldMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/FieldMember.java
new file mode 100644
index 0000000..a431f86
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/FieldMember.java
@@ -0,0 +1,22 @@
+/*
+ * 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.core.ext.soyc;
+
+/**
+ * Represents a field in a Java type.
+ */
+public interface FieldMember extends HasEnclosing, Member {
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/FunctionMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/FunctionMember.java
new file mode 100644
index 0000000..574a292
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/FunctionMember.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.core.ext.soyc;
+
+/**
+ * Represents a JavaScript function in the compiled output. Due to compiler
+ * optimizations, there may be arbitrary relationships between FunctionMembers
+ * and MethodMembers.
+ */
+public interface FunctionMember extends HasDependencies, Member {
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/HasAliases.java b/dev/core/src/com/google/gwt/core/ext/soyc/HasAliases.java
new file mode 100644
index 0000000..354aff4
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/HasAliases.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.core.ext.soyc;
+
+import java.util.SortedSet;
+
+/**
+ * A tag interface for Members to indicate that there may be additional,
+ * possibly non-unique, names in the compiled output that refer to the member.
+ */
+public interface HasAliases {
+ /**
+ * Returns any aliases used in the compiled output that refer to this
+ * MethodMember. Note that especially in the case of
+ * polymorphically-dispatched methods, there may be many MethodMembers with
+ * overlapping aliases.
+ */
+ SortedSet<String> getJsAliases();
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/HasDependencies.java b/dev/core/src/com/google/gwt/core/ext/soyc/HasDependencies.java
new file mode 100644
index 0000000..637dc52
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/HasDependencies.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+/**
+ *
+ */
+package com.google.gwt.core.ext.soyc;
+
+import java.util.SortedSet;
+
+/**
+ * A tag interface for Members to indicate that they have a static dependency on
+ * another Member.
+ */
+public interface HasDependencies {
+ SortedSet<Member> getDependencies();
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/HasEnclosing.java b/dev/core/src/com/google/gwt/core/ext/soyc/HasEnclosing.java
new file mode 100644
index 0000000..d6e1589
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/HasEnclosing.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.core.ext.soyc;
+
+/**
+ * A tag interface for Members to indicate that they have an enclosing
+ * ClassMember.
+ */
+public interface HasEnclosing {
+ ClassMember getEnclosing();
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/HasOverrides.java b/dev/core/src/com/google/gwt/core/ext/soyc/HasOverrides.java
new file mode 100644
index 0000000..5d6001b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/HasOverrides.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+/**
+ *
+ */
+package com.google.gwt.core.ext.soyc;
+
+import java.util.SortedSet;
+
+/**
+ * A tag interface for Members to indicate that they override or extend another
+ * Member.
+ *
+ * @param <T> the type of Member that is overridden or extended
+ */
+public interface HasOverrides<T extends Member> {
+ /**
+ * Returns the complete set of overridden members. For example, if
+ * <code>C</code> extends <code>B</code> extends <code>A</code>, then
+ * <code>C</code> would return the set <code>[A, B]</code>.
+ */
+ SortedSet<T> getOverrides();
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/Member.java b/dev/core/src/com/google/gwt/core/ext/soyc/Member.java
new file mode 100644
index 0000000..8a2b64e
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/Member.java
@@ -0,0 +1,75 @@
+/*
+ * 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.core.ext.soyc;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * The Member type hierarchy represents structural or logical structures in the
+ * compiled output. Members don't have a getRange() function because the bytes
+ * derived from the member are likely disjoint.
+ */
+public interface Member extends Serializable {
+
+ /**
+ * Compares Members based solely on source name. This comparator is faster
+ * than {@link #TYPE_AND_SOURCE_NAME_COMPARATOR}, but is only appropriate for
+ * use with homogeneous collections of Members.
+ */
+ Comparator<Member> SOURCE_NAME_COMPARATOR = new SourceNameComparator();
+
+ /**
+ * Compares Members based on type and source name.
+ */
+ Comparator<Member> TYPE_AND_SOURCE_NAME_COMPARATOR = new TypeAndSourceNameComparator();;
+
+ /**
+ * Returns the (possibly obfuscated) identifier used in the output.
+ */
+ String getJsName();
+
+ /**
+ * Returns a description of where the source for the Member originated.
+ * Usually, but not always, a URL.
+ */
+ String getSourceLocation();
+
+ /**
+ * Returns the name of the Member in the original source code.
+ */
+ String getSourceName();
+
+ /**
+ * Returns the Member if it is a ClassMember or <code>null</code>.
+ */
+ ClassMember isClass();
+
+ /**
+ * Returns the Member if it is a FieldMember or <code>null</code>.
+ */
+ FieldMember isField();
+
+ /**
+ * Returns the Member if it is a FunctionMember or <code>null</code>.
+ */
+ FunctionMember isFunction();
+
+ /**
+ * Returns the Member if it is a MethodMember or <code>null</code>.
+ */
+ MethodMember isMethod();
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/MethodMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/MethodMember.java
new file mode 100644
index 0000000..9966890
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/MethodMember.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.core.ext.soyc;
+
+/**
+ * Represents compiled JS code derived from a Java method.
+ */
+public interface MethodMember extends HasAliases, HasDependencies,
+ HasEnclosing, HasOverrides<MethodMember>, Member {
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/Range.java b/dev/core/src/com/google/gwt/core/ext/soyc/Range.java
new file mode 100644
index 0000000..8414263
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/Range.java
@@ -0,0 +1,113 @@
+/*
+ * 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.core.ext.soyc;
+
+import java.util.Comparator;
+
+/**
+ * Represents a contiguous region of characters in the compiler output.
+ */
+public final class Range {
+ /**
+ * Sorts Ranges so that a Range will be preceeded by any Ranges that enclose
+ * it.
+ */
+ public static final Comparator<Range> DEPENDENCY_ORDER_COMPARATOR = new Comparator<Range>() {
+ public int compare(Range o1, Range o2) {
+ int a = o1.start - o2.start;
+ if (a != 0) {
+ return a;
+ }
+
+ return o2.end - o1.end;
+ }
+ };
+
+ /**
+ * Sorts Ranges into the order in which they would appear in the source code
+ * based on start position and end position.
+ */
+ public static final Comparator<Range> SOURCE_ORDER_COMPARATOR = new Comparator<Range>() {
+ public int compare(Range o1, Range o2) {
+ int a = o1.start - o2.start;
+ if (a != 0) {
+ return a;
+ }
+
+ return o1.end - o2.end;
+ }
+ };
+
+ private final int end;
+ private final int start;
+
+ /**
+ * Constructor.
+ *
+ * @param start must be non-negative
+ * @param end must be greater than or equal to <code>start</code>
+ */
+ public Range(int start, int end) {
+ assert start >= 0;
+ assert start <= end;
+ this.start = start;
+ this.end = end;
+ }
+
+ /**
+ * Return <code>true</code> if the given Range lies wholly within the Range.
+ */
+ public boolean contains(Range o) {
+ return start <= o.start && o.end <= end;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Range)) {
+ return false;
+ }
+ Range o = (Range) obj;
+ return start == o.start && end == o.end;
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ @Override
+ public int hashCode() {
+ return 37 * start + end;
+ }
+
+ public int length() {
+ return end - start;
+ }
+
+ /**
+ * For debugging use only.
+ */
+ @Override
+ public String toString() {
+ return "[" + start + " - " + end + ")";
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/SourceNameComparator.java b/dev/core/src/com/google/gwt/core/ext/soyc/SourceNameComparator.java
new file mode 100644
index 0000000..19cd368
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/SourceNameComparator.java
@@ -0,0 +1,37 @@
+/*
+ * 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.core.ext.soyc;
+
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * This is a top-level type so that we can serialize any TreeMaps that happen to
+ * use {@link Member#SOURCE_NAME_COMPARATOR}.
+ */
+class SourceNameComparator implements Comparator<Member>, Serializable {
+ public int compare(Member o1, Member o2) {
+ return o1.getSourceName().compareTo(o2.getSourceName());
+ }
+
+ /**
+ * Always use the singleton instance.
+ */
+ private Object readResolve() throws ObjectStreamException {
+ return Member.SOURCE_NAME_COMPARATOR;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/Story.java b/dev/core/src/com/google/gwt/core/ext/soyc/Story.java
new file mode 100644
index 0000000..a08fd85
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/Story.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+/*
+ * 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.core.ext.soyc;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * Represents a (possibly disjoint) region of the JavaScript output for which
+ * metadata is available.
+ */
+public interface Story extends Serializable {
+ /*
+ * Corresponds to a SourceInfo.
+ */
+
+ /**
+ * Describes the physical or virtual source location from which a Story
+ * originated.
+ */
+ public interface Origin extends Serializable {
+ /*
+ * Corresponds to a SourceOrigin.
+ */
+
+ /**
+ * Returns the line number, or <code>0</code> if there is no physical
+ * location.
+ */
+ int getLineNumber();
+
+ /**
+ * This is usually, but not always, a URL. If it is not a URL, it will
+ * typically be a Java class name.
+ */
+ String getLocation();
+ }
+
+ /**
+ * If the Story represents a literal value, this method will return a
+ * description of the type of literal. If the Story does not represent a
+ * literal, this method will return <code>null</code>.
+ */
+ // TODO: Consider promoting the Correlation.Literal enum to a public API
+ String getLiteralTypeName();
+
+ /**
+ * Gets the Members of the compilation that the Story is about.
+ */
+ SortedSet<Member> getMembers();
+
+ /**
+ * Gets a list of transformations applied to the original source code in order
+ * to produce the story entry. This method will not return any data unless the
+ * compiler has been configured to collect mutation data.
+ */
+ List<String> getMutations();
+
+ /**
+ * Returns the locations of the Story's source. Identical structures (such as
+ * string literals) that appear in multiple locations in the source may be
+ * merged by the compiler into a single Story.
+ */
+ SortedSet<Origin> getSourceOrigin();
+
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/TypeAndSourceNameComparator.java b/dev/core/src/com/google/gwt/core/ext/soyc/TypeAndSourceNameComparator.java
new file mode 100644
index 0000000..a78746d
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/TypeAndSourceNameComparator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.soyc;
+
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * This is a top-level type so that we can serialize any TreeMaps that happen to
+ * use {@link Member#TYPE_AND_SOURCE_NAME_COMPARATOR}.
+ */
+class TypeAndSourceNameComparator implements Comparator<Member>, Serializable {
+ public int compare(Member o1, Member o2) {
+ int r = o1.getClass().getName().compareTo(o2.getClass().getName());
+ if (r != 0) {
+ return r;
+ }
+
+ return o1.getSourceName().compareTo(o2.getSourceName());
+ }
+
+ /**
+ * Always use the singleton instance.
+ */
+ private Object readResolve() throws ObjectStreamException {
+ return Member.TYPE_AND_SOURCE_NAME_COMPARATOR;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/AbstractMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/AbstractMember.java
new file mode 100644
index 0000000..136dc93
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/AbstractMember.java
@@ -0,0 +1,69 @@
+/*
+ * 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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.ClassMember;
+import com.google.gwt.core.ext.soyc.FieldMember;
+import com.google.gwt.core.ext.soyc.FunctionMember;
+import com.google.gwt.core.ext.soyc.Member;
+import com.google.gwt.core.ext.soyc.MethodMember;
+import com.google.gwt.dev.jjs.Correlation;
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.Correlation.Axis;
+
+/**
+ * Provides implementation of common Member functions.
+ */
+public abstract class AbstractMember implements Member {
+ private final String jsName;
+ private final String sourceLocation;
+
+ public AbstractMember(SourceInfo info) {
+ Correlation nameCorrelation = info.getPrimaryCorrelation(Axis.JS_NAME);
+ if (nameCorrelation != null) {
+ jsName = nameCorrelation.getName().getShortIdent();
+ } else {
+ jsName = null;
+ }
+ sourceLocation = info.getFileName();
+ }
+
+ public String getJsName() {
+ return jsName;
+ }
+
+ public String getSourceLocation() {
+ return sourceLocation;
+ }
+
+ public abstract String getSourceName();
+
+ public ClassMember isClass() {
+ return this instanceof ClassMember ? (ClassMember) this : null;
+ }
+
+ public FieldMember isField() {
+ return this instanceof FieldMember ? (FieldMember) this : null;
+ }
+
+ public FunctionMember isFunction() {
+ return this instanceof FunctionMember ? (FunctionMember) this : null;
+ }
+
+ public MethodMember isMethod() {
+ return this instanceof MethodMember ? (MethodMember) this : null;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/AbstractMemberWithDependencies.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/AbstractMemberWithDependencies.java
new file mode 100644
index 0000000..44fb5cf
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/AbstractMemberWithDependencies.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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.HasDependencies;
+import com.google.gwt.core.ext.soyc.Member;
+import com.google.gwt.dev.jjs.SourceInfo;
+
+import java.util.Collections;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Provides a common implementation of HasDependencies.
+ */
+public abstract class AbstractMemberWithDependencies extends AbstractMember
+ implements HasDependencies {
+ private final SortedSet<Member> dependencies = new TreeSet<Member>(
+ Member.TYPE_AND_SOURCE_NAME_COMPARATOR);
+ private final SortedSet<Member> dependenciesView = Collections.unmodifiableSortedSet(dependencies);
+
+ protected AbstractMemberWithDependencies(SourceInfo info) {
+ super(info);
+ }
+
+ /**
+ * Add a dependency.
+ *
+ * @return <code>true</code> if the dependency was not previously added.
+ */
+ public boolean addDependency(Member member) {
+ return dependencies.add(member);
+ }
+
+ public SortedSet<Member> getDependencies() {
+ return dependenciesView;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/MemberFactory.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/MemberFactory.java
new file mode 100644
index 0000000..273aa6b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/MemberFactory.java
@@ -0,0 +1,111 @@
+/*
+ * 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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.Member;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.js.ast.JsFunction;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+/**
+ * A factory object for the standard implementations of Member subtypes. The
+ * factory methods in this type provide canonicalized instances. The maps used
+ * by MemberFactory use hard, identity-based references.
+ */
+public class MemberFactory {
+ private final Map<Class<?>, Map<?, ?>> map = new IdentityHashMap<Class<?>, Map<?, ?>>();
+
+ public StandardFieldMember get(JField field) {
+ return getOrCreate(field, StandardFieldMember.class, JField.class);
+ }
+
+ public StandardMethodMember get(JMethod method) {
+ return getOrCreate(method, StandardMethodMember.class, JMethod.class);
+ }
+
+ public StandardClassMember get(JReferenceType type) {
+ return getOrCreate(type, StandardClassMember.class, JReferenceType.class);
+ }
+
+ public StandardFunctionMember get(JsFunction function) {
+ return getOrCreate(function, StandardFunctionMember.class, JsFunction.class);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <K, V extends Member> Map<K, V> getElementMap(K key, Class<V> clazz) {
+ Map<K, V> elementMap = (Map<K, V>) map.get(clazz);
+ if (elementMap == null) {
+ elementMap = new IdentityHashMap<K, V>();
+ map.put(clazz, elementMap);
+ }
+ return elementMap;
+ }
+
+ /**
+ * Assumes that the implementation of Member has a two-arg constructor that
+ * accepts a MemberFactory and the key.
+ *
+ * @param <K> the type of key used to canonicalize the mapping
+ * @param <V> the type of Member implementation to use
+ * @param key the key by which the value should be canonicalized
+ * @param implClazz the concrete type of Member to construct
+ * @param constructorParam the declared type of the second parameter of the
+ * concrete Member type
+ * @return the canonicalized instance of Member for the given key
+ */
+ private <K, V extends Member> V getOrCreate(K key, Class<V> implClazz,
+ Class<? super K> constructorParam) {
+ Map<K, V> elementMap = getElementMap(key, implClazz);
+
+ V toReturn = elementMap.get(key);
+ if (toReturn == null) {
+ try {
+ Constructor<V> ctor = implClazz.getConstructor(MemberFactory.class,
+ constructorParam);
+ toReturn = ctor.newInstance(this, key);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(implClazz.getName()
+ + " must declare a two-arg (MemberFactory, "
+ + constructorParam.getName() + ") constructor", e);
+ } catch (IllegalArgumentException e) {
+ // Error on the part of this type
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ // Error on the part of this type, asking for a non-instantiable type
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ // Error on the part of the coder of implClazz
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ // Probably a RuntimeException thrown from the constructor
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+ throw new RuntimeException(e);
+ }
+
+ elementMap.put(key, toReturn);
+ }
+
+ return toReturn;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/OriginImpl.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/OriginImpl.java
new file mode 100644
index 0000000..76a56fe
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/OriginImpl.java
@@ -0,0 +1,54 @@
+/*
+ * 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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.Story.Origin;
+import com.google.gwt.dev.jjs.SourceOrigin;
+
+/**
+ * An implementation of Origin, that initializes itself from a SourceOrigin.
+ */
+public class OriginImpl implements Origin, Comparable<OriginImpl> {
+
+ private final int lineNum;
+ private final String location;
+
+ public OriginImpl(SourceOrigin origin) {
+ this.location = origin.getFileName();
+ this.lineNum = origin.getStartLine();
+ }
+
+ public int compareTo(OriginImpl o) {
+ int a = location.compareTo(o.location);
+ if (a != 0) {
+ return a;
+ }
+ return lineNum - o.lineNum;
+ }
+
+ public int getLineNumber() {
+ return lineNum;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ @Override
+ public String toString() {
+ return location + " : " + lineNum;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/SnippetIterator.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/SnippetIterator.java
new file mode 100644
index 0000000..7d2fb50
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/SnippetIterator.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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.linker.CompilationAnalysis.Snippet;
+import com.google.gwt.core.ext.soyc.Range;
+import com.google.gwt.core.ext.soyc.Story;
+
+import java.util.Iterator;
+
+/**
+ * Uses a list of StoryImpls present a sequence of Snippets by synthesizing
+ * Range objects based on the length of the StoryImpls.
+ */
+public class SnippetIterator implements Iterator<Snippet> {
+ /**
+ * An Iterator over the backing object.
+ */
+ private final Iterator<StoryImpl> iter;
+
+ /**
+ * The starting position for the next Range object generated.
+ */
+ private int start = 0;
+
+ public SnippetIterator(Iterable<StoryImpl> stories) {
+ iter = stories.iterator();
+ }
+
+ public boolean hasNext() {
+ return iter.hasNext();
+ }
+
+ public Snippet next() {
+ final StoryImpl story = iter.next();
+ final Range range = new Range(start, start + story.getLength());
+ start += story.getLength();
+
+ return new Snippet() {
+ public Range getRange() {
+ return range;
+ }
+
+ public Story getStory() {
+ return story;
+ }
+ };
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardClassMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardClassMember.java
new file mode 100644
index 0000000..8a0a46f
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardClassMember.java
@@ -0,0 +1,125 @@
+/*
+ * 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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.ClassMember;
+import com.google.gwt.core.ext.soyc.FieldMember;
+import com.google.gwt.core.ext.soyc.Member;
+import com.google.gwt.core.ext.soyc.MethodMember;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * An implementation of ClassMember. This implementation always returns
+ * unmodifiable collections since it is exposed directly to user code via the
+ * Linker API.
+ */
+public class StandardClassMember extends AbstractMemberWithDependencies
+ implements ClassMember {
+ private final SortedSet<FieldMember> fields = new TreeSet<FieldMember>(
+ Member.SOURCE_NAME_COMPARATOR);
+ private final SortedSet<FieldMember> fieldsView = Collections.unmodifiableSortedSet(fields);
+ private final SortedSet<MethodMember> methods = new TreeSet<MethodMember>(
+ Member.SOURCE_NAME_COMPARATOR);
+ private final SortedSet<MethodMember> methodsView = Collections.unmodifiableSortedSet(methods);
+ private final SortedSet<ClassMember> overridesView;
+ private final String packageName;
+ private final String sourceName;
+
+ /**
+ * Constructed by {@link MemberFactory#get(JReferenceType)}.
+ */
+ public StandardClassMember(MemberFactory factory, JReferenceType type) {
+ super(type.getSourceInfo());
+
+ int index = type.getName().lastIndexOf('.');
+ if (index < 0) {
+ packageName = "";
+ } else {
+ packageName = type.getName().substring(0, index).intern();
+ }
+ sourceName = type.getName().intern();
+
+ Set<JReferenceType> seen = new HashSet<JReferenceType>();
+ Set<JReferenceType> toTraverse = new HashSet<JReferenceType>();
+ toTraverse.add(type);
+
+ SortedSet<ClassMember> overrides = new TreeSet<ClassMember>(
+ Member.SOURCE_NAME_COMPARATOR);
+
+ while (!toTraverse.isEmpty()) {
+ JReferenceType currentType = toTraverse.iterator().next();
+ seen.add(currentType);
+
+ if (currentType != type) {
+ overrides.add(factory.get(currentType));
+ }
+
+ if (currentType.extnds != null) {
+ toTraverse.add(currentType.extnds);
+ }
+
+ if (currentType.implments != null) {
+ toTraverse.addAll(currentType.implments);
+ }
+
+ toTraverse.removeAll(seen);
+ }
+ overridesView = Collections.unmodifiableSortedSet(overrides);
+ }
+
+ public void addField(FieldMember field) {
+ fields.add(field);
+ }
+
+ public void addMethod(MethodMember method) {
+ methods.add(method);
+ }
+
+ public SortedSet<FieldMember> getFields() {
+ return fieldsView;
+ }
+
+ public SortedSet<MethodMember> getMethods() {
+ return methodsView;
+ }
+
+ public SortedSet<ClassMember> getOverrides() {
+ return overridesView;
+ }
+
+ public String getPackage() {
+ return packageName;
+ }
+
+ @Override
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ /**
+ * For debugging use only.
+ */
+ @Override
+ public String toString() {
+ return "ClassMember " + getSourceName();
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardFieldMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardFieldMember.java
new file mode 100644
index 0000000..e40185c
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardFieldMember.java
@@ -0,0 +1,55 @@
+/*
+ * 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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.ClassMember;
+import com.google.gwt.core.ext.soyc.FieldMember;
+import com.google.gwt.dev.jjs.ast.JField;
+
+/**
+ * An implementation of FieldMember.
+ */
+public class StandardFieldMember extends AbstractMember implements FieldMember {
+ private final ClassMember enclosing;
+ private final String sourceName;
+
+ /**
+ * Constructed by {@link MemberFactory#get(JFieldType)}.
+ */
+ public StandardFieldMember(MemberFactory factory, JField field) {
+ super(field.getSourceInfo());
+ this.enclosing = factory.get(field.getEnclosingType());
+ this.sourceName = field.getEnclosingType().getName() + "::"
+ + field.getName();
+ }
+
+ public ClassMember getEnclosing() {
+ return enclosing;
+ }
+
+ @Override
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ /**
+ * For debugging use only.
+ */
+ @Override
+ public String toString() {
+ return "FieldMember " + sourceName;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardFunctionMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardFunctionMember.java
new file mode 100644
index 0000000..9b530b7
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardFunctionMember.java
@@ -0,0 +1,49 @@
+/*
+ * 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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.FunctionMember;
+import com.google.gwt.dev.js.ast.JsFunction;
+
+/**
+ * An implementation of FunctionMember.
+ */
+public class StandardFunctionMember extends AbstractMemberWithDependencies
+ implements FunctionMember {
+
+ private final String sourceName;
+
+ /**
+ * Constructed by {@link MemberFactory#get(JsFunction)}.
+ */
+ public StandardFunctionMember(MemberFactory factory, JsFunction function) {
+ super(function.getSourceInfo());
+ this.sourceName = function.getName().getIdent();
+ }
+
+ @Override
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ /**
+ * For debugging use only.
+ */
+ @Override
+ public String toString() {
+ return "FunctionMember " + sourceName;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardMethodMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardMethodMember.java
new file mode 100644
index 0000000..e617acf
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardMethodMember.java
@@ -0,0 +1,95 @@
+/*
+ * 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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.ClassMember;
+import com.google.gwt.core.ext.soyc.Member;
+import com.google.gwt.core.ext.soyc.MethodMember;
+import com.google.gwt.dev.jjs.Correlation;
+import com.google.gwt.dev.jjs.Correlation.Axis;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JType;
+
+import java.util.Collections;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * An implementation of MethodMember.
+ */
+public class StandardMethodMember extends AbstractMemberWithDependencies
+ implements MethodMember {
+ private final SortedSet<String> aliasesView;
+ private final ClassMember enclosing;
+ private final String sourceName;
+ private final SortedSet<MethodMember> overridesView;
+
+ /**
+ * Constructed by {@link MemberFactory#get(JMethod)}.
+ */
+ public StandardMethodMember(MemberFactory factory, JMethod method) {
+ super(method.getSourceInfo());
+ this.enclosing = factory.get(method.getEnclosingType());
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(method.getEnclosingType().getName()).append("::");
+ sb.append(method.getName()).append("(");
+ for (JType type : method.getOriginalParamTypes()) {
+ sb.append(type.getJsniSignatureName());
+ }
+ sb.append(")");
+ this.sourceName = sb.toString();
+
+ SortedSet<String> aliases = new TreeSet<String>();
+ for (Correlation c : method.getSourceInfo().getAllCorrelations(
+ Axis.JS_ALIAS)) {
+ aliases.add(c.getName().getShortIdent());
+ }
+ aliasesView = Collections.unmodifiableSortedSet(aliases);
+
+ SortedSet<MethodMember> overrides = new TreeSet<MethodMember>(
+ Member.SOURCE_NAME_COMPARATOR);
+ for (JMethod override : method.overrides) {
+ overrides.add(factory.get(override));
+ }
+ overridesView = Collections.unmodifiableSortedSet(overrides);
+ }
+
+ public ClassMember getEnclosing() {
+ return enclosing;
+ }
+
+ public SortedSet<String> getJsAliases() {
+ return aliasesView;
+ }
+
+ public SortedSet<MethodMember> getOverrides() {
+ return overridesView;
+ }
+
+ @Override
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ /**
+ * For debugging use only.
+ */
+ @Override
+ public String toString() {
+ return "MethodMember " + sourceName;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryImpl.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryImpl.java
new file mode 100644
index 0000000..7aab089
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryImpl.java
@@ -0,0 +1,146 @@
+/*
+ * 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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.Member;
+import com.google.gwt.core.ext.soyc.Story;
+import com.google.gwt.dev.jjs.SourceInfo.Mutation;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * An implementation of the Story interface. This type has two additional pieces
+ * of information not required by the Story interface. The first is a unique id
+ * number and the second is a length. Instead of storing range objects for each
+ * StoryImpl, we simply store the StoryImpls in order and calculate the Range
+ * for the StoryImpl based on its length.
+ *
+ * @see SnippetIterator#next()
+ */
+public class StoryImpl implements Story, Serializable {
+ /**
+ * Orders StoryImpl's by their id number.
+ */
+ public static final Comparator<Story> ID_COMPARATOR = new StoryImplComparator();
+
+ private final int id;
+ private final int fragment;
+ private final int length;
+ private final String literalDescription;
+ private final SortedSet<Member> members;
+ private final List<String> mutations;
+ private final SortedSet<Origin> origins;
+
+ /**
+ * Standard constructor. This constructor will create unmodifiable versions of
+ * the collections passed into it.
+ */
+ public StoryImpl(int id, SortedSet<Member> members, List<Mutation> mutations,
+ SortedSet<Origin> origins, String literalDescription, int fragment,
+ int length) {
+ assert members != null;
+ assert mutations != null;
+ assert origins != null;
+ assert fragment >= 0;
+ assert length > 0;
+ // literalDescription may be null
+
+ this.id = id;
+ this.fragment = fragment;
+ this.length = length;
+ this.literalDescription = literalDescription == null ? null
+ : literalDescription.intern();
+ this.members = Collections.unmodifiableSortedSet(members);
+
+ List<String> mutableMutations = new ArrayList<String>(mutations.size());
+ for (Mutation m : mutations) {
+ mutableMutations.add(m.getDescription() + " by " + m.getCaller());
+ }
+ this.mutations = Collections.unmodifiableList(mutableMutations);
+ this.origins = Collections.unmodifiableSortedSet(origins);
+ }
+
+ /**
+ * This is a copy-constructor that's used when we subdivide a Range. All we
+ * really care about in the shadow version is having a different length; all
+ * of the other fields are initialized from the original.
+ */
+ public StoryImpl(StoryImpl other, int length) {
+ this.id = other.id;
+ this.fragment = other.fragment;
+ this.length = length;
+ this.literalDescription = other.literalDescription;
+ this.members = other.members;
+ this.mutations = other.mutations;
+ this.origins = other.origins;
+ }
+
+ /**
+ * Identity is based on the <code>id</code> field.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof StoryImpl)) {
+ return false;
+ }
+ StoryImpl o = (StoryImpl) obj;
+ return id == o.id;
+ }
+
+ public int getFragment() {
+ return fragment;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Used internally, and not specified by the Story interface.
+ */
+ public int getLength() {
+ return length;
+ }
+
+ public String getLiteralTypeName() {
+ return literalDescription;
+ }
+
+ public SortedSet<Member> getMembers() {
+ return members;
+ }
+
+ public List<String> getMutations() {
+ return mutations;
+ }
+
+ public SortedSet<Origin> getSourceOrigin() {
+ return origins;
+ }
+
+ /**
+ * Identity is based on the <code>id</code> field.
+ */
+ @Override
+ public int hashCode() {
+ return id;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryImplComparator.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryImplComparator.java
new file mode 100644
index 0000000..f3daae8
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryImplComparator.java
@@ -0,0 +1,38 @@
+/*
+ * 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.core.ext.soyc.impl;
+
+import com.google.gwt.core.ext.soyc.Story;
+
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Exists as a real class to allow TreeMaps to be serialized.
+ */
+public class StoryImplComparator implements Comparator<Story>, Serializable {
+ public int compare(Story o1, Story o2) {
+ return ((StoryImpl) o1).getId() - ((StoryImpl) o2).getId();
+ }
+
+ /**
+ * Use the singleton instance.
+ */
+ private Object readResolve() throws ObjectStreamException {
+ return StoryImpl.ID_COMPARATOR;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/package-info.java b/dev/core/src/com/google/gwt/core/ext/soyc/package-info.java
new file mode 100644
index 0000000..5cb0045
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains interfaces that provide access to
+ * "Story of Your Compile" information. When the compiler is run with analysis
+ * turned on, these types are available to Linkers via
+ * {@link com.google.gwt.core.ext.linker.CompilationAnalysis} artifacts.
+ */
+package com.google.gwt.core.ext.soyc;
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
index e326756..26c4ab0 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
@@ -286,7 +286,7 @@
* Determines if the class can be constructed using a simple <code>new</code>
* operation. Specifically, the class must
* <ul>
- * <li>be a class rather than an interface, </li>
+ * <li>be a class rather than an interface,</li>
* <li>have either no constructors or a parameterless constructor, and</li>
* <li>be a top-level class or a static nested class.</li>
* </ul>
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
index 424a3ca..0de6e96 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
@@ -18,11 +18,13 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.generator.GenUtil;
+import com.google.gwt.dev.shell.JsValueGlue;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -198,6 +200,11 @@
private final Map<String, List<JWildcardType>> wildcardTypes = new HashMap<String, List<JWildcardType>>();
+ /**
+ * Maps SingleJsoImpl interfaces to the implementing JSO subtype.
+ */
+ private final Map<JClassType, JClassType> jsoSingleImpls = new IdentityHashMap<JClassType, JClassType>();
+
public TypeOracle() {
// Always create the default package.
//
@@ -216,10 +223,10 @@
/**
* Finds a class or interface given its fully-qualified name.
- *
- * @param name fully-qualified class/interface name - for nested
- * classes, use its source name rather than its binary name (that is, use a
- * "." rather than a "$")
+ *
+ * @param name fully-qualified class/interface name - for nested classes, use
+ * its source name rather than its binary name (that is, use a "."
+ * rather than a "$")
*
* @return <code>null</code> if the type is not found
*/
@@ -253,6 +260,7 @@
public void finish(TreeLogger logger) {
JClassType[] newTypes = recentTypes.toArray(NO_JCLASSES);
computeHierarchyRelationships(newTypes);
+ computeSingleJsoImplData(logger, newTypes);
consumeTypeArgMetaData(logger, newTypes);
recentTypes.clear();
}
@@ -434,6 +442,24 @@
}
/**
+ * Returns the single implementation type for an interface returned via
+ * {@link #getSingleJsoImplInterfaces()} or <code>null</code> if no JSO
+ * implementation is defined.
+ */
+ public JClassType getSingleJsoImpl(JClassType intf) {
+ assert intf.isInterface() == intf;
+ return jsoSingleImpls.get(intf);
+ }
+
+ /**
+ * Returns an unmodifiable, live view of all interface types that are
+ * implemented by exactly one JSO subtype.
+ */
+ public Set<JClassType> getSingleJsoImplInterfaces() {
+ return Collections.unmodifiableSet(jsoSingleImpls.keySet());
+ }
+
+ /**
* Finds a type given its fully qualified name. For nested classes, use its
* source name rather than its binary name (that is, use a "." rather than a
* "$").
@@ -618,6 +644,61 @@
}
}
+ /**
+ * Updates the list of jsoSingleImpl types from recently-added types.
+ */
+ private void computeSingleJsoImplData(TreeLogger logger, JClassType[] newTypes) {
+ JClassType jsoType = findType(JsValueGlue.JSO_CLASS);
+ if (jsoType == null) {
+ return;
+ }
+
+ for (JClassType type : newTypes) {
+ if (!jsoType.isAssignableFrom(type)) {
+ continue;
+ }
+
+ for (JClassType intf : JClassType.getFlattenedSuperTypeHierarchy(type)) {
+ if (intf.isInterface() == null) {
+ // Not an interface
+ continue;
+ }
+
+ if (intf.getOverridableMethods().length == 0) {
+ /*
+ * Record a tag interface as being implemented by JSO, since they
+ * don't actually have any methods and we want to avoid spurious
+ * messages about multiple JSO types implementing a common interface.
+ */
+ jsoSingleImpls.put(intf, jsoType);
+ continue;
+ }
+
+ /*
+ * If the previously-registered implementation type for a SingleJsoImpl
+ * interface is a subtype of the type we're currently looking at, we
+ * want to choose the least-derived class.
+ */
+ JClassType previousType = jsoSingleImpls.get(intf);
+ if (previousType == null) {
+ jsoSingleImpls.put(intf, type);
+ } else if (type.isAssignableFrom(previousType)) {
+ jsoSingleImpls.put(intf, type);
+ } else if (type.isAssignableTo(previousType)) {
+ // Do nothing
+ } else {
+ // This should have been taken care of by JSORetrictionsChecker
+ logger.log(TreeLogger.ERROR,
+ "Already seen an implementing JSO subtype ("
+ + previousType.getName() + ") for interface ("
+ + intf.getName() + ") while examining newly-added type ("
+ + type.getName() + "). This is a bug in "
+ + "JSORestrictionsChecker.");
+ }
+ }
+ }
+ }
+
private void consumeTypeArgMetaData(TreeLogger logger, JClassType[] types) {
if (GenUtil.warnAboutMetadata()) {
logger = logger.branch(
@@ -983,7 +1064,7 @@
JRealClassType classType = iter.next();
String fqcn = classType.getQualifiedSourceName();
allTypes.remove(fqcn);
-
+ jsoSingleImpls.remove(classType);
JPackage pkg = classType.getPackage();
if (pkg != null) {
pkg.remove(classType);
diff --git a/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java b/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
index 838093e..a02d487 100644
--- a/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
@@ -38,7 +38,7 @@
*/
@LinkerOrder(Order.PRIMARY)
public class IFrameLinker extends SelectionScriptLinker {
-
+ @Override
public String getDescription() {
return "Standard";
}
@@ -94,39 +94,15 @@
}
@Override
- protected String getModulePrefix(TreeLogger logger, LinkerContext context) {
- DefaultTextOutput out = new DefaultTextOutput(context.isOutputCompact());
- out.print("<html>");
- out.newlineOpt();
+ protected String getModulePrefix(TreeLogger logger, LinkerContext context,
+ String strongName) {
+ return getModulePrefix(context, strongName, true);
+ }
- // Setup the well-known variables.
- //
- out.print("<head><script>");
- out.newlineOpt();
- out.print("var $gwt_version = \"" + About.GWT_VERSION_NUM + "\";");
- out.newlineOpt();
- out.print("var $wnd = parent;");
- out.newlineOpt();
- out.print("var $doc = $wnd.document;");
- out.newlineOpt();
- out.print("var $moduleName, $moduleBase;");
- out.newlineOpt();
- out.print("var $stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null;");
- out.newlineOpt();
- out.print("$stats && $stats({moduleName:'" + context.getModuleName()
- + "',subSystem:'startup',evtGroup:'moduleStartup'"
- + ",millis:(new Date()).getTime(),type:'moduleEvalStart'});");
- out.newlineOpt();
- out.print("</script></head>");
- out.newlineOpt();
- out.print("<body>");
- out.newlineOpt();
-
- // Begin a script block inside the body. It's commented out so that the
- // browser won't mistake strings containing "<script>" for actual script.
- out.print("<script><!--");
- out.newline();
- return out.toString();
+ @Override
+ protected String getModulePrefix(TreeLogger logger, LinkerContext context,
+ String strongName, int numFragments) {
+ return getModulePrefix(context, strongName, numFragments > 1);
}
@Override
@@ -154,4 +130,59 @@
return "com/google/gwt/core/linker/IFrameTemplate.js";
}
+ /**
+ * This is the real implementation of <code>getModulePrefix</code> for this
+ * linker. The other versions forward to this one.
+ */
+ private String getModulePrefix(LinkerContext context, String strongName,
+ boolean supportRunAsync) {
+ DefaultTextOutput out = new DefaultTextOutput(context.isOutputCompact());
+ out.print("<html>");
+ out.newlineOpt();
+
+ // Setup the well-known variables.
+ out.print("<head><script>");
+ out.newlineOpt();
+ out.print("var $gwt_version = \"" + About.GWT_VERSION_NUM + "\";");
+ out.newlineOpt();
+ out.print("var $wnd = parent;");
+ out.newlineOpt();
+ out.print("var $doc = $wnd.document;");
+ out.newlineOpt();
+ out.print("var $moduleName, $moduleBase;");
+ out.newlineOpt();
+ out.print("var $strongName = '" + strongName + "';");
+ out.newlineOpt();
+ if (supportRunAsync) {
+ out.print("function __gwtStartLoadingFragment(frag) {");
+ out.newlineOpt();
+ out.indentIn();
+ out.print(" var script = document.createElement('script');");
+ out.newlineOpt();
+ out.print(" script.src = '" + FRAGMENT_SUBDIR + "/" + strongName
+ + "/' + frag + '" + FRAGMENT_EXTENSION + "';");
+ out.print(" document.getElementsByTagName('head').item(0).appendChild(script);");
+ out.indentOut();
+ out.newlineOpt();
+ out.print("};");
+ out.newlineOpt();
+ }
+ out.print("var $stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null;");
+ out.newlineOpt();
+ out.print("$stats && $stats({moduleName:'" + context.getModuleName()
+ + "',subSystem:'startup',evtGroup:'moduleStartup'"
+ + ",millis:(new Date()).getTime(),type:'moduleEvalStart'});");
+ out.newlineOpt();
+ out.print("</script></head>");
+ out.newlineOpt();
+ out.print("<body>");
+ out.newlineOpt();
+
+ // Begin a script block inside the body. It's commented out so that the
+ // browser won't mistake strings containing "<script>" for actual script.
+ out.print("<script><!--");
+ out.newline();
+ return out.toString();
+ }
+
}
diff --git a/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js b/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
index d98c012..80c148d 100644
--- a/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
+++ b/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
@@ -67,8 +67,10 @@
function isHostedMode() {
var result = false;
try {
- result = ($wnd.external && $wnd.external.gwtOnLoad &&
- ($wnd.location.search.indexOf('gwt.hybrid') == -1));
+ var query = $wnd.location.search;
+ return (query.indexOf('gwt.hosted=') != -1
+ || ($wnd.external && $wnd.external.gwtOnLoad)) &&
+ (query.indexOf('gwt.hybrid') == -1);
} catch (e) {
// Defensive: some versions of IE7 reportedly can throw an exception
// evaluating "external.gwtOnLoad".
@@ -297,7 +299,7 @@
millis:(new Date()).getTime(),
type: 'moduleRequested'
});
- iframe.contentWindow.location.replace(base + strongName);
+ iframe.contentWindow.location.replace(base + initialHtml);
}
}
@@ -342,13 +344,15 @@
computeScriptBase();
var strongName;
+ var initialHtml;
if (isHostedMode()) {
- if ($wnd.external.initModule && $wnd.external.initModule('__MODULE_NAME__')) {
+ if ($wnd.external && $wnd.external.initModule && $wnd.external.initModule('__MODULE_NAME__')) {
// Refresh the page to update this selection script!
$wnd.location.reload();
return;
}
- strongName = "hosted.html?__MODULE_FUNC__";
+ initialHtml = "hosted.html?__MODULE_FUNC__";
+ strongName = "";
}
processMetas();
@@ -363,11 +367,12 @@
type: 'selectingPermutation'
});
- if (!strongName) {
+ if (!isHostedMode()) {
try {
// __PERMUTATIONS_BEGIN__
// Permutation logic
// __PERMUTATIONS_END__
+ initialHtml = strongName + ".cache.html";
} catch (e) {
// intentionally silent on property failure
return;
diff --git a/dev/core/src/com/google/gwt/core/linker/SingleScriptLinker.java b/dev/core/src/com/google/gwt/core/linker/SingleScriptLinker.java
index 61a4371..044e68b 100644
--- a/dev/core/src/com/google/gwt/core/linker/SingleScriptLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/SingleScriptLinker.java
@@ -27,6 +27,7 @@
import com.google.gwt.dev.About;
import com.google.gwt.dev.util.DefaultTextOutput;
+import java.util.Collection;
import java.util.Set;
/**
@@ -36,6 +37,7 @@
*/
@LinkerOrder(Order.PRIMARY)
public class SingleScriptLinker extends SelectionScriptLinker {
+ @Override
public String getDescription() {
return "Single Script";
}
@@ -51,6 +53,19 @@
}
@Override
+ protected Collection<EmittedArtifact> doEmitCompilation(TreeLogger logger,
+ LinkerContext context, CompilationResult result)
+ throws UnableToCompleteException {
+ if (result.getJavaScript().length != 1) {
+ logger.branch(TreeLogger.ERROR,
+ "The module must not have multiple fragments when using the "
+ + getDescription() + " Linker.", null);
+ throw new UnableToCompleteException();
+ }
+ return super.doEmitCompilation(logger, context, result);
+ }
+
+ @Override
protected EmittedArtifact emitSelectionScript(TreeLogger logger,
LinkerContext context, ArtifactSet artifacts)
throws UnableToCompleteException {
@@ -88,7 +103,17 @@
}
CompilationResult result = results.iterator().next();
- out.print(result.getJavaScript());
+ out.print("var $strongName = '" + result.getStrongName() + "';");
+ out.newlineOpt();
+
+ String[] js = result.getJavaScript();
+ if (js.length != 1) {
+ logger = logger.branch(TreeLogger.ERROR,
+ "The module must not have multiple fragments when using the "
+ + getDescription() + " Linker.", null);
+ throw new UnableToCompleteException();
+ }
+ out.print(js[0]);
// Generate the call to tell the bootstrap code that we're ready to go.
out.newlineOpt();
@@ -117,8 +142,8 @@
* {@link #doEmitCompilation(TreeLogger, LinkerContext, CompilationResult).
*/
@Override
- protected String getModulePrefix(TreeLogger logger, LinkerContext context)
- throws UnableToCompleteException {
+ protected String getModulePrefix(TreeLogger logger, LinkerContext context,
+ String strongName) throws UnableToCompleteException {
throw new UnableToCompleteException();
}
diff --git a/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java b/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
new file mode 100644
index 0000000..a449bed
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2009 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.core.linker;
+
+import com.google.gwt.core.ext.LinkerContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.linker.AbstractLinker;
+import com.google.gwt.core.ext.linker.ArtifactSet;
+import com.google.gwt.core.ext.linker.CompilationResult;
+import com.google.gwt.core.ext.linker.EmittedArtifact;
+import com.google.gwt.core.ext.linker.LinkerOrder;
+import com.google.gwt.core.ext.linker.SelectionProperty;
+import com.google.gwt.core.ext.linker.LinkerOrder.Order;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.SortedMap;
+
+/**
+ * This Linker exports the symbol maps associated with each compilation result
+ * as a private file. The names of the symbol maps files are computed by
+ * appending {@value #STRONG_NAME_SUFFIX} to the value returned by
+ * {@link CompilationResult#getStrongName()}.
+ */
+@LinkerOrder(Order.POST)
+public class SymbolMapsLinker extends AbstractLinker {
+
+ /**
+ * This value is appended to the strong name of the CompilationResult to form
+ * the symbol map's filename.
+ */
+ public static final String STRONG_NAME_SUFFIX = "_sybolMap.properties";
+
+ @Override
+ public String getDescription() {
+ return "Export CompilationResult symbol maps";
+ }
+
+ @Override
+ public ArtifactSet link(TreeLogger logger, LinkerContext context,
+ ArtifactSet artifacts) throws UnableToCompleteException {
+
+ artifacts = new ArtifactSet(artifacts);
+
+ for (CompilationResult result : artifacts.find(CompilationResult.class)) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ PrintWriter pw = new PrintWriter(out);
+
+ doWriteSymbolMap(logger, result, pw);
+ pw.close();
+
+ doEmitSymbolMap(logger, artifacts, result, out);
+ }
+
+ return artifacts;
+ }
+
+ /**
+ * Override to change the manner in which the symbol map is emitted.
+ */
+ protected void doEmitSymbolMap(TreeLogger logger, ArtifactSet artifacts,
+ CompilationResult result, ByteArrayOutputStream out)
+ throws UnableToCompleteException {
+ EmittedArtifact symbolMapArtifact = emitBytes(logger, out.toByteArray(),
+ result.getStrongName() + STRONG_NAME_SUFFIX);
+ symbolMapArtifact.setPrivate(true);
+ artifacts.add(symbolMapArtifact);
+ }
+
+ /**
+ * Override to change the format of the symbol map.
+ */
+ protected void doWriteSymbolMap(TreeLogger logger, CompilationResult result,
+ PrintWriter pw) throws UnableToCompleteException {
+ for (SortedMap<SelectionProperty, String> map : result.getPropertyMap()) {
+ pw.print("# { ");
+
+ boolean needsComma = false;
+ for (Map.Entry<SelectionProperty, String> entry : map.entrySet()) {
+ if (needsComma) {
+ pw.print(" , ");
+ } else {
+ needsComma = true;
+ }
+
+ pw.print("'");
+ pw.print(entry.getKey().getName());
+ pw.print("' : '");
+ pw.print(entry.getValue());
+ pw.print("'");
+ }
+ pw.println(" }");
+ }
+
+ for (Map.Entry<String, String> entry : result.getSymbolMap().entrySet()) {
+ // Don't use an actual Properties object because it emits a timestamp
+ pw.print(entry.getKey());
+ pw.print(" = ");
+ pw.print(entry.getValue());
+ pw.println();
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/core/linker/XSLinker.java b/dev/core/src/com/google/gwt/core/linker/XSLinker.java
index d028248..8f3a486 100644
--- a/dev/core/src/com/google/gwt/core/linker/XSLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/XSLinker.java
@@ -18,31 +18,48 @@
import com.google.gwt.core.ext.LinkerContext;
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.EmittedArtifact;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
import com.google.gwt.core.ext.linker.impl.SelectionScriptLinker;
import com.google.gwt.dev.About;
import com.google.gwt.dev.util.DefaultTextOutput;
+import java.util.Collection;
+
/**
* Generates a cross-site compatible bootstrap sequence.
*/
@LinkerOrder(Order.PRIMARY)
public class XSLinker extends SelectionScriptLinker {
-
+ @Override
public String getDescription() {
return "Cross-Site";
}
@Override
+ protected Collection<EmittedArtifact> doEmitCompilation(TreeLogger logger,
+ LinkerContext context, CompilationResult result)
+ throws UnableToCompleteException {
+ if (result.getJavaScript().length != 1) {
+ logger.branch(TreeLogger.ERROR,
+ "The module must not have multiple fragments when using the "
+ + getDescription() + " Linker.", null);
+ throw new UnableToCompleteException();
+ }
+ return super.doEmitCompilation(logger, context, result);
+ }
+
+ @Override
protected String getCompilationExtension(TreeLogger logger,
LinkerContext context) throws UnableToCompleteException {
return ".cache.js";
}
@Override
- protected String getModulePrefix(TreeLogger logger, LinkerContext context)
- throws UnableToCompleteException {
+ protected String getModulePrefix(TreeLogger logger, LinkerContext context,
+ String strongName) throws UnableToCompleteException {
DefaultTextOutput out = new DefaultTextOutput(context.isOutputCompact());
out.print("(function(){");
@@ -58,6 +75,8 @@
out.newlineOpt();
out.print("var $moduleName, $moduleBase;");
out.newlineOpt();
+ out.print("var $strongName = '" + strongName + "';");
+ out.newlineOpt();
out.print("var $stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null;");
out.newlineOpt();
out.print("$stats && $stats({moduleName:'" + context.getModuleName()
diff --git a/dev/core/src/com/google/gwt/core/linker/XSTemplate.js b/dev/core/src/com/google/gwt/core/linker/XSTemplate.js
index a88be2a..8cbdbe9 100644
--- a/dev/core/src/com/google/gwt/core/linker/XSTemplate.js
+++ b/dev/core/src/com/google/gwt/core/linker/XSTemplate.js
@@ -368,7 +368,7 @@
// some apps. The final solution was simply to inject the compiled script
// from *within* the stats script, guaranteeing order at the expense of near
// total inscrutability :(
- var compiledScriptTag = '"<script src=\\"' + base + strongName + '\\"></scr" + "ipt>"';
+ var compiledScriptTag = '"<script src=\\"' + base + strongName + '.cache.js\\"></scr" + "ipt>"';
$doc.write('<script><!--\n'
+ 'window.__gwtStatsEvent && window.__gwtStatsEvent({'
+ 'moduleName:"__MODULE_NAME__", subSystem:"startup",'
diff --git a/dev/core/src/com/google/gwt/core/linker/soyc/SoycReportLinker.java b/dev/core/src/com/google/gwt/core/linker/soyc/SoycReportLinker.java
new file mode 100644
index 0000000..8ab22ab
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/linker/soyc/SoycReportLinker.java
@@ -0,0 +1,827 @@
+/*
+ * 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.core.linker.soyc;
+
+import com.google.gwt.core.ext.LinkerContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.linker.AbstractLinker;
+import com.google.gwt.core.ext.linker.ArtifactSet;
+import com.google.gwt.core.ext.linker.CompilationAnalysis;
+import com.google.gwt.core.ext.linker.CompilationResult;
+import com.google.gwt.core.ext.linker.LinkerOrder;
+import com.google.gwt.core.ext.linker.SelectionProperty;
+import com.google.gwt.core.ext.linker.SyntheticArtifact;
+import com.google.gwt.core.ext.linker.CompilationAnalysis.Snippet;
+import com.google.gwt.core.ext.linker.LinkerOrder.Order;
+import com.google.gwt.core.ext.soyc.ClassMember;
+import com.google.gwt.core.ext.soyc.FieldMember;
+import com.google.gwt.core.ext.soyc.FunctionMember;
+import com.google.gwt.core.ext.soyc.Member;
+import com.google.gwt.core.ext.soyc.MethodMember;
+import com.google.gwt.core.ext.soyc.Range;
+import com.google.gwt.core.ext.soyc.Story;
+import com.google.gwt.core.ext.soyc.Story.Origin;
+import com.google.gwt.dev.util.HtmlTextOutput;
+import com.google.gwt.util.tools.Utility;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * Generates the XML report containing the Story of Your Compile.
+ */
+@LinkerOrder(Order.PRE)
+public class SoycReportLinker extends AbstractLinker {
+
+ public String escapeXml(String unescaped) {
+ String escaped = unescaped.replaceAll("\\&", "&");
+ escaped = escaped.replaceAll("\\<", "<");
+ escaped = escaped.replaceAll("\\>", ">");
+ escaped = escaped.replaceAll("\\\"", """);
+ // escaped = escaped.replaceAll("\\'", "'");
+ return escaped;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Story of your compile report";
+ }
+
+ @Override
+ public ArtifactSet link(TreeLogger logger, LinkerContext context,
+ ArtifactSet artifacts) throws UnableToCompleteException {
+ SortedSet<CompilationAnalysis> reports = artifacts.find(CompilationAnalysis.class);
+
+ // Do nothing if there are no reports to be generated.
+ if (reports.isEmpty()) {
+ return artifacts;
+ }
+
+ logger = logger.branch(TreeLogger.DEBUG, "SOYC report linker");
+ initialize(logger);
+
+ if (reports.isEmpty()) {
+ logger.log(TreeLogger.DEBUG, "No SOYC report artifacts");
+ return artifacts;
+ }
+
+ artifacts = new ArtifactSet(artifacts);
+ int reportNum = 0;
+ SortedMap<CompilationResult, String> partialPathsByResult = new TreeMap<CompilationResult, String>();
+
+ // TODO: This goes much faster in parallel, but what's the policy?
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ List<Future<SyntheticArtifact>> futures = new ArrayList<Future<SyntheticArtifact>>(
+ reports.size());
+ for (final CompilationAnalysis report : reports) {
+ final TreeLogger loopLogger = logger.branch(TreeLogger.SPAM,
+ "Report for " + report.toString());
+ final String reportName = "report" + reportNum++ + ".xml.gz";
+ partialPathsByResult.put(report.getCompilationResult(), reportName);
+ Future<SyntheticArtifact> future = executor.submit(new Callable<SyntheticArtifact>() {
+ public SyntheticArtifact call() throws Exception {
+ loopLogger.log(TreeLogger.INFO, "Started");
+ SyntheticArtifact reportArtifact = emitReport(loopLogger, report,
+ reportName, true);
+ return reportArtifact;
+ }
+ });
+ futures.add(future);
+ }
+ executor.shutdown();
+
+ for (Future<SyntheticArtifact> future : futures) {
+ SyntheticArtifact artifact;
+ try {
+ artifact = future.get();
+ } catch (InterruptedException e) {
+ logger.log(TreeLogger.ERROR, "Unable to process report", e);
+ throw new UnableToCompleteException();
+ } catch (ExecutionException e) {
+ logger.log(TreeLogger.ERROR, "Unable to process report", e);
+ throw new UnableToCompleteException();
+ }
+ artifact.setPrivate(true);
+ artifacts.add(artifact);
+ }
+
+ // Emit manifest
+ try {
+ SyntheticArtifact sa = emitManifest(logger, artifacts,
+ partialPathsByResult, false);
+ sa.setPrivate(true);
+ artifacts.add(sa);
+ } catch (FileNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return artifacts;
+ }
+
+ private void emitAliases(HtmlTextOutput htmlOut, Set<String> methodAliases) {
+ String curLine;
+ if (methodAliases.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ curLine = "<aliases>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+
+ for (String methodAlias : methodAliases) {
+ curLine = "<alias jsName=\"" + methodAlias + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (methodAliases.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</aliases>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+ }
+
+ private void emitClasses(HtmlTextOutput htmlOut,
+ SortedMap<String, Set<ClassMember>> packageToClasses, String packageName) {
+ String curLine;
+ /**
+ * sort the classes alphabetically
+ */
+ TreeMap<String, ClassMember> sortedClasses = new TreeMap<String, ClassMember>();
+ for (ClassMember classMember : packageToClasses.get(packageName)) {
+ String className = classMember.getSourceName();
+ sortedClasses.put(className, classMember);
+ }
+
+ for (String className : sortedClasses.keySet()) {
+ ClassMember classMember = sortedClasses.get(className);
+ curLine = "<class id=\"" + className + "\" ";
+ htmlOut.printRaw(curLine);
+
+ String jsName = classMember.getJsName();
+ String name = className.substring(className.lastIndexOf('.') + 1);
+ curLine = "jsName=\"" + jsName + "\" name=\"" + name + "\">";
+
+ if (jsName == null) {
+ curLine = "name=\"" + name + "\">";
+ }
+
+ emitOverrides(htmlOut, curLine, classMember);
+ emitDependencies(htmlOut, classMember);
+ emitMethods(htmlOut, classMember);
+ emitFields(htmlOut, classMember);
+
+ curLine = "</class>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ }
+
+ private void emitDependencies(HtmlTextOutput htmlOut, ClassMember classMember) {
+ String curLine;
+ Set<Member> dependencies = classMember.getDependencies();
+ if (dependencies.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ curLine = "<depends>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ for (Member dependency : dependencies) {
+ curLine = "<on idref=\"" + dependency.getSourceName() + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (dependencies.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</depends>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+ }
+
+ private void emitFields(HtmlTextOutput htmlOut, ClassMember classMember) {
+ String curLine;
+ Set<FieldMember> fields = classMember.getFields();
+ if (fields.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ for (FieldMember field : fields) {
+ curLine = "<field id=\"" + field.getSourceName() + "\" jsName=\""
+ + field.getJsName() + "\"/>";
+ String curJsName = field.getJsName();
+ if (curJsName == null) {
+ curLine = "<field id=\"" + field.getSourceName() + "\"/>";
+ }
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (fields.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+ }
+
+ private void emitFunctions(CompilationAnalysis report, HtmlTextOutput htmlOut) {
+ String curLine;
+
+ Set<FunctionMember> functions = report.getFunctions();
+ for (FunctionMember function : functions) {
+ curLine = "<function ";
+ htmlOut.printRaw(curLine);
+
+ String sourceName = function.getSourceName();
+ String jsName = function.getJsName();
+ Set<Member> dependencies = function.getDependencies();
+ if (dependencies.size() == 0) {
+ curLine = "id=\"" + sourceName + "\" jsName=\"" + jsName + "\"/>";
+ if (jsName == null) {
+ curLine = "id=\"" + sourceName + "\"/>";
+ }
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ } else {
+ curLine = "id=\"" + sourceName + "\" jsName=\"" + jsName + "\">";
+ if (jsName == null) {
+ curLine = "id=\"" + sourceName + "\">";
+ }
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ curLine = "<depends>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ for (Member dependency : dependencies) {
+ curLine = "<on idref=\"" + dependency.getSourceName() + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (dependencies.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</depends>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</function>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ }
+ }
+
+ private void emitJs(CompilationAnalysis report, HtmlTextOutput htmlOut,
+ Map<Story, Integer> storyIds) {
+
+ String curLine;
+ int fragment = 0;
+ for (String contents : report.getCompilationResult().getJavaScript()) {
+ curLine = "<js fragment=\"" + fragment + "\">";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ for (Snippet snippet : report.getSnippets(fragment)) {
+ Range range = snippet.getRange();
+ Story story = snippet.getStory();
+ assert storyIds.containsKey(story);
+ int storyId = storyIds.get(story);
+
+ String jsCode = contents.substring(range.getStart(), range.getEnd());
+ jsCode = escapeXml(jsCode);
+ if ((jsCode.length() == 0) || (jsCode.compareTo("\n") == 0)) {
+ curLine = "<storyref idref=\"story" + Integer.toString(storyId)
+ + "\"/>";
+ } else {
+ curLine = "<storyref idref=\"story" + Integer.toString(storyId)
+ + "\">" + jsCode + "</storyref>";
+ }
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</js>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ fragment++;
+ }
+ }
+
+ private SyntheticArtifact emitManifest(TreeLogger logger,
+ ArtifactSet artifacts,
+ SortedMap<CompilationResult, String> partialPathsByResult,
+ boolean compress) throws UnableToCompleteException, IOException {
+
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ OutputStreamWriter out;
+ try {
+ out = new OutputStreamWriter(compress ? new GZIPOutputStream(bytes)
+ : bytes);
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to set up gzip stream", e);
+ throw new UnableToCompleteException();
+ }
+ PrintWriter pw = new PrintWriter(out);
+ HtmlTextOutput htmlOut = new HtmlTextOutput(pw, false);
+
+ String curLine = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ curLine = "<soyc-manifest>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ for (Map.Entry<CompilationResult, String> entry : partialPathsByResult.entrySet()) {
+ curLine = "<report href=\"" + entry.getValue() + "\">";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ for (Map<SelectionProperty, String> map : entry.getKey().getPropertyMap()) {
+
+ if (map.size() > 0) {
+ curLine = "<permutation>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ } else {
+ curLine = "<permutation/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ for (Map.Entry<SelectionProperty, String> propertyEntry : map.entrySet()) {
+ curLine = "<property name=\"" + propertyEntry.getKey().getName()
+ + "\" value=\"" + propertyEntry.getValue() + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (map.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</permutation>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ }
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</report>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</soyc-manifest>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+
+ pw.close();
+ Utility.close(out);
+ SyntheticArtifact toReturn = emitBytes(logger, bytes.toByteArray(),
+ "manifest.xml");
+
+ return toReturn;
+ }
+
+ private void emitMembers(CompilationAnalysis report, HtmlTextOutput htmlOut) {
+
+ String curLine = "<members>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ SortedMap<String, Set<ClassMember>> packageToClasses = new TreeMap<String, Set<ClassMember>>();
+
+ emitPackages(report, htmlOut, packageToClasses);
+ emitFunctions(report, htmlOut);
+
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ curLine = "</members>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+
+ private void emitMethodDependencies(HtmlTextOutput htmlOut,
+ Set<Member> methodDependencies) {
+ String curLine;
+ if (methodDependencies.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ curLine = "<depends>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ for (Member methodDependency : methodDependencies) {
+ curLine = "<on idref=\"" + methodDependency.getSourceName() + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</depends>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+ }
+
+ private void emitMethodOverrides(HtmlTextOutput htmlOut,
+ Set<MethodMember> methodOverrides) {
+ String curLine;
+ if (methodOverrides.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ curLine = "<override>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ for (MethodMember overrideMethodMember : methodOverrides) {
+ curLine = "<of idref=\"" + overrideMethodMember.getSourceName() + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (methodOverrides.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</override>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+ }
+
+ private void emitMethods(HtmlTextOutput htmlOut, ClassMember classMember) {
+ String curLine;
+ Set<MethodMember> methods = classMember.getMethods();
+ if (methods.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ for (MethodMember method : methods) {
+ curLine = "<method ";
+ htmlOut.printRaw(curLine);
+
+ String jsAtt = " jsName=\"" + method.getJsName() + "\"";
+ String curJsName = method.getJsName();
+
+ if (curJsName == null) {
+ jsAtt = "";
+ }
+
+ Set<String> methodAliases = method.getJsAliases();
+ Set<MethodMember> methodOverrides = method.getOverrides();
+ Set<Member> methodDependencies = method.getDependencies();
+
+ if ((methodOverrides.size() > 0) || (methodDependencies.size() > 0)
+ || (methodAliases.size() > 0)) {
+ curLine = "id=\"" + method.getSourceName() + "\"" + jsAtt + ">";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ } else {
+ curLine = "id=\"" + method.getSourceName() + "\"" + jsAtt + "/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+
+ emitAliases(htmlOut, methodAliases);
+ emitMethodOverrides(htmlOut, methodOverrides);
+ emitMethodDependencies(htmlOut, methodDependencies);
+
+ if ((methodOverrides.size() > 0) || (methodDependencies.size() > 0)
+ || (methodAliases.size() > 0)) {
+ curLine = "</method>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ }
+
+ if (methods.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+ }
+
+ private void emitOverrides(HtmlTextOutput htmlOut, String curLine,
+ ClassMember classMember) {
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ Set<ClassMember> overrides = classMember.getOverrides();
+ if (overrides.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ curLine = "<override>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ for (ClassMember overrideClassMember : overrides) {
+ curLine = "<of idref=\"" + overrideClassMember.getSourceName() + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (overrides.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</override>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+ }
+
+ private void emitPackages(CompilationAnalysis report, HtmlTextOutput htmlOut,
+ SortedMap<String, Set<ClassMember>> packageToClasses) {
+
+ String curLine;
+ for (ClassMember classMember : report.getClasses()) {
+ String packageName = classMember.getPackage();
+ if (packageToClasses.containsKey(packageName)) {
+ packageToClasses.get(packageName).add(classMember);
+ } else {
+ Set<ClassMember> insertSet = new HashSet<ClassMember>();
+ insertSet.add(classMember);
+ packageToClasses.put(packageName, insertSet);
+ }
+ }
+
+ for (String packageName : packageToClasses.keySet()) {
+
+ curLine = "<package id=\"" + packageName + "\">";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+
+ if (packageToClasses.get(packageName).size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ emitClasses(htmlOut, packageToClasses, packageName);
+ if (packageToClasses.get(packageName).size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+
+ curLine = "</package>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ }
+
+ private SyntheticArtifact emitReport(TreeLogger logger,
+ CompilationAnalysis report, String partialPath, boolean compress)
+ throws UnableToCompleteException, IOException {
+
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ OutputStreamWriter out;
+ try {
+ out = new OutputStreamWriter(compress ? new GZIPOutputStream(bytes)
+ : bytes);
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to set up gzip stream", e);
+ throw new UnableToCompleteException();
+ }
+ PrintWriter pw = new PrintWriter(out);
+ HtmlTextOutput htmlOut = new HtmlTextOutput(pw, false);
+
+ String curLine = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ curLine = "<soyc>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ Map<Integer, String> splitPointMap = new TreeMap<Integer, String>(
+ report.getSplitPointMap());
+ if (splitPointMap.size() > 0) {
+ curLine = "<splitpoints>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ for (Integer splitPointCount : splitPointMap.keySet()) {
+ curLine = "<splitpoint id=\"" + splitPointCount + "\" location=\""
+ + splitPointMap.get(splitPointCount) + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ curLine = "</splitpoints>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+
+ emitMembers(report, htmlOut);
+ Map<Story, Integer> storyIds = emitStories(report, htmlOut);
+ emitJs(report, htmlOut, storyIds);
+
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ curLine = "</soyc>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+
+ pw.close();
+ Utility.close(out);
+ SyntheticArtifact toReturn = emitBytes(logger, bytes.toByteArray(),
+ partialPath);
+
+ return toReturn;
+ }
+
+ private Map<Story, Integer> emitStories(CompilationAnalysis report,
+ HtmlTextOutput htmlOut) {
+
+ String curLine;
+ Map<Story, Integer> storyIds = new HashMap<Story, Integer>();
+ Set<Story> stories = report.getStories();
+ curLine = "<stories>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+
+ if (stories.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ for (Story story : stories) {
+
+ int storyNum = storyIds.size();
+ storyIds.put(story, storyNum);
+
+ curLine = "<story id=\"story" + Integer.toString(storyNum) + "\"";
+ if (story.getLiteralTypeName() != null) {
+ curLine = curLine + " literal=\"" + story.getLiteralTypeName() + "\"";
+ }
+ curLine = curLine + ">";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+
+ Set<Origin> origins = story.getSourceOrigin();
+ if (origins.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ curLine = "<origins>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ for (Origin origin : origins) {
+ curLine = "<origin lineNumber=\""
+ + Integer.toString(origin.getLineNumber()) + "\" location=\""
+ + origin.getLocation() + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (origins.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</origins>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+
+ Set<Member> correlations = story.getMembers();
+ if (correlations.size() > 0) {
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+
+ curLine = "<correlations>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+
+ htmlOut.indentIn();
+ htmlOut.indentIn();
+ }
+ for (Member correlation : correlations) {
+ curLine = "<by idref=\"" + correlation.getSourceName() + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (correlations.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+
+ curLine = "</correlations>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+
+ curLine = "</story>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+ if (stories.size() > 0) {
+ htmlOut.indentOut();
+ htmlOut.indentOut();
+ }
+ curLine = "</stories>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+
+ return storyIds;
+ }
+
+ private void initialize(TreeLogger logger) throws UnableToCompleteException {
+ logger = logger.branch(TreeLogger.SPAM, "Initializing");
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/ArgHandlerOutDirDeprecated.java b/dev/core/src/com/google/gwt/dev/ArgHandlerOutDirDeprecated.java
new file mode 100644
index 0000000..b9130a3
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/ArgHandlerOutDirDeprecated.java
@@ -0,0 +1,50 @@
+/*
+ * 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.OptionOutDir;
+import com.google.gwt.util.tools.ArgHandlerOutDir;
+
+import java.io.File;
+
+/**
+ * Deprecated handler for -out options.
+ */
+@Deprecated
+public class ArgHandlerOutDirDeprecated extends ArgHandlerOutDir {
+
+ OptionOutDir option;
+
+ public ArgHandlerOutDirDeprecated(OptionOutDir option) {
+ this.option = option;
+ }
+
+ @Override
+ public String getPurpose() {
+ return super.getPurpose() + " (deprecated)";
+ }
+
+ @Override
+ public boolean isUndocumented() {
+ return true;
+ }
+
+ @Override
+ public void setDir(File dir) {
+ option.setOutDir(dir);
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/CompilePerms.java b/dev/core/src/com/google/gwt/dev/CompilePerms.java
index 87f4b3a..5efa683 100644
--- a/dev/core/src/com/google/gwt/dev/CompilePerms.java
+++ b/dev/core/src/com/google/gwt/dev/CompilePerms.java
@@ -20,11 +20,14 @@
import com.google.gwt.dev.CompileTaskRunner.CompileTask;
import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
import com.google.gwt.dev.jjs.UnifiedAst;
+import com.google.gwt.dev.util.FileBackedObject;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerLocalWorkers;
import com.google.gwt.util.tools.ArgHandlerString;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -178,20 +181,16 @@
public static PermutationResult compile(TreeLogger logger,
Permutation permutation, UnifiedAst unifiedAst)
throws UnableToCompleteException {
- final String js = JavaToJavaScriptCompiler.compilePermutation(logger,
- unifiedAst, permutation.getRebindAnswers());
- return new PermutationResult() {
- public String getJs() {
- return js;
- }
- };
+ return JavaToJavaScriptCompiler.compilePermutation(logger, unifiedAst,
+ permutation.getRebindAnswers());
}
/**
* Compile multiple permutations.
*/
public static void compile(TreeLogger logger, Precompilation precompilation,
- Permutation[] perms, int localWorkers, File[] resultFiles)
+ Permutation[] perms, int localWorkers,
+ List<FileBackedObject<PermutationResult>> resultFiles)
throws UnableToCompleteException {
final TreeLogger branch = logger.branch(TreeLogger.INFO, "Compiling "
+ perms.length + " permutations");
@@ -223,12 +222,16 @@
System.exit(1);
}
- public static File[] makeResultFiles(File compilerWorkDir, Permutation[] perms) {
- File[] resultFiles = new File[perms.length];
+ public static List<FileBackedObject<PermutationResult>> makeResultFiles(
+ File compilerWorkDir, Permutation[] perms) {
+ List<FileBackedObject<PermutationResult>> toReturn = new ArrayList<FileBackedObject<PermutationResult>>(
+ perms.length);
for (int i = 0; i < perms.length; ++i) {
- resultFiles[i] = makePermFilename(compilerWorkDir, perms[i].getId());
+ File f = makePermFilename(compilerWorkDir, perms[i].getId());
+ toReturn.add(new FileBackedObject<PermutationResult>(
+ PermutationResult.class, f));
}
- return resultFiles;
+ return toReturn;
}
/**
@@ -289,7 +292,8 @@
}
}
- File[] resultFiles = makeResultFiles(compilerWorkDir, subPerms);
+ List<FileBackedObject<PermutationResult>> resultFiles = makeResultFiles(
+ compilerWorkDir, subPerms);
compile(logger, precompilation, subPerms, options.getLocalWorkers(),
resultFiles);
}
diff --git a/dev/core/src/com/google/gwt/dev/CompilePermsServer.java b/dev/core/src/com/google/gwt/dev/CompilePermsServer.java
index 3f080f8..93111de 100644
--- a/dev/core/src/com/google/gwt/dev/CompilePermsServer.java
+++ b/dev/core/src/com/google/gwt/dev/CompilePermsServer.java
@@ -19,6 +19,7 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.dev.jjs.UnifiedAst;
+import com.google.gwt.dev.util.FileBackedObject;
import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
import com.google.gwt.dev.util.arg.OptionLogLevel;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
@@ -288,6 +289,7 @@
static void compilePermutation(TreeLogger logger, UnifiedAst ast,
ObjectInputStream in, ObjectOutputStream out)
throws ClassNotFoundException, IOException {
+ FileBackedObject<PermutationResult> resultFile = (FileBackedObject<PermutationResult>) in.readObject();
Permutation p = (Permutation) in.readObject();
logger.log(TreeLogger.SPAM, "Permutation read");
@@ -295,10 +297,8 @@
try {
PermutationResult result = CompilePerms.compile(logger.branch(
TreeLogger.DEBUG, "Compiling"), p, ast);
- out.writeObject(result);
- out.flush();
+ resultFile.set(logger, result);
logger.log(TreeLogger.DEBUG, "Successfully compiled permutation");
- return;
} catch (UnableToCompleteException e) {
caught = e;
} catch (Throwable e) {
@@ -306,6 +306,7 @@
caught = e;
}
+ // Might send a placeholder null indicating no Throwable.
out.writeObject(caught);
out.flush();
logger.log(TreeLogger.SPAM, "Sent result");
diff --git a/dev/core/src/com/google/gwt/dev/Compiler.java b/dev/core/src/com/google/gwt/dev/Compiler.java
index 6778230..ffac60d 100644
--- a/dev/core/src/com/google/gwt/dev/Compiler.java
+++ b/dev/core/src/com/google/gwt/dev/Compiler.java
@@ -17,14 +17,17 @@
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.Link.LinkOptionsImpl;
import com.google.gwt.dev.Precompile.PrecompileOptionsImpl;
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.CheckForUpdates;
import com.google.gwt.dev.shell.PlatformSpecific;
import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
+import com.google.gwt.dev.util.FileBackedObject;
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
@@ -35,6 +38,7 @@
import java.io.File;
import java.io.IOException;
+import java.util.List;
import java.util.concurrent.FutureTask;
/**
@@ -88,6 +92,11 @@
return localWorkers;
}
+ @Deprecated
+ public File getOutDir() {
+ return linkOptions.getOutDir();
+ }
+
public File getWarDir() {
return linkOptions.getWarDir();
}
@@ -100,6 +109,11 @@
this.localWorkers = localWorkers;
}
+ @Deprecated
+ public void setOutDir(File outDir) {
+ linkOptions.setOutDir(outDir);
+ }
+
public void setWarDir(File outDir) {
linkOptions.setWarDir(outDir);
}
@@ -118,8 +132,8 @@
public boolean run(TreeLogger logger) throws UnableToCompleteException {
FutureTask<UpdateResult> updater = null;
if (!options.isUpdateCheckDisabled()) {
- updater = PlatformSpecific.checkForUpdatesInBackgroundThread(logger,
- CheckForUpdates.ONE_DAY);
+ updater = PlatformSpecific.checkForUpdatesInBackgroundThread(
+ logger, CheckForUpdates.ONE_DAY);
}
boolean success = new Compiler(options).run(logger);
if (success) {
@@ -175,14 +189,20 @@
}
Permutation[] allPerms = precompilation.getPermutations();
- File[] resultFiles = CompilePerms.makeResultFiles(compilerWorkDir,
- allPerms);
+ List<FileBackedObject<PermutationResult>> resultFiles = CompilePerms.makeResultFiles(
+ options.getCompilerWorkDir(moduleName), allPerms);
CompilePerms.compile(logger, precompilation, allPerms,
options.getLocalWorkers(), resultFiles);
+ ArtifactSet generatedArtifacts = precompilation.getGeneratedArtifacts();
+ JJSOptions precompileOptions = precompilation.getUnifiedAst().getOptions();
+
+ precompilation = null; // No longer needed, so save the memory
+
Link.link(logger.branch(TreeLogger.INFO, "Linking into "
- + options.getWarDir().getPath()), module, precompilation,
- resultFiles, options.getWarDir(), options.getExtraDir());
+ + options.getWarDir().getPath()), module, generatedArtifacts,
+ allPerms, resultFiles, options.getWarDir(),
+ options.getExtraDir(), precompileOptions);
long compileDone = System.currentTimeMillis();
long delta = compileDone - compileStart;
diff --git a/dev/core/src/com/google/gwt/dev/ExternalPermutationWorkerFactory.java b/dev/core/src/com/google/gwt/dev/ExternalPermutationWorkerFactory.java
index a039d07..2b0790e 100644
--- a/dev/core/src/com/google/gwt/dev/ExternalPermutationWorkerFactory.java
+++ b/dev/core/src/com/google/gwt/dev/ExternalPermutationWorkerFactory.java
@@ -18,6 +18,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.jjs.UnifiedAst;
+import com.google.gwt.dev.util.FileBackedObject;
import com.google.gwt.dev.util.Util;
import java.io.BufferedReader;
@@ -99,7 +100,8 @@
this.serverSocket = sock;
}
- public PermutationResult compile(TreeLogger logger, Permutation permutation)
+ public void compile(TreeLogger logger, Permutation permutation,
+ FileBackedObject<PermutationResult> resultFile)
throws TransientWorkerException, UnableToCompleteException {
// If we've just started, we need to get a connection from a subprocess
@@ -139,15 +141,15 @@
try {
out.writeBoolean(true);
+ out.writeObject(resultFile);
out.writeObject(permutation);
out.flush();
- Object result = in.readObject();
- if (result instanceof Throwable) {
- Throwable t = (Throwable) result;
+
+ Throwable t = (Throwable) in.readObject();
+ if (t != null) {
logger.log(TreeLogger.ERROR, "Error from external worker", t);
throw new UnableToCompleteException();
}
- return (PermutationResult) result;
} catch (IOException e) {
logger.log(TreeLogger.WARN, "Lost communication with remote process", e);
throw new TransientWorkerException(
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index 7cdcf18..5f9e30e 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -17,22 +17,27 @@
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.Precompile.PrecompileOptionsImpl;
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.CheckForUpdates;
import com.google.gwt.dev.shell.PlatformSpecific;
import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
+import com.google.gwt.dev.util.FileBackedObject;
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerLocalWorkers;
import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
+import com.google.gwt.dev.util.arg.ArgHandlerSoyc;
import com.google.gwt.dev.util.arg.ArgHandlerWorkDirOptional;
import com.google.gwt.util.tools.Utility;
import java.io.File;
import java.io.IOException;
+import java.util.List;
import java.util.concurrent.FutureTask;
/**
@@ -53,6 +58,7 @@
registerHandler(new ArgHandlerWorkDirOptional(options));
registerHandler(new ArgHandlerLocalWorkers(options));
+ registerHandler(new ArgHandlerSoyc(options));
}
@Override
@@ -113,8 +119,8 @@
public boolean run(TreeLogger logger) throws UnableToCompleteException {
FutureTask<UpdateResult> updater = null;
if (!options.isUpdateCheckDisabled()) {
- updater = PlatformSpecific.checkForUpdatesInBackgroundThread(logger,
- CheckForUpdates.ONE_DAY);
+ updater = PlatformSpecific.checkForUpdatesInBackgroundThread(
+ logger, CheckForUpdates.ONE_DAY);
}
boolean success = new GWTCompiler(options).run(logger);
if (success) {
@@ -183,16 +189,20 @@
if (precompilation == null) {
return false;
}
-
Permutation[] allPerms = precompilation.getPermutations();
- File[] resultFiles = CompilePerms.makeResultFiles(compilerWorkDir,
- allPerms);
+ List<FileBackedObject<PermutationResult>> resultFiles = CompilePerms.makeResultFiles(
+ options.getCompilerWorkDir(moduleName), allPerms);
CompilePerms.compile(logger, precompilation, allPerms,
options.getLocalWorkers(), resultFiles);
+ ArtifactSet generatedArtifacts = precompilation.getGeneratedArtifacts();
+ JJSOptions precompileOptions = precompilation.getUnifiedAst().getOptions();
+
+ precompilation = null; // No longer needed, so save the memory
+
Link.legacyLink(logger.branch(TreeLogger.INFO, "Linking into "
- + options.getOutDir().getPath()), module, precompilation,
- resultFiles, options.getOutDir());
+ + options.getOutDir().getPath()), module, generatedArtifacts,
+ allPerms, resultFiles, options.getOutDir(), precompileOptions);
long compileDone = System.currentTimeMillis();
long delta = compileDone - compileStart;
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 05b9b9e..425ca1e 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -112,6 +112,9 @@
@Override
public File getWorkDir() {
+ if (System.getProperty("com.google.gwt.shell.outdir") != null) {
+ return new File(System.getProperty("com.google.gwt.shell.outdir"));
+ }
return new File(getOutDir(), ".gwt-tmp");
}
@@ -136,6 +139,13 @@
*/
GWTShell gwtShell = new GWTShell();
ArgProcessor argProcessor = new ArgProcessor(gwtShell.options, false, false);
+
+ // deprecated old property way to set outputs
+ if (System.getProperty("com.google.gwt.shell.outdir") != null) {
+ gwtShell.options.setOutDir(new File(System.getProperty("com.google.gwt.shell.outdir")));
+ gwtShell.options.setWorkDir(new File(System.getProperty("com.google.gwt.shell.outdir")));
+ }
+
if (argProcessor.processArgs(args)) {
gwtShell.run();
// Exit w/ success code.
diff --git a/dev/core/src/com/google/gwt/dev/HostedMode.java b/dev/core/src/com/google/gwt/dev/HostedMode.java
index 18a3448..0773528 100644
--- a/dev/core/src/com/google/gwt/dev/HostedMode.java
+++ b/dev/core/src/com/google/gwt/dev/HostedMode.java
@@ -176,6 +176,7 @@
implements HostedModeOptions {
private File extraDir;
private int localWorkers;
+ private File outDir;
private ServletContainerLauncher scl;
private File warDir;
@@ -187,6 +188,11 @@
return localWorkers;
}
+ @Deprecated
+ public File getOutDir() {
+ return outDir;
+ }
+
public ServletContainerLauncher getServletContainerLauncher() {
return scl;
}
@@ -211,6 +217,11 @@
this.localWorkers = localWorkers;
}
+ @Deprecated
+ public void setOutDir(File outDir) {
+ this.outDir = outDir;
+ }
+
public void setServletContainerLauncher(ServletContainerLauncher scl) {
this.scl = scl;
}
diff --git a/dev/core/src/com/google/gwt/dev/HostedModeBase.java b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
index b341bcf..9f983a3 100644
--- a/dev/core/src/com/google/gwt/dev/HostedModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
@@ -33,6 +33,8 @@
import com.google.gwt.dev.shell.ShellModuleSpaceHost;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
+import com.google.gwt.dev.util.arg.ArgHandlerDisableClassMetadata;
+import com.google.gwt.dev.util.arg.ArgHandlerDraftCompile;
import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
@@ -319,6 +321,8 @@
registerHandler(new ArgHandlerScriptStyle(options));
registerHandler(new ArgHandlerEnableAssertions(options));
registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
+ registerHandler(new ArgHandlerDisableClassMetadata(options));
+ registerHandler(new ArgHandlerDraftCompile(options));
}
}
diff --git a/dev/core/src/com/google/gwt/dev/Link.java b/dev/core/src/com/google/gwt/dev/Link.java
index 39b8ec4..bd03f86 100644
--- a/dev/core/src/com/google/gwt/dev/Link.java
+++ b/dev/core/src/com/google/gwt/dev/Link.java
@@ -26,6 +26,8 @@
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.jjs.JJSOptions;
+import com.google.gwt.dev.util.FileBackedObject;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
import com.google.gwt.dev.util.arg.ArgHandlerWarDir;
@@ -34,7 +36,9 @@
import com.google.gwt.dev.util.arg.OptionWarDir;
import java.io.File;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -52,14 +56,16 @@
* Options for Link.
*/
public interface LinkOptions extends CompileTaskOptions, OptionExtraDir,
- OptionWarDir {
+ OptionWarDir, LegacyLinkOptions {
}
static class ArgProcessor extends CompileArgProcessor {
+ @SuppressWarnings("deprecation")
public ArgProcessor(LinkOptions options) {
super(options);
registerHandler(new ArgHandlerExtraDir(options));
registerHandler(new ArgHandlerWarDir(options));
+ registerHandler(new ArgHandlerOutDirDeprecated(options));
}
@Override
@@ -76,6 +82,7 @@
private File extraDir;
private File warDir;
+ private File outDir;
public LinkOptionsImpl() {
}
@@ -88,12 +95,18 @@
super.copyFrom(other);
setExtraDir(other.getExtraDir());
setWarDir(other.getWarDir());
+ setOutDir(other.getOutDir());
}
public File getExtraDir() {
return extraDir;
}
+ @Deprecated
+ public File getOutDir() {
+ return outDir;
+ }
+
public File getWarDir() {
return warDir;
}
@@ -102,36 +115,36 @@
this.extraDir = extraDir;
}
+ @Deprecated
+ public void setOutDir(File outDir) {
+ this.outDir = outDir;
+ }
+
public void setWarDir(File warDir) {
this.warDir = warDir;
}
}
public static void legacyLink(TreeLogger logger, ModuleDef module,
- Precompilation precompilation, File[] resultFiles, File outDir)
- throws UnableToCompleteException {
+ ArtifactSet generatedArtifacts, Permutation[] permutations,
+ List<FileBackedObject<PermutationResult>> resultFiles, File outDir,
+ JJSOptions precompileOptions) throws UnableToCompleteException {
StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
- module, precompilation.getUnifiedAst().getOptions());
- ArtifactSet artifacts = doLink(logger, linkerContext, precompilation,
- resultFiles);
+ module, precompileOptions);
+ ArtifactSet artifacts = doLink(logger, linkerContext, generatedArtifacts,
+ permutations, resultFiles);
doProduceLegacyOutput(logger, artifacts, linkerContext, module, outDir);
}
- public static ArtifactSet link(TreeLogger logger, ModuleDef module,
- Precompilation precompilation, File[] resultFiles)
+ public static void link(TreeLogger logger, ModuleDef module,
+ ArtifactSet generatedArtifacts, Permutation[] permutations,
+ List<FileBackedObject<PermutationResult>> resultFiles, File outDir,
+ File extrasDir, JJSOptions precompileOptions)
throws UnableToCompleteException {
StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
- module, precompilation.getUnifiedAst().getOptions());
- return doLink(logger, linkerContext, precompilation, resultFiles);
- }
-
- public static void link(TreeLogger logger, ModuleDef module,
- Precompilation precompilation, File[] resultFiles, File outDir,
- File extrasDir) throws UnableToCompleteException {
- StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
- module, precompilation.getUnifiedAst().getOptions());
- ArtifactSet artifacts = doLink(logger, linkerContext, precompilation,
- resultFiles);
+ module, precompileOptions);
+ ArtifactSet artifacts = doLink(logger, linkerContext, generatedArtifacts,
+ permutations, resultFiles);
doProduceOutput(logger, artifacts, linkerContext, module, outDir, extrasDir);
}
@@ -143,6 +156,7 @@
* still implementation-dependent.
*/
final LinkOptions options = new LinkOptionsImpl();
+
if (new ArgProcessor(options).processArgs(args)) {
CompileTask task = new CompileTask() {
public boolean run(TreeLogger logger) throws UnableToCompleteException {
@@ -159,19 +173,19 @@
}
private static ArtifactSet doLink(TreeLogger logger,
- StandardLinkerContext linkerContext, Precompilation precompilation,
- File[] resultFiles) throws UnableToCompleteException {
- Permutation[] perms = precompilation.getPermutations();
- if (perms.length != resultFiles.length) {
+ StandardLinkerContext linkerContext, ArtifactSet generatedArtifacts,
+ Permutation[] perms, List<FileBackedObject<PermutationResult>> resultFiles)
+ throws UnableToCompleteException {
+ if (perms.length != resultFiles.size()) {
throw new IllegalArgumentException(
"Mismatched resultFiles.length and permutation count");
}
for (int i = 0; i < perms.length; ++i) {
- finishPermuation(logger, perms[i], resultFiles[i], linkerContext);
+ finishPermuation(logger, perms[i], resultFiles.get(i), linkerContext);
}
- linkerContext.addOrReplaceArtifacts(precompilation.getGeneratedArtifacts());
+ linkerContext.addOrReplaceArtifacts(generatedArtifacts);
return linkerContext.invokeLink(logger);
}
@@ -204,10 +218,10 @@
}
private static void finishPermuation(TreeLogger logger, Permutation perm,
- File jsFile, StandardLinkerContext linkerContext)
- throws UnableToCompleteException {
+ FileBackedObject<PermutationResult> resultFile,
+ StandardLinkerContext linkerContext) throws UnableToCompleteException {
StandardCompilationResult compilation = linkerContext.getCompilation(
- logger, jsFile);
+ logger, resultFile);
StaticPropertyOracle[] propOracles = perm.getPropertyOracles();
for (StaticPropertyOracle propOracle : propOracles) {
BindingProperty[] orderedProps = propOracle.getOrderedProps();
@@ -239,7 +253,8 @@
File compilerWorkDir = options.getCompilerWorkDir(moduleName);
ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, moduleName);
- File precompilationFile = new File(compilerWorkDir,
+ File precompilationFile = new File(
+ options.getCompilerWorkDir(moduleName),
Precompile.PRECOMPILATION_FILENAME);
if (!precompilationFile.exists()) {
logger.log(TreeLogger.ERROR, "File not found '"
@@ -258,27 +273,41 @@
return false;
}
Permutation[] perms = precompilation.getPermutations();
- File[] resultFiles = new File[perms.length];
+ ArtifactSet generatedArtifacts = precompilation.getGeneratedArtifacts();
+ JJSOptions precompileOptions = precompilation.getUnifiedAst().getOptions();
+
+ precompilation = null; // No longer needed, and it needs a lot of memory
+
+ List<FileBackedObject<PermutationResult>> resultFiles = new ArrayList<FileBackedObject<PermutationResult>>(
+ perms.length);
for (int i = 0; i < perms.length; ++i) {
- resultFiles[i] = CompilePerms.makePermFilename(compilerWorkDir,
+ File f = CompilePerms.makePermFilename(compilerWorkDir,
perms[i].getId());
- if (!resultFiles[i].exists()) {
+ if (!f.exists()) {
logger.log(TreeLogger.ERROR, "File not found '"
+ precompilationFile.getAbsolutePath()
+ "'; please compile all permutations");
return false;
}
+ resultFiles.add(new FileBackedObject<PermutationResult>(
+ PermutationResult.class, f));
}
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,
- resultFiles);
+ module, precompileOptions);
- doProduceOutput(branch, artifacts, linkerContext, module,
- options.getWarDir(), options.getExtraDir());
+ ArtifactSet artifacts = doLink(branch, linkerContext, generatedArtifacts,
+ perms, resultFiles);
+
+ if (options.getOutDir() == null) {
+ doProduceOutput(branch, artifacts, linkerContext, module,
+ options.getWarDir(), options.getExtraDir());
+ } else {
+ doProduceLegacyOutput(branch, artifacts, linkerContext, module,
+ options.getOutDir());
+ }
}
return true;
}
diff --git a/dev/core/src/com/google/gwt/dev/PermutationCompiler.java b/dev/core/src/com/google/gwt/dev/PermutationCompiler.java
deleted file mode 100644
index 3b6f85d..0000000
--- a/dev/core/src/com/google/gwt/dev/PermutationCompiler.java
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.dev;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.cfg.BindingProperty;
-import com.google.gwt.dev.cfg.StaticPropertyOracle;
-import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
-import com.google.gwt.dev.jjs.UnifiedAst;
-import com.google.gwt.dev.util.PerfLogger;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Compiles a set of permutations, possibly in parallel in multiple threads.
- */
-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, int permNum, Throwable exception) {
- super(perm, permNum);
- this.exception = exception;
- }
-
- public Throwable getException() {
- return exception;
- }
- }
-
- /**
- * Represents the task of compiling a single permutation.
- */
- private static final class PermutationTask implements Callable<String> {
- private static void logProperties(TreeLogger logger,
- 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 UnifiedAst unifiedAst;
- private final TreeLogger logger;
- private final Permutation perm;
- private final int permNum;
-
- public PermutationTask(TreeLogger logger, UnifiedAst unifiedAst,
- Permutation perm, int permNum) {
- this.logger = logger;
- this.unifiedAst = unifiedAst;
- this.perm = perm;
- this.permNum = permNum;
- }
-
- public String call() throws Exception {
- PerfLogger.start("Permutation #" + permNum);
- try {
- 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;
- }
- }
-
- /**
- * Contains the results of an attempt to compile.
- */
- private abstract static class Result {
- private final Permutation perm;
- private final int permNum;
-
- public Result(Permutation perm, int permNum) {
- this.perm = perm;
- this.permNum = permNum;
- }
-
- public int getPermNum() {
- return permNum;
- }
-
- public Permutation getPermutation() {
- return perm;
- }
- }
-
- /**
- * A Result for a permutation that succeeded.
- */
- private static final class SuccessResult extends Result {
- private final String js;
-
- public SuccessResult(Permutation perm, int permNum, String js) {
- super(perm, permNum);
- this.js = js;
- }
-
- public String getJs() {
- return js;
- }
- }
-
- /**
- * Implements a memory-sensitive worker thread to compile permutations.
- */
- private class WorkerThread implements Runnable {
- private PermutationTask currentTask;
-
- private final Runnable outOfMemoryRetryAction = new Runnable() {
- public void run() {
- currentTask.logger.log(
- TreeLogger.WARN,
- "Not enough memory to run another concurrent permutation, reducing thread count; "
- + "increasing the amount of memory by using the -Xmx flag "
- + "at startup may result in faster compiles");
- tasks.add(currentTask);
- }
- };
-
- public void run() {
- try {
- while (true) {
- doTask();
- }
- } catch (ThreadDeath expected) {
- }
- }
-
- protected void doTask() throws ThreadDeath {
- currentTask = tasks.poll();
- if (currentTask == null) {
- // Nothing left to do.
- tryToExitNonFinalThread(null);
-
- // As the last thread, I must inform the main thread we're all done.
- exitFinalThread(new Runnable() {
- public void run() {
- results.add(FINISHED_RESULT);
- }
- });
- }
-
- boolean definitelyFinalThread = (threadCount.get() == 1);
- try {
- String result = currentTask.call();
- 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.
- currentTask.logger.log(TreeLogger.ERROR, "Out of memory", e);
- exitFinalThread(new Runnable() {
- public void run() {
- results.add(new FailedResult(currentTask.getPermutation(),
- currentTask.getPermNum(), new UnableToCompleteException()));
- }
- });
- }
-
- /*
- * Try the task again with fewer threads, it may not OOM this time.
- */
- tryToExitNonFinalThread(outOfMemoryRetryAction);
-
- /*
- * Okay, so we actually are the final thread. However, we weren't the
- * final thread at the beginning of the compilation, so it's possible
- * that a retry may now succeed with only one active thread. Let's
- * optimistically retry one last time, and if this doesn't work, it's a
- * hard failure.
- */
- outOfMemoryRetryAction.run();
- } catch (Throwable e) {
- // Unexpected error compiling, this is unrecoverable.
- results.add(new FailedResult(currentTask.getPermutation(),
- currentTask.getPermNum(), e));
- throw new ThreadDeath();
- }
- }
-
- private void exitFinalThread(Runnable actionOnExit) {
- boolean isFinalThread = threadCount.compareAndSet(1, 0);
- assert isFinalThread;
- if (actionOnExit != null) {
- actionOnExit.run();
- }
- throw new ThreadDeath();
- }
-
- /**
- * Exits this thread if and only if it's not the last running thread,
- * performing the specified action before terminating.
- *
- * @param actionOnExit
- */
- private void tryToExitNonFinalThread(Runnable actionOnExit) {
- int remainingThreads = threadCount.decrementAndGet();
- if (remainingThreads == 0) {
- // We are definitely the last thread.
- threadCount.incrementAndGet();
- return;
- }
-
- // We are definitely not the last thread, and have removed our count.
- if (actionOnExit != null) {
- actionOnExit.run();
- }
- throw new ThreadDeath();
- }
- }
-
- /**
- * A marker Result that tells the main thread all work is done.
- */
- private static final Result FINISHED_RESULT = new Result(null, -1) {
- };
-
- /**
- * A queue of results being sent from worker threads to the main thread.
- */
- protected final BlockingQueue<Result> results = new LinkedBlockingQueue<Result>();
-
- /**
- * A queue of tasks being sent to the worker threads.
- */
- protected final ConcurrentLinkedQueue<PermutationTask> tasks = new ConcurrentLinkedQueue<PermutationTask>();
-
- /**
- * Tracks the number of live worker threads.
- */
- protected final AtomicInteger threadCount = new AtomicInteger();
-
- private final TreeLogger logger;
-
- public PermutationCompiler(TreeLogger logger, UnifiedAst unifiedAst,
- Permutation[] perms, int[] permsToRun) {
- this.logger = logger;
- for (int permToRun : permsToRun) {
- tasks.add(new PermutationTask(logger, unifiedAst, perms[permToRun],
- permToRun));
- }
- }
-
- public void go(ResultsHandler handler) throws UnableToCompleteException {
- int initialThreadCount = computeInitialThreadCount();
- Thread[] workerThreads = new Thread[initialThreadCount];
- for (int i = 0; i < initialThreadCount; ++i) {
- workerThreads[i] = new Thread(new WorkerThread());
- }
- threadCount.set(initialThreadCount);
- for (Thread thread : workerThreads) {
- thread.start();
- }
- try {
- while (true) {
- Result result = results.take();
- if (result == FINISHED_RESULT) {
- assert threadCount.get() == 0;
- return;
- } else if (result instanceof SuccessResult) {
- 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());
- }
- // Allow GC.
- result = null;
- }
-
- } catch (InterruptedException e) {
- throw new RuntimeException("Unexpected interruption", e);
- } finally {
- for (Thread thread : workerThreads) {
- if (thread.isAlive()) {
- thread.interrupt();
- }
- }
- }
- }
-
- private int computeInitialThreadCount() {
- /*
- * Don't need more threads than the number of permutations.
- */
- int result = tasks.size();
-
- /*
- * Computation is mostly CPU bound, so don't use more threads than
- * processors.
- */
- result = Math.min(Runtime.getRuntime().availableProcessors(), result);
-
- /*
- * User-defined value caps.
- */
- result = Math.min(result, Integer.getInteger("gwt.jjs.maxThreads", 1));
-
- return result;
- }
-
- private UnableToCompleteException logAndTranslateException(Throwable e) {
- if (e instanceof UnableToCompleteException) {
- return (UnableToCompleteException) e;
- } else {
- logger.log(TreeLogger.ERROR, "Unexpected compiler failure", e);
- return new UnableToCompleteException();
- }
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/PermutationResult.java b/dev/core/src/com/google/gwt/dev/PermutationResult.java
index d0133ea..67e7da8 100644
--- a/dev/core/src/com/google/gwt/dev/PermutationResult.java
+++ b/dev/core/src/com/google/gwt/dev/PermutationResult.java
@@ -15,14 +15,28 @@
*/
package com.google.gwt.dev;
+import com.google.gwt.core.ext.linker.ArtifactSet;
+
import java.io.Serializable;
+import java.util.SortedMap;
/**
* An extensible return type for the results of compiling a single permutation.
*/
public interface PermutationResult extends Serializable {
/**
+ * Returns any Artifacts that may have been created as a result of compiling
+ * the permutation.
+ */
+ ArtifactSet getArtifacts();
+
+ /**
* The compiled JavaScript code.
*/
- String getJs();
+ String[] getJs();
+
+ /**
+ * The symbol map for the permutation.
+ */
+ SortedMap<String, String> getSymbolMap();
}
diff --git a/dev/core/src/com/google/gwt/dev/PermutationWorker.java b/dev/core/src/com/google/gwt/dev/PermutationWorker.java
index 26afa3d..124c497 100644
--- a/dev/core/src/com/google/gwt/dev/PermutationWorker.java
+++ b/dev/core/src/com/google/gwt/dev/PermutationWorker.java
@@ -17,6 +17,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.util.FileBackedObject;
/**
* Represents a facility that can compile an individual {@link Permutation}.
@@ -28,13 +29,15 @@
/**
* Compile a single permutation. The {@link com.google.gwt.dev.jjs.UnifiedAst}
* will have been provided to {@link PermutationWorkerFactory#getWorkers}
- * method.
+ * method. The compiled PermutationResult will be returned via the
+ * <code>resultFile</code> parameter.
*
* @throws TransientWorkerException if the Permutation should be tried again
* on another worker
* @throws UnableToCompleteException if the compile fails for any reason
*/
- PermutationResult compile(TreeLogger logger, Permutation permutation)
+ void compile(TreeLogger logger, Permutation permutation,
+ FileBackedObject<PermutationResult> resultFile)
throws TransientWorkerException, UnableToCompleteException;
/**
diff --git a/dev/core/src/com/google/gwt/dev/PermutationWorkerFactory.java b/dev/core/src/com/google/gwt/dev/PermutationWorkerFactory.java
index ef828ac..cc324c5 100644
--- a/dev/core/src/com/google/gwt/dev/PermutationWorkerFactory.java
+++ b/dev/core/src/com/google/gwt/dev/PermutationWorkerFactory.java
@@ -18,9 +18,8 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.jjs.UnifiedAst;
-import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.FileBackedObject;
-import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -43,8 +42,6 @@
*/
private static class Manager {
- private static final Work POISON_PILL = new Work(null, null, null);
-
private static enum Result {
SUCCESS, FAIL, WORKER_DEATH
}
@@ -69,8 +66,7 @@
}
TreeLogger logger = work.getLogger();
try {
- PermutationResult result = worker.compile(logger, work.getPerm());
- Util.writeObjectAsFile(logger, work.getResultFile(), result);
+ worker.compile(logger, work.getPerm(), work.getResultFile());
logger.log(TreeLogger.DEBUG, "Successfully compiled permutation");
resultsQueue.put(Result.SUCCESS);
} catch (TransientWorkerException e) {
@@ -97,6 +93,8 @@
}
}
+ private static final Work POISON_PILL = new Work(null, null, null);
+
public static void run(TreeLogger logger, List<Work> work,
List<PermutationWorker> workers) throws UnableToCompleteException {
new Manager().doRun(logger, work, workers);
@@ -178,9 +176,10 @@
private static class Work {
private final TreeLogger logger;
private final Permutation perm;
- private final File resultFile;
+ private final FileBackedObject<PermutationResult> resultFile;
- public Work(TreeLogger logger, Permutation perm, File resultFile) {
+ public Work(TreeLogger logger, Permutation perm,
+ FileBackedObject<PermutationResult> resultFile) {
this.logger = logger;
this.perm = perm;
this.resultFile = resultFile;
@@ -194,7 +193,7 @@
return perm;
}
- public File getResultFile() {
+ public FileBackedObject<PermutationResult> getResultFile() {
return resultFile;
}
}
@@ -219,7 +218,8 @@
* PermutationWorkersFactories.
*/
public static void compilePermutations(TreeLogger logger,
- Precompilation precompilation, int localWorkers, File[] resultFiles)
+ Precompilation precompilation, int localWorkers,
+ List<FileBackedObject<PermutationResult>> resultFiles)
throws UnableToCompleteException {
compilePermutations(logger, precompilation,
precompilation.getPermutations(), localWorkers, resultFiles);
@@ -240,8 +240,9 @@
*/
public static void compilePermutations(TreeLogger logger,
Precompilation precompilation, Permutation[] permutations,
- int localWorkers, File[] resultFiles) throws UnableToCompleteException {
- assert permutations.length == resultFiles.length;
+ int localWorkers, List<FileBackedObject<PermutationResult>> resultFiles)
+ throws UnableToCompleteException {
+ assert permutations.length == resultFiles.size();
assert Arrays.asList(precompilation.getPermutations()).containsAll(
Arrays.asList(permutations));
@@ -251,7 +252,7 @@
Permutation perm = permutations[i];
TreeLogger permLogger = logger.branch(TreeLogger.DEBUG,
"Worker permutation " + perm.getId() + " of " + permutations.length);
- work.add(new Work(permLogger, perm, resultFiles[i]));
+ work.add(new Work(permLogger, perm, resultFiles.get(i)));
}
// Create the workers.
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index 0b97f1e..b477267 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -36,6 +36,7 @@
import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
import com.google.gwt.dev.jjs.JsOutputOption;
import com.google.gwt.dev.jjs.UnifiedAst;
+import com.google.gwt.dev.jjs.impl.FragmentLoaderCreator;
import com.google.gwt.dev.shell.CheckForUpdates;
import com.google.gwt.dev.shell.PlatformSpecific;
import com.google.gwt.dev.shell.StandardRebindOracle;
@@ -43,6 +44,9 @@
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
+import com.google.gwt.dev.util.arg.ArgHandlerDisableClassMetadata;
+import com.google.gwt.dev.util.arg.ArgHandlerDisableRunAsync;
+import com.google.gwt.dev.util.arg.ArgHandlerDraftCompile;
import com.google.gwt.dev.util.arg.ArgHandlerDisableUpdateCheck;
import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
@@ -80,7 +84,10 @@
registerHandler(new ArgHandlerScriptStyle(options));
registerHandler(new ArgHandlerEnableAssertions(options));
registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
+ registerHandler(new ArgHandlerDisableClassMetadata(options));
registerHandler(new ArgHandlerValidateOnlyFlag(options));
+ registerHandler(new ArgHandlerDisableRunAsync(options));
+ registerHandler(new ArgHandlerDraftCompile(options));
registerHandler(new ArgHandlerDisableUpdateCheck(options));
}
@@ -126,10 +133,26 @@
return jjsOptions.isAggressivelyOptimize();
}
+ public boolean isClassMetadataDisabled() {
+ return jjsOptions.isClassMetadataDisabled();
+ }
+
+ public boolean isDraftCompile() {
+ return jjsOptions.isDraftCompile();
+ }
+
public boolean isEnableAssertions() {
return jjsOptions.isEnableAssertions();
}
+ public boolean isRunAsyncEnabled() {
+ return jjsOptions.isRunAsyncEnabled();
+ }
+
+ public boolean isSoycEnabled() {
+ return jjsOptions.isSoycEnabled();
+ }
+
public boolean isUpdateCheckDisabled() {
return disableUpdateCheck;
}
@@ -142,10 +165,18 @@
jjsOptions.setAggressivelyOptimize(aggressivelyOptimize);
}
+ public void setClassMetadataDisabled(boolean disabled) {
+ jjsOptions.setClassMetadataDisabled(disabled);
+ }
+
public void setDisableUpdateCheck(boolean disabled) {
disableUpdateCheck = disabled;
}
+ public void setDraftCompile(boolean draft) {
+ jjsOptions.setDraftCompile(draft);
+ }
+
public void setEnableAssertions(boolean enableAssertions) {
jjsOptions.setEnableAssertions(enableAssertions);
}
@@ -158,6 +189,14 @@
jjsOptions.setOutput(output);
}
+ public void setRunAsyncEnabled(boolean enabled) {
+ jjsOptions.setRunAsyncEnabled(enabled);
+ }
+
+ public void setSoycEnabled(boolean enabled) {
+ jjsOptions.setSoycEnabled(enabled);
+ }
+
public void setValidateOnly(boolean validateOnly) {
this.validateOnly = validateOnly;
}
@@ -293,9 +332,11 @@
module, compilationState, generatedArtifacts,
new PropertyPermutations(module.getProperties()), genDir,
generatorResourcesDir);
-
+ FragmentLoaderCreator fragmentLoaderCreator = new FragmentLoaderCreator(
+ compilationState, module, genDir, generatorResourcesDir,
+ generatedArtifacts);
WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
- compilationState, rpo);
+ compilationState, rpo, fragmentLoaderCreator);
PerfLogger.start("Precompile");
UnifiedAst unifiedAst = JavaToJavaScriptCompiler.precompile(logger,
frontEnd, declEntryPts, null, jjsOptions,
@@ -357,9 +398,11 @@
module, compilationState, generatorArtifacts,
new PropertyPermutations(module.getProperties()), genDir,
generatorResourcesDir);
-
+ FragmentLoaderCreator fragmentLoaderCreator = new FragmentLoaderCreator(
+ compilationState, module, genDir, generatorResourcesDir,
+ generatorArtifacts);
WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
- compilationState, rpo);
+ compilationState, rpo, fragmentLoaderCreator);
JavaToJavaScriptCompiler.precompile(logger, frontEnd, declEntryPts,
additionalRootTypes, jjsOptions, true);
return true;
diff --git a/dev/core/src/com/google/gwt/dev/ThreadedPermutationWorkerFactory.java b/dev/core/src/com/google/gwt/dev/ThreadedPermutationWorkerFactory.java
index 89eebf0..fe8e467 100644
--- a/dev/core/src/com/google/gwt/dev/ThreadedPermutationWorkerFactory.java
+++ b/dev/core/src/com/google/gwt/dev/ThreadedPermutationWorkerFactory.java
@@ -18,6 +18,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.jjs.UnifiedAst;
+import com.google.gwt.dev.util.FileBackedObject;
import java.util.ArrayList;
import java.util.Collection;
@@ -40,11 +41,13 @@
this.id = id;
}
- public PermutationResult compile(final TreeLogger logger,
- final Permutation permutation) throws TransientWorkerException,
- UnableToCompleteException {
+ public void compile(TreeLogger logger, Permutation permutation,
+ FileBackedObject<PermutationResult> resultFile)
+ throws TransientWorkerException, UnableToCompleteException {
try {
- return CompilePerms.compile(logger, permutation, ast);
+ PermutationResult result = CompilePerms.compile(logger, permutation,
+ ast);
+ resultFile.set(logger, result);
} catch (OutOfMemoryError e) {
logger.log(TreeLogger.ERROR,
"OutOfMemoryError: Increase heap size or lower "
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 7517cee..599a7dd 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -26,16 +26,14 @@
import com.google.gwt.dev.javac.JavaSourceOracle;
import com.google.gwt.dev.javac.impl.JavaSourceOracleImpl;
import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.impl.DefaultFilters;
import com.google.gwt.dev.resource.impl.PathPrefix;
import com.google.gwt.dev.resource.impl.PathPrefixSet;
-import com.google.gwt.dev.resource.impl.ResourceFilter;
import com.google.gwt.dev.resource.impl.ResourceOracleImpl;
import com.google.gwt.dev.util.Empty;
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.Util;
-import org.apache.tools.ant.types.ZipScanner;
-
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
@@ -54,11 +52,6 @@
* XML for unit tests.
*/
public class ModuleDef implements PublicOracle {
- /**
- * Default to recursive inclusion of java files if no explicit include
- * directives are specified.
- */
- private static final String[] DEFAULT_SOURCE_FILE_INCLUDES_LIST = new String[] {"**/*.java"};
private static final Comparator<Map.Entry<String, ?>> REV_NAME_CMP = new Comparator<Map.Entry<String, ?>>() {
public int compare(Map.Entry<String, ?> entry1, Map.Entry<String, ?> entry2) {
@@ -123,9 +116,11 @@
private PathPrefixSet sourcePrefixSet = new PathPrefixSet();
private final Styles styles = new Styles();
+ private final DefaultFilters defaultFilters;
public ModuleDef(String name) {
this.name = name;
+ defaultFilters = new DefaultFilters();
}
public synchronized void addEntryPointTypeName(String typeName) {
@@ -155,15 +150,9 @@
if (lazyPublicOracle != null) {
throw new IllegalStateException("Already normalized");
}
-
- final ZipScanner scanner = getScanner(includeList, excludeList,
- defaultExcludes, caseSensitive);
-
- publicPrefixSet.add(new PathPrefix(publicPackage, new ResourceFilter() {
- public boolean allows(String path) {
- return scanner.match(path);
- }
- }, true));
+ publicPrefixSet.add(new PathPrefix(publicPackage,
+ defaultFilters.customResourceFilter(includeList, excludeList,
+ defaultExcludes, caseSensitive), true));
}
public void addSourcePackage(String sourcePackage, String[] includeList,
@@ -178,25 +167,9 @@
if (lazySourceOracle != null) {
throw new IllegalStateException("Already normalized");
}
-
- if (includeList.length == 0) {
- /*
- * If no includes list was provided then, use the default.
- */
- includeList = DEFAULT_SOURCE_FILE_INCLUDES_LIST;
- }
-
- final ZipScanner scanner = getScanner(includeList, excludeList,
- defaultExcludes, caseSensitive);
-
- ResourceFilter sourceFileFilter = new ResourceFilter() {
- public boolean allows(String path) {
- return path.endsWith(".java") && scanner.match(path);
- }
- };
-
- PathPrefix pathPrefix = new PathPrefix(sourcePackage, sourceFileFilter,
- isSuperSource);
+ PathPrefix pathPrefix = new PathPrefix(sourcePackage,
+ defaultFilters.customJavaFilter(includeList, excludeList,
+ defaultExcludes, caseSensitive), isSuperSource);
sourcePrefixSet.add(pathPrefix);
}
@@ -470,27 +443,4 @@
PerfLogger.end();
}
- private ZipScanner getScanner(String[] includeList, String[] excludeList,
- boolean defaultExcludes, boolean caseSensitive) {
- /*
- * Hijack Ant's ZipScanner to handle inclusions/exclusions exactly as Ant
- * does. We're only using its pattern-matching capabilities; the code path
- * I'm using never tries to hit the filesystem in Ant 1.6.5.
- */
- ZipScanner scanner = new ZipScanner();
- if (includeList.length > 0) {
- scanner.setIncludes(includeList);
- }
- if (excludeList.length > 0) {
- scanner.setExcludes(excludeList);
- }
- if (defaultExcludes) {
- scanner.addDefaultExcludes();
- }
- scanner.setCaseSensitive(caseSensitive);
- scanner.init();
-
- return scanner;
- }
-
}
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
index f66bce6..5cc8bb9 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
@@ -241,6 +241,9 @@
ModuleDefSchema schema = new ModuleDefSchema(logger, this, moduleURL,
moduleDir, moduleDef);
ReflectiveParser.parse(logger, schema, r);
+ } catch (Throwable e) {
+ logger.log(TreeLogger.ERROR, "Unexpected error while processing XML", e);
+ throw new UnableToCompleteException();
} finally {
Utility.close(r);
}
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
index a0c2e94..f35fb11 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
@@ -50,6 +50,10 @@
protected final String __add_linker_1_name = null;
+ protected final String __append_configuration_property_1_name = null;
+
+ protected final String __append_configuration_property_2_value = null;
+
protected final String __define_linker_1_name = null;
protected final String __define_linker_2_class = null;
@@ -130,6 +134,31 @@
return null;
}
+ protected Schema __append_configuration_property_begin(PropertyName name,
+ String value) throws UnableToCompleteException {
+
+ // Property must already exist
+ Property prop = moduleDef.getProperties().find(name.token);
+ if (prop == null || !(prop instanceof ConfigurationProperty)) {
+ logger.log(TreeLogger.ERROR, "The property " + name.token
+ + " must already exist as a configuration property");
+ throw new UnableToCompleteException();
+ }
+
+ ConfigurationProperty configProp = (ConfigurationProperty) prop;
+ String oldValue = configProp.getValue();
+ if (oldValue == null) {
+ oldValue = "";
+ }
+ if (oldValue.length() > 0) {
+ oldValue += ",";
+ }
+ configProp.setValue(oldValue + value);
+
+ // No children.
+ return null;
+ }
+
protected Schema __define_linker_begin(LinkerName name,
Class<? extends Linker> linker) throws UnableToCompleteException {
if (!Linker.class.isAssignableFrom(linker)) {
@@ -913,8 +942,8 @@
}
/**
- * Returns <code>true</code> if the string equals "true" or "yes" using a
- * case insensitive comparison.
+ * Returns <code>true</code> if the string equals "true" or "yes" using a case
+ * insensitive comparison.
*/
private static boolean toPrimitiveBoolean(String s) {
return "yes".equalsIgnoreCase(s) || "true".equalsIgnoreCase(s);
@@ -1004,6 +1033,9 @@
StringReader r = new StringReader(script);
List<JsStatement> stmts;
try {
+ // TODO Provide more context here
+ jsParser.setSourceInfo(jsPgm.createSourceInfoSynthetic(
+ ModuleDefSchema.class, "Module.xml"));
stmts = jsParser.parse(jsPgm.getScope(), r, startLineNumber);
} catch (IOException e) {
logger.log(TreeLogger.ERROR, "Error reading script source", e);
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationState.java b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
index 2c52e79..d9c710a 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
@@ -82,6 +82,8 @@
*/
private final JavaSourceOracle sourceOracle;
+ private CompilationUnitInvalidator.InvalidatorState invalidatorState = new CompilationUnitInvalidator.InvalidatorState();
+
/**
* Construct a new {@link CompilationState}.
*
@@ -174,6 +176,19 @@
CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(TreeLogger.NULL,
getCompilationUnits());
+ /*
+ * Only retain state for units marked as CHECKED; because CHECKED units
+ * won't be revalidated.
+ */
+ Set<CompilationUnit> toRetain = new HashSet<CompilationUnit>(exposedUnits);
+ for (Iterator<CompilationUnit> it = toRetain.iterator(); it.hasNext();) {
+ CompilationUnit unit = it.next();
+ if (unit.getState() != State.CHECKED) {
+ it.remove();
+ }
+ }
+ invalidatorState.retainAll(toRetain);
+
jdtCompiler = new JdtCompiler();
compile(logger, getCompilationUnits());
mediator.refresh(logger, getCompilationUnits());
@@ -195,8 +210,8 @@
logger, newUnits);
// Check all units using our custom checks.
- CompilationUnitInvalidator.validateCompilationUnits(newUnits,
- jdtCompiler.getBinaryTypeNames());
+ CompilationUnitInvalidator.validateCompilationUnits(invalidatorState,
+ newUnits, jdtCompiler.getBinaryTypeNames());
// More units may have errors now.
anyErrors |= CompilationUnitInvalidator.invalidateUnitsWithErrors(logger,
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java
index 0992cea..270e504 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java
@@ -25,6 +25,7 @@
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@@ -33,12 +34,23 @@
* Helper class to invalidate units in a set based on errors or references to
* other invalidate units.
*
- * TODO: {@link ClassFileReader#hasStructuralChanges(byte[])} could help us
- * optimize this process!
+ * TODO: ClassFileReader#hasStructuralChanges(byte[]) could help us optimize
+ * this process!
*/
public class CompilationUnitInvalidator {
/**
+ * Maintain cross-validation state.
+ */
+ public static class InvalidatorState {
+ private final JSORestrictionsChecker.CheckerState jsoState = new JSORestrictionsChecker.CheckerState();
+
+ public void retainAll(Collection<CompilationUnit> toRetain) {
+ jsoState.retainAll(toRetain);
+ }
+ }
+
+ /**
* For all units containing one or more errors whose state is currently
* {@link State#COMPILED}, each unit's error(s) will be logged to
* <code>logger</code> and each unit's state will be set to
@@ -150,16 +162,17 @@
} while (changed);
}
- public static void validateCompilationUnits(Set<CompilationUnit> units,
- Set<String> validBinaryTypeNames) {
+ public static void validateCompilationUnits(InvalidatorState state,
+ Set<CompilationUnit> units, Set<String> validBinaryTypeNames) {
for (CompilationUnit unit : units) {
if (unit.getState() == State.COMPILED) {
CompilationUnitDeclaration jdtCud = unit.getJdtCud();
- JSORestrictionsChecker.check(jdtCud);
+ JSORestrictionsChecker.check(state.jsoState, jdtCud);
JsniChecker.check(jdtCud);
BinaryTypeReferenceRestrictionsChecker.check(jdtCud,
validBinaryTypeNames);
}
}
+ state.jsoState.finalCheck();
}
}
diff --git a/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
index b6c7390..1d56076 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
@@ -17,6 +17,7 @@
import com.google.gwt.dev.util.InstalledHelpInfo;
+import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
@@ -33,32 +34,152 @@
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
import java.util.Stack;
/**
* Check a compilation unit for violations of
* {@link com.google.gwt.core.client.JavaScriptObject JavaScriptObject} (JSO)
- * restrictions. The restrictions are:
+ * restrictions. The restrictions are summarized in
+ * <code>jsoRestrictions.html</code>.
*
- * <ul>
- * <li> All instance methods on JSO classes must be one of: final, private, or a
- * member of a final class.
- * <li> JSO classes cannot implement interfaces that define methods.
- * <li> No instance methods on JSO classes may override another method. (This
- * catches accidents where JSO itself did not finalize some method from its
- * superclass.)
- * <li> JSO classes cannot have instance fields.
- * <li> "new" operations cannot be used with JSO classes.
- * <li> Every JSO class must have precisely one constructor, and it must be
- * protected, empty, and no-argument.
- * <li> Nested JSO classes must be static.
- * </ul>
*
* Any violations found are attached as errors on the
* CompilationUnitDeclaration.
+ *
+ * @see <a
+ * href="http://code.google.com/p/google-web-toolkit/wiki/OverlayTypes">Overlay
+ * types design doc</a>
+ * @see jsoRestrictions.html
*/
public class JSORestrictionsChecker {
+ /**
+ * The order in which the checker will process types is undefined, so this
+ * type accumulates the information necessary for sanity-checking the JSO
+ * types.
+ */
+ public static class CheckerState {
+
+ /**
+ * This maps JSO implementation types to their implemented SingleJsoImpl
+ * interfaces.
+ */
+ private final Map<TypeDeclaration, Set<String>> jsoImplsToInterfaces = new HashMap<TypeDeclaration, Set<String>>();
+
+ /**
+ * Used for error reporting.
+ */
+ private final Map<TypeDeclaration, CompilationUnitDeclaration> nodesToCuds = new IdentityHashMap<TypeDeclaration, CompilationUnitDeclaration>();
+
+ /**
+ * This method should be called after all CUDs are passed into check().
+ */
+ public void finalCheck() {
+ /*
+ * Ensure that every interfaces has exactly zero or one JSO subtype that
+ * implements it.
+ */
+ Map<String, TypeDeclaration> singleImplementations = new HashMap<String, TypeDeclaration>();
+ for (Map.Entry<TypeDeclaration, Set<String>> entry : jsoImplsToInterfaces.entrySet()) {
+ TypeDeclaration node = entry.getKey();
+ for (String intfName : entry.getValue()) {
+
+ if (!singleImplementations.containsKey(intfName)) {
+ singleImplementations.put(intfName, node);
+ } else {
+ /*
+ * Emit an error if the previously-defined type is neither a
+ * supertype nor subtype of the current type
+ */
+ TypeDeclaration previous = singleImplementations.get(intfName);
+ if (!(hasSupertypeNamed(node, previous.binding.compoundName) || hasSupertypeNamed(
+ previous, node.binding.compoundName))) {
+ String nodeName = CharOperation.toString(node.binding.compoundName);
+ String previousName = CharOperation.toString(previous.binding.compoundName);
+
+ // Provide consistent reporting, regardless of visitation order
+ if (nodeName.compareTo(previousName) < 0) {
+ String msg = errAlreadyImplemented(intfName, nodeName,
+ previousName);
+ errorOn(node, nodesToCuds.get(node), msg);
+ errorOn(previous, nodesToCuds.get(previous), msg);
+ } else {
+ String msg = errAlreadyImplemented(intfName, previousName,
+ nodeName);
+ errorOn(previous, nodesToCuds.get(previous), msg);
+ errorOn(node, nodesToCuds.get(node), msg);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void retainAll(Collection<CompilationUnit> units) {
+ // Fast-path for removing everything
+ if (units.isEmpty()) {
+ jsoImplsToInterfaces.clear();
+ nodesToCuds.clear();
+ return;
+ }
+
+ // Build up a list of the types that should be retained
+ Set<String> retainedTypeNames = new HashSet<String>();
+
+ for (CompilationUnit u : units) {
+ for (CompiledClass c : u.getCompiledClasses()) {
+ // Can't rely on getJdtCud() because those are pruned
+ retainedTypeNames.add(c.getSourceName());
+ }
+ }
+
+ // Loop over all TypeDeclarations that we have
+ for (Iterator<TypeDeclaration> it = nodesToCuds.keySet().iterator(); it.hasNext();) {
+ TypeDeclaration decl = it.next();
+
+ // Remove the TypeDeclaration if it's not in the list of retained types
+ if (!retainedTypeNames.contains(CharOperation.toString(decl.binding.compoundName))) {
+ it.remove();
+
+ jsoImplsToInterfaces.remove(decl);
+ }
+ }
+ }
+
+ private void add(Map<TypeDeclaration, Set<String>> map,
+ TypeDeclaration key, String value) {
+ Set<String> set = map.get(key);
+ if (set == null) {
+ map.put(key, set = new HashSet<String>());
+ }
+ set.add(value);
+ }
+
+ private void addJsoInterface(TypeDeclaration jsoType,
+ CompilationUnitDeclaration cud, String interfaceName) {
+ nodesToCuds.put(jsoType, cud);
+ add(jsoImplsToInterfaces, jsoType, interfaceName);
+ }
+
+ private boolean hasSupertypeNamed(TypeDeclaration type, char[][] qType) {
+ ReferenceBinding b = type.binding;
+ while (b != null) {
+ if (CharOperation.equals(b.compoundName, qType)) {
+ return true;
+ }
+ b = b.superclass();
+ }
+ return false;
+ }
+ }
+
private class JSORestrictionsVisitor extends ASTVisitor implements
ClassFileConstants {
@@ -156,6 +277,7 @@
if (!isJsoSubclass(type.binding)) {
return false;
}
+
if (type.enclosingType != null && !type.binding.isStatic()) {
errorOn(type, ERR_IS_NONSTATIC_NESTED);
}
@@ -163,12 +285,17 @@
ReferenceBinding[] interfaces = type.binding.superInterfaces();
if (interfaces != null) {
for (ReferenceBinding interf : interfaces) {
- if (interf.methods() != null && interf.methods().length > 0) {
- String intfName = String.copyValueOf(interf.shortReadableName());
- errorOn(type, errInterfaceWithMethods(intfName));
+ if (interf.methods() == null) {
+ continue;
+ }
+
+ if (interf.methods().length > 0) {
+ String intfName = CharOperation.toString(interf.compoundName);
+ state.addJsoInterface(type, cud, intfName);
}
}
}
+
return true;
}
@@ -200,20 +327,32 @@
* {@link org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration}.
*
*/
- public static void check(CompilationUnitDeclaration cud) {
- JSORestrictionsChecker checker = new JSORestrictionsChecker(cud);
+ public static void check(CheckerState state, CompilationUnitDeclaration cud) {
+ JSORestrictionsChecker checker = new JSORestrictionsChecker(state, cud);
checker.check();
}
- static String errInterfaceWithMethods(String intfName) {
- return "JavaScriptObject classes cannot implement interfaces with methods ("
- + intfName + ")";
+ static String errAlreadyImplemented(String intfName, String impl1,
+ String impl2) {
+ return "Only one JavaScriptObject type may implement the methods of an "
+ + "interface that declared methods. The interface (" + intfName
+ + ") is implemented by both (" + impl1 + ") and (" + impl2 + ")";
+ }
+
+ private static void errorOn(ASTNode node, CompilationUnitDeclaration cud,
+ String error) {
+ GWTProblem.recordInCud(node, cud, error, new InstalledHelpInfo(
+ "jsoRestrictions.html"));
}
private final CompilationUnitDeclaration cud;
- private JSORestrictionsChecker(CompilationUnitDeclaration cud) {
+ private final CheckerState state;
+
+ private JSORestrictionsChecker(CheckerState state,
+ CompilationUnitDeclaration cud) {
this.cud = cud;
+ this.state = state;
}
private void check() {
@@ -221,8 +360,7 @@
}
private void errorOn(ASTNode node, String error) {
- GWTProblem.recordInCud(node, cud, error, new InstalledHelpInfo(
- "jsoRestrictions.html"));
+ errorOn(node, cud, error);
}
private boolean isJsoSubclass(TypeBinding typeBinding) {
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
index b909b3e..0bc1d6f 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
@@ -85,22 +85,32 @@
return func;
}
+ @Override
public int line() {
return line;
}
+ @Override
public String location() {
return location;
}
+ @Override
public String name() {
return name;
}
+ @Override
public String[] paramNames() {
return paramNames;
}
+ @Override
+ public JsProgram program() {
+ return program;
+ }
+
+ @Override
public String source() {
return source;
}
@@ -271,8 +281,9 @@
}
try {
- List<JsStatement> stmts = new JsParser().parse(program.getScope(), r,
- startLine);
+ JsParser parser = new JsParser();
+ parser.setSourceInfo(program.createSourceInfo(startLine, location));
+ List<JsStatement> stmts = parser.parse(program.getScope(), r, startLine);
return (JsFunction) ((JsExprStmt) stmts.get(0)).getExpression();
} catch (IOException e) {
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java b/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
index d45a460..6e51146 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
@@ -17,6 +17,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsProgram;
/**
* Represents a single JsniMethod in a compiled class file.
@@ -49,6 +50,11 @@
public abstract String[] paramNames();
/**
+ * Gets the JsProgram in which {@link #function(TreeLogger)} is located.
+ */
+ public abstract JsProgram program();
+
+ /**
* The script body.
*/
public abstract String source();
diff --git a/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
index 0fd5810..5c6ee23 100644
--- a/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
+++ b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
@@ -101,6 +101,10 @@
private static final JClassType[] NO_JCLASSES = new JClassType[0];
private static final Pattern PATTERN_WHITESPACE = Pattern.compile("\\s");
+ /**
+ * Returns the binary name of a type. This is the same name that would be
+ * returned by {@link Class#getName()} for this type.
+ */
public static String computeBinaryClassName(JType type) {
JPrimitiveType primitiveType = type.isPrimitive();
if (primitiveType != null) {
diff --git a/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java b/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java
index e9e1eab..e4baf2c 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java
@@ -26,8 +26,10 @@
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -42,21 +44,22 @@
* Information about the site at which a rebind request was found, used to
* report problems.
*/
- public static class DeferredBindingSite {
+ public static class MessageSendSite {
public final MessageSend messageSend;
public final Scope scope;
- public DeferredBindingSite(MessageSend messageSend, Scope scope) {
+ public MessageSendSite(MessageSend messageSend, Scope scope) {
this.messageSend = messageSend;
this.scope = scope;
}
}
- public static final String REBIND_MAGIC_CLASS = "com.google.gwt.core.client.GWT";
+ public static final String MAGIC_CLASS = "com.google.gwt.core.client.GWT";
public static final String REBIND_MAGIC_METHOD = "create";
+ public static final String ASYNC_MAGIC_METHOD = "runAsync";
- public static void reportRebindProblem(DeferredBindingSite site,
+ public static void reportRebindProblem(MessageSendSite site,
String message) {
MessageSend messageSend = site.messageSend;
Scope scope = site.scope;
@@ -65,52 +68,77 @@
GWTProblem.recordInCud(messageSend, cud, message, null);
}
- private final Map<String, DeferredBindingSite> results = new HashMap<String, DeferredBindingSite>();
+ private final Map<String, MessageSendSite> results = new HashMap<String, MessageSendSite>();
+ private final List<MessageSendSite> runAsyncCalls = new ArrayList<MessageSendSite>();
+
+ @Override
public void endVisit(MessageSend messageSend, BlockScope scope) {
if (messageSend.binding == null) {
// Some sort of problem.
- //
return;
}
String methodName = String.valueOf(messageSend.selector);
- if (!methodName.equals(REBIND_MAGIC_METHOD)) {
- // Not the create() method.
- //
+ boolean rebindMagicMethod = methodName.equals(REBIND_MAGIC_METHOD);
+ boolean asyncMagicMethod = methodName.equals(ASYNC_MAGIC_METHOD);
+ if (!(rebindMagicMethod || asyncMagicMethod)) {
+ // Not the create() method or the runAsync() method.
return;
}
char[][] targetClass = messageSend.binding.declaringClass.compoundName;
String targetClassName = CharOperation.toString(targetClass);
- if (!targetClassName.equals(REBIND_MAGIC_CLASS)) {
+ if (!targetClassName.equals(MAGIC_CLASS)) {
// Not being called on the Rebind class.
return;
}
- DeferredBindingSite site = new DeferredBindingSite(messageSend, scope);
+ MessageSendSite site = new MessageSendSite(messageSend, scope);
Expression[] args = messageSend.arguments;
- if (args.length != 1) {
- reportRebindProblem(site, "GWT.create() should take exactly one argument");
+ if (rebindMagicMethod) {
+ if (args.length != 1) {
+ reportRebindProblem(site,
+ "GWT.create() should take exactly one argument");
+ return;
+ }
+
+ if (!(args[0] instanceof ClassLiteralAccess)) {
+ reportRebindProblem(site,
+ "Only class literals may be used as arguments to GWT.create()");
+ return;
+ }
+ } else {
+ assert asyncMagicMethod;
+ if (args.length != 1) {
+ reportRebindProblem(site,
+ "GWT.runAsync() should take exactly one argument");
+ return;
+ }
+ }
+
+ if (asyncMagicMethod) {
+ runAsyncCalls.add(new MessageSendSite(messageSend, scope));
return;
}
- Expression arg = args[0];
- if (!(arg instanceof ClassLiteralAccess)) {
- reportRebindProblem(site,
- "Only class literals may be used as arguments to GWT.create()");
- return;
- }
-
- ClassLiteralAccess cla = (ClassLiteralAccess) arg;
+ ClassLiteralAccess cla = (ClassLiteralAccess) args[0];
String typeName = String.valueOf(cla.targetType.readableName());
+
if (!results.containsKey(typeName)) {
results.put(typeName, site);
}
}
- public Map<String, DeferredBindingSite> getSites() {
+ /**
+ * Return the calls to GWT.runAsync() that were seen.
+ */
+ public List<MessageSendSite> getRunAsyncSites() {
+ return runAsyncCalls;
+ }
+
+ public Map<String, MessageSendSite> getSites() {
return Collections.unmodifiableMap(results);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java b/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
index a8261cd..5267605 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
@@ -17,10 +17,14 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.CompilationUnit;
import com.google.gwt.dev.javac.CompiledClass;
import com.google.gwt.dev.javac.JdtCompiler.CompilationUnitAdapter;
-import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor.DeferredBindingSite;
+import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor.MessageSendSite;
+import com.google.gwt.dev.jjs.impl.FragmentLoaderCreator;
import com.google.gwt.dev.util.Empty;
import com.google.gwt.dev.util.JsniRef;
@@ -30,8 +34,10 @@
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -41,36 +47,79 @@
*/
public class WebModeCompilerFrontEnd extends AbstractCompiler {
+ private final FragmentLoaderCreator fragmentLoaderCreator;
private final RebindPermutationOracle rebindPermOracle;
+ /**
+ * Construct a WebModeCompilerFrontEnd. The reason a
+ * {@link FragmentLoaderCreator} needs to be passed in is that it uses
+ * generator infrastructure, and therefore needs access to more parts of the
+ * compiler than WebModeCompilerFrontEnd currently has.
+ */
public WebModeCompilerFrontEnd(CompilationState compilationState,
- RebindPermutationOracle rebindPermOracle) {
+ RebindPermutationOracle rebindPermOracle,
+ FragmentLoaderCreator fragmentLoaderCreator) {
super(compilationState, false);
this.rebindPermOracle = rebindPermOracle;
+ this.fragmentLoaderCreator = fragmentLoaderCreator;
}
+ /**
+ * Build the initial set of compilation units.
+ */
public CompilationUnitDeclaration[] getCompilationUnitDeclarations(
TreeLogger logger, String[] seedTypeNames)
throws UnableToCompleteException {
- // Build the initial set of compilation units.
+ TypeOracle oracle = compilationState.getTypeOracle();
+ Set<JClassType> intfTypes = oracle.getSingleJsoImplInterfaces();
Map<String, CompiledClass> classMapBySource = compilationState.getClassFileMapBySource();
- ICompilationUnit[] icus = new ICompilationUnit[seedTypeNames.length];
- for (int i = 0; i < seedTypeNames.length; i++) {
- String seedTypeName = seedTypeNames[i];
- CompiledClass compiledClass = classMapBySource.get(seedTypeName);
- if (compiledClass == null) {
- logger.log(TreeLogger.ERROR,
- "Unable to find compilation unit for type '" + seedTypeName + "'");
- throw new UnableToCompleteException();
+
+ /*
+ * The alreadyAdded set prevents duplicate CompilationUnits from being added
+ * to the icu list in the case of multiple JSO implementations as inner
+ * classes in the same top-level class or seed classes as SingleJsoImpls
+ * (e.g. JSO itself as the SingleImpl for all tag interfaces).
+ */
+ Set<CompilationUnit> alreadyAdded = new HashSet<CompilationUnit>();
+
+ List<ICompilationUnit> icus = new ArrayList<ICompilationUnit>(
+ seedTypeNames.length + intfTypes.size());
+
+ for (String seedTypeName : seedTypeNames) {
+ CompilationUnit unit = getUnitForType(logger, classMapBySource,
+ seedTypeName);
+
+ if (alreadyAdded.add(unit)) {
+ icus.add(new CompilationUnitAdapter(unit));
+ } else {
+ logger.log(TreeLogger.WARN, "Duplicate compilation unit '"
+ + unit.getDisplayLocation() + "'in seed types");
}
- icus[i] = new CompilationUnitAdapter(compiledClass.getUnit());
}
- // Compile, which will pull in everything else via
- // doFindAdditionalTypesUsingMagic()
- //
- CompilationUnitDeclaration[] cuds = compile(logger, icus);
+ /*
+ * Add all SingleJsoImpl types that we know about. It's likely that the
+ * concrete types are never explicitly referenced from the seed types.
+ */
+ for (JClassType intf : intfTypes) {
+ String implName = oracle.getSingleJsoImpl(intf).getQualifiedSourceName();
+ CompilationUnit unit = getUnitForType(logger, classMapBySource, implName);
+
+ if (alreadyAdded.add(unit)) {
+ icus.add(new CompilationUnitAdapter(unit));
+ logger.log(TreeLogger.SPAM, "Forced compilation of unit '"
+ + unit.getDisplayLocation()
+ + "' becasue it contains a SingleJsoImpl type");
+ }
+ }
+
+ /*
+ * Compile, which will pull in everything else via
+ * doFindAdditionalTypesUsingMagic()
+ */
+ CompilationUnitDeclaration[] cuds = compile(logger,
+ icus.toArray(new ICompilationUnit[icus.size()]));
return cuds;
}
@@ -90,6 +139,7 @@
/**
* Pull in types referenced only via JSNI.
*/
+ @Override
protected String[] doFindAdditionalTypesUsingJsni(TreeLogger logger,
CompilationUnitDeclaration cud) {
FindJsniRefVisitor v = new FindJsniRefVisitor();
@@ -109,20 +159,19 @@
/**
* Pull in types implicitly referenced through rebind answers.
*/
+ @Override
protected String[] doFindAdditionalTypesUsingRebinds(TreeLogger logger,
CompilationUnitDeclaration cud) {
Set<String> dependentTypeNames = new HashSet<String>();
// Find all the deferred binding request types.
- //
FindDeferredBindingSitesVisitor v = new FindDeferredBindingSitesVisitor();
cud.traverse(v, cud.scope);
- Map<String, DeferredBindingSite> requestedTypes = v.getSites();
+ Map<String, MessageSendSite> requestedTypes = v.getSites();
// For each, ask the host for every possible deferred binding answer.
- //
for (String reqType : requestedTypes.keySet()) {
- DeferredBindingSite site = requestedTypes.get(reqType);
+ MessageSendSite site = requestedTypes.get(reqType);
try {
String[] resultTypes = rebindPermOracle.getAllPossibleRebindAnswers(
@@ -134,7 +183,6 @@
// This causes the compiler to find the additional type, possibly
// winding its back to ask for the compilation unit from the source
// oracle.
- //
ReferenceBinding type = resolvePossiblyNestedType(typeName);
// Sanity check rebind results.
@@ -165,9 +213,7 @@
continue;
}
// Look for a noArg ctor.
- MethodBinding noArgCtor = type.getExactMethod("<init>".toCharArray(),
- TypeBinding.NO_PARAMETERS, cud.scope);
-
+ MethodBinding noArgCtor = type.getExactConstructor(TypeBinding.NO_PARAMETERS);
if (noArgCtor == null) {
FindDeferredBindingSitesVisitor.reportRebindProblem(site,
"Rebind result '" + typeName
@@ -182,6 +228,46 @@
"Failed to resolve '" + reqType + "' via deferred binding");
}
}
+
+ /*
+ * Create a a fragment loader for each GWT.runAsync call. They must be
+ * created now, rather than in ReplaceRunAsyncs, because all generated
+ * classes need to be created before GenerateJavaAST. Note that the loaders
+ * created are not yet associated with the specific sites. The present task
+ * is only to make sure that enough loaders exist. The real association
+ * between loaders and runAsync sites will be made in ReplaceRunAsyncs.
+ */
+ for (MessageSendSite site : v.getRunAsyncSites()) {
+ FragmentLoaderCreator loaderCreator = fragmentLoaderCreator;
+ String resultType;
+ try {
+ resultType = loaderCreator.create(logger);
+ dependentTypeNames.add(resultType);
+ } catch (UnableToCompleteException e) {
+ FindDeferredBindingSitesVisitor.reportRebindProblem(site,
+ "Failed to create a runAsync fragment loader");
+ }
+ }
+
return dependentTypeNames.toArray(Empty.STRINGS);
}
+
+ /**
+ * Get the CompilationUnit for a named type or throw an
+ * UnableToCompleteException.
+ */
+ private CompilationUnit getUnitForType(TreeLogger logger,
+ Map<String, CompiledClass> classMapBySource, String typeName)
+ throws UnableToCompleteException {
+
+ CompiledClass compiledClass = classMapBySource.get(typeName);
+ if (compiledClass == null) {
+ logger.log(TreeLogger.ERROR, "Unable to find compilation unit for type '"
+ + typeName + "'");
+ throw new UnableToCompleteException();
+ }
+
+ assert compiledClass.getUnit() != null;
+ return compiledClass.getUnit();
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/Correlation.java b/dev/core/src/com/google/gwt/dev/jjs/Correlation.java
new file mode 100644
index 0000000..0688003
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/Correlation.java
@@ -0,0 +1,415 @@
+/*
+ * 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.JField;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsName;
+
+import org.apache.commons.collections.map.ReferenceMap;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumMap;
+import java.util.Map;
+
+/**
+ * Each SourceInfo may define one or more axes by which it can be correlated
+ * with other SourceInfo objects. Correlation has set and map-key semantics.
+ */
+public final class Correlation implements Serializable {
+ /*
+ * NB: The Correlation type uses AST nodes in its factory methods to make it
+ * easier to extract whatever information we want to include in the SOYC
+ * reports without having to update call sites with additional parameters.
+ *
+ * In the general case, references to AST nodes should not be exposed to any
+ * public-API consumers of the Correlation.
+ */
+
+ /**
+ * The axes on which we'll want to pivot the SourceInfo data-set.
+ */
+ public enum Axis {
+ /*
+ * Note to implementors: Possibly the switch statement in
+ * StandardCompilationArtifact if additional member-type enum values are
+ * added.
+ */
+
+ /**
+ * A Java class or interface type.
+ */
+ CLASS(true, false),
+
+ /**
+ * A field defined within a Java type.
+ */
+ FIELD(true, false),
+
+ /**
+ * A JavaScript function derived from a class or method.
+ */
+ FUNCTION(false, true),
+
+ /**
+ * Objects with global names may be aliased (e.g. polymorphic method
+ * dispatch).
+ */
+ JS_ALIAS(false, true),
+
+ /**
+ * The globally-unique identifier used to represent the Member in the
+ * compiled output.
+ */
+ JS_NAME(false, true),
+
+ /**
+ * Indicates a literal value in the original source.
+ */
+ LITERAL(true, true),
+
+ /**
+ * A Java method.
+ */
+ METHOD(true, false),
+
+ /**
+ * Represents a physical source file.
+ */
+ ORIGIN(true, true);
+
+ private final boolean isJava;
+ private final boolean isJs;
+
+ /**
+ * Arguments indicate which AST the axis is relevant to.
+ */
+ private Axis(boolean isJava, boolean isJs) {
+ this.isJava = isJava;
+ this.isJs = isJs;
+ }
+
+ public boolean isJava() {
+ return isJava;
+ }
+
+ public boolean isJs() {
+ return isJs;
+ }
+ }
+
+ /**
+ * Specifies the type of literal value.
+ */
+ public enum Literal {
+ VOID("void"), NULL("null"), BYTE("byte"), SHORT("short"), INT("int"), LONG(
+ "long"), FLOAT("float"), DOUBLE("double"), BOOLEAN("boolean"), CHAR(
+ "char"), STRING("string"), CLASS("class"), JS_BOOLEAN("boolean", true), JS_NUMBER(
+ "number", true), JS_NULL("null", true), JS_STRING("string", true),
+ /**
+ * undefined isn't actually a literal in JS, but we more-or-less treat it as
+ * though it were.
+ */
+ JS_UNDEFINED("undefined", true);
+
+ private final String description;
+ private final boolean isJava;
+ private final boolean isJs;
+
+ private Literal(String description) {
+ this.description = description;
+ isJava = true;
+ isJs = false;
+ }
+
+ private Literal(String description, boolean isJs) {
+ this.description = description;
+ isJava = !isJs;
+ this.isJs = isJs;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public boolean isJava() {
+ return isJava;
+ }
+
+ public boolean isJs() {
+ return isJs;
+ }
+ }
+
+ /**
+ * Compares Correlations based on axis and idents. Note that due to inherent
+ * limitations of mapping AST nodes into Strings, this Comparator may not
+ * always agree with {@link Correlation#equals(Object)}.
+ */
+ public static final Comparator<Correlation> AXIS_IDENT_COMPARATOR = new Comparator<Correlation>() {
+ public int compare(Correlation a, Correlation b) {
+ int r = a.axis.compareTo(b.axis);
+ if (r != 0) {
+ return r;
+ }
+
+ return a.ident.compareTo(b.ident);
+ }
+ };
+
+ /**
+ * This cuts down on the total number of Correlation objects allocated.
+ */
+ @SuppressWarnings("unchecked")
+ private static final Map<Object, Correlation> CANONICAL_MAP = Collections.synchronizedMap(new ReferenceMap(
+ ReferenceMap.WEAK, ReferenceMap.WEAK));
+
+ /**
+ * Correlations based on Literals are all the same, so we'll just cook up a
+ * Map to make {@link #by(Literal)} fast.
+ */
+ private static final Map<Literal, Correlation> LITERAL_CORRELATIONS = new EnumMap<Literal, Correlation>(
+ Literal.class);
+
+ static {
+ for (Literal l : Literal.values()) {
+ LITERAL_CORRELATIONS.put(l, new Correlation(Axis.LITERAL,
+ l.getDescription(), l));
+ }
+ }
+
+ public static Correlation by(JField field) {
+ Correlation toReturn = CANONICAL_MAP.get(field);
+ if (toReturn == null) {
+ toReturn = new Correlation(Axis.FIELD, field.getEnclosingType().getName()
+ + "::" + field.getName(), field);
+ CANONICAL_MAP.put(field, toReturn);
+ }
+ return toReturn;
+ }
+
+ public static Correlation by(JMethod method) {
+ Correlation toReturn = CANONICAL_MAP.get(method);
+ if (toReturn == null) {
+
+ toReturn = new Correlation(Axis.METHOD, getMethodIdent(method), method);
+ CANONICAL_MAP.put(method, toReturn);
+ }
+ return toReturn;
+ }
+
+ public static Correlation by(JReferenceType type) {
+ Correlation toReturn = CANONICAL_MAP.get(type);
+ if (toReturn == null) {
+ toReturn = new Correlation(Axis.CLASS, type.getName(), type);
+ CANONICAL_MAP.put(type, toReturn);
+ }
+ return toReturn;
+ }
+
+ public static Correlation by(JsFunction function) {
+ Correlation toReturn = CANONICAL_MAP.get(function);
+ if (toReturn == null) {
+ toReturn = new Correlation(Axis.FUNCTION, function.getName().getIdent(),
+ function);
+ CANONICAL_MAP.put(function, toReturn);
+ }
+ return toReturn;
+ }
+
+ /**
+ * Creates a JS_NAME Correlation.
+ */
+ public static Correlation by(JsName name) {
+ return by(name, false);
+ }
+
+ /**
+ * Creates either a JS_NAME or JS_ALIAS correlation, based on the value of
+ * <code>isAlias</code>.
+ */
+ public static Correlation by(JsName name, boolean isAlias) {
+ Correlation toReturn = CANONICAL_MAP.get(name);
+ if (toReturn == null) {
+ toReturn = new Correlation(isAlias ? Axis.JS_ALIAS : Axis.JS_NAME,
+ name.getIdent(), name);
+ CANONICAL_MAP.put(name, toReturn);
+ }
+ return toReturn;
+ }
+
+ public static Correlation by(Literal type) {
+ assert LITERAL_CORRELATIONS.containsKey(type);
+ return LITERAL_CORRELATIONS.get(type);
+ }
+
+ public static Correlation by(SourceOrigin origin) {
+ Correlation toReturn = CANONICAL_MAP.get(origin);
+ if (toReturn == null) {
+ toReturn = new Correlation(Axis.ORIGIN, origin.getFileName() + ":"
+ + origin.getStartLine(), origin);
+ CANONICAL_MAP.put(origin, toReturn);
+ }
+ return toReturn;
+ }
+
+ private static String getMethodIdent(JMethod method) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(method.getEnclosingType().getName()).append("::");
+ sb.append(method.getName()).append("(");
+ for (JType type : method.getOriginalParamTypes()) {
+ sb.append(type.getJsniSignatureName());
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ /**
+ * This may contain a reference to either a Java or Js AST node.
+ */
+ protected final Serializable astReference;
+
+ protected final Axis axis;
+
+ /**
+ * This should be a uniquely-identifying value within the Correlation's axis
+ * that is suitable for human consumption. It may be the case that two
+ * Correlations have different AST references, but the same calculated ident,
+ * so this should not be relied upon for uniqueness.
+ */
+ protected final String ident;
+
+ private Correlation(Axis axis, String ident, Serializable astReference) {
+ if (axis == null) {
+ throw new NullPointerException("axis");
+ } else if (ident == null) {
+ throw new NullPointerException("ident");
+ } else if (astReference == null) {
+ throw new NullPointerException("astReference");
+ }
+
+ this.axis = axis;
+ this.ident = ident;
+ this.astReference = astReference;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Correlation)) {
+ return false;
+ }
+ Correlation c = (Correlation) obj;
+
+ boolean astSame = astReference == c.astReference
+ || (astReference != null && astReference.equals(c.astReference));
+ return axis == c.axis && astSame;
+ }
+
+ public Axis getAxis() {
+ return axis;
+ }
+
+ public JField getField() {
+ if (axis == Axis.FIELD) {
+ return (JField) astReference;
+ } else {
+ return null;
+ }
+ }
+
+ public JsFunction getFunction() {
+ if (axis == Axis.FUNCTION) {
+ return (JsFunction) astReference;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns a human-readable identifier that can be used to identify the
+ * Correlation within its axis.
+ */
+ public String getIdent() {
+ return ident;
+ }
+
+ public Literal getLiteral() {
+ if (axis == Axis.LITERAL) {
+ return (Literal) astReference;
+ } else {
+ return null;
+ }
+ }
+
+ public JMethod getMethod() {
+ if (axis == Axis.METHOD) {
+ return (JMethod) astReference;
+ } else {
+ return null;
+ }
+ }
+
+ public JsName getName() {
+ if (axis == Axis.JS_NAME || axis == Axis.JS_ALIAS) {
+ return (JsName) astReference;
+ } else {
+ return null;
+ }
+ }
+
+ public SourceOrigin getOrigin() {
+ if (axis == Axis.ORIGIN) {
+ return (SourceOrigin) astReference;
+ } else {
+ return null;
+ }
+ }
+
+ public JReferenceType getType() {
+ if (axis == Axis.CLASS) {
+ return (JReferenceType) astReference;
+ } else if (axis == Axis.METHOD) {
+ return ((JMethod) astReference).getEnclosingType();
+ } else if (axis == Axis.FIELD) {
+ return ((JField) astReference).getEnclosingType();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ /*
+ * The null checks are because this method gets called during
+ * deserialization, but without values having been set.
+ */
+ return 37 * (axis == null ? 1 : axis.hashCode())
+ + (astReference == null ? 0 : astReference.hashCode()) + 13;
+ }
+
+ /**
+ * Defined for debugging convenience.
+ */
+ @Override
+ public String toString() {
+ return axis.toString() + ": " + ident;
+ }
+}
\ No newline at end of file
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 6e9e162..050e236 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
@@ -16,12 +16,17 @@
package com.google.gwt.dev.jjs;
import com.google.gwt.dev.util.arg.OptionAggressivelyOptimize;
+import com.google.gwt.dev.util.arg.OptionDisableClassMetadata;
+import com.google.gwt.dev.util.arg.OptionDraftCompile;
import com.google.gwt.dev.util.arg.OptionEnableAssertions;
+import com.google.gwt.dev.util.arg.OptionRunAsyncEnabled;
import com.google.gwt.dev.util.arg.OptionScriptStyle;
+import com.google.gwt.dev.util.arg.OptionSoycEnabled;
/**
* Controls options for the {@link JavaToJavaScriptCompiler}.
*/
public interface JJSOptions extends OptionAggressivelyOptimize,
- OptionEnableAssertions, OptionScriptStyle {
+ OptionDisableClassMetadata, OptionDraftCompile, OptionEnableAssertions,
+ OptionRunAsyncEnabled, OptionScriptStyle, OptionSoycEnabled {
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java b/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
index 8873c41..5403614 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
@@ -23,8 +23,12 @@
public class JJSOptionsImpl implements JJSOptions, Serializable {
private boolean aggressivelyOptimize = true;
+ private boolean disableClassMetadata = false;
+ private boolean draftCompile = false;
private boolean enableAssertions;
private JsOutputOption output = JsOutputOption.OBFUSCATED;
+ private boolean runAsyncEnabled = true;
+ private boolean soycEnabled = false;
public JJSOptionsImpl() {
}
@@ -35,8 +39,12 @@
public void copyFrom(JJSOptions other) {
setAggressivelyOptimize(other.isAggressivelyOptimize());
+ setClassMetadataDisabled(other.isClassMetadataDisabled());
+ setDraftCompile(other.isDraftCompile());
setEnableAssertions(other.isEnableAssertions());
setOutput(other.getOutput());
+ setRunAsyncEnabled(other.isRunAsyncEnabled());
+ setSoycEnabled(other.isSoycEnabled());
}
public JsOutputOption getOutput() {
@@ -47,14 +55,38 @@
return aggressivelyOptimize;
}
+ public boolean isClassMetadataDisabled() {
+ return disableClassMetadata;
+ }
+
+ public boolean isDraftCompile() {
+ return draftCompile;
+ }
+
public boolean isEnableAssertions() {
return enableAssertions;
}
+ public boolean isRunAsyncEnabled() {
+ return runAsyncEnabled;
+ }
+
+ public boolean isSoycEnabled() {
+ return soycEnabled;
+ }
+
public void setAggressivelyOptimize(boolean aggressivelyOptimize) {
this.aggressivelyOptimize = aggressivelyOptimize;
}
+ public void setClassMetadataDisabled(boolean disabled) {
+ disableClassMetadata = disabled;
+ }
+
+ public void setDraftCompile(boolean draft) {
+ this.draftCompile = draft;
+ }
+
public void setEnableAssertions(boolean enableAssertions) {
this.enableAssertions = enableAssertions;
}
@@ -62,4 +94,12 @@
public void setOutput(JsOutputOption output) {
this.output = output;
}
+
+ public void setRunAsyncEnabled(boolean enabled) {
+ runAsyncEnabled = enabled;
+ }
+
+ public void setSoycEnabled(boolean enabled) {
+ soycEnabled = enabled;
+ }
}
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 fa6aeca..b5e1739 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -17,6 +17,10 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.linker.ArtifactSet;
+import com.google.gwt.core.ext.linker.impl.StandardCompilationAnalysis;
+import com.google.gwt.core.ext.soyc.Range;
+import com.google.gwt.dev.PermutationResult;
import com.google.gwt.dev.jdt.RebindPermutationOracle;
import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
import com.google.gwt.dev.jjs.InternalCompilerException.NodeInfo;
@@ -25,6 +29,7 @@
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JGwtCreate;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
@@ -39,13 +44,16 @@
import com.google.gwt.dev.jjs.impl.BuildTypeMap;
import com.google.gwt.dev.jjs.impl.CastNormalizer;
import com.google.gwt.dev.jjs.impl.CatchBlockNormalizer;
+import com.google.gwt.dev.jjs.impl.CodeSplitter;
import com.google.gwt.dev.jjs.impl.DeadCodeElimination;
import com.google.gwt.dev.jjs.impl.EqualityNormalizer;
import com.google.gwt.dev.jjs.impl.Finalizer;
import com.google.gwt.dev.jjs.impl.FixAssignmentToUnbox;
+import com.google.gwt.dev.jjs.impl.FragmentLoaderCreator;
import com.google.gwt.dev.jjs.impl.GenerateJavaAST;
import com.google.gwt.dev.jjs.impl.GenerateJavaScriptAST;
import com.google.gwt.dev.jjs.impl.JavaScriptObjectNormalizer;
+import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
import com.google.gwt.dev.jjs.impl.JsoDevirtualizer;
import com.google.gwt.dev.jjs.impl.LongCastNormalizer;
import com.google.gwt.dev.jjs.impl.LongEmulationNormalizer;
@@ -56,21 +64,27 @@
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.ReplaceRunAsyncs;
import com.google.gwt.dev.jjs.impl.ResolveRebinds;
import com.google.gwt.dev.jjs.impl.TypeMap;
import com.google.gwt.dev.jjs.impl.TypeTightener;
+import com.google.gwt.dev.js.EvalFunctionsAtTopScope;
import com.google.gwt.dev.js.JsIEBlockSizeVisitor;
import com.google.gwt.dev.js.JsInliner;
import com.google.gwt.dev.js.JsNormalizer;
import com.google.gwt.dev.js.JsObfuscateNamer;
import com.google.gwt.dev.js.JsPrettyNamer;
+import com.google.gwt.dev.js.JsReportGenerationVisitor;
import com.google.gwt.dev.js.JsSourceGenerationVisitor;
import com.google.gwt.dev.js.JsStaticEval;
import com.google.gwt.dev.js.JsStringInterner;
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.JsReportGenerationVisitor.CountingTextOutput;
+import com.google.gwt.dev.js.ast.JsName;
import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsStatement;
import com.google.gwt.dev.util.DefaultTextOutput;
import com.google.gwt.dev.util.Empty;
import com.google.gwt.dev.util.PerfLogger;
@@ -82,18 +96,45 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
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 {
+ private static class PermutationResultImpl implements PermutationResult {
+ private final ArtifactSet artifacts = new ArtifactSet();
+ private final String[] js;
+ private final SortedMap<String, String> symbolMap;
+
+ public PermutationResultImpl(String[] js,
+ SortedMap<String, String> symbolMap) {
+ this.js = js;
+ this.symbolMap = symbolMap;
+ }
+
+ public ArtifactSet getArtifacts() {
+ return artifacts;
+ }
+
+ public String[] getJs() {
+ return js;
+ }
+
+ public SortedMap<String, String> getSymbolMap() {
+ return symbolMap;
+ }
+ }
+
/**
* Compiles a particular permutation, based on a precompiled unified AST.
*
@@ -106,7 +147,7 @@
* @throws UnableToCompleteException if an error other than
* {@link OutOfMemoryError} occurs
*/
- public static String compilePermutation(TreeLogger logger,
+ public static PermutationResult compilePermutation(TreeLogger logger,
UnifiedAst unifiedAst, Map<String, String> rebindAnswers)
throws UnableToCompleteException {
try {
@@ -120,6 +161,7 @@
JProgram jprogram = ast.getJProgram();
JsProgram jsProgram = ast.getJsProgram();
JJSOptions options = unifiedAst.getOptions();
+ Map<String, JsName> symbolTable = new HashMap<String, JsName>();
ResolveRebinds.exec(jprogram, rebindAnswers);
@@ -143,17 +185,17 @@
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;
+ jprogram.typeOracle.recomputeAfterOptimizations();
+ JavaToJavaScriptMap map = GenerateJavaScriptAST.exec(jprogram, jsProgram,
+ options.getOutput(), symbolTable);
// (8) Normalize the JS AST.
// Fix invalid constructs created during JS AST gen.
JsNormalizer.exec(jsProgram);
// Resolve all unresolved JsNameRefs.
JsSymbolResolver.exec(jsProgram);
+ // Move all function definitions to a top-level scope, to reduce weirdness
+ EvalFunctionsAtTopScope.exec(jsProgram);
// (9) Optimize the JS AST.
if (options.isAggressivelyOptimize()) {
@@ -174,23 +216,33 @@
}
// (10) Obfuscate
+ final Map<JsName, String> stringLiteralMap;
switch (options.getOutput()) {
case OBFUSCATED:
- JsStringInterner.exec(jsProgram);
+ stringLiteralMap = JsStringInterner.exec(jsProgram);
JsObfuscateNamer.exec(jsProgram);
break;
case PRETTY:
// We don't intern strings in pretty mode to improve readability
+ stringLiteralMap = new HashMap<JsName, String>();
JsPrettyNamer.exec(jsProgram);
break;
case DETAILED:
- JsStringInterner.exec(jsProgram);
+ stringLiteralMap = JsStringInterner.exec(jsProgram);
JsVerboseNamer.exec(jsProgram);
break;
default:
throw new InternalCompilerException("Unknown output mode");
}
+ JavaToJavaScriptMap postStringInterningMap = addStringLiteralMap(map,
+ stringLiteralMap);
+
+ // (10.5) Split up the program into fragments
+ if (options.isAggressivelyOptimize() && options.isRunAsyncEnabled()) {
+ CodeSplitter.exec(logger, jprogram, jsProgram, postStringInterningMap);
+ }
+
// (11) Perform any post-obfuscation normalizations.
// Work around an IE7 bug,
@@ -198,11 +250,38 @@
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();
+ String[] js = new String[jsProgram.getFragmentCount()];
+ List<Map<Range, SourceInfo>> sourceInfoMaps = options.isSoycEnabled()
+ ? new ArrayList<Map<Range, SourceInfo>>(jsProgram.getFragmentCount())
+ : null;
+
+ for (int i = 0; i < js.length; i++) {
+ if (sourceInfoMaps != null) {
+ CountingTextOutput out = new CountingTextOutput(
+ options.getOutput().shouldMinimize());
+ JsReportGenerationVisitor v = new JsReportGenerationVisitor(out);
+ v.accept(jsProgram.getFragmentBlock(i));
+ js[i] = out.toString();
+ sourceInfoMaps.add(v.getSourceInfoMap());
+ } else {
+ DefaultTextOutput out = new DefaultTextOutput(
+ options.getOutput().shouldMinimize());
+ JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out);
+ v.accept(jsProgram.getFragmentBlock(i));
+ js[i] = out.toString();
+ }
+ }
+
+ SortedMap<String, String> symbolMap = makeSymbolMap(symbolTable);
+
+ PermutationResult toReturn = new PermutationResultImpl(js, symbolMap);
+ if (sourceInfoMaps != null) {
+ toReturn.getArtifacts().add(
+ new StandardCompilationAnalysis(logger, sourceInfoMaps,
+ jprogram.getSplitPointMap()));
+ }
+
+ return toReturn;
} catch (Throwable e) {
throw logAndTranslateException(logger, e);
}
@@ -248,6 +327,7 @@
Collections.addAll(allRootTypes, additionalRootTypes);
allRootTypes.addAll(JProgram.CODEGEN_TYPES_SET);
allRootTypes.addAll(JProgram.INDEX_TYPES_SET);
+ allRootTypes.add(FragmentLoaderCreator.ASYNC_FRAGMENT_LOADER);
// Compile the source and get the compiler so we can get the parse tree
//
@@ -260,8 +340,8 @@
checkForErrors(logger, goldenCuds, false);
PerfLogger.start("Build AST");
- JProgram jprogram = new JProgram();
- JsProgram jsProgram = new JsProgram();
+ JProgram jprogram = new JProgram(options.isSoycEnabled());
+ JsProgram jsProgram = new JsProgram(options.isSoycEnabled());
try {
/*
@@ -281,7 +361,7 @@
// (2) Create our own Java AST from the JDT AST.
GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram, jsProgram,
- options.isEnableAssertions());
+ options);
// GenerateJavaAST can uncover semantic JSNI errors; report & abort
checkForErrors(logger, goldenCuds, true);
@@ -310,6 +390,11 @@
// Replace GWT.create calls with JGwtCreate nodes.
ReplaceRebinds.exec(logger, jprogram, rpo);
+ // Fix up GWT.runAsync()
+ if (options.isAggressivelyOptimize() && options.isRunAsyncEnabled()) {
+ ReplaceRunAsyncs.exec(logger, jprogram);
+ }
+
// Resolve entry points, rebinding non-static entry points.
findEntryPoints(logger, rpo, declEntryPts, jprogram);
@@ -356,9 +441,9 @@
}
// Recompute clinits each time, they can become empty.
- jprogram.typeOracle.recomputeClinits();
-
+ jprogram.typeOracle.recomputeAfterOptimizations();
didChange = false;
+
// Remove unreferenced types, fields, methods, [params, locals]
didChange = Pruner.exec(jprogram, true) || didChange;
// finalize locals, params, fields, methods, classes
@@ -386,7 +471,50 @@
}
// prove that any types that have been culled from the main tree are
// unreferenced due to type tightening?
- } while (didChange);
+ } while (didChange && !options.isDraftCompile());
+
+ if (options.isDraftCompile()) {
+ /*
+ * Ensure that references to dead clinits are removed. Otherwise, the
+ * application won't run reliably.
+ */
+ jprogram.typeOracle.recomputeAfterOptimizations();
+ DeadCodeElimination.exec(jprogram);
+ }
+ }
+
+ private static JavaToJavaScriptMap addStringLiteralMap(
+ final JavaToJavaScriptMap map, final Map<JsName, String> stringLiteralMap) {
+ JavaToJavaScriptMap postStringInterningMap = new JavaToJavaScriptMap() {
+ public JsName nameForMethod(JMethod method) {
+ return map.nameForMethod(method);
+ }
+
+ public JsName nameForType(JReferenceType type) {
+ return map.nameForType(type);
+ }
+
+ public JField nameToField(JsName name) {
+ return map.nameToField(name);
+ }
+
+ public JMethod nameToMethod(JsName name) {
+ return map.nameToMethod(name);
+ }
+
+ public String stringLiteralForName(JsName name) {
+ return stringLiteralMap.get(name);
+ }
+
+ public JReferenceType typeForStatement(JsStatement stat) {
+ return map.typeForStatement(stat);
+ }
+
+ public JMethod vtableInitToMethod(JsStatement stat) {
+ return map.vtableInitToMethod(stat);
+ }
+ };
+ return postStringInterningMap;
}
private static void checkForErrors(TreeLogger logger,
@@ -469,10 +597,12 @@
+ 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, null,
+ qualifier = JGwtCreate.createInstantiationExpression(program, sourceInfo,
entryClass);
if (qualifier == null) {
@@ -485,14 +615,17 @@
throw new UnableToCompleteException();
}
}
- return new JMethodCall(program, null, qualifier, entryMethod);
+ return new JMethodCall(program, sourceInfo, qualifier, entryMethod);
}
private static void findEntryPoints(TreeLogger logger,
RebindPermutationOracle rpo, String[] mainClassNames, JProgram program)
throws UnableToCompleteException {
- JMethod bootStrapMethod = program.createMethod(null, "init".toCharArray(),
- null, program.getTypeVoid(), false, true, true, false, false);
+ SourceInfo sourceInfo = program.createSourceInfoSynthetic(
+ JavaToJavaScriptCompiler.class, "Bootstrap method");
+ JMethod bootStrapMethod = program.createMethod(sourceInfo,
+ "init".toCharArray(), program.getIndexedType("EntryMethodHolder"),
+ program.getTypeVoid(), false, true, true, false, false);
bootStrapMethod.freezeParamTypes();
JMethodBody body = (JMethodBody) bootStrapMethod.getBody();
@@ -621,20 +754,34 @@
*/
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, null, null,
+ JMethodCall availableCall = new JMethodCall(program, sourceInfo, null,
isStatsAvailableMethod);
- JMethodCall onModuleStartCall = new JMethodCall(program, null, null,
+ JMethodCall onModuleStartCall = new JMethodCall(program, sourceInfo, null,
onModuleStartMethod);
- onModuleStartCall.getArgs().add(program.getLiteralString(mainClassName));
+ onModuleStartCall.getArgs().add(
+ program.getLiteralString(sourceInfo, mainClassName));
- JBinaryOperation amp = new JBinaryOperation(program, null,
+ JBinaryOperation amp = new JBinaryOperation(program, sourceInfo,
program.getTypePrimitiveBoolean(), JBinaryOperator.AND, availableCall,
onModuleStartCall);
return amp.makeStatement();
}
+ private static SortedMap<String, String> makeSymbolMap(
+ Map<String, JsName> symbolTable) {
+
+ SortedMap<String, String> toReturn = new TreeMap<String, String>();
+
+ for (Map.Entry<String, JsName> entry : symbolTable.entrySet()) {
+ toReturn.put(entry.getKey(), entry.getValue().getShortIdent());
+ }
+
+ return toReturn;
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/SourceInfo.java b/dev/core/src/com/google/gwt/dev/jjs/SourceInfo.java
index 7debc2c..f4381b8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/SourceInfo.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/SourceInfo.java
@@ -15,38 +15,341 @@
*/
package com.google.gwt.dev.jjs;
+import com.google.gwt.dev.jjs.Correlation.Axis;
+
import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
/**
* Tracks file and line information for AST nodes.
*/
public class SourceInfo implements Serializable {
- private final int endPos;
- private final String fileName;
- private final int startLine;
- private final int startPos;
+ /**
+ * Describes how the SourceInfo's node was mutated during the compile cycle.
+ */
+ public static final class Mutation implements Serializable {
+ private final String caller;
+ private final String description;
+ private final long ts = System.currentTimeMillis();
- public SourceInfo(int startPos, int endPos, int startLine, String fileName) {
- this.startPos = startPos;
- this.endPos = endPos;
- this.startLine = startLine;
- this.fileName = fileName;
+ private Mutation(String description, String caller) {
+ this.caller = caller;
+ this.description = description;
+ }
+
+ public String getCaller() {
+ return caller;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public long getTimestamp() {
+ return ts;
+ }
+ }
+
+ /**
+ * A totally-immutable version of SourceInfo.
+ */
+ protected static class Immutable extends SourceInfo {
+ public Immutable(int startPos, int endPos, int startLine, String fileName,
+ boolean createDescendants) {
+ super(startPos, endPos, startLine, fileName, createDescendants);
+ }
+
+ @Override
+ public void addCorrelation(Correlation c) {
+ throw new UnsupportedOperationException(
+ "May not add correlations to the " + getFileName()
+ + "SourceInfo. Call makeChild() first.");
+ }
+
+ @Override
+ public void copyMissingCorrelationsFrom(SourceInfo other) {
+ throw new UnsupportedOperationException(
+ "May not copy correlations into the " + getFileName()
+ + "SourceInfo. Call makeChild() first.");
+ }
+
+ @Override
+ public void merge(SourceInfo... sourceInfos) {
+ if (sourceInfos.length > 0) {
+ throw new UnsupportedOperationException(
+ "May not merge SourceInfos into the " + getFileName()
+ + " SourceInfo. Call makeChild() first.");
+ }
+ }
+ }
+
+ /**
+ * Indicates that the source for an AST element is unknown. This indicates a
+ * deficiency in the compiler.
+ */
+ public static final SourceInfo UNKNOWN = new Immutable(0, 0, 0,
+ "Unknown source", true);
+
+ /**
+ * Collecting mutation data is expensive in terms of additional objects and
+ * string literals and only of interest to compiler hackers, so we'll just
+ * normally have it disabled.
+ */
+ private static final boolean COLLECT_MUTATIONS = Boolean.getBoolean("gwt.soyc.collectMutations");
+
+ /**
+ * Micro-opt for {@link #makeChild(Class, String)}.
+ */
+ private static final SourceInfo[] EMPTY_SOURCEINFO_ARRAY = new SourceInfo[0];
+
+ /**
+ * This flag controls the behavior of the mutable methods to make them no-ops.
+ */
+ private final boolean accumulateData;
+
+ /**
+ * Any Correlation associated with the SourceInfo.
+ */
+ private final Set<Correlation> allCorrelations;
+
+ /**
+ * Holds Mutation objects if the compiler is configured to collect mutations.
+ */
+ private final List<Mutation> mutations = COLLECT_MUTATIONS
+ ? new ArrayList<Mutation>() : null;
+
+ /**
+ * Holds the origin data for the SourceInfo.
+ */
+ private final SourceOrigin origin;
+
+ /**
+ * Records the first Correlation on any given Axis applied to the SourceInfo.
+ */
+ private final EnumMap<Axis, Correlation> primaryCorrelations;
+
+ protected SourceInfo(int startPos, int endPos, int startLine,
+ String fileName, boolean accumulateData) {
+ assert fileName != null;
+
+ this.accumulateData = accumulateData;
+ origin = SourceOrigin.create(startPos, endPos, startLine, fileName);
+
+ // Be very aggressive in not allocating collections that we don't need.
+ if (accumulateData) {
+ allCorrelations = new HashSet<Correlation>();
+ primaryCorrelations = new EnumMap<Axis, Correlation>(Axis.class);
+ // Don't use addCorrelation because of the immutable subclasses
+ Correlation originCorrelation = Correlation.by(origin);
+ allCorrelations.add(originCorrelation);
+ primaryCorrelations.put(Axis.ORIGIN, originCorrelation);
+ } else {
+ allCorrelations = null;
+ primaryCorrelations = null;
+ }
+ }
+
+ private SourceInfo(SourceInfo parent, String mutation, String caller,
+ SourceInfo... additionalAncestors) {
+ assert parent != null;
+ assert mutation != null;
+ assert caller != null;
+
+ this.accumulateData = parent.accumulateData;
+ this.origin = parent.origin;
+
+ if (accumulateData) {
+ this.allCorrelations = new HashSet<Correlation>(parent.allCorrelations);
+ this.primaryCorrelations = new EnumMap<Axis, Correlation>(
+ parent.primaryCorrelations);
+ } else {
+ allCorrelations = null;
+ primaryCorrelations = null;
+ }
+
+ if (COLLECT_MUTATIONS) {
+ this.mutations.addAll(parent.mutations);
+ this.mutations.add(new Mutation(mutation, caller));
+ }
+
+ merge(additionalAncestors);
+ }
+
+ /**
+ * Add a Correlation to the SourceInfo.
+ */
+ public void addCorrelation(Correlation c) {
+ if (!accumulateData) {
+ return;
+ }
+
+ allCorrelations.add(c);
+
+ if (!primaryCorrelations.containsKey(c.getAxis())) {
+ primaryCorrelations.put(c.getAxis(), c);
+ }
+ }
+
+ /**
+ * Copy any Correlations from another SourceInfo node if there are no
+ * Correlations on this SourceInfo with the same Axis.
+ */
+ public void copyMissingCorrelationsFrom(SourceInfo other) {
+ if (!accumulateData) {
+ return;
+ }
+
+ EnumSet<Axis> toAdd = EnumSet.allOf(Axis.class);
+ for (Correlation c : allCorrelations) {
+ toAdd.remove(c.getAxis());
+ }
+
+ for (Correlation c : other.getAllCorrelations()) {
+ if (toAdd.contains(c.getAxis())) {
+ addCorrelation(c);
+ }
+ }
+ }
+
+ /**
+ * Returns all Correlations applied to this SourceInfo, its parent, additional
+ * ancestor SourceInfo, and any supertype SourceInfos.
+ */
+ public Set<Correlation> getAllCorrelations() {
+ return accumulateData ? allCorrelations
+ : Collections.<Correlation> emptySet();
+ }
+
+ /**
+ * Returns all Correlations along a given axis applied to this SourceInfo, its
+ * parent, additional ancestor SourceInfo, and any supertype SourceInfos.
+ */
+ public Set<Correlation> getAllCorrelations(Axis axis) {
+ if (!accumulateData) {
+ return Collections.emptySet();
+ }
+
+ Set<Correlation> toReturn = new HashSet<Correlation>();
+ for (Correlation c : getAllCorrelations()) {
+ if (c.getAxis() == axis) {
+ toReturn.add(c);
+ }
+ }
+ return toReturn;
}
public int getEndPos() {
- return endPos;
+ return getOrigin().getEndPos();
}
public String getFileName() {
- return fileName;
+ return getOrigin().getFileName();
+ }
+
+ /**
+ * Returns a summary of the mutations applied to the SourceInfo. It it
+ * expensive to collect mutation data, so this method will only return useful
+ * values if the <code>gwt.jjs.collectMutations</code> system property is
+ * defined.
+ */
+ public List<Mutation> getMutations() {
+ if (COLLECT_MUTATIONS) {
+ return mutations;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ public SourceOrigin getOrigin() {
+ return origin;
+ }
+
+ /**
+ * Returns the first Correlation that had been set with a given Axis, or
+ * <code>null</code> if no Correlation has been set on the given axis.
+ */
+ public Correlation getPrimaryCorrelation(Axis axis) {
+ return accumulateData ? primaryCorrelations.get(axis) : null;
+ }
+
+ /**
+ * Returns the first Correlations added along each Axis on which a Correlation
+ * has been set.
+ */
+ public Set<Correlation> getPrimaryCorrelations() {
+ return accumulateData ? new HashSet<Correlation>(
+ primaryCorrelations.values()) : Collections.<Correlation> emptySet();
}
public int getStartLine() {
- return startLine;
+ return getOrigin().getStartLine();
}
public int getStartPos() {
- return startPos;
+ return getOrigin().getStartPos();
+ }
+
+ /**
+ * If data accumulation is enabled, create a derived SourceInfo object that
+ * indicates that one or more AST nodes were merged to create a new node. The
+ * derived node will inherit its Origin and Correlations from the SourceInfo
+ * object on which the method is invoked.
+ */
+ public SourceInfo makeChild(Class<?> caller, String description) {
+ return accumulateData ? makeChild(caller, description,
+ EMPTY_SOURCEINFO_ARRAY) : this;
+ }
+
+ /**
+ * If data accumulation is enabled, create a derived SourceInfo object that
+ * indicates that one or more AST nodes were merged to create a new node. The
+ * derived node will inherit its Origin and Correlations from the SourceInfo
+ * object on which the method is invoked.
+ */
+ public SourceInfo makeChild(Class<?> caller, String description,
+ SourceInfo... merge) {
+ if (!accumulateData) {
+ return this;
+ }
+
+ String callerName = caller == null ? "Unrecorded caller" : caller.getName();
+ return new SourceInfo(this, description, callerName, merge);
+ }
+
+ /**
+ * Add additional ancestor SourceInfos. These SourceInfo objects indicate that
+ * a merge-type operation took place or that the additional ancestors have a
+ * containment relationship with the SourceInfo.
+ */
+ public void merge(SourceInfo... sourceInfos) {
+ if (!accumulateData) {
+ return;
+ }
+
+ for (SourceInfo info : sourceInfos) {
+ if (this == info || !info.accumulateData) {
+ continue;
+ }
+
+ allCorrelations.addAll(info.getAllCorrelations());
+
+ if (primaryCorrelations.size() < Axis.values().length) {
+ EnumMap<Axis, Correlation> copy = new EnumMap<Axis, Correlation>(
+ info.primaryCorrelations);
+ copy.keySet().removeAll(primaryCorrelations.keySet());
+ primaryCorrelations.putAll(copy);
+ }
+
+ if (COLLECT_MUTATIONS) {
+ mutations.addAll(0, info.getMutations());
+ }
+ }
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/SourceOrigin.java b/dev/core/src/com/google/gwt/dev/jjs/SourceOrigin.java
new file mode 100644
index 0000000..0b57c9f
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/SourceOrigin.java
@@ -0,0 +1,108 @@
+/*
+ * 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 org.apache.commons.collections.map.ReferenceMap;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Describes where a SourceInfo's node came from. This class currently includes
+ * only physical origin information, but could be extended to provide support
+ * for source-Module and -Generators.
+ */
+public final class SourceOrigin implements Serializable {
+ /**
+ * This is synchronized since several threads could operate on it at once
+ * during parallel optimization phases.
+ */
+ @SuppressWarnings("unchecked")
+ private static final Map<SourceOrigin, SourceOrigin> CANONICAL_SOURCE_ORIGINS = Collections.synchronizedMap(new ReferenceMap(
+ ReferenceMap.WEAK, ReferenceMap.SOFT));
+
+ /**
+ * Creates SourceOrigin nodes. This factory method will attempt to provide
+ * canonicalized instances of SourceOrigin objects.
+ */
+ public static SourceOrigin create(int startPos, int endPos, int startLine,
+ String fileName) {
+
+ SourceOrigin newInstance = new SourceOrigin(fileName, startLine, startPos,
+ endPos);
+ SourceOrigin canonical = CANONICAL_SOURCE_ORIGINS.get(newInstance);
+
+ assert canonical == null
+ || (newInstance != canonical && newInstance.equals(canonical));
+
+ if (canonical != null) {
+ return canonical;
+ } else {
+ CANONICAL_SOURCE_ORIGINS.put(newInstance, newInstance);
+ return newInstance;
+ }
+ }
+
+ // TODO: Add Module and Generator tracking
+ private final int endPos;
+ private final String fileName;
+ private final int hash;
+ private final int startLine;
+ private final int startPos;
+
+ private SourceOrigin(String location, int startLine, int startPos, int endPos) {
+ this.fileName = location;
+ this.startLine = startLine;
+ this.startPos = startPos;
+ this.endPos = endPos;
+
+ // Go ahead and compute the hash, since it'll be used for canonicalization
+ this.hash = 13 * endPos + 17 * fileName.hashCode() + 29 * startLine + 31
+ * startPos + 2;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof SourceOrigin)) {
+ return false;
+ }
+ SourceOrigin other = (SourceOrigin) o;
+ return endPos == other.endPos && fileName.equals(other.fileName)
+ && startLine == other.startLine && startPos == other.startPos;
+ }
+
+ public int getEndPos() {
+ return endPos;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public int getStartLine() {
+ return startLine;
+ }
+
+ public int getStartPos() {
+ return startPos;
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JAbsentArrayDimension.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JAbsentArrayDimension.java
index 09c0a5f..e4cff33 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JAbsentArrayDimension.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JAbsentArrayDimension.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents an array dimension that was not specified in an array
* instantiation expression.
@@ -24,8 +26,8 @@
/**
* These are only supposed to be constructed by JProgram.
*/
- JAbsentArrayDimension(JProgram program) {
- super(program);
+ JAbsentArrayDimension(JProgram program, SourceInfo sourceInfo) {
+ super(program, sourceInfo);
}
public JType getType() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
index a220699..67869ad 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
@@ -35,7 +35,8 @@
* These are only supposed to be constructed by JProgram.
*/
JArrayType(JProgram program, JType leafType, int dims) {
- super(program, null, calcName(leafType, dims), false, false);
+ super(program, leafType.getSourceInfo().makeChild(JArrayType.class,
+ "Array type"), calcName(leafType, dims), false, false);
this.leafType = leafType;
this.dims = dims;
}
@@ -86,6 +87,7 @@
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
+ visitor.acceptWithInsertRemove(fields);
}
visitor.endVisit(this, ctx);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JBooleanLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JBooleanLiteral.java
index 4499762..34acce3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JBooleanLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JBooleanLiteral.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Java boolean literal expression.
*/
@@ -25,8 +27,8 @@
/**
* These are only supposed to be constructed by JProgram.
*/
- JBooleanLiteral(JProgram program, boolean value) {
- super(program);
+ JBooleanLiteral(JProgram program, SourceInfo sourceInfo, boolean value) {
+ super(program, sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JCharLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JCharLiteral.java
index 1e71bfa..361971d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JCharLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JCharLiteral.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Java character literal expression.
*/
@@ -25,8 +27,8 @@
/**
* These are only supposed to be constructed by JProgram.
*/
- JCharLiteral(JProgram program, char value) {
- super(program);
+ JCharLiteral(JProgram program, SourceInfo sourceInfo, char value) {
+ super(program, sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
index a2c27fa..aeada25 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
@@ -36,11 +36,25 @@
String typeName = getTypeName(program, type);
JMethod method = program.getIndexedMethod(type.getClassLiteralFactoryMethod());
+
+ /*
+ * Use the classForEnum() constructor even for enum subtypes to aid in
+ * pruning supertype data.
+ */
+ boolean isEnumOrSubclass = false;
+ if (type instanceof JClassType) {
+ JEnumType maybeEnum = ((JClassType) type).isEnumOrSubclass();
+ if (maybeEnum != null) {
+ isEnumOrSubclass = true;
+ method = program.getIndexedMethod(maybeEnum.getClassLiteralFactoryMethod());
+ }
+ }
+
assert method != null;
JMethodCall call = new JMethodCall(program, info, null, method);
- call.getArgs().add(program.getLiteralString(getPackageName(typeName)));
- call.getArgs().add(program.getLiteralString(getClassName(typeName)));
+ call.getArgs().add(program.getLiteralString(info, getPackageName(typeName)));
+ call.getArgs().add(program.getLiteralString(info, getClassName(typeName)));
if (type instanceof JClassType && !(type instanceof JArrayType)) {
/*
@@ -80,9 +94,16 @@
JsniMethodRef jsniMethodRef = new JsniMethodRef(program, info, null,
valuesMethod);
call.getArgs().add(jsniMethodRef);
+ } else if (isEnumOrSubclass) {
+ // A subclass of an enum class
+ call.getArgs().add(program.getLiteralNull());
}
+ } else if (type instanceof JArrayType) {
+ JArrayType arrayType = (JArrayType) type;
+ JClassLiteral componentLiteral = program.getLiteralClass(arrayType.getElementType());
+ call.getArgs().add(componentLiteral);
} else {
- assert (type instanceof JArrayType || type instanceof JInterfaceType || type instanceof JPrimitiveType);
+ assert (type instanceof JInterfaceType || type instanceof JPrimitiveType);
}
return call;
}
@@ -121,8 +142,9 @@
/**
* This constructor is only used by {@link JProgram}.
*/
- JClassLiteral(JProgram program, JType type, JField field) {
- super(program);
+ JClassLiteral(JProgram program, SourceInfo sourceInfo, JType type,
+ JField field) {
+ super(program, sourceInfo);
refType = type;
this.field = field;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JDoubleLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JDoubleLiteral.java
index df35d14..2429c0e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JDoubleLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JDoubleLiteral.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Java double literal expression.
*/
@@ -25,8 +27,8 @@
/**
* These are only supposed to be constructed by JProgram.
*/
- JDoubleLiteral(JProgram program, double value) {
- super(program);
+ JDoubleLiteral(JProgram program, SourceInfo sourceInfo, double value) {
+ super(program, sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JFloatLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JFloatLiteral.java
index 289f99d..25efecc 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JFloatLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JFloatLiteral.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Java literal typed as a float.
*/
@@ -25,8 +27,8 @@
/**
* These are only supposed to be constructed by JProgram.
*/
- JFloatLiteral(JProgram program, float value) {
- super(program);
+ JFloatLiteral(JProgram program, SourceInfo sourceInfo, float value) {
+ super(program, sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JIntLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JIntLiteral.java
index 6c01603..a502ffd 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JIntLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JIntLiteral.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Java integer literal expression.
*/
@@ -25,8 +27,8 @@
/**
* These are only supposed to be constructed by JProgram.
*/
- JIntLiteral(JProgram program, int value) {
- super(program);
+ JIntLiteral(JProgram program, SourceInfo sourceInfo, int value) {
+ super(program, sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JLiteral.java
index 3c3b5ff..4798701 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JLiteral.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
@@ -15,13 +15,15 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Base class for any Java literal expression.
*/
public abstract class JLiteral extends JExpression {
- public JLiteral(JProgram program) {
- super(program, null);
+ public JLiteral(JProgram program, SourceInfo sourceInfo) {
+ super(program, sourceInfo);
}
public boolean hasSideEffects() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JLongLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JLongLiteral.java
index ba73371..2e4a075 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JLongLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JLongLiteral.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Java literal expression that evaluates to a Long.
*/
@@ -25,8 +27,8 @@
/**
* These are only supposed to be constructed by JProgram.
*/
- JLongLiteral(JProgram program, long value) {
- super(program);
+ JLongLiteral(JProgram program, SourceInfo sourceInfo, long value) {
+ super(program, sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java
index 88fc652..7126366 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java
@@ -38,7 +38,18 @@
} else {
this.program = program;
}
- this.info = info;
+
+ if (info != null) {
+ this.info = info;
+ } else {
+ /*
+ * This indicates a deficiency in the compiler. We use getClass() instead
+ * of the usual class literal to figure out what kind of thing was being
+ * constructed.
+ */
+ this.info = SourceInfo.UNKNOWN.makeChild(getClass(), "Unknown "
+ + getClass().getSimpleName());
+ }
}
public JProgram getProgram() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JNullLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JNullLiteral.java
index cfd99c7..6d9a8b2 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JNullLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JNullLiteral.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Java null literal expression.
*/
@@ -23,8 +25,8 @@
/**
* These are only supposed to be constructed by JProgram.
*/
- JNullLiteral(JProgram program) {
- super(program);
+ JNullLiteral(JProgram program, SourceInfo sourceInfo) {
+ super(program, sourceInfo);
}
@Override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JNullType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JNullType.java
index bc52521..3f69adb 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JNullType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JNullType.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,14 +16,15 @@
package com.google.gwt.dev.jjs.ast;
import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.jjs.SourceInfo;
/**
* Java null reference type.
*/
public class JNullType extends JReferenceType {
- public JNullType(JProgram program) {
- super(program, null, "<null>");
+ public JNullType(JProgram program, SourceInfo sourceInfo) {
+ super(program, sourceInfo, "<null>");
}
@Override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
index 320b1c5..903897c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
@@ -28,7 +28,8 @@
*/
JPrimitiveType(JProgram program, String name, String signatureName,
String wrapperTypeName, JLiteral defaultValue) {
- super(program, null, name, defaultValue);
+ super(program, program.createSourceInfoSynthetic(JPrimitiveType.class, name
+ + " primitive type"), name, defaultValue);
this.signatureName = signatureName;
this.wrapperTypeName = wrapperTypeName;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index 0d3e6b7..01b2667 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -15,8 +15,10 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.Correlation;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.Correlation.Literal;
import com.google.gwt.dev.jjs.ast.JField.Disposition;
import com.google.gwt.dev.jjs.ast.js.JClassSeed;
import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
@@ -35,6 +37,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
import java.util.TreeSet;
/**
@@ -66,7 +69,10 @@
"java.lang.Iterable", "java.util.Iterator",
"com.google.gwt.core.client.GWT",
"com.google.gwt.core.client.JavaScriptObject",
- "com.google.gwt.lang.ClassLiteralHolder",}));
+ "com.google.gwt.lang.ClassLiteralHolder",
+ "com.google.gwt.core.client.RunAsyncCallback",
+ "com.google.gwt.core.client.AsyncFragmentLoader",
+ "com.google.gwt.lang.EntryMethodHolder",}));
static final Map<String, Set<String>> traceMethods = new HashMap<String, Set<String>>();
@@ -135,6 +141,15 @@
return traceMethods.size() > 0;
}
+ /**
+ * This method is used to create SourceInfos for fields in JProgram. This
+ * method always creates a SourceInfo that has collection enabled.
+ */
+ private static SourceInfo createSourceInfoEnabled(String description) {
+ return new SourceInfoJava(-1, -1, 0, JProgram.class.getName(), true).makeChild(
+ JProgram.class, description);
+ }
+
private static String dotify(char[][] name) {
StringBuffer result = new StringBuffer();
for (int i = 0; i < name.length; ++i) {
@@ -149,7 +164,13 @@
public final List<JClassType> codeGenTypes = new ArrayList<JClassType>();
- public final List<JMethod> entryMethods = new ArrayList<JMethod>();
+ /**
+ * There is a list containing the main entry methods as well as the entry
+ * methods for each split point. The main entry methods are at entry 0 of this
+ * list. Split points are numbered sequentially from 1, and the entry methods
+ * for split point <em>i</em> are at entry <em>i</em> of this list.
+ */
+ public final List<List<JMethod>> entryMethods = new ArrayList<List<JMethod>>();
public final Map<String, HasEnclosingType> jsniMap = new HashMap<String, HasEnclosingType>();
@@ -172,6 +193,8 @@
*/
private final ArrayList<HashMap<JType, JArrayType>> dimensions = new ArrayList<HashMap<JType, JArrayType>>();
+ private final boolean enableSourceInfoDescendants;
+
private final Map<String, JField> indexedFields = new HashMap<String, JField>();
private final Map<String, JMethod> indexedMethods = new HashMap<String, JMethod>();
@@ -183,19 +206,25 @@
private List<JsonObject> jsonTypeTable;
private final JAbsentArrayDimension literalAbsentArrayDim = new JAbsentArrayDimension(
- this);
+ this, createSourceInfoEnabled("Absent array dimension"));
- private final JBooleanLiteral literalFalse = new JBooleanLiteral(this, false);
+ private final JBooleanLiteral literalFalse = new JBooleanLiteral(this,
+ createSourceInfoEnabled("false literal"), false);
- private final JIntLiteral literalIntNegOne = new JIntLiteral(this, -1);
+ private final JIntLiteral literalIntNegOne = new JIntLiteral(this,
+ createSourceInfoEnabled("-1 literal"), -1);
- private final JIntLiteral literalIntOne = new JIntLiteral(this, 1);
+ private final JIntLiteral literalIntOne = new JIntLiteral(this,
+ createSourceInfoEnabled("1 literal"), 1);
- private final JIntLiteral literalIntZero = new JIntLiteral(this, 0);
+ private final JIntLiteral literalIntZero = new JIntLiteral(this,
+ createSourceInfoEnabled("0 literal"), 0);
- private final JNullLiteral literalNull = new JNullLiteral(this);
+ private final JNullLiteral literalNull = new JNullLiteral(this,
+ createSourceInfoEnabled("null literal"));
- private final JBooleanLiteral literalTrue = new JBooleanLiteral(this, true);
+ private final JBooleanLiteral literalTrue = new JBooleanLiteral(this,
+ createSourceInfoEnabled("true literal"), true);
private JField nullField;
@@ -208,6 +237,8 @@
private Map<JReferenceType, Integer> queryIds;
+ private Map<Integer, String> splitPointMap = new TreeMap<Integer, String>();
+
private final Map<JMethod, JMethod> staticToInstanceMap = new IdentityHashMap<JMethod, JMethod>();
private final JPrimitiveType typeBoolean = new JPrimitiveType(this,
@@ -241,7 +272,8 @@
private final Map<String, JReferenceType> typeNameMap = new HashMap<String, JReferenceType>();
- private final JNullType typeNull = new JNullType(this);
+ private final JNullType typeNull = new JNullType(this,
+ createSourceInfoEnabled("null type"));
private final JPrimitiveType typeShort = new JPrimitiveType(this, "short",
"S", "java.lang.Short", literalIntZero);
@@ -255,13 +287,50 @@
private final JPrimitiveType typeVoid = new JPrimitiveType(this, "void", "V",
"java.lang.Void", null);
+ private final SourceInfo stringPoolSourceInfo;
+
+ private final Map<String, JStringLiteral> stringLiteralMap = new HashMap<String, JStringLiteral>();
+
public JProgram() {
- super(null, null);
+ this(false);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param enableSourceInfoDescendants Controls whether or not SourceInfo nodes
+ * created via the JProgram will record descendant information.
+ * Enabling this feature will collect extra data during the
+ * compilation cycle, but at a cost of memory and object allocations.
+ */
+ public JProgram(boolean enableSourceInfoDescendants) {
+ super(null, SourceInfoJava.INTRINSIC.makeChild(JProgram.class,
+ "Top-level program"));
+
+ this.enableSourceInfoDescendants = enableSourceInfoDescendants;
+ literalFalse.getSourceInfo().addCorrelation(Correlation.by(Literal.BOOLEAN));
+ literalIntNegOne.getSourceInfo().addCorrelation(Correlation.by(Literal.INT));
+ literalIntOne.getSourceInfo().addCorrelation(Correlation.by(Literal.INT));
+ literalIntZero.getSourceInfo().addCorrelation(Correlation.by(Literal.INT));
+ literalNull.getSourceInfo().addCorrelation(Correlation.by(Literal.NULL));
+ literalTrue.getSourceInfo().addCorrelation(Correlation.by(Literal.BOOLEAN));
+ stringPoolSourceInfo = createSourceInfoSynthetic(JProgram.class,
+ "String pool");
+ stringPoolSourceInfo.addCorrelation(Correlation.by(Literal.STRING));
}
public void addEntryMethod(JMethod entryPoint) {
- if (!entryMethods.contains(entryPoint)) {
- entryMethods.add(entryPoint);
+ addEntryMethod(entryPoint, 0);
+ }
+
+ public void addEntryMethod(JMethod entryPoint, int fragmentNumber) {
+ assert entryPoint.isStatic();
+ while (fragmentNumber >= entryMethods.size()) {
+ entryMethods.add(new ArrayList<JMethod>());
+ }
+ List<JMethod> methods = entryMethods.get(fragmentNumber);
+ if (!methods.contains(entryPoint)) {
+ methods.add(entryPoint);
}
}
@@ -394,11 +463,11 @@
public JMethod createMethod(SourceInfo info, char[] name,
JReferenceType enclosingType, JType returnType, boolean isAbstract,
boolean isStatic, boolean isFinal, boolean isPrivate, boolean isNative) {
- assert (name != null);
+ String sname = String.valueOf(name);
+ assert (sname != null);
+ assert (enclosingType != null);
assert (returnType != null);
assert (!isAbstract || !isNative);
-
- String sname = String.valueOf(name);
JMethod x = new JMethod(this, info, sname, enclosingType, returnType,
isAbstract, isStatic, isFinal, isPrivate);
if (isNative) {
@@ -431,6 +500,34 @@
return x;
}
+ /**
+ * Create a SourceInfo object when the source is derived from a physical
+ * location.
+ */
+ public SourceInfo createSourceInfo(int startPos, int endPos, int startLine,
+ String fileName) {
+ return new SourceInfoJava(startPos, endPos, startLine, fileName,
+ enableSourceInfoDescendants);
+ }
+
+ /**
+ * Create a SourceInfo object when the source is derived from a physical
+ * location.
+ */
+ public SourceInfo createSourceInfo(int startLine, String fileName) {
+ return new SourceInfoJava(-1, -1, startLine, fileName,
+ enableSourceInfoDescendants);
+ }
+
+ /**
+ * Create a SourceInfo object when the source is created by the compiler
+ * itself.
+ */
+ public SourceInfo createSourceInfoSynthetic(Class<?> caller,
+ String description) {
+ return createSourceInfo(0, caller.getName()).makeChild(caller, description);
+ }
+
public JReferenceType generalizeTypes(
Collection<? extends JReferenceType> types) {
assert (types != null);
@@ -451,16 +548,33 @@
return allArrayTypes;
}
+ public List<JMethod> getAllEntryMethods() {
+ List<JMethod> allEntryMethods = new ArrayList<JMethod>();
+ for (List<JMethod> entries : entryMethods) {
+ allEntryMethods.addAll(entries);
+ }
+ return allEntryMethods;
+ }
+
public List<JReferenceType> getDeclaredTypes() {
return allTypes;
}
+ public int getEntryCount(int fragment) {
+ return entryMethods.get(fragment).size();
+ }
+
public JThisRef getExprThisRef(SourceInfo info, JClassType enclosingType) {
return new JThisRef(this, info, enclosingType);
}
+ public int getFragmentCount() {
+ return entryMethods.size();
+ }
+
public JReferenceType getFromTypeMap(String qualifiedBinaryOrSourceName) {
String srcTypeName = qualifiedBinaryOrSourceName.replace('$', '.');
+
return typeNameMap.get(srcTypeName);
}
@@ -509,7 +623,9 @@
public JCharLiteral getLiteralChar(char c) {
// could be interned
- return new JCharLiteral(this, c);
+ SourceInfo info = createSourceInfoSynthetic(JProgram.class, c + " literal");
+ info.addCorrelation(Correlation.by(Literal.CHAR));
+ return new JCharLiteral(this, info, c);
}
/**
@@ -547,7 +663,10 @@
0).getBody();
clinitBody.getStatements().add(decl);
- classLiteral = new JClassLiteral(this, type, field);
+ SourceInfo literalInfo = createSourceInfoSynthetic(JProgram.class,
+ "class literal for " + type.getName());
+ literalInfo.addCorrelation(Correlation.by(Literal.CLASS));
+ classLiteral = new JClassLiteral(this, literalInfo, type, field);
classLiterals.put(type, classLiteral);
} else {
// Make sure the field hasn't been pruned.
@@ -567,17 +686,22 @@
*/
public JClassSeed getLiteralClassSeed(JClassType type) {
// could be interned
- return new JClassSeed(this, type);
+ return new JClassSeed(this, createSourceInfoSynthetic(JProgram.class,
+ "class seed"), type);
}
public JDoubleLiteral getLiteralDouble(double d) {
// could be interned
- return new JDoubleLiteral(this, d);
+ SourceInfo info = createSourceInfoSynthetic(JProgram.class, d + " literal");
+ info.addCorrelation(Correlation.by(Literal.DOUBLE));
+ return new JDoubleLiteral(this, info, d);
}
public JFloatLiteral getLiteralFloat(float f) {
// could be interned
- return new JFloatLiteral(this, f);
+ SourceInfo info = createSourceInfoSynthetic(JProgram.class, f + " literal");
+ info.addCorrelation(Correlation.by(Literal.FLOAT));
+ return new JFloatLiteral(this, info, f);
}
public JIntLiteral getLiteralInt(int i) {
@@ -588,42 +712,54 @@
return literalIntZero;
case 1:
return literalIntOne;
- default:
+ default: {
// could be interned
- return new JIntLiteral(this, i);
+ SourceInfo info = createSourceInfoSynthetic(JProgram.class, i
+ + " literal");
+ info.addCorrelation(Correlation.by(Literal.INT));
+ return new JIntLiteral(this, info, i);
+ }
}
}
public JLongLiteral getLiteralLong(long l) {
- return new JLongLiteral(this, l);
+ SourceInfo info = createSourceInfoSynthetic(JProgram.class, l + " literal");
+ info.addCorrelation(Correlation.by(Literal.LONG));
+ return new JLongLiteral(this, info, l);
}
public JNullLiteral getLiteralNull() {
return literalNull;
}
- public JStringLiteral getLiteralString(char[] s) {
- // should consolidate so we can build a string table in output code later?
- return new JStringLiteral(this, String.valueOf(s));
+ public JStringLiteral getLiteralString(SourceInfo sourceInfo, char[] s) {
+ return getLiteralString(sourceInfo, String.valueOf(s));
}
- public JStringLiteral getLiteralString(String s) {
- // should consolidate so we can build a string table in output code later?
- return new JStringLiteral(this, s);
+ public JStringLiteral getLiteralString(SourceInfo sourceInfo, String s) {
+ JStringLiteral toReturn = stringLiteralMap.get(s);
+ if (toReturn == null) {
+ toReturn = new JStringLiteral(this, stringPoolSourceInfo.makeChild(
+ JProgram.class, "String literal: " + s), s);
+ stringLiteralMap.put(s, toReturn);
+ }
+ toReturn.getSourceInfo().merge(sourceInfo);
+ return toReturn;
}
public JField getNullField() {
if (nullField == null) {
- nullField = new JField(this, null, "nullField", null, typeNull, false,
- Disposition.FINAL);
+ nullField = new JField(this, createSourceInfoSynthetic(JProgram.class,
+ "Null field"), "nullField", null, typeNull, false, Disposition.FINAL);
}
return nullField;
}
public JMethod getNullMethod() {
if (nullMethod == null) {
- nullMethod = new JMethod(this, null, "nullMethod", null, typeNull, false,
- false, true, true);
+ nullMethod = new JMethod(this, createSourceInfoSynthetic(JProgram.class,
+ "Null method"), "nullMethod", null, typeNull, false, false, true,
+ true);
}
return nullMethod;
}
@@ -637,6 +773,10 @@
return integer.intValue();
}
+ public Map<Integer, String> getSplitPointMap() {
+ return splitPointMap;
+ }
+
public JMethod getStaticImpl(JMethod method) {
return instanceToStaticMap.get(method);
}
@@ -678,6 +818,46 @@
return typeSpecialClassLiteralHolder;
}
+ /**
+ * Returns the JType corresponding to a JSNI type reference.
+ */
+ public JType getTypeFromJsniRef(String className) {
+ int dim = 0;
+ while (className.endsWith("[]")) {
+ dim++;
+ className = className.substring(0, className.length() - 2);
+ }
+
+ JType type;
+ if ("Z".equals(className)) {
+ type = program.getTypePrimitiveBoolean();
+ } else if ("B".equals(className)) {
+ type = program.getTypePrimitiveByte();
+ } else if ("C".equals(className)) {
+ type = program.getTypePrimitiveChar();
+ } else if ("D".equals(className)) {
+ type = program.getTypePrimitiveDouble();
+ } else if ("F".equals(className)) {
+ type = program.getTypePrimitiveFloat();
+ } else if ("I".equals(className)) {
+ type = program.getTypePrimitiveInt();
+ } else if ("J".equals(className)) {
+ type = program.getTypePrimitiveLong();
+ } else if ("S".equals(className)) {
+ type = program.getTypePrimitiveShort();
+ } else if ("V".equals(className)) {
+ type = program.getTypeVoid();
+ } else {
+ type = getFromTypeMap(className);
+ }
+
+ if (type == null || dim == 0) {
+ return type;
+ } else {
+ return getTypeArray(type, dim);
+ }
+ }
+
public int getTypeId(JClassType classType) {
Integer integer = typeIdMap.get(classType);
if (integer == null) {
@@ -782,10 +962,14 @@
this.queryIds = queryIds;
}
+ public void setSplitPointMap(Map<Integer, String> splitPointMap) {
+ this.splitPointMap = splitPointMap;
+ }
+
/**
- * If <code>method</code> is a static impl method, returns the instance
- * method that <code>method</code> is the implementation of. Otherwise,
- * returns <code>null</code>.
+ * If <code>method</code> is a static impl method, returns the instance method
+ * that <code>method</code> is the implementation of. Otherwise, returns
+ * <code>null</code>.
*/
public JMethod staticImplFor(JMethod method) {
return staticToInstanceMap.get(method);
@@ -811,8 +995,8 @@
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
- visitor.accept(entryMethods);
visitor.accept(allTypes);
+ visitor.accept(new ArrayList<JArrayType>(allArrayTypes));
}
visitor.endVisit(this, ctx);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JStringLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JStringLiteral.java
index be45a1f..d6f3df2 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JStringLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JStringLiteral.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Java literal expression that evaluates to a string.
*/
@@ -25,8 +27,8 @@
/**
* These are only supposed to be constructed by JProgram.
*/
- JStringLiteral(JProgram program, String value) {
- super(program);
+ JStringLiteral(JProgram program, SourceInfo sourceInfo, String value) {
+ super(program, sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
index b7774a2..cdbd1de 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -19,9 +19,11 @@
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -143,7 +145,7 @@
* here regarding methods with type parameters in their argument lists. The
* caller must be careful that this level of matching is sufficient.
*/
- private static boolean methodsDoMatch(JMethod method1, JMethod method2) {
+ public static boolean methodsDoMatch(JMethod method1, JMethod method2) {
// static methods cannot match each other
if (method1.isStatic() || method2.isStatic()) {
return false;
@@ -170,10 +172,41 @@
return true;
}
+ /**
+ * Determine whether a type is instantiated, given an assumed list of
+ * instantiated types.
+ *
+ * @param type any type
+ * @param instantiatedTypes a set of types assumed to be instantiated. If
+ * <code>null</code>, then there are no assumptions about which types
+ * are instantiated.
+ * @return whether the type is instantiated
+ */
+ private static boolean isInstantiatedType(JReferenceType type,
+ Set<JReferenceType> instantiatedTypes) {
+ if (instantiatedTypes == null) {
+ return true;
+ }
+
+ if (type instanceof JNullType) {
+ return true;
+ }
+
+ if (type instanceof JArrayType) {
+ JArrayType arrayType = (JArrayType) type;
+ if (arrayType.getLeafType() instanceof JNullType) {
+ return true;
+ }
+ }
+ return instantiatedTypes.contains(type);
+ }
+
private final Map<JInterfaceType, Set<JClassType>> couldBeImplementedMap = new IdentityHashMap<JInterfaceType, Set<JClassType>>();
private final Map<JClassType, Set<JInterfaceType>> couldImplementMap = new IdentityHashMap<JClassType, Set<JInterfaceType>>();
+ private final Set<JInterfaceType> dualImpl = new HashSet<JInterfaceType>();
+
private final Set<JReferenceType> hasClinitSet = new HashSet<JReferenceType>();
private final Map<JClassType, Set<JInterfaceType>> implementsMap = new IdentityHashMap<JClassType, Set<JInterfaceType>>();
@@ -184,6 +217,8 @@
private JClassType javaLangObject = null;
+ private final Map<JInterfaceType, JClassType> jsoSingleImpls = new IdentityHashMap<JInterfaceType, JClassType>();
+
private final JProgram program;
private final Map<JClassType, Set<JClassType>> subClassMap = new IdentityHashMap<JClassType, Set<JClassType>>();
@@ -200,6 +235,29 @@
this.program = program;
}
+ /**
+ * Collect all supertypes and superinterfaces for a type.
+ */
+ public Set<JReferenceType> allAssignableFrom(JReferenceType type) {
+ Set<JReferenceType> toReturn = new HashSet<JReferenceType>();
+ List<JReferenceType> q = new LinkedList<JReferenceType>();
+ q.add(type);
+
+ while (!q.isEmpty()) {
+ JReferenceType t = q.remove(0);
+
+ if (toReturn.add(t)) {
+ if (t.extnds != null) {
+ q.add(t.extnds);
+ }
+
+ q.addAll(t.implments);
+ }
+ }
+
+ return toReturn;
+ }
+
public boolean canTheoreticallyCast(JReferenceType type, JReferenceType qType) {
JClassType jlo = program.getTypeJavaLangObject();
if (type == qType || type == jlo) {
@@ -318,15 +376,15 @@
/**
* Returns <code>true</code> if a static field access of <code>toType</code>
- * from within <code>fromType</code> should generate a clinit call. This
- * will be true in cases where <code>toType</code> has a live clinit method
- * which we cannot statically know has already run. We can statically know the
+ * from within <code>fromType</code> should generate a clinit call. This will
+ * be true in cases where <code>toType</code> has a live clinit method which
+ * we cannot statically know has already run. We can statically know the
* clinit method has already run when:
* <ol>
* <li><code>fromType == toType</code></li>
- * <li><code>toType</code> is a superclass of <code>fromType</code>
- * (because <code>toType</code>'s clinit would have already run
- * <code>fromType</code>'s clinit; see JLS 12.4)</li>
+ * <li><code>toType</code> is a superclass of <code>fromType</code> (because
+ * <code>toType</code>'s clinit would have already run <code>fromType</code>'s
+ * clinit; see JLS 12.4)</li>
* </ol>
*/
public boolean checkClinit(JReferenceType fromType, JReferenceType toType) {
@@ -380,6 +438,8 @@
computeVirtualUpRefs((JClassType) type);
}
}
+
+ computeSingleJsoImplData();
}
/**
@@ -389,14 +449,31 @@
return getOrCreate(superInterfaceMap, type).contains(qType);
}
+ public JMethod findConcreteImplementation(JMethod method,
+ JClassType concreteType) {
+ for (JMethod m : concreteType.methods) {
+ if (getAllOverrides(m).contains(method)) {
+ if (!m.isAbstract()) {
+ return m;
+ }
+ }
+ }
+ return null;
+ }
+
+ public Set<JMethod> getAllOverrides(JMethod method) {
+ return getAllOverrides(method, instantiatedTypes);
+ }
+
/**
* References to any methods which this method implementation might override
* or implement in any instantiable class.
*/
- public Set<JMethod> getAllOverrides(JMethod method) {
+ public Set<JMethod> getAllOverrides(JMethod method,
+ Set<JReferenceType> instantiatedTypes) {
Set<JMethod> results = new HashSet<JMethod>();
getAllRealOverrides(method, results);
- getAllVirtualOverrides(method, results);
+ getAllVirtualOverrides(method, instantiatedTypes, results);
return results;
}
@@ -419,10 +496,18 @@
*/
public Set<JMethod> getAllVirtualOverrides(JMethod method) {
Set<JMethod> results = new HashSet<JMethod>();
- getAllVirtualOverrides(method, results);
+ getAllVirtualOverrides(method, instantiatedTypes, results);
return results;
}
+ public Set<JInterfaceType> getInterfacesWithJavaAndJsoImpls() {
+ return Collections.unmodifiableSet(dualImpl);
+ }
+
+ public Map<JInterfaceType, JClassType> getSingleJsoImpls() {
+ return Collections.unmodifiableMap(jsoSingleImpls);
+ }
+
public boolean hasClinit(JReferenceType type) {
return hasClinitSet.contains(type);
}
@@ -436,22 +521,7 @@
}
public boolean isInstantiatedType(JReferenceType type) {
- if (instantiatedTypes == null) {
- // The instantiated types have not yet been computed.
- return true;
- }
-
- if (type instanceof JNullType) {
- return true;
- }
-
- if (type instanceof JArrayType) {
- JArrayType arrayType = (JArrayType) type;
- if (arrayType.getLeafType() instanceof JNullType) {
- return true;
- }
- }
- return instantiatedTypes.contains(type);
+ return isInstantiatedType(type, instantiatedTypes);
}
/**
@@ -468,13 +538,19 @@
return getOrCreate(superClassMap, type).contains(qType);
}
- public void recomputeClinits() {
+ /**
+ * This method should be called after altering the types that are live in the
+ * associated JProgram.
+ */
+ public void recomputeAfterOptimizations() {
hasClinitSet.clear();
Set<JReferenceType> computed = new HashSet<JReferenceType>();
for (int i = 0; i < program.getDeclaredTypes().size(); ++i) {
JReferenceType type = program.getDeclaredTypes().get(i);
computeHasClinit(type, computed);
}
+
+ computeSingleJsoImplData();
}
public void setInstantiatedTypes(Set<JReferenceType> instantiatedTypes) {
@@ -572,6 +648,59 @@
}
}
+ private void computeSingleJsoImplData() {
+ dualImpl.clear();
+ jsoSingleImpls.clear();
+
+ for (JReferenceType type : program.getDeclaredTypes()) {
+ if (!program.isJavaScriptObject(type)) {
+ if (type instanceof JClassType) {
+ dualImpl.addAll(type.implments);
+ }
+ continue;
+ }
+
+ for (JReferenceType refType : allAssignableFrom(type)) {
+ if (!(refType instanceof JInterfaceType)) {
+ continue;
+ }
+ JInterfaceType intr = (JInterfaceType) refType;
+
+ if (intr.methods.size() <= 1) {
+ /*
+ * Record a tag interface as being implemented by JSO, since they
+ * don't actually have any methods and we want to avoid spurious
+ * messages about multiple JSO types implementing a common interface.
+ */
+ assert intr.methods.size() == 0
+ || intr.methods.get(0).getName().equals("$clinit");
+ jsoSingleImpls.put(intr, program.getJavaScriptObject());
+ continue;
+ }
+
+ if (jsoSingleImpls.containsKey(intr)) {
+ // See if we're looking at a supertype
+ JClassType alreadySeen = jsoSingleImpls.get(intr);
+
+ if (allAssignableFrom(alreadySeen).contains(type)) {
+ jsoSingleImpls.put(intr, (JClassType) type);
+
+ } else {
+ assert allAssignableFrom(type).contains(alreadySeen) : "Already recorded "
+ + alreadySeen.getName()
+ + " as single impl for "
+ + intr.getName()
+ + " while looking at unrelated type "
+ + type.getName();
+ }
+ } else {
+ jsoSingleImpls.put(intr, (JClassType) type);
+ }
+ }
+ }
+ dualImpl.retainAll(jsoSingleImpls.keySet());
+ }
+
/**
* WEIRD: Suppose class Foo declares void f(){} and unrelated interface I also
* declares void f(). Then suppose Bar extends Foo implements I and doesn't
@@ -639,17 +768,16 @@
private void getAllRealOverrides(JMethod method, Set<JMethod> results) {
for (JMethod possibleOverride : method.overrides) {
- // if (instantiatedTypes.contains(possibleOverride.getEnclosingType())) {
results.add(possibleOverride);
- // }
}
}
- private void getAllVirtualOverrides(JMethod method, Set<JMethod> results) {
+ private void getAllVirtualOverrides(JMethod method,
+ Set<JReferenceType> instantiatedTypes, Set<JMethod> results) {
Map<JClassType, Set<JMethod>> overrideMap = getOrCreateMap(virtualUpRefMap,
method);
for (JClassType classType : overrideMap.keySet()) {
- if (isInstantiatedType(classType)) {
+ if (isInstantiatedType(classType, instantiatedTypes)) {
Set<JMethod> set = overrideMap.get(classType);
results.addAll(set);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JValueLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JValueLiteral.java
index 5d80cfb..35334b5 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JValueLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JValueLiteral.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
@@ -15,13 +15,15 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Base class for any Java literal expression.
*/
public abstract class JValueLiteral extends JLiteral {
- public JValueLiteral(JProgram program) {
- super(program);
+ public JValueLiteral(JProgram program, SourceInfo sourceInfo) {
+ super(program, sourceInfo);
}
public abstract Object getValueObj();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java
index 3001dd7..b37e953 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java
@@ -43,6 +43,17 @@
}
return null;
}
+
+ public JDeclarationStatement getDeclarationStatement() {
+ return declStmt;
+ }
+
+ public JExpression getInitializer() {
+ if (declStmt != null) {
+ return declStmt.getInitializer();
+ }
+ return null;
+ }
public String getName() {
return name;
@@ -68,11 +79,4 @@
type = newType;
}
- protected JExpression getInitializer() {
- if (declStmt != null) {
- return declStmt.getInitializer();
- }
- return null;
- }
-
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/SourceInfoJava.java b/dev/core/src/com/google/gwt/dev/jjs/ast/SourceInfoJava.java
new file mode 100644
index 0000000..07e4267
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/SourceInfoJava.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 com.google.gwt.dev.jjs.ast;
+
+import com.google.gwt.dev.jjs.SourceInfo;
+
+/**
+ * An implementation of SourceInfo representing SourceInfo nodes derived from
+ * the Java AST. Instances of this class should only be constructed by JProgram.
+ */
+public class SourceInfoJava extends SourceInfo {
+ /**
+ * Indicates that an AST element is an intrinsic element of the AST and has no
+ * meaningful source location. This is typically used by singleton AST
+ * elements or for literal values.
+ */
+ public static final SourceInfo INTRINSIC = new Immutable(0, 0, 0,
+ "Java intrinsics", true);
+
+ /**
+ * Called only from JProgram.
+ */
+ SourceInfoJava(int startPos, int endPos, int startLine, String fileName,
+ boolean createDescendants) {
+ super(startPos, endPos, startLine, fileName, createDescendants);
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JClassSeed.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JClassSeed.java
index 07fa28c..8aefa08 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JClassSeed.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JClassSeed.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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.jjs.ast.js;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JLiteral;
@@ -33,8 +34,8 @@
*/
private final JClassType refType;
- public JClassSeed(JProgram program, JClassType type) {
- super(program);
+ public JClassSeed(JProgram program, SourceInfo sourceInfo, JClassType type) {
+ super(program, sourceInfo);
refType = type;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java
index ccc613f..7095710 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java
@@ -20,10 +20,16 @@
import com.google.gwt.dev.jjs.ast.JAbstractMethodBody;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.js.ast.JsContext;
+import com.google.gwt.dev.js.ast.JsExpression;
import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsStringLiteral;
+import com.google.gwt.dev.js.ast.JsVisitor;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* Represents a the body of a method. Can be Java or JSNI.
@@ -31,8 +37,8 @@
public class JsniMethodBody extends JAbstractMethodBody {
public final List<JsniFieldRef> jsniFieldRefs = new ArrayList<JsniFieldRef>();
-
public final List<JsniMethodRef> jsniMethodRefs = new ArrayList<JsniMethodRef>();
+ private final Set<String> stringLiterals = new HashSet<String>();
private JsFunction jsFunction = null;
@@ -45,6 +51,11 @@
return jsFunction;
}
+ public Set<String> getUsedStrings() {
+ return stringLiterals;
+ }
+
+ @Override
public boolean isNative() {
return true;
}
@@ -52,6 +63,13 @@
public void setFunc(JsFunction jsFunction) {
assert (this.jsFunction == null);
this.jsFunction = jsFunction;
+ class RecordStrings extends JsVisitor {
+ @Override
+ public void endVisit(JsStringLiteral lit, JsContext<JsExpression> ctx) {
+ stringLiterals.add(lit.getValue());
+ }
+ }
+ (new RecordStrings()).accept(jsFunction);
}
public void traverse(JVisitor visitor, Context ctx) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java
index 4bf9d26..9221003 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.jjs.ast.js;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JExpression;
@@ -32,8 +33,8 @@
public List<JExpression> exprs = new ArrayList<JExpression>();
- public JsonArray(JProgram program) {
- super(program, null);
+ public JsonArray(JProgram program, SourceInfo sourceInfo) {
+ super(program, sourceInfo);
}
public JType getType() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonObject.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonObject.java
index 8602bc0..f1b8c83 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonObject.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonObject.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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.jjs.ast.js;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JExpression;
@@ -39,9 +40,9 @@
public JExpression labelExpr;
public JExpression valueExpr;
- public JsonPropInit(JProgram program, JExpression labelExpr,
+ public JsonPropInit(JProgram program, SourceInfo sourceInfo, JExpression labelExpr,
JExpression valueExpr) {
- super(program, null);
+ super(program, sourceInfo);
this.labelExpr = labelExpr;
this.valueExpr = valueExpr;
}
@@ -57,8 +58,8 @@
public final List<JsonPropInit> propInits = new ArrayList<JsonPropInit>();
- public JsonObject(JProgram program) {
- super(program, null);
+ public JsonObject(JProgram program, SourceInfo sourceInfo) {
+ super(program, sourceInfo);
}
public JType getType() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
index 4c0ac80..baddacc 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
import com.google.gwt.dev.jjs.ast.JArrayRef;
@@ -137,12 +138,14 @@
private void processDims(JNewArray x, Context ctx, JArrayType arrayType,
int dims) {
// override the type of the called method with the array's type
- JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
- initDims, arrayType);
- JsonArray classLitList = new JsonArray(program);
- JsonArray typeIdList = new JsonArray(program);
- JsonArray queryIdList = new JsonArray(program);
- JsonArray dimList = new JsonArray(program);
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ ArrayVisitor.class, "Creating dimensions");
+ JMethodCall call = new JMethodCall(program, sourceInfo, null, initDims,
+ arrayType);
+ JsonArray classLitList = new JsonArray(program, sourceInfo);
+ JsonArray typeIdList = new JsonArray(program, sourceInfo);
+ JsonArray queryIdList = new JsonArray(program, sourceInfo);
+ JsonArray dimList = new JsonArray(program, sourceInfo);
JType cur = arrayType;
for (int i = 0; i < dims; ++i) {
// Walk down each type from most dims to least.
@@ -172,12 +175,14 @@
private void processInitializers(JNewArray x, Context ctx,
JArrayType arrayType) {
// override the type of the called method with the array's type
- JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
- initValues, arrayType);
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ ArrayVisitor.class, "Array initializer");
+ JMethodCall call = new JMethodCall(program, sourceInfo, null, initValues,
+ arrayType);
JLiteral classLit = x.getClassLiteral();
JLiteral typeIdLit = program.getLiteralInt(program.getTypeId(arrayType));
JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType));
- JsonArray initList = new JsonArray(program);
+ JsonArray initList = new JsonArray(program, sourceInfo);
for (int i = 0; i < x.initializers.size(); ++i) {
initList.exprs.add(x.initializers.get(i));
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
index 1c641a4..99f9121 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.jjs.Correlation;
+import com.google.gwt.dev.jjs.HasSourceInfo;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.JClassType;
@@ -114,40 +116,14 @@
*/
private static class BuildDeclMapVisitor extends ASTVisitor {
- private static SourceInfo makeSourceInfo(
- AbstractMethodDeclaration methodDecl) {
- CompilationResult compResult = methodDecl.compilationResult;
- int[] indexes = compResult.lineSeparatorPositions;
- String fileName = String.valueOf(compResult.fileName);
- int startLine = Util.getLineNumber(methodDecl.sourceStart, indexes, 0,
- indexes.length - 1);
- return new SourceInfo(methodDecl.sourceStart, methodDecl.bodyEnd,
- startLine, fileName);
- }
-
- private static InternalCompilerException translateException(
- AbstractMethodDeclaration amd, Throwable e) {
- if (e instanceof OutOfMemoryError) {
- // Always rethrow OOMs (might have no memory to load ICE class anyway).
- throw (OutOfMemoryError) e;
- }
- InternalCompilerException ice;
- if (e instanceof InternalCompilerException) {
- ice = (InternalCompilerException) e;
- } else {
- ice = new InternalCompilerException("Error building type map", e);
- }
- ice.addNode(amd.getClass().getName(), amd.toString(), makeSourceInfo(amd));
- return ice;
- }
-
private String currentFileName;
+
private int[] currentSeparatorPositions;
+
private final JsParser jsParser = new JsParser();
private final JsProgram jsProgram;
private JProgram program;
private List<TypeDeclaration> typeDecls = new ArrayList<TypeDeclaration>();
-
private final TypeMap typeMap;
public BuildDeclMapVisitor(TypeMap typeMap, JsProgram jsProgram) {
@@ -173,10 +149,10 @@
return true;
}
- SourceInfo info = makeSourceInfo(argument);
+ JMethodBody enclosingBody = findEnclosingMethod(scope);
+ SourceInfo info = makeSourceInfo(argument, enclosingBody.getMethod());
LocalVariableBinding b = argument.binding;
JType localType = (JType) typeMap.get(b.type);
- JMethodBody enclosingBody = findEnclosingMethod(scope);
JLocal newLocal = program.createLocal(info, argument.name, localType,
b.isFinal(), enclosingBody);
typeMap.put(b, newLocal);
@@ -199,7 +175,7 @@
MethodBinding b = ctorDecl.binding;
JClassType enclosingType = (JClassType) typeMap.get(scope.enclosingSourceType());
String name = enclosingType.getShortName();
- SourceInfo info = makeSourceInfo(ctorDecl);
+ SourceInfo info = makeSourceInfo(ctorDecl, enclosingType);
JMethod newMethod = program.createMethod(info, name.toCharArray(),
enclosingType, enclosingType, false, false, true, b.isPrivate(),
false);
@@ -217,6 +193,8 @@
mapParameters(newMethod, ctorDecl);
// original params are now frozen
+ info.addCorrelation(Correlation.by(newMethod));
+
int syntheticParamCount = 0;
ReferenceBinding declaringClass = b.declaringClass;
if (declaringClass.isNestedType() && !declaringClass.isStatic()) {
@@ -272,8 +250,8 @@
public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
try {
FieldBinding b = fieldDeclaration.binding;
- SourceInfo info = makeSourceInfo(fieldDeclaration);
JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
+ SourceInfo info = makeSourceInfo(fieldDeclaration, enclosingType);
Expression initialization = fieldDeclaration.initialization;
if (initialization != null
&& initialization instanceof AllocationExpression
@@ -294,7 +272,8 @@
LocalVariableBinding b = localDeclaration.binding;
JType localType = (JType) typeMap.get(localDeclaration.type.resolvedType);
JMethodBody enclosingBody = findEnclosingMethod(scope);
- SourceInfo info = makeSourceInfo(localDeclaration);
+ SourceInfo info = makeSourceInfo(localDeclaration,
+ enclosingBody.getMethod());
JLocal newLocal = program.createLocal(info, localDeclaration.name,
localType, b.isFinal(), enclosingBody);
typeMap.put(b, newLocal);
@@ -308,10 +287,11 @@
public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
try {
MethodBinding b = methodDeclaration.binding;
- SourceInfo info = makeSourceInfo(methodDeclaration);
JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
+ SourceInfo info = makeSourceInfo(methodDeclaration, enclosingType);
JMethod newMethod = processMethodBinding(b, enclosingType, info);
mapParameters(newMethod, methodDeclaration);
+ info.addCorrelation(Correlation.by(newMethod));
if (newMethod.isNative()) {
processNativeMethod(methodDeclaration, info, enclosingType, newMethod);
@@ -344,6 +324,7 @@
JType type = (JType) typeMap.get(binding.type);
JField field = program.createEnumField(info, binding.name,
(JEnumType) enclosingType, (JClassType) type, binding.original().id);
+ info.addCorrelation(Correlation.by(field));
typeMap.put(binding, field);
return field;
}
@@ -372,14 +353,18 @@
JField field = program.createField(info, binding.name, enclosingType,
type, binding.isStatic(), disposition);
typeMap.put(binding, field);
+ info.addCorrelation(Correlation.by(field));
return field;
}
private JField createField(SyntheticArgumentBinding binding,
JReferenceType enclosingType) {
JType type = (JType) typeMap.get(binding.type);
- JField field = program.createField(null, binding.name, enclosingType,
+ SourceInfo info = enclosingType.getSourceInfo().makeChild(
+ BuildDeclMapVisitor.class, "Field " + String.valueOf(binding.name));
+ JField field = program.createField(info, binding.name, enclosingType,
type, false, Disposition.FINAL);
+ info.addCorrelation(Correlation.by(field));
if (binding.matchingField != null) {
typeMap.put(binding.matchingField, field);
}
@@ -390,7 +375,7 @@
private JParameter createParameter(LocalVariableBinding binding,
JMethod enclosingMethod) {
JType type = (JType) typeMap.get(binding.type);
- SourceInfo info = makeSourceInfo(binding.declaration);
+ SourceInfo info = makeSourceInfo(binding.declaration, enclosingMethod);
JParameter param = program.createParameter(info, binding.name, type,
binding.isFinal(), false, enclosingMethod);
typeMap.put(binding, param);
@@ -400,8 +385,10 @@
private JParameter createParameter(SyntheticArgumentBinding arg,
String argName, JMethod enclosingMethod) {
JType type = (JType) typeMap.get(arg.type);
- JParameter param = program.createParameter(null, argName.toCharArray(),
- type, true, false, enclosingMethod);
+ JParameter param = program.createParameter(
+ enclosingMethod.getSourceInfo().makeChild(BuildTypeMap.class,
+ "Parameter " + argName), argName.toCharArray(), type, true,
+ false, enclosingMethod);
return param;
}
@@ -421,15 +408,19 @@
JClassType type = (JClassType) constructor.getEnclosingType();
// Define the method
- JMethod synthetic = program.createMethod(null, "new".toCharArray(), type,
- type, false, true, true, false, false);
+ JMethod synthetic = program.createMethod(type.getSourceInfo().makeChild(
+ BuildDeclMapVisitor.class, "Synthetic constructor"),
+ "new".toCharArray(), type, type, false, true, true, false, false);
// new Foo() : Create the instance
- JNewInstance newInstance = new JNewInstance(program, null, type);
+ JNewInstance newInstance = new JNewInstance(program,
+ type.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
+ "new instance"), type);
// (new Foo()).Foo() : Invoke the constructor method on the instance
- JMethodCall call = new JMethodCall(program, null, newInstance,
- constructor);
+ JMethodCall call = new JMethodCall(program,
+ type.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
+ "constructor invocation"), newInstance, constructor);
List<JExpression> args = call.getArgs();
/*
@@ -439,8 +430,10 @@
*/
JParameter enclosingInstance = null;
if (!staticClass) {
- enclosingInstance = program.createParameter(null,
- "this$outer".toCharArray(), enclosingType, false, false, synthetic);
+ enclosingInstance = program.createParameter(
+ synthetic.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
+ "outer instance"), "this$outer".toCharArray(), enclosingType,
+ false, false, synthetic);
}
/*
@@ -454,12 +447,18 @@
* implicitly as the last argument to the constructor.
*/
if (enclosingInstance != null && !i.hasNext()) {
- args.add(new JParameterRef(program, null, enclosingInstance));
+ args.add(new JParameterRef(program,
+ synthetic.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
+ "enclosing instance"), enclosingInstance));
} else {
- JParameter syntheticParam = program.createParameter(null,
+ JParameter syntheticParam = program.createParameter(
+ synthetic.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
+ "Argument " + param.getName()),
param.getName().toCharArray(), param.getType(), true, false,
synthetic);
- args.add(new JParameterRef(program, null, syntheticParam));
+ args.add(new JParameterRef(program,
+ syntheticParam.getSourceInfo().makeChild(
+ BuildDeclMapVisitor.class, "reference"), syntheticParam));
}
}
@@ -467,7 +466,9 @@
synthetic.freezeParamTypes();
// return (new Foo()).Foo() : The only statement in the function
- JReturnStatement ret = new JReturnStatement(program, null, call);
+ JReturnStatement ret = new JReturnStatement(program,
+ synthetic.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
+ "Return statement"), call);
// Add the return statement to the method body
JMethodBody body = (JMethodBody) synthetic.getBody();
@@ -499,11 +500,36 @@
return (JMethodBody) method.getBody();
}
- private SourceInfo makeSourceInfo(Statement stmt) {
+ private SourceInfo makeSourceInfo(AbstractMethodDeclaration methodDecl,
+ HasSourceInfo enclosing) {
+ CompilationResult compResult = methodDecl.compilationResult;
+ int[] indexes = compResult.lineSeparatorPositions;
+ String fileName = String.valueOf(compResult.fileName);
+ int startLine = Util.getLineNumber(methodDecl.sourceStart, indexes, 0,
+ indexes.length - 1);
+ SourceInfo toReturn = program.createSourceInfo(methodDecl.sourceStart,
+ methodDecl.bodyEnd, startLine, fileName);
+
+ // The SourceInfo will inherit Correlations from its enclosing object
+ if (enclosing != null) {
+ toReturn.copyMissingCorrelationsFrom(enclosing.getSourceInfo());
+ }
+
+ return toReturn;
+ }
+
+ private SourceInfo makeSourceInfo(Statement stmt, HasSourceInfo enclosing) {
int startLine = Util.getLineNumber(stmt.sourceStart,
currentSeparatorPositions, 0, currentSeparatorPositions.length - 1);
- return new SourceInfo(stmt.sourceStart, stmt.sourceEnd, startLine,
- currentFileName);
+ SourceInfo toReturn = program.createSourceInfo(stmt.sourceStart,
+ stmt.sourceEnd, startLine, currentFileName);
+
+ // The SourceInfo will inherit Correlations from its enclosing object
+ if (enclosing != null) {
+ toReturn.copyMissingCorrelationsFrom(enclosing.getSourceInfo());
+ }
+
+ return toReturn;
}
private void mapParameters(JMethod method, AbstractMethodDeclaration x) {
@@ -556,9 +582,10 @@
if (type instanceof JClassType
&& type != program.getTypeJavaLangObject()
&& type != program.getIndexedType("Array")) {
- JMethod getClassMethod = program.createMethod(null,
- "getClass".toCharArray(), type, program.getTypeJavaLangClass(),
- false, false, false, false, false);
+ JMethod getClassMethod = program.createMethod(
+ type.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
+ "Synthetic getClass()"), "getClass".toCharArray(), type,
+ program.getTypeJavaLangClass(), false, false, false, false, false);
assert (type.methods.get(2) == getClassMethod);
getClassMethod.freezeParamTypes();
}
@@ -621,15 +648,18 @@
// Visit the synthetic values() and valueOf() methods.
for (MethodBinding methodBinding : binding.methods()) {
if (methodBinding instanceof SyntheticMethodBinding) {
- JMethod newMethod = processMethodBinding(methodBinding, type, null);
+ JMethod newMethod = processMethodBinding(methodBinding, type,
+ type.getSourceInfo());
TypeBinding[] parameters = methodBinding.parameters;
if (parameters.length == 0) {
assert newMethod.getName().equals("values");
} else if (parameters.length == 1) {
assert newMethod.getName().equals("valueOf");
assert typeMap.get(parameters[0]) == program.getTypeJavaLangString();
- program.createParameter(null, "name".toCharArray(),
- program.getTypeJavaLangString(), true, false, newMethod);
+ program.createParameter(newMethod.getSourceInfo().makeChild(
+ BuildDeclMapVisitor.class, "name parameter"),
+ "name".toCharArray(), program.getTypeJavaLangString(), true,
+ false, newMethod);
} else {
assert false;
}
@@ -702,6 +732,7 @@
try {
// start at -1 to avoid counting our synthetic header
// TODO: get the character position start correct
+ jsParser.setSourceInfo(info);
List<JsStatement> result = jsParser.parse(jsProgram.getScope(), sr, -1);
JsExprStmt jsExprStmt = (JsExprStmt) result.get(0);
JsFunction jsFunction = (JsFunction) jsExprStmt.getExpression();
@@ -746,12 +777,29 @@
// TODO: check this
// Map into the original source stream;
i += startPos + detail.getLineOffset();
- info = new SourceInfo(i, i, info.getStartLine() + detail.getLine(),
- info.getFileName());
+ info = program.createSourceInfo(i, i, info.getStartLine()
+ + detail.getLine(), info.getFileName());
GenerateJavaAST.reportJsniError(info, methodDeclaration, e.getMessage());
}
}
+ private InternalCompilerException translateException(
+ AbstractMethodDeclaration amd, Throwable e) {
+ if (e instanceof OutOfMemoryError) {
+ // Always rethrow OOMs (might have no memory to load ICE class anyway).
+ throw (OutOfMemoryError) e;
+ }
+ InternalCompilerException ice;
+ if (e instanceof InternalCompilerException) {
+ ice = (InternalCompilerException) e;
+ } else {
+ ice = new InternalCompilerException("Error building type map", e);
+ }
+ ice.addNode(amd.getClass().getName(), amd.toString(), makeSourceInfo(amd,
+ null));
+ return ice;
+ }
+
private InternalCompilerException translateException(Statement stmt,
Throwable e) {
if (e instanceof OutOfMemoryError) {
@@ -764,8 +812,8 @@
} else {
ice = new InternalCompilerException("Error building type map", e);
}
- ice.addNode(stmt.getClass().getName(), stmt.toString(),
- makeSourceInfo(stmt));
+ ice.addNode(stmt.getClass().getName(), stmt.toString(), makeSourceInfo(
+ stmt, null));
return ice;
}
}
@@ -778,34 +826,8 @@
*/
private static class BuildTypeMapVisitor extends ASTVisitor {
- private static SourceInfo makeSourceInfo(TypeDeclaration typeDecl) {
- CompilationResult compResult = typeDecl.compilationResult;
- int[] indexes = compResult.lineSeparatorPositions;
- String fileName = String.valueOf(compResult.fileName);
- int startLine = Util.getLineNumber(typeDecl.sourceStart, indexes, 0,
- indexes.length - 1);
- return new SourceInfo(typeDecl.sourceStart, typeDecl.bodyEnd, startLine,
- fileName);
- }
-
- private static InternalCompilerException translateException(
- TypeDeclaration typeDecl, Throwable e) {
- if (e instanceof OutOfMemoryError) {
- // Always rethrow OOMs (might have no memory to load ICE class anyway).
- throw (OutOfMemoryError) e;
- }
- InternalCompilerException ice;
- if (e instanceof InternalCompilerException) {
- ice = (InternalCompilerException) e;
- } else {
- ice = new InternalCompilerException("Error building type map", e);
- }
- ice.addNode(typeDecl.getClass().getName(), typeDecl.toString(),
- makeSourceInfo(typeDecl));
- return ice;
- }
-
private final JProgram program;
+
private final TypeMap typeMap;
public BuildTypeMapVisitor(TypeMap typeMap) {
@@ -830,6 +852,16 @@
return process(typeDeclaration);
}
+ private SourceInfo makeSourceInfo(TypeDeclaration typeDecl) {
+ CompilationResult compResult = typeDecl.compilationResult;
+ int[] indexes = compResult.lineSeparatorPositions;
+ String fileName = String.valueOf(compResult.fileName);
+ int startLine = Util.getLineNumber(typeDecl.sourceStart, indexes, 0,
+ indexes.length - 1);
+ return program.createSourceInfo(typeDecl.sourceStart, typeDecl.bodyEnd,
+ startLine, fileName);
+ }
+
private boolean process(TypeDeclaration typeDeclaration) {
try {
char[][] name = typeDeclaration.binding.compoundName;
@@ -871,6 +903,7 @@
assert (false);
return false;
}
+ info.addCorrelation(Correlation.by(newType));
/**
* We emulate static initializers and instance initializers as methods.
@@ -878,13 +911,17 @@
* more like output JavaScript. Clinit is always in slot 0, init (if it
* exists) is always in slot 1.
*/
- JMethod clinit = program.createMethod(null, "$clinit".toCharArray(),
- newType, program.getTypeVoid(), false, true, true, true, false);
+ JMethod clinit = program.createMethod(info.makeChild(
+ BuildTypeMapVisitor.class, "Class initializer"),
+ "$clinit".toCharArray(), newType, program.getTypeVoid(), false,
+ true, true, true, false);
clinit.freezeParamTypes();
if (newType instanceof JClassType) {
- JMethod init = program.createMethod(null, "$init".toCharArray(),
- newType, program.getTypeVoid(), false, false, true, true, false);
+ JMethod init = program.createMethod(info.makeChild(
+ BuildTypeMapVisitor.class, "Instance initializer"),
+ "$init".toCharArray(), newType, program.getTypeVoid(), false,
+ false, true, true, false);
init.freezeParamTypes();
}
@@ -894,6 +931,23 @@
throw translateException(typeDeclaration, e);
}
}
+
+ private InternalCompilerException translateException(
+ TypeDeclaration typeDecl, Throwable e) {
+ if (e instanceof OutOfMemoryError) {
+ // Always rethrow OOMs (might have no memory to load ICE class anyway).
+ throw (OutOfMemoryError) e;
+ }
+ InternalCompilerException ice;
+ if (e instanceof InternalCompilerException) {
+ ice = (InternalCompilerException) e;
+ } else {
+ ice = new InternalCompilerException("Error building type map", e);
+ }
+ ice.addNode(typeDecl.getClass().getName(), typeDecl.toString(),
+ makeSourceInfo(typeDecl));
+ return ice;
+ }
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
index 3dd6b4f..7fd3680 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JArrayType;
@@ -26,6 +27,7 @@
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JInstanceOf;
import com.google.gwt.dev.jjs.ast.JIntLiteral;
+import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JModVisitor;
@@ -102,7 +104,9 @@
// the 0th entry is the "always false" entry
classes.add(null);
- jsonObjects.add(new JsonObject(program));
+ jsonObjects.add(new JsonObject(program,
+ program.createSourceInfoSynthetic(AssignTypeIdsVisitor.class,
+ "always-false typeinfo entry")));
/*
* Do String first to reserve typeIds 1 and 2 for Object and String,
@@ -256,14 +260,16 @@
}
// Create a sparse lookup object.
- JsonObject jsonObject = new JsonObject(program);
+ SourceInfo sourceInfo = program.createSourceInfoSynthetic(
+ AssignTypeIdsVisitor.class, "typeinfo lookup");
+ JsonObject jsonObject = new JsonObject(program, sourceInfo);
// Start at 1; 0 is Object and always true.
for (int i = 1; i < nextQueryId; ++i) {
if (yesArray[i] != null) {
JIntLiteral labelExpr = program.getLiteralInt(i);
JIntLiteral valueExpr = program.getLiteralInt(1);
- jsonObject.propInits.add(new JsonPropInit(program, labelExpr,
- valueExpr));
+ jsonObject.propInits.add(new JsonPropInit(program, sourceInfo,
+ labelExpr, valueExpr));
}
}
@@ -354,7 +360,8 @@
if (expr.getType() == charType) {
if (expr instanceof JCharLiteral) {
JCharLiteral charLit = (JCharLiteral) expr;
- return program.getLiteralString(new char[] {charLit.getValue()});
+ return program.getLiteralString(expr.getSourceInfo(),
+ new char[] {charLit.getValue()});
} else {
// Replace with Cast.charToString(c)
JMethodCall call = new JMethodCall(program, expr.getSourceInfo(),
@@ -406,6 +413,12 @@
*/
private class ReplaceTypeChecksVisitor extends JModVisitor {
+ private final Set<JInterfaceType> dualImpls;
+
+ public ReplaceTypeChecksVisitor(JProgram program) {
+ dualImpls = program.typeOracle.getInterfacesWithJavaAndJsoImpls();
+ }
+
@Override
public void endVisit(JCastOperation x, Context ctx) {
JExpression replaceExpr;
@@ -435,9 +448,19 @@
// just remove the cast
replaceExpr = curExpr;
} else {
+
+ JMethod method;
boolean isJsoCast = program.isJavaScriptObject(toType);
- JMethod method = program.getIndexedMethod(isJsoCast
- ? "Cast.dynamicCastJso" : "Cast.dynamicCast");
+ if (isJsoCast) {
+ // A cast to JSO
+ method = program.getIndexedMethod("Cast.dynamicCastJso");
+ } else if (dualImpls.contains(toType)) {
+ // A cast that may succeed when the object is a JSO
+ method = program.getIndexedMethod("Cast.dynamicCastAllowJso");
+ } else {
+ // A regular cast
+ method = program.getIndexedMethod("Cast.dynamicCast");
+ }
// override the type of the called method with the target cast type
JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
method, toType);
@@ -542,9 +565,15 @@
x.getExpr(), nullLit);
ctx.replaceMe(eq);
} else {
+ JMethod method;
boolean isJsoCast = program.isJavaScriptObject(toType);
- JMethod method = program.getIndexedMethod(isJsoCast
- ? "Cast.instanceOfJso" : "Cast.instanceOf");
+ if (isJsoCast) {
+ method = program.getIndexedMethod("Cast.instanceOfJso");
+ } else if (dualImpls.contains(toType)) {
+ method = program.getIndexedMethod("Cast.instanceOfOrJso");
+ } else {
+ method = program.getIndexedMethod("Cast.instanceOf");
+ }
JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
method);
call.getArgs().add(x.getExpr());
@@ -584,7 +613,7 @@
assigner.computeTypeIds();
}
{
- ReplaceTypeChecksVisitor replacer = new ReplaceTypeChecksVisitor();
+ ReplaceTypeChecksVisitor replacer = new ReplaceTypeChecksVisitor(program);
replacer.accept(program);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CatchBlockNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CatchBlockNormalizer.java
index 1833665..14aa9f9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CatchBlockNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CatchBlockNormalizer.java
@@ -82,7 +82,7 @@
* Go backwards so we can nest the else statements in the correct order!
*/
// rethrow the current exception if no one caught it
- JStatement cur = new JThrowStatement(program, null, exRef);
+ JStatement cur = new JThrowStatement(program, catchInfo, exRef);
for (int i = x.getCatchBlocks().size() - 1; i >= 0; --i) {
JBlock block = x.getCatchBlocks().get(i);
JLocalRef arg = x.getCatchArgs().get(i);
@@ -118,7 +118,7 @@
@Override
public boolean visit(JTryStatement x, Context ctx) {
if (!x.getCatchBlocks().isEmpty()) {
- pushTempLocal();
+ pushTempLocal(x.getSourceInfo());
}
return true;
}
@@ -151,9 +151,9 @@
return tempLocals.get(--localIndex);
}
- private void pushTempLocal() {
+ private void pushTempLocal(SourceInfo sourceInfo) {
if (localIndex == tempLocals.size()) {
- JLocal newTemp = program.createLocal(null,
+ JLocal newTemp = program.createLocal(sourceInfo,
("$e" + localIndex).toCharArray(), program.getTypeJavaLangObject(),
false, currentMethodBody);
tempLocals.add(newTemp);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
index eb70ed3..7e3455c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
@@ -142,7 +142,7 @@
@Override
public boolean visit(JClassSeed x, Context ctx) {
- expression = new JClassSeed(program, x.getRefType());
+ expression = new JClassSeed(program, x.getSourceInfo(), x.getRefType());
return false;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
new file mode 100644
index 0000000..a44816d
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
@@ -0,0 +1,664 @@
+/*
+ * 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.core.ext.TreeLogger;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
+import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JNode;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.jjs.ast.JStringLiteral;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.jjs.impl.FragmentExtractor.CfaLivenessPredicate;
+import com.google.gwt.dev.jjs.impl.FragmentExtractor.LivenessPredicate;
+import com.google.gwt.dev.jjs.impl.FragmentExtractor.NothingAlivePredicate;
+import com.google.gwt.dev.jjs.impl.FragmentExtractor.StatementLogger;
+import com.google.gwt.dev.js.ast.JsBlock;
+import com.google.gwt.dev.js.ast.JsExprStmt;
+import com.google.gwt.dev.js.ast.JsExpression;
+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 com.google.gwt.dev.js.ast.JsVars;
+import com.google.gwt.dev.js.ast.JsVars.JsVar;
+import com.google.gwt.dev.util.PerfLogger;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+
+/**
+ * <p>
+ * Divides the code in a {@link JsProgram} into multiple fragments. The initial
+ * fragment is sufficient to run all of the program's functionality except for
+ * anything called in a callback supplied to
+ * {@link com.google.gwt.core.client.GWT#runAsync(com.google.gwt.core.client.RunAsyncCallback) GWT.runAsync()}.
+ * The remaining code should be downloadable via
+ * {@link com.google.gwt.core.client.AsyncFragmentLoader#inject(int)}.
+ * </p>
+ *
+ * <p>
+ * The precise way the program is fragmented is an implementation detail that is
+ * subject to change. Whenever the fragment strategy changes,
+ * <code>AsyncFragmentLoader</code> must be updated in tandem. That said, the
+ * current fragmentation strategy is to create an initial fragment and then
+ * three more fragments for each split point. For each split point, there is:
+ * </p>
+ *
+ * <ul>
+ * <li>a secondary base fragment, which is downloaded if this split point is
+ * the first one reached. It contains enough code to continue running as soon as
+ * it downloads.
+ * <li>an exclusively live fragment, which is downloaded if this split point is
+ * reached but is not the first one. It includes only that code that is
+ * exclusively needed by this split point.
+ * <li>a leftovers fragment, which includes all code that is in none of: the
+ * initial download, any exclusive fragment, or the secondary base fragment for
+ * this split point.
+ * </ul>
+ */
+public class CodeSplitter {
+ /**
+ * A statement logger that immediately prints out everything live that it
+ * sees.
+ */
+ public class EchoStatementLogger implements StatementLogger {
+ public void logStatement(JsStatement stat, boolean isIncluded) {
+ if (isIncluded) {
+ if (stat instanceof JsExprStmt) {
+ JsExpression expr = ((JsExprStmt) stat).getExpression();
+ if (expr instanceof JsFunction) {
+ JsFunction func = (JsFunction) expr;
+ if (func.getName() != null) {
+ JMethod method = map.nameToMethod(func.getName());
+ if (method != null) {
+ System.out.println(fullNameString(method));
+ }
+ }
+ }
+ }
+
+ if (stat instanceof JsVars) {
+ JsVars vars = (JsVars) stat;
+ for (JsVar var : vars) {
+ JField field = map.nameToField(var.getName());
+ if (field != null) {
+ System.out.println(fullNameString(field));
+ }
+ String string = map.stringLiteralForName(var.getName());
+ if (string != null) {
+ System.out.println("STRING " + var.getName());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * A map from program atoms to the fragment they should be placed in. An entry
+ * of 0 means it did not go into any fragment in particular.
+ */
+ private static class FragmentMap {
+ public Map<JField, Integer> fields = new HashMap<JField, Integer>();
+ public Map<JMethod, Integer> methods = new HashMap<JMethod, Integer>();
+ public Map<String, Integer> strings = new HashMap<String, Integer>();
+ public Map<JReferenceType, Integer> types = new HashMap<JReferenceType, Integer>();
+ }
+
+ /**
+ * A liveness predicate that is based on a fragment map. See
+ * {@link #mapFragments()}. Note that all non-zero fragments are assumed to
+ * load after fragment 0, and so everything in fragment 0 is always live.
+ */
+ private static class FragmentMapLivenessPredicate implements
+ LivenessPredicate {
+ private final int fragment;
+ private final FragmentMap fragmentMap;
+
+ public FragmentMapLivenessPredicate(FragmentMap fragmentMap, int fragment) {
+ this.fragmentMap = fragmentMap;
+ this.fragment = fragment;
+ }
+
+ public boolean isLive(JField field) {
+ return checkMap(fragmentMap.fields, field);
+ }
+
+ public boolean isLive(JMethod method) {
+ return checkMap(fragmentMap.methods, method);
+ }
+
+ public boolean isLive(JReferenceType type) {
+ return checkMap(fragmentMap.types, type);
+ }
+
+ public boolean isLive(String literal) {
+ return checkMap(fragmentMap.strings, literal);
+ }
+
+ public boolean miscellaneousStatementsAreLive() {
+ return true;
+ }
+
+ private <T> boolean checkMap(Map<T, Integer> map, T x) {
+ Integer entryForX = map.get(x);
+ if (entryForX == null) {
+ // unrecognized items are always live
+ return true;
+ } else {
+ return (fragment == entryForX) || (entryForX == 0);
+ }
+ }
+ }
+
+ /**
+ * A liveness predicate that checks two separate underlying predicates.
+ */
+ private static class UnionLivenessPredicate implements LivenessPredicate {
+ private final LivenessPredicate pred1;
+ private final LivenessPredicate pred2;
+
+ public UnionLivenessPredicate(LivenessPredicate pred1,
+ LivenessPredicate pred2) {
+ this.pred1 = pred1;
+ this.pred2 = pred2;
+ }
+
+ public boolean isLive(JField field) {
+ return pred1.isLive(field) || pred2.isLive(field);
+ }
+
+ public boolean isLive(JMethod method) {
+ return pred1.isLive(method) || pred2.isLive(method);
+ }
+
+ public boolean isLive(JReferenceType type) {
+ return pred1.isLive(type) || pred2.isLive(type);
+ }
+
+ public boolean isLive(String literal) {
+ return pred1.isLive(literal) || pred2.isLive(literal);
+ }
+
+ public boolean miscellaneousStatementsAreLive() {
+ return pred1.miscellaneousStatementsAreLive()
+ || pred2.miscellaneousStatementsAreLive();
+ }
+ }
+
+ /**
+ * A Java property that causes the fragment map to be logged.
+ *
+ * TODO(spoon) save the logging data to an auxiliary compiler output and, if
+ * the logging is not too slow, always enable it.
+ */
+ private static String PROP_LOG_FRAGMENT_MAP = "gwt.jjs.logFragmentMap";
+
+ public static void exec(TreeLogger logger, JProgram jprogram,
+ JsProgram jsprogram, JavaToJavaScriptMap map) {
+ if (jprogram.entryMethods.size() == 1) {
+ // Don't do anything if there is no call to runAsync
+ return;
+ }
+
+ new CodeSplitter(logger, jprogram, jsprogram, map).execImpl();
+ }
+
+ private static Map<JField, JClassLiteral> buildFieldToClassLiteralMap(
+ JProgram jprogram) {
+ final Map<JField, JClassLiteral> map = new HashMap<JField, JClassLiteral>();
+ class BuildFieldToLiteralVisitor extends JVisitor {
+ @Override
+ public void endVisit(JClassLiteral lit, Context ctx) {
+ map.put(lit.getField(), lit);
+ }
+ }
+ (new BuildFieldToLiteralVisitor()).accept(jprogram);
+ return map;
+ }
+
+ private static String fullNameString(JField field) {
+ return field.getEnclosingType().getName() + "." + field.getName();
+ }
+
+ private static String fullNameString(JMethod method) {
+ return method.getEnclosingType().getName() + "."
+ + JProgram.getJsniSig(method);
+ }
+
+ private static <T> int getOrZero(Map<T, Integer> map, T key) {
+ Integer value = map.get(key);
+ return (value == null) ? 0 : value;
+ }
+
+ private static <T> Set<T> union(Set<? extends T> set1, Set<? extends T> set2) {
+ Set<T> union = new HashSet<T>();
+ union.addAll(set1);
+ union.addAll(set2);
+ return union;
+ }
+
+ private static <T> void updateMap(int entry, Map<T, Integer> map,
+ Set<?> liveWithoutEntry, Iterable<T> all) {
+ for (T each : all) {
+ if (!liveWithoutEntry.contains(each)) {
+ /*
+ * Note that it is fine to overwrite a preexisting entry in the map. If
+ * an atom is dead until split point i has been reached, and is also
+ * dead until entry j has been reached, then it is dead until both have
+ * been reached. Thus, it can be downloaded along with either i's or j's
+ * code.
+ */
+ map.put(each, entry);
+ }
+ }
+ }
+
+ private final Map<JField, JClassLiteral> fieldToLiteralOfClass;
+ private final FragmentExtractor fragmentExtractor;
+
+ /**
+ * Code that is initially live when the program first downloads.
+ */
+ private final ControlFlowAnalyzer initiallyLive;
+ private JProgram jprogram;
+ private JsProgram jsprogram;
+ private final TreeLogger logger;
+ private final boolean logging;
+ private JavaToJavaScriptMap map;
+ private final Set<JMethod> methodsInJavaScript;
+ private final int numEntries;
+
+ private CodeSplitter(TreeLogger logger, JProgram jprogram,
+ JsProgram jsprogram, JavaToJavaScriptMap map) {
+ this.logger = logger.branch(TreeLogger.TRACE,
+ "Splitting JavaScript for incremental download");
+ this.jprogram = jprogram;
+ this.jsprogram = jsprogram;
+ this.map = map;
+
+ numEntries = jprogram.entryMethods.size();
+ logging = Boolean.getBoolean(PROP_LOG_FRAGMENT_MAP);
+ fieldToLiteralOfClass = buildFieldToClassLiteralMap(jprogram);
+ fragmentExtractor = new FragmentExtractor(jprogram, jsprogram, map);
+
+ initiallyLive = new ControlFlowAnalyzer(jprogram);
+ traverseEntry(initiallyLive, 0);
+
+ methodsInJavaScript = fragmentExtractor.findAllMethodsInJavaScript();
+ }
+
+ /**
+ * Create a new fragment and add it to the list.
+ *
+ * @param alreadyLoaded The code that should be assumed to have already been
+ * loaded
+ * @param liveNow The code that needs to be live once this fragment loads
+ * @param statsToAppend Additional statements to append to the end of the new
+ * fragment
+ * @param fragmentStats The list of fragments to append to
+ */
+ private void addFragment(LivenessPredicate alreadyLoaded,
+ LivenessPredicate liveNow, List<JsStatement> statsToAppend,
+ List<List<JsStatement>> fragmentStats) {
+ if (logging) {
+ System.out.println();
+ System.out.println("==== Fragment " + fragmentStats.size() + " ====");
+ fragmentExtractor.setStatementLogger(new EchoStatementLogger());
+ }
+ List<JsStatement> stats = fragmentExtractor.extractStatements(liveNow,
+ alreadyLoaded);
+ stats.addAll(statsToAppend);
+ fragmentStats.add(stats);
+ }
+
+ /**
+ * For each split point other than the initial one (0), compute a CFA that
+ * traces every other split point.
+ */
+ private List<ControlFlowAnalyzer> computeAllButOneCfas() {
+ List<ControlFlowAnalyzer> allButOnes = new ArrayList<ControlFlowAnalyzer>(
+ numEntries - 1);
+
+ for (int entry = 1; entry < numEntries; entry++) {
+ ControlFlowAnalyzer cfa = new ControlFlowAnalyzer(initiallyLive);
+ traverseAllButEntry(cfa, entry);
+ // Traverse leftoversFragmentHasLoaded, because it should not
+ // go into any of the exclusive fragments.
+ cfa.traverseFromLeftoversFragmentHasLoaded();
+ allButOnes.add(cfa);
+ }
+
+ return allButOnes;
+ }
+
+ /**
+ * Compute a CFA that covers the entire live code of the program.
+ */
+ private ControlFlowAnalyzer computeCompleteCfa() {
+ ControlFlowAnalyzer everything = new ControlFlowAnalyzer(jprogram);
+ for (int entry = 0; entry < numEntries; entry++) {
+ traverseEntry(everything, entry);
+ }
+ everything.traverseFromLeftoversFragmentHasLoaded();
+ return everything;
+ }
+
+ private void execImpl() {
+ PerfLogger.start("CodeSplitter");
+
+ FragmentMap fragmentMap = mapFragments();
+
+ List<List<JsStatement>> fragmentStats = new ArrayList<List<JsStatement>>(
+ 3 * numEntries - 2);
+
+ {
+ /*
+ * Compute the base fragment. It includes everything that is live when the
+ * program starts.
+ */
+ LivenessPredicate alreadyLoaded = new NothingAlivePredicate();
+ LivenessPredicate liveNow = new CfaLivenessPredicate(initiallyLive);
+ List<JsStatement> noStats = new ArrayList<JsStatement>();
+ addFragment(alreadyLoaded, liveNow, noStats, fragmentStats);
+ }
+
+ /*
+ * Compute the exclusively live fragments. Each includes everything
+ * exclusively live after entry point i.
+ */
+ for (int i = 1; i < numEntries; i++) {
+ LivenessPredicate alreadyLoaded = new FragmentMapLivenessPredicate(
+ fragmentMap, 0);
+ LivenessPredicate liveNow = new FragmentMapLivenessPredicate(fragmentMap,
+ i);
+ List<JsStatement> statsToAppend = fragmentExtractor.createCallsToEntryMethods(i);
+ addFragment(alreadyLoaded, liveNow, statsToAppend, fragmentStats);
+ }
+
+ /*
+ * Add secondary base fragments and their associated leftover fragments.
+ */
+ for (int base = 1; base < numEntries; base++) {
+ ControlFlowAnalyzer baseCfa = new ControlFlowAnalyzer(initiallyLive);
+ traverseEntry(baseCfa, base);
+ LivenessPredicate baseLive = new CfaLivenessPredicate(baseCfa);
+
+ // secondary base
+ List<JsStatement> baseStatsToAppend = fragmentExtractor.createCallsToEntryMethods(base);
+ addFragment(new CfaLivenessPredicate(initiallyLive), baseLive,
+ baseStatsToAppend, fragmentStats);
+
+ // leftovers
+ LivenessPredicate globalLeftoversLive = new FragmentMapLivenessPredicate(
+ fragmentMap, 0);
+ LivenessPredicate associatedExclusives = new FragmentMapLivenessPredicate(
+ fragmentMap, base);
+ // Be sure to add in anything in the exclusives for base that is
+ // not in its secondary base.
+ LivenessPredicate leftoversLive = new UnionLivenessPredicate(
+ globalLeftoversLive, associatedExclusives);
+ List<JsStatement> statsToAppend = fragmentExtractor.createCallToLeftoversFragmentHasLoaded();
+ addFragment(baseLive, leftoversLive, statsToAppend, fragmentStats);
+ }
+
+ // now install the new statements in the program fragments
+ jsprogram.setFragmentCount(fragmentStats.size());
+ for (int i = 0; i < fragmentStats.size(); i++) {
+ JsBlock fragBlock = jsprogram.getFragmentBlock(i);
+ fragBlock.getStatements().clear();
+ fragBlock.getStatements().addAll(fragmentStats.get(i));
+ }
+
+ PerfLogger.end();
+ }
+
+ /**
+ * <p>
+ * Patch up the fragment map to satisfy load-order dependencies, as described
+ * in the comment of {@link LivenessPredicate}. Load-order dependencies can
+ * be violated when an atom is mapped to 0 as a leftover, but it has some
+ * load-order dependency on an atom that was put in an exclusive fragment.
+ * </p>
+ *
+ * <p>
+ * In general, it might be possible to split things better by considering load
+ * order dependencies when building the fragment map. However, fixing them
+ * after the fact makes CodeSplitter simpler. In practice, for programs tried
+ * so far, there are very few load order dependency fixups that actually
+ * happen, so it seems better to keep the compiler simpler.
+ * </p>
+ */
+ private void fixUpLoadOrderDependencies(FragmentMap fragmentMap) {
+ fixUpLoadOrderDependenciesForMethods(fragmentMap);
+ fixUpLoadOrderDependenciesForTypes(fragmentMap);
+ fixUpLoadOrderDependenciesForClassLiterals(fragmentMap);
+ fixUpLoadOrderDependenciesForFieldsInitializedToStrings(fragmentMap);
+ }
+
+ private void fixUpLoadOrderDependenciesForClassLiterals(
+ FragmentMap fragmentMap) {
+ int numClassLitStrings = 0;
+ int numFixups = 0;
+ for (JField field : fragmentMap.fields.keySet()) {
+ JClassLiteral classLit = fieldToLiteralOfClass.get(field);
+ if (classLit != null) {
+ int classLitFrag = fragmentMap.fields.get(field);
+ for (String string : stringsIn(field.getInitializer())) {
+ numClassLitStrings++;
+ int stringFrag = getOrZero(fragmentMap.strings, string);
+ if (stringFrag != classLitFrag && stringFrag != 0) {
+ numFixups++;
+ fragmentMap.strings.put(string, 0);
+ }
+ }
+ }
+ }
+ logger.log(TreeLogger.DEBUG, "Fixed up load-order dependencies by moving "
+ + numFixups
+ + " strings in class literal constructors to fragment 0, out of "
+ + numClassLitStrings);
+ }
+
+ private void fixUpLoadOrderDependenciesForFieldsInitializedToStrings(
+ FragmentMap fragmentMap) {
+ int numFixups = 0;
+ int numFieldStrings = 0;
+
+ for (JField field : fragmentMap.fields.keySet()) {
+ if (field.getInitializer() instanceof JStringLiteral) {
+ numFieldStrings++;
+
+ String string = ((JStringLiteral) field.getInitializer()).getValue();
+ int fieldFrag = getOrZero(fragmentMap.fields, field);
+ int stringFrag = getOrZero(fragmentMap.strings, string);
+ if (fieldFrag != stringFrag && stringFrag != 0) {
+ numFixups++;
+ fragmentMap.strings.put(string, 0);
+ }
+ }
+ }
+
+ logger.log(TreeLogger.DEBUG, "Fixed up load-order dependencies by moving "
+ + numFixups
+ + " strings used to initialize fields to fragment 0, out of "
+ + +numFieldStrings);
+ }
+
+ private void fixUpLoadOrderDependenciesForMethods(FragmentMap fragmentMap) {
+ int numFixups = 0;
+
+ for (JReferenceType type : jprogram.getDeclaredTypes()) {
+ int typeFrag = getOrZero(fragmentMap.types, type);
+
+ if (typeFrag != 0) {
+ /*
+ * If the type is in an exclusive fragment, all its instance methods
+ * must be in the same one.
+ */
+ for (JMethod method : type.methods) {
+ if (!method.isStatic() && methodsInJavaScript.contains(method)) {
+ int methodFrag = getOrZero(fragmentMap.methods, method);
+ if (methodFrag != typeFrag) {
+ fragmentMap.types.put(type, 0);
+ numFixups++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ logger.log(TreeLogger.DEBUG,
+ "Fixed up load-order dependencies for instance methods by moving "
+ + numFixups + " types to fragment 0, out of "
+ + jprogram.getDeclaredTypes().size());
+ }
+
+ private void fixUpLoadOrderDependenciesForTypes(FragmentMap fragmentMap) {
+ int numFixups = 0;
+ Queue<JReferenceType> typesToCheck = new ArrayBlockingQueue<JReferenceType>(
+ jprogram.getDeclaredTypes().size());
+ typesToCheck.addAll(jprogram.getDeclaredTypes());
+
+ while (!typesToCheck.isEmpty()) {
+ JReferenceType type = typesToCheck.remove();
+ if (type.extnds != null) {
+ int typeFrag = getOrZero(fragmentMap.types, type);
+ int supertypeFrag = getOrZero(fragmentMap.types, type.extnds);
+ if (typeFrag != supertypeFrag && supertypeFrag != 0) {
+ numFixups++;
+ fragmentMap.types.put(type.extnds, 0);
+ typesToCheck.add(type.extnds);
+ }
+ }
+ }
+
+ logger.log(TreeLogger.DEBUG,
+ "Fixed up load-order dependencies on supertypes by moving " + numFixups
+ + " types to fragment 0, out of "
+ + jprogram.getDeclaredTypes().size());
+ }
+
+ /**
+ * Map code to fragments. Do this by trying to find code atoms that are only
+ * needed by a single split point. Such code can be moved to the exclusively
+ * live fragment associated with that split point.
+ */
+ private void mapExclusiveAtoms(FragmentMap fragmentMap) {
+ List<ControlFlowAnalyzer> allButOnes = computeAllButOneCfas();
+
+ ControlFlowAnalyzer everything = computeCompleteCfa();
+
+ Set<JField> allFields = new HashSet<JField>();
+ Set<JMethod> allMethods = new HashSet<JMethod>();
+
+ for (JNode node : everything.getLiveFieldsAndMethods()) {
+ if (node instanceof JField) {
+ allFields.add((JField) node);
+ }
+ if (node instanceof JMethod) {
+ allMethods.add((JMethod) node);
+ }
+ }
+ allFields.addAll(everything.getFieldsWritten());
+
+ for (int entry = 1; entry < numEntries; entry++) {
+ ControlFlowAnalyzer allButOne = allButOnes.get(entry - 1);
+ Set<JNode> allLiveNodes = union(allButOne.getLiveFieldsAndMethods(),
+ allButOne.getFieldsWritten());
+ updateMap(entry, fragmentMap.fields, allLiveNodes, allFields);
+ updateMap(entry, fragmentMap.methods,
+ allButOne.getLiveFieldsAndMethods(), allMethods);
+ updateMap(entry, fragmentMap.strings, allButOne.getLiveStrings(),
+ everything.getLiveStrings());
+ updateMap(entry, fragmentMap.types, allButOne.getInstantiatedTypes(),
+ everything.getInstantiatedTypes());
+ }
+ }
+
+ /**
+ * Map each program atom to a fragment. Atoms are mapped to a non-zero
+ * fragment whenever they are known not to be needed whenever that fragment's
+ * split point has not been reached. Any atoms that cannot be so mapped are
+ * left in fragment zero.
+ */
+ private FragmentMap mapFragments() {
+ FragmentMap fragmentMap = new FragmentMap();
+
+ mapExclusiveAtoms(fragmentMap);
+ fixUpLoadOrderDependencies(fragmentMap);
+
+ return fragmentMap;
+ }
+
+ /**
+ * Traverse <code>exp</code> and find all string literals within it.
+ */
+ private Set<String> stringsIn(JExpression exp) {
+ final Set<String> strings = new HashSet<String>();
+ class StringFinder extends JVisitor {
+ @Override
+ public void endVisit(JStringLiteral stringLiteral, Context ctx) {
+ strings.add(stringLiteral.getValue());
+ }
+ }
+ (new StringFinder()).accept(exp);
+ return strings;
+ }
+
+ /**
+ * Traverse all code in the program except for that reachable only via
+ * fragment <code>frag</code>. This does not call
+ * {@link ControlFlowAnalyzer#finishTraversal()}.
+ */
+ private void traverseAllButEntry(ControlFlowAnalyzer cfa, int entry) {
+ for (int otherEntry = 0; otherEntry < numEntries; otherEntry++) {
+ if (otherEntry != entry) {
+ traverseEntry(cfa, otherEntry);
+ }
+ }
+ }
+
+ /**
+ * Traverse all code in the program that is reachable via fragment
+ * <code>frag</code>. This does not call
+ * {@link ControlFlowAnalyzer#finishTraversal()}.
+ */
+ private void traverseEntry(ControlFlowAnalyzer cfa, int splitPoint) {
+ for (JMethod entryMethod : jprogram.entryMethods.get(splitPoint)) {
+ cfa.traverseFrom(entryMethod);
+ }
+ if (splitPoint == 0) {
+ /*
+ * Include class literal factories for simplicity. It is possible to move
+ * them out, if they are only needed by one fragment, but they are tiny,
+ * so it does not seem worth the complexity in the compiler.
+ */
+ cfa.traverseFromClassLiteralFactories();
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
new file mode 100644
index 0000000..f2868c3
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
@@ -0,0 +1,783 @@
+/*
+ * 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.JAbsentArrayDimension;
+import com.google.gwt.dev.jjs.ast.JArrayType;
+import com.google.gwt.dev.jjs.ast.JBinaryOperation;
+import com.google.gwt.dev.jjs.ast.JBinaryOperator;
+import com.google.gwt.dev.jjs.ast.JCastOperation;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
+import com.google.gwt.dev.jjs.ast.JClassType;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JFieldRef;
+import com.google.gwt.dev.jjs.ast.JInterfaceType;
+import com.google.gwt.dev.jjs.ast.JLocal;
+import com.google.gwt.dev.jjs.ast.JLocalRef;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JMethodCall;
+import com.google.gwt.dev.jjs.ast.JModVisitor;
+import com.google.gwt.dev.jjs.ast.JNewArray;
+import com.google.gwt.dev.jjs.ast.JNewInstance;
+import com.google.gwt.dev.jjs.ast.JNode;
+import com.google.gwt.dev.jjs.ast.JParameter;
+import com.google.gwt.dev.jjs.ast.JParameterRef;
+import com.google.gwt.dev.jjs.ast.JPrimitiveType;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.jjs.ast.JStringLiteral;
+import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.jjs.ast.JVariable;
+import com.google.gwt.dev.jjs.ast.JVariableRef;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
+import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
+import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
+import com.google.gwt.dev.js.ast.JsContext;
+import com.google.gwt.dev.js.ast.JsExpression;
+import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsName;
+import com.google.gwt.dev.js.ast.JsNameRef;
+import com.google.gwt.dev.js.ast.JsVisitor;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This class finds out what code in a program is live based on starting
+ * execution at a specified location.
+ */
+public class ControlFlowAnalyzer {
+
+ /**
+ * Marks as "referenced" any types, methods, and fields that are reachable.
+ * Also marks as "instantiable" any the classes and interfaces that can
+ * possibly be instantiated.
+ *
+ * TODO(later): make RescueVisitor use less stack?
+ */
+ private class RescueVisitor extends JVisitor {
+ @Override
+ public boolean visit(JArrayType type, Context ctx) {
+ assert (referencedTypes.contains(type));
+ boolean isInstantiated = instantiatedTypes.contains(type);
+
+ JType leafType = type.getLeafType();
+ int dims = type.getDims();
+
+ // Rescue my super array type
+ if (leafType instanceof JReferenceType) {
+ JReferenceType rLeafType = (JReferenceType) leafType;
+ if (rLeafType.extnds != null) {
+ JArrayType superArray = program.getTypeArray(rLeafType.extnds, dims);
+ rescue(superArray, true, isInstantiated);
+ }
+
+ for (int i = 0; i < rLeafType.implments.size(); ++i) {
+ JInterfaceType intfType = rLeafType.implments.get(i);
+ JArrayType intfArray = program.getTypeArray(intfType, dims);
+ rescue(intfArray, true, isInstantiated);
+ }
+ }
+
+ // Rescue the base Array type
+ rescue(program.getIndexedType("Array"), true, isInstantiated);
+ return false;
+ }
+
+ @Override
+ public boolean visit(JBinaryOperation x, Context ctx) {
+ if (x.isAssignment() && x.getLhs() instanceof JFieldRef) {
+ fieldsWritten.add(((JFieldRef) x.getLhs()).getField());
+ }
+
+ // special string concat handling
+ if ((x.getOp() == JBinaryOperator.ADD || x.getOp() == JBinaryOperator.ASG_ADD)
+ && x.getType() == program.getTypeJavaLangString()) {
+ rescueByConcat(x.getLhs().getType());
+ rescueByConcat(x.getRhs().getType());
+ } else if (x.getOp() == JBinaryOperator.ASG) {
+ // Don't rescue variables that are merely assigned to and never read
+ boolean doSkip = false;
+ JExpression lhs = x.getLhs();
+ if (lhs.hasSideEffects() || isVolatileField(lhs)) {
+ /*
+ * If the lhs has side effects, skipping it would lose the side
+ * effect. If the lhs is volatile, also keep it. This behavior
+ * provides a useful idiom for test cases to prevent code from being
+ * pruned.
+ */
+ } else if (lhs instanceof JLocalRef) {
+ // locals are ok to skip
+ doSkip = true;
+ } else if (lhs instanceof JParameterRef) {
+ // parameters are ok to skip
+ doSkip = true;
+ } else if (lhs instanceof JFieldRef) {
+ // fields must rescue the qualifier
+ doSkip = true;
+ JFieldRef fieldRef = (JFieldRef) lhs;
+ JExpression instance = fieldRef.getInstance();
+ if (instance != null) {
+ accept(instance);
+ }
+ }
+
+ if (doSkip) {
+ accept(x.getRhs());
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(JCastOperation x, Context ctx) {
+ // Rescue any JavaScriptObject type that is the target of a cast.
+ JType targetType = x.getCastType();
+ if (program.isJavaScriptObject(targetType)) {
+ rescue((JReferenceType) targetType, true, true);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(JClassLiteral x, Context ctx) {
+ JField field = x.getField();
+ rescue(field);
+ return true;
+ }
+
+ @Override
+ public boolean visit(JClassType type, Context ctx) {
+ assert (referencedTypes.contains(type));
+ boolean isInstantiated = instantiatedTypes.contains(type);
+
+ // Rescue my super type
+ rescue(type.extnds, true, isInstantiated);
+
+ // Rescue my clinit (it won't ever be explicitly referenced)
+ rescue(type.methods.get(0));
+
+ // JLS 12.4.1: don't rescue my super interfaces just because I'm rescued.
+ // However, if I'm instantiated, let's mark them as instantiated.
+ for (int i = 0; i < type.implments.size(); ++i) {
+ JInterfaceType intfType = type.implments.get(i);
+ rescue(intfType, false, isInstantiated);
+ }
+
+ rescueMethodsIfInstantiable(type);
+
+ return false;
+ }
+
+ @Override
+ public boolean visit(JDeclarationStatement x, Context ctx) {
+ /*
+ * A declaration by itself doesn't rescue a local (even if it has an
+ * initializer). Writes don't count, only reads.
+ */
+ if (x.getInitializer() != null) {
+
+ if (!isStaticFieldInitializedToLiteral(x.getVariableRef().getTarget())) {
+ /*
+ * Don't traverse literal initializers, because those become live when
+ * the variable is accessed, not when its declaration runs.
+ */
+ accept(x.getInitializer());
+
+ if (x.getVariableRef().getTarget() instanceof JField) {
+ fieldsWritten.add((JField) x.getVariableRef().getTarget());
+ }
+ }
+ }
+
+ // If the lhs is a field ref, we have to visit its qualifier.
+ JVariableRef variableRef = x.getVariableRef();
+ if (variableRef instanceof JFieldRef) {
+ JFieldRef fieldRef = (JFieldRef) variableRef;
+ JExpression instance = fieldRef.getInstance();
+ if (instance != null) {
+ accept(instance);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(JFieldRef ref, Context ctx) {
+ JField target = ref.getField();
+
+ // JLS 12.4.1: references to static, non-final, or
+ // non-compile-time-constant fields rescue the enclosing class.
+ // JDT already folds in compile-time constants as literals, so we must
+ // rescue the enclosing types for any static fields that make it here.
+ if (target.isStatic()) {
+ rescue(target.getEnclosingType(), true, false);
+ }
+ rescue(target);
+ return true;
+ }
+
+ @Override
+ public boolean visit(JInterfaceType type, Context ctx) {
+ boolean isReferenced = referencedTypes.contains(type);
+ boolean isInstantiated = instantiatedTypes.contains(type);
+ assert (isReferenced || isInstantiated);
+
+ // Rescue my clinit (it won't ever be explicitly referenced
+ rescue(type.methods.get(0));
+
+ // JLS 12.4.1: don't rescue my super interfaces just because I'm rescued.
+ // However, if I'm instantiated, let's mark them as instantiated.
+ if (isInstantiated) {
+ for (int i = 0; i < type.implments.size(); ++i) {
+ JInterfaceType intfType = type.implments.get(i);
+ rescue(intfType, false, true);
+ }
+ }
+
+ // visit any field initializers
+ for (int i = 0; i < type.fields.size(); ++i) {
+ JField it = type.fields.get(i);
+ accept(it);
+ }
+
+ rescueMethodsIfInstantiable(type);
+
+ return false;
+ }
+
+ @Override
+ public boolean visit(JLocalRef ref, Context ctx) {
+ JLocal target = ref.getLocal();
+ rescue(target);
+ return true;
+ }
+
+ @Override
+ public boolean visit(final JMethod x, Context ctx) {
+ JReferenceType enclosingType = x.getEnclosingType();
+ if (program.isJavaScriptObject(enclosingType)) {
+ // Calls to JavaScriptObject types rescue those types.
+ boolean instance = !x.isStatic() || program.isStaticImpl(x);
+ rescue(enclosingType, true, instance);
+ } else if (x.isStatic()) {
+ // JLS 12.4.1: references to static methods rescue the enclosing class
+ rescue(enclosingType, true, false);
+ }
+
+ if (x.isNative()) {
+ // Manually rescue native parameter references
+ final JsniMethodBody body = (JsniMethodBody) x.getBody();
+ final JsFunction func = body.getFunc();
+
+ new JsVisitor() {
+ @Override
+ public void endVisit(JsNameRef nameRef, JsContext<JsExpression> ctx) {
+ JsName ident = nameRef.getName();
+
+ if (ident != null) {
+ // If we're referencing a parameter, rescue the associated
+ // JParameter
+ int index = func.getParameters().indexOf(ident.getStaticRef());
+ if (index != -1) {
+ rescue(x.params.get(index));
+ }
+ }
+ }
+ }.accept(func);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean visit(JMethodCall call, Context ctx) {
+ JMethod method = call.getTarget();
+ if (method.isStatic()
+ || program.isJavaScriptObject(method.getEnclosingType())
+ || instantiatedTypes.contains(method.getEnclosingType())) {
+ rescue(method);
+ } else {
+ // It's a virtual method whose class is not instantiable
+ if (!liveFieldsAndMethods.contains(method)) {
+ methodsLiveExceptForInstantiability.add(method);
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean visit(JNewArray newArray, Context ctx) {
+ // rescue and instantiate the array type
+ JArrayType arrayType = newArray.getArrayType();
+ if (newArray.dims != null) {
+ // rescue my type and all the implicitly nested types (with fewer dims)
+ int nDims = arrayType.getDims();
+ JType leafType = arrayType.getLeafType();
+ assert (newArray.dims.size() == nDims);
+ for (int i = 0; i < nDims; ++i) {
+ if (newArray.dims.get(i) instanceof JAbsentArrayDimension) {
+ break;
+ }
+ rescue(program.getTypeArray(leafType, nDims - i), true, true);
+ }
+ } else {
+ // just rescue my own specific type
+ rescue(arrayType, true, true);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(JNewInstance newInstance, Context ctx) {
+ // rescue and instantiate the target class!
+ rescue(newInstance.getClassType(), true, true);
+ return true;
+ }
+
+ @Override
+ public boolean visit(JParameterRef x, Context ctx) {
+ // rescue the parameter for future pruning purposes
+ rescue(x.getParameter());
+ return true;
+ }
+
+ @Override
+ public boolean visit(JsniFieldRef x, Context ctx) {
+ /*
+ * SPECIAL: this could be an assignment that passes a value from
+ * JavaScript into Java.
+ */
+ if (x.isLvalue()) {
+ maybeRescueJavaScriptObjectPassingIntoJava(x.getField().getType());
+ }
+ // JsniFieldRef rescues as JFieldRef
+ return visit((JFieldRef) x, ctx);
+ }
+
+ @Override
+ public boolean visit(JsniMethodBody body, Context ctx) {
+ liveStrings.addAll(body.getUsedStrings());
+ return true;
+ }
+
+ @Override
+ public boolean visit(JsniMethodRef x, Context ctx) {
+ /*
+ * SPECIAL: each argument of the call passes a value from JavaScript into
+ * Java.
+ */
+ ArrayList<JParameter> params = x.getTarget().params;
+ for (int i = 0, c = params.size(); i < c; ++i) {
+ JParameter param = params.get(i);
+ maybeRescueJavaScriptObjectPassingIntoJava(param.getType());
+
+ /*
+ * Because we're not currently tracking methods through JSNI, we need to
+ * assume that it's not safe to prune parameters of a method referenced
+ * as such.
+ *
+ * A better solution would be to perform basic escape analysis to ensure
+ * that the function reference never escapes, or at minimum, ensure that
+ * the method is immediately called after retrieving the method
+ * reference.
+ */
+ rescue(param);
+ }
+ // JsniMethodRef rescues as JMethodCall
+ return visit((JMethodCall) x, ctx);
+ }
+
+ @Override
+ public boolean visit(JStringLiteral literal, Context ctx) {
+ liveStrings.add(literal.getValue());
+
+ // rescue and instantiate java.lang.String
+ rescue(program.getTypeJavaLangString(), true, true);
+ return true;
+ }
+
+ private boolean isStaticFieldInitializedToLiteral(JVariable var) {
+ if (var instanceof JField) {
+ JField field = (JField) var;
+ return field.isStatic() && field.getLiteralInitializer() != null;
+ }
+ return false;
+ }
+
+ private boolean isVolatileField(JExpression x) {
+ if (x instanceof JFieldRef) {
+ JFieldRef xFieldRef = (JFieldRef) x;
+ if (xFieldRef.getField().isVolatile()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Subclasses of JavaScriptObject are never instantiated directly. They are
+ * created "magically" when a JSNI method passes a reference to an existing
+ * JS object into Java code. If any point in the program can pass a value
+ * from JS into Java which could potentially be cast to JavaScriptObject, we
+ * must rescue JavaScriptObject.
+ *
+ * @param type The type of the value passing from Java to JavaScript.
+ * @see com.google.gwt.core.client.JavaScriptObject
+ */
+ private void maybeRescueJavaScriptObjectPassingIntoJava(JType type) {
+ boolean doIt = false;
+ if (program.isJavaScriptObject(type)
+ || type == program.getTypeJavaLangString()) {
+ doIt = true;
+ } else if (type instanceof JArrayType) {
+ /*
+ * Hackish: in our own JRE we sometimes create "not quite baked" arrays
+ * in JavaScript for expediency.
+ */
+ JArrayType arrayType = (JArrayType) type;
+ JType elementType = arrayType.getElementType();
+ if (elementType instanceof JPrimitiveType
+ || elementType == program.getTypeJavaLangString()
+ || program.isJavaScriptObject(elementType)) {
+ doIt = true;
+ }
+ }
+ if (doIt) {
+ rescue((JReferenceType) type, true, true);
+ }
+ }
+
+ private boolean rescue(JMethod method) {
+ if (method != null) {
+ if (!liveFieldsAndMethods.contains(method)) {
+ liveFieldsAndMethods.add(method);
+ methodsLiveExceptForInstantiability.remove(method);
+
+ accept(method);
+
+ if (method.isNative()) {
+ /*
+ * SPECIAL: returning from this method passes a value from
+ * JavaScript into Java.
+ */
+ maybeRescueJavaScriptObjectPassingIntoJava(method.getType());
+ }
+
+ rescueOverridingMethods(method);
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void rescue(JReferenceType type, boolean isReferenced,
+ boolean isInstantiated) {
+ if (type != null) {
+
+ boolean doVisit = false;
+ if (isInstantiated && !instantiatedTypes.contains(type)) {
+ instantiatedTypes.add(type);
+ doVisit = true;
+ }
+
+ if (isReferenced && !referencedTypes.contains(type)) {
+ referencedTypes.add(type);
+ doVisit = true;
+ }
+
+ if (doVisit) {
+ accept(type);
+ }
+ }
+ }
+
+ private void rescue(JVariable var) {
+ if (var != null) {
+ if (liveFieldsAndMethods.add(var)) {
+ if (isStaticFieldInitializedToLiteral(var)) {
+ /*
+ * Rescue literal initializers when the field is rescued, not when
+ * the static initializer runs. This allows fields initialized to
+ * string literals to only need the string literals when the field
+ * itself becomes live.
+ */
+ accept(((JField) var).getLiteralInitializer());
+ } else if (var instanceof JField
+ && (program.getTypeClassLiteralHolder().equals(((JField) var).getEnclosingType()))) {
+ /*
+ * Rescue just slightly less than what would normally be rescued for
+ * a field reference to the literal's field. Rescue the field
+ * itself, and its initializer, but do NOT rescue the whole
+ * enclosing class. That would pull in the clinit of that class,
+ * which has initializers for all the class literals, which in turn
+ * have all of the strings of all of the class names.
+ *
+ * This work is done in rescue() to allow JSNI references to class
+ * literals (via the @Foo::class syntax) to correctly rescue class
+ * literal initializers.
+ *
+ * TODO: Model ClassLiteral access a different way to avoid special
+ * magic. See
+ * Pruner.transformToNullFieldRef()/transformToNullMethodCall().
+ */
+ JField field = (JField) var;
+ accept(field.getInitializer());
+ referencedTypes.add(field.getEnclosingType());
+ liveFieldsAndMethods.add(field.getEnclosingType().methods.get(0));
+ }
+ }
+ }
+ }
+
+ /**
+ * Handle special rescues needed implicitly to support concat.
+ */
+ private void rescueByConcat(JType type) {
+ JClassType stringType = program.getTypeJavaLangString();
+ JPrimitiveType charType = program.getTypePrimitiveChar();
+ if (type instanceof JReferenceType && type != stringType
+ && type != program.getTypeNull()) {
+ /*
+ * Any reference types (except String, which works by default) that take
+ * part in a concat must rescue java.lang.Object.toString().
+ *
+ * TODO: can we narrow the focus by walking up the type hierarchy or
+ * doing explicit toString calls?
+ */
+ JMethod toStringMethod = program.getIndexedMethod("Object.toString");
+ rescue(toStringMethod);
+ } else if (type == charType) {
+ /*
+ * Characters must rescue String.valueOf(char)
+ */
+ if (stringValueOfChar == null) {
+ for (int i = 0; i < stringType.methods.size(); ++i) {
+ JMethod meth = stringType.methods.get(i);
+ if (meth.getName().equals("valueOf")) {
+ List<JType> params = meth.getOriginalParamTypes();
+ if (params.size() == 1) {
+ if (params.get(0) == charType) {
+ stringValueOfChar = meth;
+ break;
+ }
+ }
+ }
+ }
+ assert (stringValueOfChar != null);
+ }
+ rescue(stringValueOfChar);
+ }
+ }
+
+ /**
+ * If the type is instantiable, rescue any of its virtual methods that a
+ * previously seen method call could call.
+ */
+ private void rescueMethodsIfInstantiable(JReferenceType type) {
+ if (instantiatedTypes.contains(type)) {
+ for (JMethod method : type.methods) {
+ if (!method.isStatic()) {
+ if (methodsLiveExceptForInstantiability.contains(method)) {
+ rescue(method);
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Assume that <code>method</code> is live. Rescue any overriding methods
+ * that might be called if <code>method</code> is called through virtual
+ * dispatch.
+ */
+ private void rescueOverridingMethods(JMethod method) {
+ if (!method.isStatic()) {
+
+ List<JMethod> overriders = methodsThatOverrideMe.get(method);
+ if (overriders != null) {
+ for (JMethod overrider : overriders) {
+ if (liveFieldsAndMethods.contains(overrider)) {
+ // The override is already alive, do nothing.
+ } else if (instantiatedTypes.contains(overrider.getEnclosingType())) {
+ // The enclosing class is alive, make my override reachable.
+ rescue(overrider);
+ } else {
+ // The enclosing class is not yet alive, put override in limbo.
+ methodsLiveExceptForInstantiability.add(overrider);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private Set<JField> fieldsWritten = new HashSet<JField>();
+ private Set<JReferenceType> instantiatedTypes = new HashSet<JReferenceType>();
+ private Set<JNode> liveFieldsAndMethods = new HashSet<JNode>();
+ private Set<String> liveStrings = new HashSet<String>();
+
+ /**
+ * Schrodinger's methods... aka "limbo". :) These are instance methods that
+ * seem to be reachable, only their enclosing type is uninstantiable. We place
+ * these methods into purgatory until/unless the enclosing type is found to be
+ * instantiable.
+ */
+ private Set<JMethod> methodsLiveExceptForInstantiability = new HashSet<JMethod>();
+
+ /**
+ * A precomputed map of all instance methods onto a set of methods that
+ * override each key method.
+ */
+ private Map<JMethod, List<JMethod>> methodsThatOverrideMe;
+
+ private final JProgram program;
+ private Set<JReferenceType> referencedTypes = new HashSet<JReferenceType>();
+ private final RescueVisitor rescuer = new RescueVisitor();
+ private JMethod stringValueOfChar = null;
+
+ public ControlFlowAnalyzer(ControlFlowAnalyzer cfa) {
+ program = cfa.program;
+ fieldsWritten = new HashSet<JField>(cfa.fieldsWritten);
+ instantiatedTypes = new HashSet<JReferenceType>(cfa.instantiatedTypes);
+ liveFieldsAndMethods = new HashSet<JNode>(cfa.liveFieldsAndMethods);
+ referencedTypes = new HashSet<JReferenceType>(cfa.referencedTypes);
+ stringValueOfChar = cfa.stringValueOfChar;
+ liveStrings = new HashSet<String>(cfa.liveStrings);
+ methodsLiveExceptForInstantiability = new HashSet<JMethod>(
+ cfa.methodsLiveExceptForInstantiability);
+ methodsThatOverrideMe = cfa.methodsThatOverrideMe;
+ }
+
+ public ControlFlowAnalyzer(JProgram program) {
+ this.program = program;
+ buildMethodsOverriding();
+ }
+
+ /**
+ * Return the set of all fields that are written.
+ */
+ public Set<JField> getFieldsWritten() {
+ return fieldsWritten;
+ }
+
+ /**
+ * Return the complete set of types that have been instantiated.
+ */
+ public Set<JReferenceType> getInstantiatedTypes() {
+ return instantiatedTypes;
+ }
+
+ /**
+ * Return all methods that could be executed, and all variables that could be
+ * read, based on the given entry points so far.
+ */
+ public Set<? extends JNode> getLiveFieldsAndMethods() {
+ return liveFieldsAndMethods;
+ }
+
+ public Set<String> getLiveStrings() {
+ return liveStrings;
+ }
+
+ /**
+ * Return the complete set of types that have been referenced.
+ */
+ public Set<? extends JReferenceType> getReferencedTypes() {
+ return referencedTypes;
+ }
+
+ /**
+ * Traverse all code executed by <code>expr</code>.
+ */
+ public void traverseFrom(JExpression expr) {
+ rescuer.accept(expr);
+ }
+
+ /**
+ * Assume <code>method</code> is live, and find out what else might execute.
+ */
+ public void traverseFrom(JMethod method) {
+ rescuer.rescue(method);
+ }
+
+ /**
+ * Trace all code needed by class literal constructor expressions except for
+ * the string literals they include. At the time of writing, these would
+ * include the factory methods for class literals.
+ */
+ public void traverseFromClassLiteralFactories() {
+ class ReplaceStringLiterals extends JModVisitor {
+ @Override
+ public void endVisit(JStringLiteral stringLiteral, Context ctx) {
+ ctx.replaceMe(program.getLiteralNull());
+ }
+ }
+
+ final JModVisitor stringLiteralReplacer = new ReplaceStringLiterals();
+ final CloneExpressionVisitor cloner = new CloneExpressionVisitor(program);
+
+ class ClassLitTraverser extends JVisitor {
+ @Override
+ public void endVisit(JClassLiteral classLiteral, Context ctx) {
+ JExpression initializer = classLiteral.getField().getInitializer();
+ JExpression initializerWithoutStrings = stringLiteralReplacer.accept(cloner.cloneExpression(initializer));
+ rescuer.accept(initializerWithoutStrings);
+ }
+ }
+
+ (new ClassLitTraverser()).accept(program);
+ }
+
+ public void traverseFromLeftoversFragmentHasLoaded() {
+ if (program.entryMethods.size() > 1) {
+ traverseFrom(program.getIndexedMethod("AsyncFragmentLoader.leftoversFragmentHasLoaded"));
+ }
+ }
+
+ public void traverseFromReferenceTo(JReferenceType type) {
+ rescuer.rescue(type, true, false);
+ }
+
+ private void buildMethodsOverriding() {
+ methodsThatOverrideMe = new HashMap<JMethod, List<JMethod>>();
+ for (JReferenceType type : program.getDeclaredTypes()) {
+ for (JMethod method : type.methods) {
+ for (JMethod overridden : program.typeOracle.getAllOverrides(method)) {
+ List<JMethod> overs = methodsThatOverrideMe.get(overridden);
+ if (overs == null) {
+ overs = new ArrayList<JMethod>();
+ methodsThatOverrideMe.put(overridden, overs);
+ }
+ overs.add(method);
+ }
+ }
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
index 01800bc..81370c1 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
@@ -84,8 +84,8 @@
* operations in favor of pure side effects.
*
* TODO(spoon): move more simplifications into methods like
- * {@link #cast(JExpression, SourceInfo, JType, JExpression) simplifyCast},
- * so that more simplifications can be made on a single pass through a tree.
+ * {@link #cast(JExpression, SourceInfo, JType, JExpression) simplifyCast}, so
+ * that more simplifications can be made on a single pass through a tree.
*/
public class DeadCodeVisitor extends JModVisitor {
@@ -94,8 +94,8 @@
/**
* Expressions whose result does not matter. A parent node should add any
* children whose result does not matter to this set during the parent's
- * <code>visit()</code> method. It should then remove those children
- * during its own <code>endVisit()</code>.
+ * <code>visit()</code> method. It should then remove those children during
+ * its own <code>endVisit()</code>.
*
* TODO: there's a latent bug here: some immutable nodes (such as literals)
* can be multiply referenced in the AST. In theory, one reference to that
@@ -666,8 +666,10 @@
if (lhs instanceof JValueLiteral && rhs instanceof JValueLiteral) {
Object lhsObj = ((JValueLiteral) lhs).getValueObj();
Object rhsObj = ((JValueLiteral) rhs).getValueObj();
- ctx.replaceMe(program.getLiteralString(String.valueOf(lhsObj)
- + String.valueOf(rhsObj)));
+ ctx.replaceMe(program.getLiteralString(
+ lhs.getSourceInfo().makeChild(DeadCodeVisitor.class,
+ "String concatenation", rhs.getSourceInfo()),
+ String.valueOf(lhsObj) + String.valueOf(rhsObj)));
}
}
@@ -1344,8 +1346,8 @@
}
/**
- * Simplify <code>exp == bool</code>, where <code>bool</code> is a
- * boolean literal.
+ * Simplify <code>exp == bool</code>, where <code>bool</code> is a boolean
+ * literal.
*/
private void simplifyBooleanEq(JExpression exp, boolean bool, Context ctx) {
if (bool) {
@@ -1359,8 +1361,8 @@
/**
* Simplify <code>lhs == rhs</code>, where <code>lhs</code> and
* <code>rhs</code> are known to be boolean. If <code>negate</code> is
- * <code>true</code>, then treat it as <code>lhs != rhs</code> instead
- * of <code>lhs == rhs</code>. Assumes that the case where both sides are
+ * <code>true</code>, then treat it as <code>lhs != rhs</code> instead of
+ * <code>lhs == rhs</code>. Assumes that the case where both sides are
* literals has already been checked.
*/
private void simplifyBooleanEq(JExpression lhs, JExpression rhs,
@@ -1392,8 +1394,8 @@
}
/**
- * Simplify <code>lhs == rhs</code>. If <code>negate</code> is true,
- * then it's actually static evaluation of <code>lhs != rhs</code>.
+ * Simplify <code>lhs == rhs</code>. If <code>negate</code> is true, then
+ * it's actually static evaluation of <code>lhs != rhs</code>.
*/
private void simplifyEq(JExpression lhs, JExpression rhs, Context ctx,
boolean negated) {
@@ -1626,7 +1628,8 @@
}
Object result = actual.invoke(instance, paramValues);
if (result instanceof String) {
- ctx.replaceMe(program.getLiteralString((String) result));
+ ctx.replaceMe(program.getLiteralString(x.getSourceInfo().makeChild(
+ DeadCodeVisitor.class, "Optimized String call"), (String) result));
} else if (result instanceof Boolean) {
ctx.replaceMe(program.getLiteralBoolean(((Boolean) result).booleanValue()));
} else if (result instanceof Character) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
new file mode 100644
index 0000000..7e33287
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
@@ -0,0 +1,561 @@
+/*
+ * 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.SourceInfo;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.js.ast.JsBinaryOperation;
+import com.google.gwt.dev.js.ast.JsBinaryOperator;
+import com.google.gwt.dev.js.ast.JsEmpty;
+import com.google.gwt.dev.js.ast.JsExprStmt;
+import com.google.gwt.dev.js.ast.JsExpression;
+import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsInvocation;
+import com.google.gwt.dev.js.ast.JsName;
+import com.google.gwt.dev.js.ast.JsNameRef;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsStatement;
+import com.google.gwt.dev.js.ast.JsVars;
+import com.google.gwt.dev.js.ast.JsVars.JsVar;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A class that extracts a fragment of code based on a supplied liveness
+ * condition.
+ */
+public class FragmentExtractor {
+ /**
+ * A {@link LivenessPredicate} that bases liveness on a single
+ * {@link ControlFlowAnalyzer}.
+ */
+ public static class CfaLivenessPredicate implements LivenessPredicate {
+ private final ControlFlowAnalyzer cfa;
+
+ public CfaLivenessPredicate(ControlFlowAnalyzer cfa) {
+ this.cfa = cfa;
+ }
+
+ public boolean isLive(JField field) {
+ return cfa.getLiveFieldsAndMethods().contains(field)
+ || cfa.getFieldsWritten().contains(field);
+ }
+
+ public boolean isLive(JMethod method) {
+ return cfa.getLiveFieldsAndMethods().contains(method);
+ }
+
+ public boolean isLive(JReferenceType type) {
+ return cfa.getInstantiatedTypes().contains(type);
+ }
+
+ public boolean isLive(String string) {
+ return cfa.getLiveStrings().contains(string);
+ }
+
+ public boolean miscellaneousStatementsAreLive() {
+ return true;
+ }
+ }
+
+ /**
+ * <p>
+ * A predicate on whether statements and variables should be considered live.
+ * </p>
+ *
+ *
+ * <p>
+ * Any supplied predicate must satisfy load-order dependencies. For any atom
+ * considered live, the atoms it depends on at load time should also be live.
+ * The following load-order dependencies exist:
+ * </p>
+ *
+ * <ul>
+ * <li>A class literal depends on the strings contained in its instantiation
+ * instruction.</li>
+ *
+ * <li>Types depend on their supertype.</li>
+ *
+ * <li>Instance methods depend on their enclosing type.</li>
+ *
+ * <li>Static fields that are initialized to strings depend on the string
+ * they are initialized to.</li>
+ * </ul>
+ */
+ public static interface LivenessPredicate {
+ boolean isLive(JField field);
+
+ boolean isLive(JMethod method);
+
+ boolean isLive(JReferenceType type);
+
+ boolean isLive(String literal);
+
+ /**
+ * Whether miscellelaneous statements should be considered live.
+ * Miscellaneous statements are any that the fragment extractor does not
+ * recognize as being in any particular category. This method should almost
+ * always return <code>true</code>, but does return <code>false</code>
+ * for {@link NothingAlivePredicate}.
+ */
+ boolean miscellaneousStatementsAreLive();
+ }
+
+ /**
+ * A {@link LivenessPredicate} where nothing is alive.
+ */
+ public static class NothingAlivePredicate implements LivenessPredicate {
+ public boolean isLive(JField field) {
+ return false;
+ }
+
+ public boolean isLive(JMethod method) {
+ return false;
+ }
+
+ public boolean isLive(JReferenceType type) {
+ return false;
+ }
+
+ public boolean isLive(String string) {
+ return false;
+ }
+
+ public boolean miscellaneousStatementsAreLive() {
+ return false;
+ }
+ }
+
+ /**
+ * A logger for statements that the fragment extractor encounters. Install one
+ * using
+ * {@link FragmentExtractor#setStatementLogger(com.google.gwt.fragserv.FragmentExtractor.StatementLogger)}.
+ */
+ public static interface StatementLogger {
+ void logStatement(JsStatement stat, boolean isIncluded);
+ }
+
+ private static class NullStatementLogger implements StatementLogger {
+ public void logStatement(JsStatement method, boolean isIncluded) {
+ }
+ }
+
+ private Set<JsName> entryMethodNames;
+
+ private final JProgram jprogram;
+
+ private final JsProgram jsprogram;
+
+ private final JavaToJavaScriptMap map;
+
+ private StatementLogger statementLogger = new NullStatementLogger();
+
+ public FragmentExtractor(JavaAndJavaScript javaAndJavaScript) {
+ this(javaAndJavaScript.jprogram, javaAndJavaScript.jsprogram,
+ javaAndJavaScript.map);
+ }
+
+ public FragmentExtractor(JProgram jprogram, JsProgram jsprogram,
+ JavaToJavaScriptMap map) {
+ this.jprogram = jprogram;
+ this.jsprogram = jsprogram;
+ this.map = map;
+
+ buildEntryMethodSet();
+ }
+
+ /**
+ * Add direct calls to the entry methods of the specified entry number.
+ */
+ public List<JsStatement> createCallsToEntryMethods(int splitPoint) {
+ List<JsStatement> callStats = new ArrayList<JsStatement>(
+ jprogram.entryMethods.size());
+ for (JMethod entryMethod : jprogram.entryMethods.get(splitPoint)) {
+ JsName name = map.nameForMethod(entryMethod);
+ assert name != null;
+ SourceInfo sourceInfo = jsprogram.getSourceInfo().makeChild(
+ FragmentExtractor.class, "call to entry function " + splitPoint);
+ JsInvocation call = new JsInvocation(sourceInfo);
+ call.setQualifier(name.makeRef(sourceInfo));
+ callStats.add(call.makeStmt());
+ }
+ return callStats;
+ }
+
+ /**
+ * Create a call to
+ * {@link com.google.gwt.lang.AsyncFragmentLoader#leftoversFragmentHasLoaded()}.
+ */
+ public List<JsStatement> createCallToLeftoversFragmentHasLoaded() {
+ JMethod loadedMethod = jprogram.getIndexedMethod("AsyncFragmentLoader.leftoversFragmentHasLoaded");
+ JsName loadedMethodName = map.nameForMethod(loadedMethod);
+ SourceInfo sourceInfo = jsprogram.getSourceInfo().makeChild(
+ FragmentExtractor.class, "call to leftoversFragmentHasLoaded ");
+ JsInvocation call = new JsInvocation(sourceInfo);
+ call.setQualifier(loadedMethodName.makeRef(sourceInfo));
+ List<JsStatement> newStats = Collections.<JsStatement> singletonList(call.makeStmt());
+ return newStats;
+ }
+
+ /**
+ * Assume that all code described by <code>alreadyLoadedPredicate</code> has
+ * been downloaded. Extract enough JavaScript statements that the code
+ * described by <code>livenessPredicate</code> can also run. The caller
+ * should ensure that <code>livenessPredicate</code> includes strictly more
+ * live code than <code>alreadyLoadedPredicate</code>.
+ */
+ public List<JsStatement> extractStatements(
+ LivenessPredicate livenessPredicate,
+ LivenessPredicate alreadyLoadedPredicate) {
+ List<JsStatement> extractedStats = new ArrayList<JsStatement>();
+
+ /**
+ * The type whose vtables can currently be installed.
+ */
+ JReferenceType currentVtableType = null;
+
+ for (int frag = 0; frag < jsprogram.getFragmentCount(); frag++) {
+ List<JsStatement> stats = jsprogram.getFragmentBlock(frag).getStatements();
+ for (JsStatement stat : stats) {
+ if (isEntryCall(stat)) {
+ continue;
+ }
+
+ boolean keepIt;
+
+ if (containsRemovableVars(stat)) {
+ stat = removeSomeVars((JsVars) stat, livenessPredicate,
+ alreadyLoadedPredicate);
+ keepIt = !(stat instanceof JsEmpty);
+ } else {
+ keepIt = isLive(stat, livenessPredicate)
+ && !isLive(stat, alreadyLoadedPredicate);
+ }
+
+ statementLogger.logStatement(stat, keepIt);
+
+ if (keepIt) {
+ if (vtableTypeAssigned(stat) != null) {
+ currentVtableType = vtableTypeAssigned(stat);
+ }
+ JReferenceType vtableType = vtableTypeNeeded(stat);
+ if (vtableType != null && vtableType != currentVtableType) {
+ extractedStats.add(vtableStatFor(vtableType));
+ currentVtableType = vtableType;
+ }
+ extractedStats.add(stat);
+ }
+ }
+ }
+
+ return extractedStats;
+ }
+
+ /**
+ * Find all Java methods that still exist in the resulting JavaScript, even
+ * after JavaScript inlining and pruning.
+ */
+ public Set<JMethod> findAllMethodsInJavaScript() {
+ Set<JMethod> methodsInJs = new HashSet<JMethod>();
+ for (int frag = 0; frag < jsprogram.getFragmentCount(); frag++) {
+ List<JsStatement> stats = jsprogram.getFragmentBlock(frag).getStatements();
+ for (JsStatement stat : stats) {
+ JMethod method = methodFor(stat);
+ if (method != null) {
+ methodsInJs.add(method);
+ }
+ }
+ }
+ return methodsInJs;
+ }
+
+ public void setStatementLogger(StatementLogger logger) {
+ statementLogger = logger;
+ }
+
+ private void buildEntryMethodSet() {
+ entryMethodNames = new HashSet<JsName>();
+ for (JMethod entryMethod : jprogram.getAllEntryMethods()) {
+ JsName name = map.nameForMethod(entryMethod);
+ assert name != null;
+ entryMethodNames.add(name);
+ }
+
+ JMethod leftoverFragmentLoaded = jprogram.getIndexedMethod("AsyncFragmentLoader.leftoversFragmentHasLoaded");
+ if (leftoverFragmentLoaded != null) {
+ JsName name = map.nameForMethod(leftoverFragmentLoaded);
+ assert name != null;
+ entryMethodNames.add(name);
+ }
+ }
+
+ /**
+ * Check whether this statement is a <code>JsVars</code> that contains
+ * individual vars that could be removed. If it does, then
+ * {@link #removeSomeVars(JsVars, LivenessPredicate, LivenessPredicate)} is
+ * sensible for this statement and should be used instead of
+ * {@link #isLive(JsStatement, com.google.gwt.fragserv.FragmentExtractor.LivenessPredicate)}.
+ */
+ private boolean containsRemovableVars(JsStatement stat) {
+ if (stat instanceof JsVars) {
+ for (JsVar var : (JsVars) stat) {
+ String lit = map.stringLiteralForName(var.getName());
+ if (lit != null) {
+ // It's an intern variable for a string literal
+ return true;
+ }
+
+ JField field = map.nameToField(var.getName());
+ if (field != null) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check whether the statement invokes an entry method. Detect JavaScript code
+ * of the form foo() where foo is a the JavaScript function corresponding to
+ * an entry method.
+ */
+ private boolean isEntryCall(JsStatement stat) {
+ if (stat instanceof JsExprStmt) {
+ JsExpression expr = ((JsExprStmt) stat).getExpression();
+ if (expr instanceof JsInvocation) {
+ JsInvocation inv = (JsInvocation) expr;
+ if (inv.getArguments().isEmpty()
+ && (inv.getQualifier() instanceof JsNameRef)) {
+ JsNameRef calleeRef = (JsNameRef) inv.getQualifier();
+ if (calleeRef.getQualifier() == null) {
+ return entryMethodNames.contains(calleeRef.getName());
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isLive(JsStatement stat, LivenessPredicate livenessPredicate) {
+ JReferenceType type = map.typeForStatement(stat);
+ if (type != null) {
+ // This is part of the code only needed once a type is instantiable
+ return livenessPredicate.isLive(type);
+ }
+
+ JMethod meth = methodFor(stat);
+ if (meth == null) {
+ meth = map.vtableInitToMethod(stat);
+ }
+
+ if (meth != null) {
+ /*
+ * This statement either defines a method or installs it in a vtable.
+ */
+ if (!livenessPredicate.isLive(meth)) {
+ // The method is not live. Skip it.
+ return false;
+ }
+ // The method is live. Check that its enclosing type is instantiable.
+ // TODO(spoon): this check should not be needed once the CFA is updated
+ return meth.isStatic()
+ || livenessPredicate.isLive(meth.getEnclosingType());
+ }
+
+ return livenessPredicate.miscellaneousStatementsAreLive();
+ }
+
+ /**
+ * Check whether a variable is needed. If the variable is an intern variable,
+ * then return whether the interned value is live. If the variable corresponds
+ * to a Java field, then return whether the Java field is live. Otherwise,
+ * assume the variable is needed and return <code>true</code>.
+ *
+ * Whenever this method is updated, also look at
+ * {@link #containsRemovableVars(JsStatement)}.
+ */
+ private boolean isLive(JsVar var, LivenessPredicate livenessPredicate) {
+ String lit = map.stringLiteralForName(var.getName());
+ if (lit != null) {
+ // It's an intern variable for a string literal
+ return livenessPredicate.isLive(lit);
+ }
+
+ JField field = map.nameToField(var.getName());
+ if (field != null) {
+ // It's a field
+ return livenessPredicate.isLive(field);
+ }
+
+ // It's not an intern variable at all
+ return livenessPredicate.miscellaneousStatementsAreLive();
+ }
+
+ /**
+ * Return the Java method corresponding to <code>stat</code>, or
+ * <code>null</code> if there isn't one. It recognizes JavaScript of the
+ * form <code>function foo(...) { ...}</code>, where <code>foo</code> is
+ * the name of the JavaScript translation of a Java method.
+ */
+ private JMethod methodFor(JsStatement stat) {
+ if (stat instanceof JsExprStmt) {
+ JsExpression exp = ((JsExprStmt) stat).getExpression();
+ if (exp instanceof JsFunction) {
+ JsFunction func = (JsFunction) exp;
+ if (func.getName() != null) {
+ return map.nameToMethod(func.getName());
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * If stat is a {@link JsVars} that initializes a bunch of intern vars, return
+ * a modified statement that skips any vars are needed by
+ * <code>currentLivenessPredicate</code> but not by
+ * <code>alreadyLoadedPredicate</code>.
+ */
+ private JsStatement removeSomeVars(JsVars stat,
+ LivenessPredicate currentLivenessPredicate,
+ LivenessPredicate alreadyLoadedPredicate) {
+ JsVars newVars = new JsVars(stat.getSourceInfo().makeChild(
+ FragmentExtractor.class, "subsetting of interned values"));
+
+ for (JsVar var : stat) {
+ if (isLive(var, currentLivenessPredicate)
+ && !isLive(var, alreadyLoadedPredicate)) {
+ newVars.add(var);
+ }
+ }
+
+ if (newVars.getNumVars() == stat.getNumVars()) {
+ // no change
+ return stat;
+ }
+
+ if (newVars.iterator().hasNext()) {
+ /*
+ * The new variables are non-empty; return them.
+ */
+ return newVars;
+ } else {
+ /*
+ * An empty JsVars seems possibly surprising; return a true empty
+ * statement instead.
+ */
+ return jsprogram.getEmptyStmt();
+ }
+ }
+
+ /**
+ * Compute a statement that can be used to set up for installing instance
+ * methods into a vtable. It will be of the form
+ * <code>_ = foo.prototype</code>, where <code>foo</code> is the
+ * constructor function for <code>vtableType</code>.
+ */
+ private JsStatement vtableStatFor(JReferenceType vtableType) {
+ JsNameRef prototypeField = new JsNameRef(
+ jsprogram.createSourceInfoSynthetic(FragmentExtractor.class,
+ "prototype field"), "prototype");
+ JsExpression constructorRef;
+ SourceInfo sourceInfoVtableSetup = jsprogram.createSourceInfoSynthetic(
+ FragmentExtractor.class, "vtable setup");
+ if (vtableType == jprogram.getTypeJavaLangString()) {
+ // The methods of java.lang.String are put onto JavaScript's String
+ // prototype
+ SourceInfo sourceInfoConstructorRef = jsprogram.createSourceInfoSynthetic(
+ FragmentExtractor.class, "String constructor");
+ constructorRef = new JsNameRef(sourceInfoConstructorRef, "String");
+ } else {
+ constructorRef = map.nameForType(vtableType).makeRef(
+ sourceInfoVtableSetup);
+ }
+ prototypeField.setQualifier(constructorRef);
+ SourceInfo underlineSourceInfo = jsprogram.createSourceInfoSynthetic(
+ FragmentExtractor.class, "global _ field");
+ return (new JsBinaryOperation(sourceInfoVtableSetup, JsBinaryOperator.ASG,
+ jsprogram.getScope().declareName("_").makeRef(underlineSourceInfo),
+ prototypeField)).makeStmt();
+ }
+
+ /**
+ * If <code>state</code> is of the form <code>_ = Foo.prototype = exp</code>,
+ * then return <code>Foo</code>. Otherwise return <code>null</code>.
+ *
+ * TODO(spoon): get this information via source info on the statement
+ */
+ private JReferenceType vtableTypeAssigned(JsStatement stat) {
+ if (!(stat instanceof JsExprStmt)) {
+ return null;
+ }
+ JsExprStmt expr = (JsExprStmt) stat;
+ if (!(expr.getExpression() instanceof JsBinaryOperation)) {
+ return null;
+ }
+ JsBinaryOperation binExpr = (JsBinaryOperation) expr.getExpression();
+ if (binExpr.getOperator() != JsBinaryOperator.ASG) {
+ return null;
+ }
+ if (!(binExpr.getArg1() instanceof JsNameRef)) {
+ return null;
+ }
+ JsNameRef lhs = (JsNameRef) binExpr.getArg1();
+ if (lhs.getQualifier() != null) {
+ return null;
+ }
+ if (lhs.getName() == null) {
+ return null;
+ }
+ if (!lhs.getName().getShortIdent().equals("_")) {
+ return null;
+ }
+ if (!(binExpr.getArg2() instanceof JsBinaryOperation)) {
+ return null;
+ }
+ JsBinaryOperation binExprRhs = (JsBinaryOperation) binExpr.getArg2();
+ if (binExprRhs.getOperator() != JsBinaryOperator.ASG) {
+ return null;
+ }
+ if (!(binExprRhs.getArg1() instanceof JsNameRef)) {
+ return null;
+ }
+ JsNameRef middleNameRef = (JsNameRef) binExprRhs.getArg1();
+ if (!middleNameRef.getName().getShortIdent().equals("prototype")) {
+ return null;
+ }
+
+ return map.typeForStatement(stat);
+ }
+
+ private JReferenceType vtableTypeNeeded(JsStatement stat) {
+ JMethod meth = map.vtableInitToMethod(stat);
+ if (meth != null) {
+ if (!meth.isStatic()) {
+ return meth.getEnclosingType();
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
new file mode 100644
index 0000000..ea097c9
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
@@ -0,0 +1,337 @@
+/*
+ * 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.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.PropertyOracle;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.linker.ArtifactSet;
+import com.google.gwt.dev.cfg.BindingProperty;
+import com.google.gwt.dev.cfg.ConfigurationProperty;
+import com.google.gwt.dev.cfg.PublicOracle;
+import com.google.gwt.dev.cfg.StaticPropertyOracle;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor;
+import com.google.gwt.dev.shell.StandardGeneratorContext;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Generates code for loading an island. The pattern of generated classes is
+ * more complicated than otherwise necessary so that the loader code is
+ * precisely handled by TypeTightener and LivenessAnalyzer.
+ *
+ * TODO(spoon) Remove this generator by making LivenessAnalyzer know about
+ * runAsync and how it works.
+ */
+public class FragmentLoaderCreator {
+ public static final String ASYNC_FRAGMENT_LOADER = "com.google.gwt.core.client.AsyncFragmentLoader";
+ public static final String ASYNC_LOADER_CLASS_PREFIX = "AsyncLoader";
+ public static final String ASYNC_LOADER_PACKAGE = "com.google.gwt.lang.asyncloaders";
+ public static final String RUN_ASYNC_CALLBACK = "com.google.gwt.core.client.RunAsyncCallback";
+ private static final String GWT_CLASS = FindDeferredBindingSitesVisitor.MAGIC_CLASS;
+ private static final String PROP_RUN_ASYNC_NEVER_RUNS = "gwt.jjs.runAsyncNeverRuns";
+ private static final String UNCAUGHT_EXCEPTION_HANDLER_CLASS = GWT_CLASS
+ + ".UncaughtExceptionHandler";
+
+ private final ArtifactSet artifactSet;
+ private final CompilationState compilationState;
+ private int entryNumber;
+ private final File genDir;
+ private final File outDir;
+ private final PublicOracle publicOracle;
+
+ /**
+ * Construct a FragmentLoaderCreator. The reason it needs so many parameters
+ * is that it uses generator infrastructure.
+ */
+ public FragmentLoaderCreator(CompilationState compilationState,
+ PublicOracle publicOracle, File genDir, File moduleOutDir,
+ ArtifactSet artifactSet) {
+ this.compilationState = compilationState;
+ this.publicOracle = publicOracle;
+ this.genDir = genDir;
+ this.outDir = moduleOutDir;
+ this.artifactSet = artifactSet;
+ }
+
+ public String create(TreeLogger logger) throws UnableToCompleteException {
+ chooseEntryNumber();
+ StandardGeneratorContext context = makeGeneratorContext();
+
+ PrintWriter loaderWriter = getSourceWriterForLoader(logger, context);
+ if (loaderWriter == null) {
+ logger.log(TreeLogger.ERROR, "Failed to create island loader named "
+ + getLoaderQualifiedName());
+ throw new UnableToCompleteException();
+ }
+
+ generateLoaderFields(loaderWriter);
+ generateOnErrorMethod(loaderWriter);
+ generateOnLoadMethod(loaderWriter);
+ generateRunAsyncMethod(loaderWriter);
+ generateRunCallbacksMethod(loaderWriter);
+ generateRunCallbackOnFailuresMethod(loaderWriter);
+
+ loaderWriter.println("}");
+ loaderWriter.close();
+ context.commit(logger, loaderWriter);
+
+ writeCallbackListClass(logger, context);
+ writeLoaderSuperclass(logger, context);
+
+ context.finish(logger);
+
+ return getLoaderQualifiedName();
+ }
+
+ /**
+ * Pick the lowest-numbered entry number that has not yet had loaders
+ * generated.
+ */
+ private void chooseEntryNumber() {
+ entryNumber = 1;
+ while (compilationState.getTypeOracle().findType(getLoaderQualifiedName()) != null) {
+ entryNumber++;
+ }
+ }
+
+ private void generateLoaderFields(PrintWriter srcWriter) {
+ srcWriter.println("// Whether the code for this entry point has loaded");
+ srcWriter.println("private static boolean loaded = false;");
+
+ srcWriter.println("// Whether the code for this entry point is currently loading");
+ srcWriter.println("private static boolean loading = false;");
+
+ srcWriter.println("// A callback caller for this entry point");
+ srcWriter.println("private static " + getLoaderSuperclassSimpleName()
+ + " instance = new " + getLoaderSuperclassSimpleName() + "();");
+
+ srcWriter.println("// Callbacks that are pending");
+ srcWriter.println("private static " + getCallbackListSimpleName()
+ + " callbacksHead = null;");
+
+ srcWriter.println("// The tail of the callbacks list");
+ srcWriter.println("private static " + getCallbackListSimpleName()
+ + " callbacksTail = null;");
+ }
+
+ private void generateOnErrorMethod(PrintWriter srcWriter) {
+ srcWriter.println("public static void onError(Throwable e) {");
+ srcWriter.println("loading = false;");
+ srcWriter.println("runCallbackOnFailures(e);");
+ srcWriter.println("}");
+ }
+
+ private void generateOnLoadMethod(PrintWriter srcWriter) {
+ srcWriter.println("public static void onLoad() {");
+ srcWriter.println("loaded = true;");
+ srcWriter.println("instance = new " + getLoaderSimpleName() + "();");
+ srcWriter.println(ASYNC_FRAGMENT_LOADER + ".fragmentHasLoaded("
+ + entryNumber + ");");
+
+ srcWriter.println(ASYNC_FRAGMENT_LOADER
+ + ".logEventProgress(\"runCallbacks" + entryNumber + "\", \"begin\");");
+ srcWriter.println("instance.runCallbacks();");
+ srcWriter.println(ASYNC_FRAGMENT_LOADER
+ + ".logEventProgress(\"runCallbacks" + entryNumber + "\", \"end\");");
+
+ srcWriter.println("}");
+ }
+
+ /**
+ * Generate the <code>runAsync</code> method. Calls to
+ * <code>GWT.runAsync</code> are replaced by calls to this method.
+ */
+ private void generateRunAsyncMethod(PrintWriter srcWriter) {
+ srcWriter.println("public static void runAsync(RunAsyncCallback callback) {");
+ srcWriter.println(getCallbackListSimpleName() + " newCallback = new "
+ + getCallbackListSimpleName() + "();");
+ srcWriter.println("newCallback.callback = callback;");
+
+ srcWriter.println("if (callbacksTail != null) {");
+ srcWriter.println(" callbacksTail.next = newCallback;");
+ srcWriter.println("}");
+
+ srcWriter.println("callbacksTail = newCallback;");
+ srcWriter.println("if (callbacksHead == null) {");
+ srcWriter.println(" callbacksHead = newCallback;");
+ srcWriter.println("}");
+
+ srcWriter.println("if (loaded) {");
+ srcWriter.println("instance.runCallbacks();");
+ srcWriter.println("return;");
+ srcWriter.println("}");
+ srcWriter.println("if (!loading) {");
+ srcWriter.println("loading = true;");
+ srcWriter.println("AsyncFragmentLoader.inject(" + entryNumber + ");");
+ srcWriter.println("}");
+ srcWriter.println("}");
+ }
+
+ private void generateRunCallbackOnFailuresMethod(PrintWriter srcWriter) {
+ srcWriter.println("private static void runCallbackOnFailures(Throwable e) {");
+ srcWriter.println("while (callbacksHead != null) {");
+ srcWriter.println("callbacksHead.callback.onFailure(e);");
+ srcWriter.println("callbacksHead = callbacksHead.next;");
+ srcWriter.println("}");
+ srcWriter.println("callbacksTail = null;");
+ srcWriter.println("}");
+ }
+
+ private void generateRunCallbacksMethod(PrintWriter srcWriter) {
+ srcWriter.println("public void runCallbacks() {");
+
+ srcWriter.println("while (callbacksHead != null) {");
+
+ srcWriter.println(" " + UNCAUGHT_EXCEPTION_HANDLER_CLASS + " handler = "
+ + FindDeferredBindingSitesVisitor.MAGIC_CLASS
+ + ".getUncaughtExceptionHandler();");
+
+ srcWriter.println(" " + getCallbackListSimpleName() + " next = callbacksHead;");
+ srcWriter.println(" callbacksHead = callbacksHead.next;");
+ srcWriter.println(" if (callbacksHead == null) {");
+ srcWriter.println(" callbacksTail = null;");
+ srcWriter.println(" }");
+
+ if (!Boolean.getBoolean(PROP_RUN_ASYNC_NEVER_RUNS)) {
+ // TODO(spoon): this runs the callbacks immediately; deferred would be
+ // better
+ srcWriter.println(" if (handler == null) {");
+ srcWriter.println(" next.callback.onSuccess();");
+ srcWriter.println(" } else {");
+ srcWriter.println(" try {");
+ srcWriter.println(" next.callback.onSuccess();");
+ srcWriter.println(" } catch (Throwable e) {");
+ srcWriter.println(" handler.onUncaughtException(e);");
+ srcWriter.println(" }");
+ srcWriter.println(" }");
+ }
+
+ srcWriter.println("}");
+ srcWriter.println("}");
+ }
+
+ private String getCallbackListQualifiedName() {
+ return ASYNC_LOADER_PACKAGE + "__Callback";
+ }
+
+ private String getCallbackListSimpleName() {
+ return getLoaderSimpleName() + "__Callback";
+ }
+
+ private String getLoaderQualifiedName() {
+ return ASYNC_LOADER_PACKAGE + "." + getLoaderSimpleName();
+ }
+
+ private String getLoaderSimpleName() {
+ return ASYNC_LOADER_CLASS_PREFIX + entryNumber;
+ }
+
+ private String getLoaderSuperclassQualifiedName() {
+ return ASYNC_LOADER_PACKAGE + getLoaderSuperclassSimpleName();
+ }
+
+ private String getLoaderSuperclassSimpleName() {
+ return getLoaderSimpleName() + "__Super";
+ }
+
+ private String getPackage() {
+ return ASYNC_LOADER_PACKAGE;
+ }
+
+ private PrintWriter getSourceWriterForLoader(TreeLogger logger,
+ GeneratorContext ctx) {
+ PrintWriter printWriter = ctx.tryCreate(logger, getPackage(),
+ getLoaderSimpleName());
+ if (printWriter == null) {
+ return null;
+ }
+
+ printWriter.println("package " + getPackage() + ";");
+ String[] imports = new String[] {
+ RUN_ASYNC_CALLBACK, List.class.getCanonicalName(),
+ ASYNC_FRAGMENT_LOADER};
+ for (String imp : imports) {
+ printWriter.println("import " + imp + ";");
+ }
+
+ printWriter.println("public class " + getLoaderSimpleName() + " extends "
+ + getLoaderSuperclassSimpleName() + " {");
+
+ return printWriter;
+ }
+
+ private StandardGeneratorContext makeGeneratorContext() {
+ // An empty property oracle is fine, because fragment loaders aren't
+ // affected by properties anyway
+ PropertyOracle propOracle = new StaticPropertyOracle(
+ new BindingProperty[0], new String[0], new ConfigurationProperty[0]);
+ StandardGeneratorContext context = new StandardGeneratorContext(
+ compilationState, propOracle, publicOracle, genDir, outDir, artifactSet);
+ return context;
+ }
+
+ private void writeCallbackListClass(TreeLogger logger, GeneratorContext ctx)
+ throws UnableToCompleteException {
+ PrintWriter printWriter = ctx.tryCreate(logger, getPackage(),
+ getCallbackListSimpleName());
+ if (printWriter == null) {
+ logger.log(TreeLogger.ERROR, "Could not create type: "
+ + getCallbackListQualifiedName());
+ throw new UnableToCompleteException();
+ }
+
+ printWriter.println("package " + getPackage() + ";");
+ printWriter.println("public class " + getCallbackListSimpleName() + "{");
+ printWriter.println(RUN_ASYNC_CALLBACK + " callback;");
+ printWriter.println(getCallbackListSimpleName() + " next;");
+ printWriter.println("}");
+
+ printWriter.close();
+ ctx.commit(logger, printWriter);
+ }
+
+ /**
+ * Create a stand-in superclass of the actual loader. This is used to keep the
+ * liveness analyzer from thinking the real <code>runCallbacks()</code> method
+ * is available until <code>onLoad</code> has been called and the real loader
+ * instantiated. A little work on TypeTightener could prevent the need for
+ * this class.
+ */
+ private void writeLoaderSuperclass(TreeLogger logger, GeneratorContext ctx)
+ throws UnableToCompleteException {
+ PrintWriter printWriter = ctx.tryCreate(logger, getPackage(),
+ getLoaderSuperclassSimpleName());
+ if (printWriter == null) {
+ logger.log(TreeLogger.ERROR, "Could not create type: "
+ + getLoaderSuperclassQualifiedName());
+ throw new UnableToCompleteException();
+ }
+
+ printWriter.println("package " + getPackage() + ";");
+ printWriter.println("public class " + getLoaderSuperclassSimpleName()
+ + " {");
+ printWriter.println("public void runCallbacks() { }");
+ printWriter.println("}");
+
+ printWriter.close();
+ ctx.commit(logger, printWriter);
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index b3f3b9a..7b3c27f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -17,6 +17,7 @@
import com.google.gwt.dev.jjs.HasSourceInfo;
import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.jjs.JJSOptions;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.HasEnclosingType;
@@ -31,6 +32,7 @@
import com.google.gwt.dev.jjs.ast.JCaseStatement;
import com.google.gwt.dev.jjs.ast.JCastOperation;
import com.google.gwt.dev.jjs.ast.JCharLiteral;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConditional;
import com.google.gwt.dev.jjs.ast.JContinueStatement;
@@ -76,6 +78,7 @@
import com.google.gwt.dev.jjs.ast.JThrowStatement;
import com.google.gwt.dev.jjs.ast.JTryStatement;
import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.jjs.ast.JTypeOracle;
import com.google.gwt.dev.jjs.ast.JUnaryOperator;
import com.google.gwt.dev.jjs.ast.JVariable;
import com.google.gwt.dev.jjs.ast.JVariableRef;
@@ -182,14 +185,19 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
+import java.util.Set;
import java.util.TreeSet;
/**
@@ -220,6 +228,54 @@
*/
private static class JavaASTGenerationVisitor {
+ /**
+ * Find all interface methods declared to be implemented by a specified
+ * class.
+ */
+ private static Collection<MethodBinding> findInterfaceMethods(
+ ReferenceBinding clazzBinding) {
+ List<MethodBinding> methods = new ArrayList<MethodBinding>();
+ Set<ReferenceBinding> seen = new HashSet<ReferenceBinding>();
+ findInterfaceMethodsRecursive(clazzBinding, methods, seen);
+ return methods;
+ }
+
+ private static void findInterfaceMethodsRecursive(
+ ReferenceBinding clazzBinding, List<MethodBinding> methods,
+ Set<ReferenceBinding> seen) {
+ if (!seen.add(clazzBinding)) {
+ return;
+ }
+
+ if (clazzBinding.isInterface()) {
+ methods.addAll(Arrays.asList(clazzBinding.methods()));
+ }
+
+ ReferenceBinding superclass = clazzBinding.superclass();
+ if (superclass != null) {
+ findInterfaceMethodsRecursive(superclass, methods, seen);
+ }
+
+ ReferenceBinding[] interfaces = clazzBinding.superInterfaces();
+ if (interfaces != null) {
+ for (ReferenceBinding supinterf : interfaces) {
+ findInterfaceMethodsRecursive(supinterf, methods, seen);
+ }
+ }
+ }
+
+ private static boolean inheritsMethodWithIdenticalSignature(
+ JClassType clazz, JMethod method) {
+ for (JClassType sup = clazz.extnds; sup != null; sup = sup.extnds) {
+ for (JMethod m : sup.methods) {
+ if (JTypeOracle.methodsDoMatch(m, method)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private static InternalCompilerException translateException(JNode node,
Throwable e) {
if (e instanceof OutOfMemoryError) {
@@ -253,7 +309,9 @@
private int[] currentSeparatorPositions;
- private boolean enableAsserts;
+ private final boolean disableClassMetadata;
+
+ private final boolean enableAsserts;
private final Map<JsniMethodBody, AbstractMethodDeclaration> jsniMethodMap = new HashMap<JsniMethodBody, AbstractMethodDeclaration>();
@@ -264,13 +322,100 @@
private final TypeMap typeMap;
public JavaASTGenerationVisitor(TypeMap typeMap, JProgram program,
- boolean enableAsserts) {
+ JJSOptions options) {
this.typeMap = typeMap;
this.program = program;
- this.enableAsserts = enableAsserts;
+ this.enableAsserts = options.isEnableAssertions();
+
+ /*
+ * TODO: Determine if this should be controlled by a compiler flag or a
+ * module property.
+ */
+ this.disableClassMetadata = options.isClassMetadataDisabled();
autoboxUtils = new AutoboxUtils(program);
}
+ /**
+ * <p>
+ * Add a bridge method to <code>clazzBinding</code> for any method it
+ * inherits that implements an interface method but that has a different
+ * erased signature from the interface method.
+ * </p>
+ *
+ * <p>
+ * This method assumes that method overrides are already recorded for the
+ * class and all its inherited classes and interfaces.
+ * </p>
+ *
+ * <p>
+ * The need for these bridges was pointed out in issue 3064. The goal is
+ * that virtual method calls through an interface type are translated to
+ * JavaScript that will function correctly. If the interface signature
+ * matches the signature of the implementing method, then nothing special
+ * needs to be done. If they are different, due to the use of generics, then
+ * GenerateJavaScriptAST is careful to do the right thing. There is a
+ * remaining case, though, that GenerateJavaScriptAST is not in a good
+ * position to fix: a method could be inherited from a superclass, used to
+ * implement an interface method that has a different type signature, and
+ * does not have the interface method in its list of overrides. In that
+ * case, a bridge method should be added that overrides the interface method
+ * and then calls the implementation method.
+ * </p>
+ */
+ public void addBridgeMethods(ReferenceBinding clazzBinding,
+ JProgram program, Set<ReferenceBinding> typesWithBridges) {
+ if (clazzBinding.isInterface() || clazzBinding.isAbstract()) {
+ // Only add bridges in concrete classes, to simplify matters.
+ return;
+ }
+
+ if (!typesWithBridges.add(clazzBinding)) {
+ // Nothing to do -- this class already has bridges added.
+ return;
+ }
+
+ /*
+ * Add to the superclass first, so that bridge methods end up as high in
+ * the hierarchy as possible.
+ */
+ if (clazzBinding.superclass() != null) {
+ addBridgeMethods(clazzBinding.superclass(), program, typesWithBridges);
+ }
+
+ JClassType clazz = (JClassType) typeMap.get(clazzBinding);
+
+ for (MethodBinding imethBinding : findInterfaceMethods(clazzBinding)) {
+ JMethod interfmeth = (JMethod) typeMap.get(imethBinding);
+ JMethod implmeth = (JMethod) typeMap.get(findMethodImplementing(
+ imethBinding, clazzBinding));
+
+ assert (!implmeth.isStatic());
+
+ if (!implmeth.overrides.contains(interfmeth)) {
+ if (JTypeOracle.methodsDoMatch(interfmeth, implmeth)) {
+ /*
+ * Two cases are caught here. First, a bridge method might already
+ * be included in a superclass. In that case, there's nothing to do.
+ * Second, the bridge method might have the exact signature as the
+ * bridged-to method. In that case, leave out the bridge method. It
+ * makes things harder on the optimizers, but it avoids adding a
+ * bridge method that must later be removed. Further, such a bridge
+ * method would need to be different from the current ones in order
+ * to avoid an infinite recursion.
+ */
+ continue;
+ }
+
+ if (inheritsMethodWithIdenticalSignature(clazz, interfmeth)) {
+ // An equivalent bridge has already been added in a superclass
+ continue;
+ }
+
+ createBridgeMethod(program, clazz, interfmeth, implmeth);
+ }
+ }
+ }
+
public void processEnumType(JEnumType type) {
// Create a JSNI map for string-based lookup.
JField mapField = createEnumValueMap(type);
@@ -396,10 +541,33 @@
implementMethod(method, program.getLiteralBoolean(true));
}
- // Implement Class.desiredAssertionStatus
+ // Implement various methods on Class
if (currentClass == program.getTypeJavaLangClass()) {
JMethod method = program.getIndexedMethod("Class.desiredAssertionStatus");
implementMethod(method, program.getLiteralBoolean(enableAsserts));
+
+ if (disableClassMetadata) {
+ SourceInfo info = currentClass.getSourceInfo().makeChild(
+ JavaASTGenerationVisitor.class, "Disabled class metadata");
+
+ JMethod nameMethod = program.getIndexedMethod("Class.getName");
+
+ // this.hashCode()
+ JMethodCall hashCall = new JMethodCall(program, info,
+ program.getExprThisRef(info, (JClassType) currentClass),
+ program.getIndexedMethod("Object.hashCode"));
+
+ // "Class$" + hashCode()
+ JBinaryOperation op = new JBinaryOperation(program, info,
+ program.getTypeJavaLangString(), JBinaryOperator.ADD,
+ program.getLiteralString(info, "Class$"), hashCall);
+
+ implementMethod(nameMethod, op);
+
+ // Forget the superclass
+ JMethod superclassMethod = program.getIndexedMethod("Class.getSuperclass");
+ implementMethod(superclassMethod, program.getLiteralNull());
+ }
}
if (currentClass instanceof JEnumType) {
@@ -531,7 +699,9 @@
}
JStringLiteral processConstant(StringConstant x) {
- return program.getLiteralString(x.stringValue().toCharArray());
+ return program.getLiteralString(currentMethod.getSourceInfo().makeChild(
+ JavaASTGenerationVisitor.class, "String literal"),
+ x.stringValue().toCharArray());
}
/**
@@ -677,7 +847,7 @@
currentMethod = null;
// synthesize a return statement to emulate returning the new object
- statements.add(new JReturnStatement(program, null, thisRef));
+ statements.add(new JReturnStatement(program, info, thisRef));
} catch (Throwable e) {
throw translateException(ctor, e);
}
@@ -734,7 +904,7 @@
// Enums: hidden arguments for the name and id.
if (x.enumConstant != null) {
- call.getArgs().add(program.getLiteralString(x.enumConstant.name));
+ call.getArgs().add(program.getLiteralString(info, x.enumConstant.name));
call.getArgs().add(
program.getLiteralInt(x.enumConstant.binding.original().id));
}
@@ -995,7 +1165,6 @@
}
JExpression processExpression(FieldReference x) {
- SourceInfo info = makeSourceInfo(x);
FieldBinding fieldBinding = x.binding;
JField field;
if (fieldBinding.declaringClass == null) {
@@ -1007,6 +1176,7 @@
} else {
field = (JField) typeMap.get(fieldBinding);
}
+ SourceInfo info = makeSourceInfo(x);
JExpression instance = dispProcessExpression(x.receiver);
JExpression fieldRef = new JFieldRef(program, info, instance, field,
currentClass);
@@ -1948,6 +2118,67 @@
}
}
+ /**
+ * Create a bridge method. It calls a same-named method with the same
+ * arguments, but with a different type signature.
+ *
+ * @param program The program being modified
+ * @param clazz The class to put the bridge method in
+ * @param interfmeth The interface method to bridge from
+ * @param implmeth The implementation method to bridge to
+ */
+ private void createBridgeMethod(JProgram program, JClassType clazz,
+ JMethod interfmeth, JMethod implmeth) {
+ SourceInfo info = program.createSourceInfoSynthetic(
+ GenerateJavaAST.class, "bridge method");
+
+ // create the method itself
+ JMethod bridgeMethod = program.createMethod(info,
+ interfmeth.getName().toCharArray(), clazz, interfmeth.getType(),
+ false, false, true, false, false);
+ for (JParameter param : interfmeth.params) {
+ program.createParameter(program.createSourceInfoSynthetic(
+ GenerateJavaAST.class, "part of a bridge method"),
+ param.getName().toCharArray(), param.getType(), true, false,
+ bridgeMethod);
+ }
+ bridgeMethod.freezeParamTypes();
+
+ // create a call
+ JMethodCall call = new JMethodCall(program,
+ program.createSourceInfoSynthetic(GenerateJavaAST.class,
+ "call to inherited method"), program.getExprThisRef(
+ program.createSourceInfoSynthetic(GenerateJavaAST.class,
+ "part of a bridge method"), clazz), implmeth);
+
+ for (int i = 0; i < bridgeMethod.params.size(); i++) {
+ JParameter param = bridgeMethod.params.get(i);
+ JParameterRef paramRef = new JParameterRef(program,
+ program.createSourceInfoSynthetic(GenerateJavaAST.class,
+ "part of a bridge method"), param);
+ call.getArgs().add(
+ maybeCast(implmeth.params.get(i).getType(), paramRef));
+ }
+
+ // wrap it in a return if necessary
+ JStatement callOrReturn;
+ if (bridgeMethod.getType() == program.getTypeVoid()) {
+ callOrReturn = call.makeStatement();
+ } else {
+ callOrReturn = new JReturnStatement(program,
+ program.createSourceInfoSynthetic(GenerateJavaAST.class,
+ "part of a bridge method"), call);
+ }
+
+ // create a body that is just that call
+ JMethodBody body = (JMethodBody) bridgeMethod.getBody();
+ body.getStatements().add(callOrReturn);
+
+ // make the bridge override the interface method
+ bridgeMethod.overrides.add(interfmeth);
+ bridgeMethod.overrides.addAll(interfmeth.overrides);
+ }
+
private JDeclarationStatement createDeclaration(SourceInfo info,
JLocal local, JExpression value) {
return new JDeclarationStatement(program, info, new JLocalRef(program,
@@ -1955,20 +2186,25 @@
}
private JField createEnumValueMap(JEnumType type) {
- JsonObject map = new JsonObject(program);
+ SourceInfo sourceInfo = type.getSourceInfo().makeChild(
+ JavaASTGenerationVisitor.class, "enum value lookup map");
+ JsonObject map = new JsonObject(program, sourceInfo);
for (JEnumField field : type.enumList) {
// JSON maps require leading underscores to prevent collisions.
- JStringLiteral key = program.getLiteralString("_" + field.getName());
- JFieldRef value = new JFieldRef(program, null, null, field, type);
- map.propInits.add(new JsonObject.JsonPropInit(program, key, value));
+ JStringLiteral key = program.getLiteralString(field.getSourceInfo(),
+ "_" + field.getName());
+ JFieldRef value = new JFieldRef(program, sourceInfo, null, field, type);
+ map.propInits.add(new JsonObject.JsonPropInit(program, sourceInfo, key,
+ value));
}
- JField mapField = program.createField(null, "enum$map".toCharArray(),
- type, map.getType(), true, Disposition.FINAL);
+ JField mapField = program.createField(sourceInfo,
+ "enum$map".toCharArray(), type, map.getType(), true,
+ Disposition.FINAL);
// Initialize in clinit.
JMethodBody clinitBody = (JMethodBody) type.methods.get(0).getBody();
- JExpressionStatement assignment = program.createAssignmentStmt(null,
- createVariableRef(null, mapField), map);
+ JExpressionStatement assignment = program.createAssignmentStmt(
+ sourceInfo, createVariableRef(sourceInfo, mapField), map);
clinitBody.getStatements().add(assignment);
return mapField;
}
@@ -2086,7 +2322,9 @@
"FieldRef referencing field in a different type.");
}
}
- return new JFieldRef(program, info, instance, field, currentClass);
+ return new JFieldRef(program, info.makeChild(
+ JavaASTGenerationVisitor.class, "Reference",
+ variable.getSourceInfo()), instance, field, currentClass);
}
throw new InternalCompilerException("Unknown JVariable subclass.");
}
@@ -2119,6 +2357,27 @@
}
/**
+ * Search the class hierarchy starting at <code>clazz</code> looking for a
+ * method implementing <code>imeth</code>. Look only in classes, not
+ * interfaces.
+ */
+ private MethodBinding findMethodImplementing(MethodBinding interfmeth,
+ ReferenceBinding clazz) {
+ for (MethodBinding tryMethod : clazz.getMethods(interfmeth.selector)) {
+ if (methodParameterErasuresAreEqual(interfmeth, tryMethod)) {
+ return tryMethod;
+ }
+ }
+
+ if (clazz.superclass() == null) {
+ throw new InternalCompilerException("Could not find implementation of "
+ + interfmeth + " for class " + clazz);
+ }
+
+ return findMethodImplementing(interfmeth, clazz.superclass());
+ }
+
+ /**
* Get a new label of a particular name, or create a new one if it doesn't
* exist already.
*/
@@ -2197,14 +2456,15 @@
* expression. Beware that when autoboxing, the type of the expression is
* not necessarily the same as the type of the box to be created. The JDT
* figures out what the necessary conversion is, depending on the context
- * the expression appears in, and stores it in <code>x.implicitConversion</code>,
- * so extract it from there.
+ * the expression appears in, and stores it in
+ * <code>x.implicitConversion</code>, so extract it from there.
*/
private JPrimitiveType implicitConversionTargetType(Expression x)
throws InternalCompilerException {
/*
* This algorithm for finding the target type is copied from
- * org.eclipse.jdt.internal.compiler.codegen.CodeStream.generateReturnBytecode() .
+ * org.eclipse.jdt
+ * .internal.compiler.codegen.CodeStream.generateReturnBytecode() .
*/
switch ((x.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) {
case TypeIds.T_boolean:
@@ -2232,8 +2492,15 @@
private SourceInfo makeSourceInfo(Statement x) {
int startLine = Util.getLineNumber(x.sourceStart,
currentSeparatorPositions, 0, currentSeparatorPositions.length - 1);
- return new SourceInfo(x.sourceStart, x.sourceEnd, startLine,
- currentFileName);
+ SourceInfo toReturn = program.createSourceInfo(x.sourceStart,
+ x.sourceEnd, startLine, currentFileName);
+ if (currentClass != null) {
+ toReturn.copyMissingCorrelationsFrom(currentClass.getSourceInfo());
+ }
+ if (currentMethod != null) {
+ toReturn.copyMissingCorrelationsFrom(currentMethod.getSourceInfo());
+ }
+ return toReturn;
}
private JExpression maybeCast(JType expected, JExpression expression) {
@@ -2248,6 +2515,32 @@
}
/**
+ * Check whether two methods have matching parameter types. Assumes the
+ * selectors match.
+ */
+ private boolean methodParameterErasuresAreEqual(MethodBinding meth1,
+ MethodBinding meth2) {
+ /*
+ * Don't use MethodBinding.areParameterErasuresEqual because that method
+ * assumes equal types are ==, but that's not necessarily true in this
+ * context.
+ */
+ if (meth1.parameters.length != meth2.parameters.length) {
+ return false;
+ }
+
+ for (int i = 0; i < meth1.parameters.length; i++) {
+ TypeBinding type1 = meth1.parameters[i].erasure();
+ TypeBinding type2 = meth2.parameters[i].erasure();
+ if (typeMap.get(type1) != typeMap.get(type2)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
* Sometimes a variable reference can be to a local or parameter in an an
* enclosing method. This is a tricky situation to detect. There's no
* obvious way to tell, but the clue we can get from JDT is that the local's
@@ -2488,28 +2781,34 @@
private void writeEnumValueOfMethod(JEnumType type, JField mapField) {
// return Enum.valueOf(map, name);
- JFieldRef mapRef = new JFieldRef(program, null, null, mapField, type);
- JVariableRef nameRef = createVariableRef(null,
+ SourceInfo sourceInfo = mapField.getSourceInfo().makeChild(
+ JavaASTGenerationVisitor.class, "enum accessor method");
+ JFieldRef mapRef = new JFieldRef(program, sourceInfo, null, mapField,
+ type);
+ JVariableRef nameRef = createVariableRef(sourceInfo,
currentMethod.params.get(0));
JMethod delegateTo = program.getIndexedMethod("Enum.valueOf");
- JMethodCall call = new JMethodCall(program, null, null, delegateTo);
+ JMethodCall call = new JMethodCall(program, sourceInfo, null, delegateTo);
call.getArgs().add(mapRef);
call.getArgs().add(nameRef);
currentMethodBody.getStatements().add(
- new JReturnStatement(program, null, call));
+ new JReturnStatement(program, sourceInfo, call));
}
private void writeEnumValuesMethod(JEnumType type) {
// return new E[]{A,B,C};
+ SourceInfo sourceInfo = type.getSourceInfo().makeChild(
+ JavaASTGenerationVisitor.class, "enum values method");
List<JExpression> initializers = new ArrayList<JExpression>();
for (JEnumField field : type.enumList) {
- JFieldRef fieldRef = new JFieldRef(program, null, null, field, type);
+ JFieldRef fieldRef = new JFieldRef(program, sourceInfo, null, field,
+ type);
initializers.add(fieldRef);
}
- JNewArray newExpr = JNewArray.createInitializers(program, null,
+ JNewArray newExpr = JNewArray.createInitializers(program, sourceInfo,
program.getTypeArray(type, 1), initializers);
currentMethodBody.getStatements().add(
- new JReturnStatement(program, null, newExpr));
+ new JReturnStatement(program, sourceInfo, newExpr));
}
}
@@ -2545,9 +2844,9 @@
}
String className = parsed.className();
- JReferenceType type = null;
+ JType type = null;
if (!className.equals("null")) {
- type = program.getFromTypeMap(className);
+ type = program.getTypeFromJsniRef(className);
if (type == null) {
reportJsniError(info, methodDecl,
"Unresolvable native reference to type '" + className + "'");
@@ -2562,9 +2861,24 @@
if (fieldName.equals("nullField")) {
return program.getNullField();
}
+
+ } else if (fieldName.equals("class")) {
+ JClassLiteral lit = program.getLiteralClass(type);
+ return lit.getField();
+
+ } else if (type instanceof JPrimitiveType) {
+ reportJsniError(info, methodDecl,
+ "May not refer to fields on primitive types");
+ return null;
+
+ } else if (type instanceof JArrayType) {
+ reportJsniError(info, methodDecl,
+ "May not refer to fields on array types");
+ return null;
+
} else {
- for (int i = 0; i < type.fields.size(); ++i) {
- JField field = type.fields.get(i);
+ for (int i = 0; i < ((JReferenceType) type).fields.size(); ++i) {
+ JField field = ((JReferenceType) type).fields.get(i);
if (field.getName().equals(fieldName)) {
return field;
}
@@ -2575,6 +2889,12 @@
"Unresolvable native reference to field '" + fieldName
+ "' in type '" + className + "'");
return null;
+
+ } else if (type instanceof JPrimitiveType) {
+ reportJsniError(info, methodDecl,
+ "May not refer to methods on primitive types");
+ return null;
+
} else {
// look for a method
TreeSet<String> almostMatches = new TreeSet<String>();
@@ -2586,7 +2906,7 @@
}
} else {
Queue<JReferenceType> workList = new LinkedList<JReferenceType>();
- workList.add(type);
+ workList.add((JReferenceType) type);
while (!workList.isEmpty()) {
JReferenceType cur = workList.poll();
for (int i = 0; i < cur.methods.size(); ++i) {
@@ -2677,7 +2997,15 @@
JMethod method, JsContext<JsExpression> ctx) {
JReferenceType enclosingType = method.getEnclosingType();
if (enclosingType != null) {
- if (method.isStatic() && nameRef.getQualifier() != null) {
+ JClassType jsoImplType = program.typeOracle.getSingleJsoImpls().get(
+ enclosingType);
+ if (jsoImplType != null) {
+ reportJsniError(info, methodDecl, "Illegal reference to method '"
+ + method.getName() + "' in type '" + enclosingType.getName()
+ + "', which is implemented by an overlay type '"
+ + jsoImplType.getName() + "'. Use a stronger type in the JSNI "
+ + "identifier or a Java trampoline method.");
+ } else if (method.isStatic() && nameRef.getQualifier() != null) {
reportJsniError(info, methodDecl,
"Cannot make a qualified reference to the static method "
+ method.getName());
@@ -2763,15 +3091,21 @@
* a JProgram structure.
*/
public static void exec(TypeDeclaration[] types, TypeMap typeMap,
- JProgram jprogram, JsProgram jsProgram, boolean enableAsserts) {
+ JProgram jprogram, JsProgram jsProgram, JJSOptions options) {
// Construct the basic AST.
JavaASTGenerationVisitor v = new JavaASTGenerationVisitor(typeMap,
- jprogram, enableAsserts);
+ jprogram, options);
for (int i = 0; i < types.length; ++i) {
v.processType(types[i]);
}
Collections.sort(jprogram.getDeclaredTypes(), new HasNameSort());
+ // add any necessary bridge methods
+ Set<ReferenceBinding> typesWithBridges = new HashSet<ReferenceBinding>();
+ for (TypeDeclaration decl : types) {
+ v.addBridgeMethods(decl.binding, jprogram, typesWithBridges);
+ }
+
// Process JSNI.
Map<JsniMethodBody, AbstractMethodDeclaration> jsniMethodMap = v.getJsniMethodMap();
new JsniRefGenerationVisitor(jprogram, jsProgram, jsniMethodMap).accept(jprogram);
@@ -2797,6 +3131,32 @@
return null;
}
+ private static void addSuperclassesAndInterfaces(JReferenceType clazz,
+ Set<JReferenceType> supers) {
+ if (clazz == null) {
+ return;
+ }
+ if (supers.contains(clazz)) {
+ return;
+ }
+ supers.add(clazz);
+ addSuperclassesAndInterfaces(clazz.extnds, supers);
+ for (JReferenceType intf : clazz.implments) {
+ addSuperclassesAndInterfaces(intf, supers);
+ }
+ }
+
+ /**
+ * Returns a collection of all inherited classes and interfaces, plus the
+ * class itself.
+ */
+ private static Collection<JReferenceType> allSuperClassesAndInterfaces(
+ JClassType clazz) {
+ Set<JReferenceType> supers = new LinkedHashSet<JReferenceType>();
+ addSuperclassesAndInterfaces(clazz, supers);
+ return supers;
+ }
+
/**
* Returns <code>true</code> if JDT optimized the condition to
* <code>false</code>.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index b79c1f8..079e17f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -15,8 +15,10 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.jjs.Correlation;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.JsOutputOption;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.HasEnclosingType;
import com.google.gwt.dev.jjs.ast.HasName;
@@ -160,7 +162,10 @@
String name = x.getName();
String mangleName = mangleName(x);
if (x.isStatic()) {
- names.put(x, topScope.declareName(mangleName, name));
+ JsName jsName = topScope.declareName(mangleName, name);
+ x.getSourceInfo().addCorrelation(Correlation.by(jsName));
+ names.put(x, jsName);
+ recordSymbol(x, jsName);
} else {
JsName jsName;
if (x == arrayLengthField) {
@@ -172,7 +177,9 @@
} else {
jsName = peek().declareName(mangleName, name);
}
+ x.getSourceInfo().addCorrelation(Correlation.by(jsName));
names.put(x, jsName);
+ recordSymbol(x, jsName);
}
}
@@ -237,7 +244,10 @@
}
// My seed function name
- names.put(x, topScope.declareName(getNameString(x), x.getShortName()));
+ JsName jsName = topScope.declareName(getNameString(x), x.getShortName());
+ x.getSourceInfo().addCorrelation(Correlation.by(jsName));
+ names.put(x, jsName);
+ recordSymbol(x, jsName);
// My class scope
if (x.extnds == null) {
@@ -287,6 +297,8 @@
} else {
polyName = interfaceScope.declareName(mangleName, name);
}
+ // Record this as an alias, not the primary name
+ x.getSourceInfo().addCorrelation(Correlation.by(polyName, true));
polymorphicNames.put(x, polyName);
}
}
@@ -299,13 +311,12 @@
// my global name
JsName globalName;
- if (x.getEnclosingType() == null) {
- globalName = topScope.declareName(name);
- } else {
- String mangleName = mangleNameForGlobal(x);
- globalName = topScope.declareName(mangleName, name);
- }
+ assert x.getEnclosingType() != null;
+ String mangleName = mangleNameForGlobal(x);
+ globalName = topScope.declareName(mangleName, name);
+ x.getSourceInfo().addCorrelation(Correlation.by(globalName));
names.put(x, globalName);
+ recordSymbol(x, globalName);
JsFunction jsFunction;
if (x.isNative()) {
@@ -315,9 +326,13 @@
jsFunction.setName(globalName);
} else {
// create a new peer JsFunction
- jsFunction = new JsFunction(topScope, globalName, true);
- methodBodyMap.put(x.getBody(), jsFunction);
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ CreateNamesAndScopesVisitor.class, "Translated JS function");
+ jsFunction = new JsFunction(sourceInfo, topScope, globalName, true);
}
+ methodBodyMap.put(x.getBody(), jsFunction);
+ jsFunction.getSourceInfo().addCorrelation(Correlation.by(jsFunction));
+ jsFunction.getSourceInfo().addCorrelation(Correlation.by(globalName));
push(jsFunction.getScope());
return true;
}
@@ -331,7 +346,8 @@
for (int i = 0, c = catchArgs.size(); i < c; ++i) {
JLocalRef arg = catchArgs.get(i);
JBlock catchBlock = catchBlocks.get(i);
- JsCatch jsCatch = new JsCatch(peek(), arg.getTarget().getName());
+ JsCatch jsCatch = new JsCatch(x.getSourceInfo(), peek(),
+ arg.getTarget().getName());
JsParameter jsParam = jsCatch.getParameter();
names.put(arg.getTarget(), jsParam.getName());
catchMap.put(catchBlock, jsCatch);
@@ -359,6 +375,45 @@
private void push(JsScope scope) {
scopeStack.push(scope);
}
+
+ private void recordSymbol(JReferenceType x, JsName jsName) {
+ assert !symbolTable.containsKey(x.getName());
+ symbolTable.put(x.getName(), jsName);
+ }
+
+ private <T extends HasEnclosingType & HasName> void recordSymbol(T x,
+ JsName jsName) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(x.getEnclosingType().getName());
+ sb.append("::");
+
+ /*
+ * NB: The use of x.getName() can produce confusion in cases where a type
+ * has both polymorphic and static dispatch for a method, because you
+ * might see HashSet::$add() and HashSet::add(). Logically, these methods
+ * should be treated equally, however they will be implemented with
+ * separate global functions and must be recorded independently.
+ *
+ * Automated systems that process the symbol information can easily map
+ * the statically-dispatched function by looking for method names that
+ * begin with a dollar-sign and whose first parameter is the enclosing
+ * type.
+ */
+ sb.append(x.getName());
+
+ if (x instanceof JMethod) {
+ sb.append('(');
+ for (JType t : ((JMethod) x).getOriginalParamTypes()) {
+ sb.append(t.getJsniSignatureName());
+ }
+ sb.append(')');
+ }
+
+ assert !symbolTable.containsKey(sb.toString()) : "Duplicate symbol "
+ + "recorded " + jsName.getIdent() + " for " + x.getName()
+ + " and key " + sb.toString();
+ symbolTable.put(sb.toString(), jsName);
+ }
}
private class GenerateJavaScriptVisitor extends GenerateJavaScriptLiterals {
@@ -369,6 +424,19 @@
private JMethod currentMethod = null;
+ /**
+ * The JavaScript functions corresponding to the entry methods of the
+ * program ({@link JProgram#getAllEntryMethods()}).
+ */
+ private JsFunction[] entryFunctions;
+
+ /**
+ * A reverse index for the entry methods of the program (
+ * {@link JProgram#getAllEntryMethods()}). Each entry method is mapped to
+ * its integer index.
+ */
+ private Map<JMethod, Integer> entryMethodToIndex;
+
private final JsName globalTemp = topScope.declareName("_");
private final JsName prototype = objectScope.declareName("prototype");
@@ -389,7 +457,7 @@
@Override
public void endVisit(JArrayRef x, Context ctx) {
- JsArrayAccess jsArrayAccess = new JsArrayAccess();
+ JsArrayAccess jsArrayAccess = new JsArrayAccess(x.getSourceInfo());
jsArrayAccess.setIndexExpr((JsExpression) pop());
jsArrayAccess.setArrayExpr((JsExpression) pop());
push(jsArrayAccess);
@@ -420,12 +488,12 @@
myOp = JsBinaryOperator.REF_NEQ;
}
- push(new JsBinaryOperation(myOp, lhs, rhs));
+ push(new JsBinaryOperation(x.getSourceInfo(), myOp, lhs, rhs));
}
@Override
public void endVisit(JBlock x, Context ctx) {
- JsBlock jsBlock = new JsBlock();
+ JsBlock jsBlock = new JsBlock(x.getSourceInfo());
List<JsStatement> stmts = jsBlock.getStatements();
popList(stmts, x.statements.size()); // stmts
Iterator<JsStatement> iterator = stmts.iterator();
@@ -443,17 +511,17 @@
JsNameRef labelRef = null;
if (x.getLabel() != null) {
JsLabel label = (JsLabel) pop(); // label
- labelRef = label.getName().makeRef();
+ labelRef = label.getName().makeRef(x.getSourceInfo());
}
- push(new JsBreak(labelRef));
+ push(new JsBreak(x.getSourceInfo(), labelRef));
}
@Override
public void endVisit(JCaseStatement x, Context ctx) {
if (x.getExpr() == null) {
- push(new JsDefault());
+ push(new JsDefault(x.getSourceInfo()));
} else {
- JsCase jsCase = new JsCase();
+ JsCase jsCase = new JsCase(x.getSourceInfo());
jsCase.setCaseExpr((JsExpression) pop()); // expr
push(jsCase);
}
@@ -467,12 +535,12 @@
@Override
public void endVisit(JClassLiteral x, Context ctx) {
JsName classLit = names.get(x.getField());
- push(classLit.makeRef());
+ push(classLit.makeRef(x.getSourceInfo()));
}
@Override
public void endVisit(JClassSeed x, Context ctx) {
- push(names.get(x.getRefType()).makeRef());
+ push(names.get(x.getRefType()).makeRef(x.getSourceInfo()));
}
@SuppressWarnings("unchecked")
@@ -516,17 +584,19 @@
}
// setup fields
- JsVars vars = new JsVars();
+ JsVars vars = new JsVars(x.getSourceInfo());
for (int i = 0; i < jsFields.size(); ++i) {
JsNode node = jsFields.get(i);
if (node instanceof JsVar) {
vars.add((JsVar) node);
} else {
assert (node instanceof JsStatement);
- JsStatement stmt = (JsStatement) jsFields.get(i);
+ JsStatement stmt = (JsStatement) node;
globalStmts.add(stmt);
+ typeForStatMap.put(stmt, x);
}
}
+
if (!vars.isEmpty()) {
globalStmts.add(vars);
}
@@ -537,7 +607,7 @@
JsExpression elseExpr = (JsExpression) pop(); // elseExpr
JsExpression thenExpr = (JsExpression) pop(); // thenExpr
JsExpression ifTest = (JsExpression) pop(); // ifTest
- push(new JsConditional(ifTest, thenExpr, elseExpr));
+ push(new JsConditional(x.getSourceInfo(), ifTest, thenExpr, elseExpr));
}
@Override
@@ -545,9 +615,9 @@
JsNameRef labelRef = null;
if (x.getLabel() != null) {
JsLabel label = (JsLabel) pop(); // label
- labelRef = label.getName().makeRef();
+ labelRef = label.getName().makeRef(x.getSourceInfo());
}
- push(new JsContinue(labelRef));
+ push(new JsContinue(x.getSourceInfo(), labelRef));
}
@Override
@@ -573,15 +643,15 @@
return;
}
- JsBinaryOperation binOp = new JsBinaryOperation(JsBinaryOperator.ASG,
- localRef, initializer);
+ JsBinaryOperation binOp = new JsBinaryOperation(x.getSourceInfo(),
+ JsBinaryOperator.ASG, localRef, initializer);
push(binOp.makeStmt());
}
@Override
public void endVisit(JDoStatement x, Context ctx) {
- JsDoWhile stmt = new JsDoWhile();
+ JsDoWhile stmt = new JsDoWhile(x.getSourceInfo());
if (x.getBody() != null) {
stmt.setBody((JsStatement) pop()); // body
} else {
@@ -619,16 +689,16 @@
if (x.isStatic()) {
// setup a var for the static
- JsVar var = new JsVar(name);
+ JsVar var = new JsVar(x.getSourceInfo(), name);
var.setInitExpr(rhs);
push(var);
} else {
// for non-statics, only setup an assignment if needed
if (rhs != null) {
- JsNameRef fieldRef = name.makeRef();
- fieldRef.setQualifier(globalTemp.makeRef());
+ JsNameRef fieldRef = name.makeRef(x.getSourceInfo());
+ fieldRef.setQualifier(globalTemp.makeRef(x.getSourceInfo()));
JsExpression asg = createAssignment(fieldRef, rhs);
- push(new JsExprStmt(asg));
+ push(new JsExprStmt(x.getSourceInfo(), asg));
} else {
push(null);
}
@@ -639,7 +709,7 @@
public void endVisit(JFieldRef x, Context ctx) {
JField field = x.getField();
JsName jsFieldName = names.get(field);
- JsNameRef nameRef = jsFieldName.makeRef();
+ JsNameRef nameRef = jsFieldName.makeRef(x.getSourceInfo());
JsExpression curExpr = nameRef;
/*
@@ -670,7 +740,7 @@
@Override
public void endVisit(JForStatement x, Context ctx) {
- JsFor jsFor = new JsFor();
+ JsFor jsFor = new JsFor(x.getSourceInfo());
// body
if (x.getBody() != null) {
@@ -716,7 +786,7 @@
@Override
public void endVisit(JIfStatement x, Context ctx) {
- JsIf stmt = new JsIf();
+ JsIf stmt = new JsIf(x.getSourceInfo());
if (x.getElseStmt() != null) {
stmt.setElseStmt((JsStatement) pop()); // elseStmt
@@ -750,7 +820,7 @@
}
// setup fields
- JsVars vars = new JsVars();
+ JsVars vars = new JsVars(x.getSourceInfo());
for (int i = 0; i < jsFields.size(); ++i) {
vars.add(jsFields.get(i));
}
@@ -761,7 +831,7 @@
@Override
public void endVisit(JLabel x, Context ctx) {
- push(new JsLabel(names.get(x)));
+ push(new JsLabel(x.getSourceInfo(), names.get(x)));
}
@Override
@@ -774,12 +844,12 @@
@Override
public void endVisit(JLocal x, Context ctx) {
- push(names.get(x).makeRef());
+ push(names.get(x).makeRef(x.getSourceInfo()));
}
@Override
public void endVisit(JLocalRef x, Context ctx) {
- push(names.get(x.getTarget()).makeRef());
+ push(names.get(x.getTarget()).makeRef(x.getSourceInfo()));
}
@Override
@@ -798,7 +868,7 @@
JsName longLit = topScope.declareName(nameString);
longLits.put(x.getValue(), longLit);
longObjects.put(longLit, longLiteralAllocation);
- push(longLit.makeRef());
+ push(longLit.makeRef(x.getSourceInfo()));
}
@Override
@@ -832,6 +902,10 @@
}
push(jsFunc);
+ Integer entryIndex = entryMethodToIndex.get(x);
+ if (entryIndex != null) {
+ entryFunctions[entryIndex] = jsFunc;
+ }
currentMethod = null;
}
@@ -856,14 +930,14 @@
* other in Java. We use the alreadySeen set to make sure we don't declare
* the same-named local var twice.
*/
- JsVars vars = new JsVars();
+ JsVars vars = new JsVars(x.getSourceInfo());
Set<String> alreadySeen = new HashSet<String>();
for (int i = 0; i < locals.size(); ++i) {
JsName name = names.get(x.locals.get(i));
String ident = name.getIdent();
if (!alreadySeen.contains(ident)) {
alreadySeen.add(ident);
- vars.add(new JsVar(name));
+ vars.add(new JsVar(x.getSourceInfo(), name));
}
}
@@ -877,7 +951,7 @@
@Override
public void endVisit(JMethodCall x, Context ctx) {
JMethod method = x.getTarget();
- JsInvocation jsInvocation = new JsInvocation();
+ JsInvocation jsInvocation = new JsInvocation(x.getSourceInfo());
popList(jsInvocation.getArguments(), x.getArgs().size()); // args
@@ -887,7 +961,7 @@
if (x.getInstance() != null) {
unnecessaryQualifier = (JsExpression) pop(); // instance
}
- qualifier = names.get(method).makeRef();
+ qualifier = names.get(method).makeRef(x.getSourceInfo());
} else {
if (x.isStaticDispatchOnly()) {
/*
@@ -901,12 +975,12 @@
*/
JsName callName = objectScope.declareName("call");
callName.setObfuscatable(false);
- qualifier = callName.makeRef();
- qualifier.setQualifier(names.get(method).makeRef());
+ qualifier = callName.makeRef(x.getSourceInfo());
+ qualifier.setQualifier(names.get(method).makeRef(x.getSourceInfo()));
jsInvocation.getArguments().add(0, (JsExpression) pop()); // instance
} else {
// Dispatch polymorphically (normal case).
- qualifier = polymorphicNames.get(method).makeRef();
+ qualifier = polymorphicNames.get(method).makeRef(x.getSourceInfo());
qualifier.setQualifier((JsExpression) pop()); // instance
}
}
@@ -936,32 +1010,32 @@
@Override
public void endVisit(JNewInstance x, Context ctx) {
- JsNew newOp = new JsNew();
- JsNameRef nameRef = names.get(x.getType()).makeRef();
+ JsNew newOp = new JsNew(x.getSourceInfo());
+ JsNameRef nameRef = names.get(x.getType()).makeRef(x.getSourceInfo());
newOp.setConstructorExpression(nameRef);
push(newOp);
}
@Override
public void endVisit(JParameter x, Context ctx) {
- push(new JsParameter(names.get(x)));
+ push(new JsParameter(x.getSourceInfo(), names.get(x)));
}
@Override
public void endVisit(JParameterRef x, Context ctx) {
- push(names.get(x.getTarget()).makeRef());
+ push(names.get(x.getTarget()).makeRef(x.getSourceInfo()));
}
@Override
public void endVisit(JPostfixOperation x, Context ctx) {
- JsUnaryOperation op = new JsPostfixOperation(
+ JsUnaryOperation op = new JsPostfixOperation(x.getSourceInfo(),
JavaToJsOperatorMap.get(x.getOp()), ((JsExpression) pop())); // arg
push(op);
}
@Override
public void endVisit(JPrefixOperation x, Context ctx) {
- JsUnaryOperation op = new JsPrefixOperation(
+ JsUnaryOperation op = new JsPrefixOperation(x.getSourceInfo(),
JavaToJsOperatorMap.get(x.getOp()), ((JsExpression) pop())); // arg
push(op);
}
@@ -970,25 +1044,16 @@
public void endVisit(JProgram x, Context ctx) {
List<JsStatement> globalStmts = jsProgram.getGlobalBlock().getStatements();
- // types don't push
-
// Generate entry methods
- List<JsFunction> entryFuncs = popList(x.entryMethods.size()); // entryMethods
- for (int i = 0; i < entryFuncs.size(); ++i) {
- JsFunction func = entryFuncs.get(i);
- if (func != null) {
- globalStmts.add(func.makeStmt());
- }
- }
-
- generateGwtOnLoad(entryFuncs, globalStmts);
+ generateGwtOnLoad(Arrays.asList(entryFunctions).subList(0,
+ x.getEntryCount(0)), globalStmts);
generateNullFunc(globalStmts);
// Add a few things onto the beginning.
// Reserve the "_" identifier.
- JsVars vars = new JsVars();
- vars.add(new JsVar(globalTemp));
+ JsVars vars = new JsVars(jsProgram.getSourceInfo());
+ vars.add(new JsVar(jsProgram.getSourceInfo(), globalTemp));
globalStmts.add(0, vars);
// Long lits must go at the top, they can be constant field initializers.
@@ -997,12 +1062,40 @@
// Class objects, but only if there are any.
if (x.getDeclaredTypes().contains(x.getTypeClassLiteralHolder())) {
// TODO: perhaps they could be constant field initializers also?
- vars = new JsVars();
+ vars = new JsVars(jsProgram.getSourceInfo());
generateClassLiterals(vars);
if (!vars.isEmpty()) {
globalStmts.add(vars);
}
}
+
+ /*
+ * Add calls to all non-initial entry points. That way, if the code
+ * splitter does not run, the resulting code will still function.
+ * Likewise, add a call to
+ * AsyncFragmentLoader.leftoversFragmentHasLoaded().
+ */
+ List<JsFunction> nonInitialEntries = Arrays.asList(entryFunctions).subList(
+ x.getEntryCount(0), entryFunctions.length);
+ if (!nonInitialEntries.isEmpty()) {
+ JMethod loadedMethod = program.getIndexedMethod("AsyncFragmentLoader.leftoversFragmentHasLoaded");
+ JsName loadedMethodName = names.get(loadedMethod);
+ SourceInfo sourceInfo = jsProgram.getSourceInfo().makeChild(
+ GenerateJavaScriptAST.class, "call to leftoversFragmentHasLoaded ");
+ JsInvocation call = new JsInvocation(sourceInfo);
+ call.setQualifier(loadedMethodName.makeRef(sourceInfo));
+ globalStmts.add(call.makeStmt());
+ }
+ for (JsFunction func : nonInitialEntries) {
+ if (func != null) {
+ SourceInfo sourceInfo = jsProgram.getSourceInfo().makeChild(
+ GenerateJavaScriptAST.class,
+ "call to entry non-initial entry function");
+ JsInvocation call = new JsInvocation(sourceInfo);
+ call.setQualifier(func.getName().makeRef(sourceInfo));
+ globalStmts.add(call.makeStmt());
+ }
+ }
}
@Override
@@ -1013,29 +1106,29 @@
@Override
public void endVisit(JReturnStatement x, Context ctx) {
if (x.getExpr() != null) {
- push(new JsReturn((JsExpression) pop())); // expr
+ push(new JsReturn(x.getSourceInfo(), (JsExpression) pop())); // expr
} else {
- push(new JsReturn());
+ push(new JsReturn(x.getSourceInfo()));
}
}
@Override
public void endVisit(JsniMethodRef x, Context ctx) {
JMethod method = x.getTarget();
- JsNameRef nameRef = names.get(method).makeRef();
+ JsNameRef nameRef = names.get(method).makeRef(x.getSourceInfo());
push(nameRef);
}
@Override
public void endVisit(JsonArray x, Context ctx) {
- JsArrayLiteral jsArrayLiteral = new JsArrayLiteral();
+ JsArrayLiteral jsArrayLiteral = new JsArrayLiteral(x.getSourceInfo());
popList(jsArrayLiteral.getExpressions(), x.exprs.size());
push(jsArrayLiteral);
}
@Override
public void endVisit(JsonObject x, Context ctx) {
- JsObjectLiteral jsObjectLiteral = new JsObjectLiteral();
+ JsObjectLiteral jsObjectLiteral = new JsObjectLiteral(x.getSourceInfo());
popList(jsObjectLiteral.getPropertyInitializers(), x.propInits.size());
push(jsObjectLiteral);
}
@@ -1044,22 +1137,22 @@
public void endVisit(JsonPropInit init, Context ctx) {
JsExpression valueExpr = (JsExpression) pop();
JsExpression labelExpr = (JsExpression) pop();
- push(new JsPropertyInitializer(labelExpr, valueExpr));
+ push(new JsPropertyInitializer(init.getSourceInfo(), labelExpr, valueExpr));
}
@Override
public void endVisit(JThisRef x, Context ctx) {
- push(new JsThisRef());
+ push(new JsThisRef(x.getSourceInfo()));
}
@Override
public void endVisit(JThrowStatement x, Context ctx) {
- push(new JsThrow((JsExpression) pop())); // expr
+ push(new JsThrow(x.getSourceInfo(), (JsExpression) pop())); // expr
}
@Override
public void endVisit(JTryStatement x, Context ctx) {
- JsTry jsTry = new JsTry();
+ JsTry jsTry = new JsTry(x.getSourceInfo());
if (x.getFinallyBlock() != null) {
JsBlock finallyBlock = (JsBlock) pop(); // finallyBlock
@@ -1085,7 +1178,7 @@
@Override
public void endVisit(JWhileStatement x, Context ctx) {
- JsWhile stmt = new JsWhile();
+ JsWhile stmt = new JsWhile(x.getSourceInfo());
if (x.getBody() != null) {
stmt.setBody((JsStatement) pop()); // body
} else {
@@ -1125,6 +1218,21 @@
}
@Override
+ public boolean visit(JProgram x, Context ctx) {
+ /*
+ * Arrange for entryFunctions to be filled in as functions are visited.
+ * See their Javadoc comments for more details.
+ */
+ List<JMethod> entryMethods = x.getAllEntryMethods();
+ entryFunctions = new JsFunction[entryMethods.size()];
+ entryMethodToIndex = new IdentityHashMap<JMethod, Integer>();
+ for (int i = 0; i < entryMethods.size(); i++) {
+ entryMethodToIndex.put(entryMethods.get(i), i);
+ }
+ return true;
+ }
+
+ @Override
public boolean visit(JsniMethodBody x, Context ctx) {
JsFunction jsFunc = x.getFunc();
@@ -1181,7 +1289,7 @@
* What a pain.. JSwitchStatement and JsSwitch are modeled completely
* differently. Here we try to resolve those differences.
*/
- JsSwitch jsSwitch = new JsSwitch();
+ JsSwitch jsSwitch = new JsSwitch(x.getSourceInfo());
accept(x.getExpr());
jsSwitch.setExpr((JsExpression) pop()); // expr
@@ -1213,7 +1321,8 @@
}
private JsExpression createAssignment(JsExpression lhs, JsExpression rhs) {
- return new JsBinaryOperation(JsBinaryOperator.ASG, lhs, rhs);
+ return new JsBinaryOperation(lhs.getSourceInfo(), JsBinaryOperator.ASG,
+ lhs, rhs);
}
private JsExpression createCommaExpression(JsExpression lhs,
@@ -1223,7 +1332,8 @@
} else if (rhs == null) {
return lhs;
}
- return new JsBinaryOperation(JsBinaryOperator.COMMA, lhs, rhs);
+ return new JsBinaryOperation(lhs.getSourceInfo(), JsBinaryOperator.COMMA,
+ lhs, rhs);
}
private void generateClassLiteral(JDeclarationStatement decl, JsVars vars) {
@@ -1231,7 +1341,7 @@
JsName jsName = names.get(field);
this.accept(decl.getInitializer());
JsExpression classObjectAlloc = pop();
- JsVar var = new JsVar(jsName);
+ JsVar var = new JsVar(decl.getSourceInfo(), jsName);
var.setInitExpr(classObjectAlloc);
vars.add(var);
}
@@ -1283,58 +1393,63 @@
* }
* </pre>
*/
+ SourceInfo sourceInfo = program.createSourceInfoSynthetic(
+ GenerateJavaScriptAST.class, "gwtOnLoad");
JsName gwtOnLoadName = topScope.declareName("gwtOnLoad");
gwtOnLoadName.setObfuscatable(false);
- JsFunction gwtOnLoad = new JsFunction(topScope, gwtOnLoadName, true);
+ JsFunction gwtOnLoad = new JsFunction(sourceInfo, topScope,
+ gwtOnLoadName, true);
+ sourceInfo.addCorrelation(Correlation.by(gwtOnLoad));
globalStmts.add(gwtOnLoad.makeStmt());
- JsBlock body = new JsBlock();
+ JsBlock body = new JsBlock(sourceInfo);
gwtOnLoad.setBody(body);
JsScope fnScope = gwtOnLoad.getScope();
List<JsParameter> params = gwtOnLoad.getParameters();
JsName errFn = fnScope.declareName("errFn");
JsName modName = fnScope.declareName("modName");
JsName modBase = fnScope.declareName("modBase");
- params.add(new JsParameter(errFn));
- params.add(new JsParameter(modName));
- params.add(new JsParameter(modBase));
+ params.add(new JsParameter(sourceInfo, errFn));
+ params.add(new JsParameter(sourceInfo, modName));
+ params.add(new JsParameter(sourceInfo, modBase));
JsExpression asg = createAssignment(
- topScope.findExistingUnobfuscatableName("$moduleName").makeRef(),
- modName.makeRef());
+ topScope.findExistingUnobfuscatableName("$moduleName").makeRef(
+ sourceInfo), modName.makeRef(sourceInfo));
body.getStatements().add(asg.makeStmt());
asg = createAssignment(topScope.findExistingUnobfuscatableName(
- "$moduleBase").makeRef(), modBase.makeRef());
+ "$moduleBase").makeRef(sourceInfo), modBase.makeRef(sourceInfo));
body.getStatements().add(asg.makeStmt());
- JsIf jsIf = new JsIf();
+ JsIf jsIf = new JsIf(sourceInfo);
body.getStatements().add(jsIf);
- jsIf.setIfExpr(errFn.makeRef());
- JsTry jsTry = new JsTry();
+ jsIf.setIfExpr(errFn.makeRef(sourceInfo));
+ JsTry jsTry = new JsTry(sourceInfo);
jsIf.setThenStmt(jsTry);
- JsBlock callBlock = new JsBlock();
+ JsBlock callBlock = new JsBlock(sourceInfo);
jsIf.setElseStmt(callBlock);
jsTry.setTryBlock(callBlock);
- for (int i = 0; i < entryFuncs.size(); ++i) {
- JsFunction func = entryFuncs.get(i);
+ for (JsFunction func : entryFuncs) {
if (func != null) {
- JsInvocation call = new JsInvocation();
- call.setQualifier(func.getName().makeRef());
+ JsInvocation call = new JsInvocation(sourceInfo);
+ call.setQualifier(func.getName().makeRef(sourceInfo));
callBlock.getStatements().add(call.makeStmt());
}
}
- JsCatch jsCatch = new JsCatch(fnScope, "e");
+ JsCatch jsCatch = new JsCatch(sourceInfo, fnScope, "e");
jsTry.getCatches().add(jsCatch);
- JsBlock catchBlock = new JsBlock();
+ JsBlock catchBlock = new JsBlock(sourceInfo);
jsCatch.setBody(catchBlock);
- JsInvocation errCall = new JsInvocation();
+ JsInvocation errCall = new JsInvocation(sourceInfo);
catchBlock.getStatements().add(errCall.makeStmt());
- errCall.setQualifier(errFn.makeRef());
- errCall.getArguments().add(modName.makeRef());
+ errCall.setQualifier(errFn.makeRef(sourceInfo));
+ errCall.getArguments().add(modName.makeRef(sourceInfo));
}
private void generateLongLiterals(JsVars vars) {
for (Entry<Long, JsName> entry : longLits.entrySet()) {
JsName jsName = entry.getValue();
JsExpression longObjectAlloc = longObjects.get(jsName);
- JsVar var = new JsVar(jsName);
+ JsVar var = new JsVar(vars.getSourceInfo().makeChild(
+ GenerateJavaScriptVisitor.class, "Long literal " + entry.getKey()),
+ jsName);
var.setInitExpr(longObjectAlloc);
vars.add(var);
}
@@ -1342,47 +1457,66 @@
private void generateNullFunc(List<JsStatement> globalStatements) {
// handle null method
- JsFunction nullFunc = new JsFunction(topScope, nullMethodName, true);
- nullFunc.setBody(new JsBlock());
+ SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(
+ GenerateJavaScriptAST.class, "Null function");
+ JsFunction nullFunc = new JsFunction(sourceInfo, topScope,
+ nullMethodName, true);
+ sourceInfo.addCorrelation(Correlation.by(nullFunc));
+ nullFunc.setBody(new JsBlock(sourceInfo));
globalStatements.add(nullFunc.makeStmt());
}
private void generateSeedFuncAndPrototype(JClassType x,
List<JsStatement> globalStmts) {
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ GenerateJavaScriptVisitor.class, "Seed and function prototype");
if (x != program.getTypeJavaLangString()) {
JsName seedFuncName = names.get(x);
// seed function
// function com_example_foo_Foo() { }
- JsFunction seedFunc = new JsFunction(topScope, seedFuncName, true);
- JsBlock body = new JsBlock();
+ JsFunction seedFunc = new JsFunction(sourceInfo, topScope,
+ seedFuncName, true);
+ seedFuncName.setStaticRef(seedFunc);
+ sourceInfo.addCorrelation(Correlation.by(seedFunc));
+ JsBlock body = new JsBlock(sourceInfo);
seedFunc.setBody(body);
- globalStmts.add(seedFunc.makeStmt());
+ JsExprStmt seedFuncStmt = seedFunc.makeStmt();
+ globalStmts.add(seedFuncStmt);
+ typeForStatMap.put(seedFuncStmt, x);
// setup prototype, assign to temp
// _ = com_example_foo_Foo.prototype = new com_example_foo_FooSuper();
- JsNameRef lhs = prototype.makeRef();
- lhs.setQualifier(seedFuncName.makeRef());
+ JsNameRef lhs = prototype.makeRef(sourceInfo);
+ lhs.setQualifier(seedFuncName.makeRef(sourceInfo));
JsExpression rhs;
if (x.extnds != null) {
- JsNew newExpr = new JsNew();
- newExpr.setConstructorExpression(names.get(x.extnds).makeRef());
+ JsNew newExpr = new JsNew(sourceInfo);
+ JsNameRef superPrototypeRef = names.get(x.extnds).makeRef(sourceInfo);
+ newExpr.setConstructorExpression(superPrototypeRef);
rhs = newExpr;
} else {
- rhs = new JsObjectLiteral();
+ rhs = new JsObjectLiteral(sourceInfo);
}
JsExpression protoAsg = createAssignment(lhs, rhs);
- JsExpression tmpAsg = createAssignment(globalTemp.makeRef(), protoAsg);
- globalStmts.add(tmpAsg.makeStmt());
+ JsExpression tmpAsg = createAssignment(globalTemp.makeRef(sourceInfo),
+ protoAsg);
+ JsExprStmt tmpAsgStmt = tmpAsg.makeStmt();
+ globalStmts.add(tmpAsgStmt);
+ typeForStatMap.put(tmpAsgStmt, x);
} else {
/*
* MAGIC: java.lang.String is implemented as a JavaScript String
* primitive with a modified prototype.
*/
- JsNameRef rhs = prototype.makeRef();
- rhs.setQualifier(jsProgram.getRootScope().declareName("String").makeRef());
- JsExpression tmpAsg = createAssignment(globalTemp.makeRef(), rhs);
- globalStmts.add(tmpAsg.makeStmt());
+ JsNameRef rhs = prototype.makeRef(sourceInfo);
+ rhs.setQualifier(jsProgram.getRootScope().declareName("String").makeRef(
+ sourceInfo));
+ JsExpression tmpAsg = createAssignment(globalTemp.makeRef(sourceInfo),
+ rhs);
+ JsExprStmt tmpAsgStmt = tmpAsg.makeStmt();
+ globalStmts.add(tmpAsgStmt);
+ typeForStatMap.put(tmpAsgStmt, x);
}
}
@@ -1390,29 +1524,33 @@
List<JsStatement> globalStmts) {
JMethod toStringMeth = program.getIndexedMethod("Object.toString");
if (x.methods.contains(toStringMeth)) {
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ GenerateJavaScriptVisitor.class, "_.toString");
// _.toString = function(){return this.java_lang_Object_toString();}
// lhs
JsName lhsName = objectScope.declareName("toString");
lhsName.setObfuscatable(false);
- JsNameRef lhs = lhsName.makeRef();
- lhs.setQualifier(globalTemp.makeRef());
+ JsNameRef lhs = lhsName.makeRef(sourceInfo);
+ lhs.setQualifier(globalTemp.makeRef(sourceInfo));
// rhs
- JsInvocation call = new JsInvocation();
- JsNameRef toStringRef = new JsNameRef(
+ JsInvocation call = new JsInvocation(sourceInfo);
+ JsNameRef toStringRef = new JsNameRef(sourceInfo,
polymorphicNames.get(toStringMeth));
- toStringRef.setQualifier(new JsThisRef());
+ toStringRef.setQualifier(new JsThisRef(sourceInfo));
call.setQualifier(toStringRef);
- JsReturn jsReturn = new JsReturn(call);
- JsFunction rhs = new JsFunction(topScope);
- JsBlock body = new JsBlock();
+ JsReturn jsReturn = new JsReturn(sourceInfo, call);
+ JsFunction rhs = new JsFunction(sourceInfo, topScope);
+ JsBlock body = new JsBlock(sourceInfo);
body.getStatements().add(jsReturn);
rhs.setBody(body);
// asg
JsExpression asg = createAssignment(lhs, rhs);
- globalStmts.add(new JsExprStmt(asg));
+ JsExprStmt stmt = asg.makeStmt();
+ globalStmts.add(stmt);
+ typeForStatMap.put(stmt, program.getTypeJavaLangObject());
}
}
@@ -1425,11 +1563,15 @@
// Was pruned; this compilation must have no dynamic casts.
return;
}
- JsNameRef fieldRef = typeIdName.makeRef();
- fieldRef.setQualifier(globalTemp.makeRef());
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ GenerateJavaScriptVisitor.class, "Type id assignment");
+ JsNameRef fieldRef = typeIdName.makeRef(sourceInfo);
+ fieldRef.setQualifier(globalTemp.makeRef(sourceInfo));
JsNumberLiteral typeIdLit = jsProgram.getNumberLiteral(typeId);
JsExpression asg = createAssignment(fieldRef, typeIdLit);
- globalStmts.add(new JsExprStmt(asg));
+ JsExprStmt asgStmt = asg.makeStmt();
+ globalStmts.add(asgStmt);
+ typeForStatMap.put(asgStmt, x);
}
}
@@ -1440,14 +1582,21 @@
// Was pruned; this compilation must have no JSO instanceof tests.
return;
}
- JsNameRef fieldRef = typeMarkerName.makeRef();
- fieldRef.setQualifier(globalTemp.makeRef());
- JsExpression asg = createAssignment(fieldRef, nullMethodName.makeRef());
- globalStmts.add(new JsExprStmt(asg));
+ SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(
+ GenerateJavaScriptAST.class, "Type marker");
+ JsNameRef fieldRef = typeMarkerName.makeRef(sourceInfo);
+ fieldRef.setQualifier(globalTemp.makeRef(sourceInfo));
+ JsExpression asg = createAssignment(fieldRef,
+ nullMethodName.makeRef(sourceInfo));
+ JsExprStmt stmt = asg.makeStmt();
+ globalStmts.add(stmt);
+ typeForStatMap.put(stmt, program.getTypeJavaLangObject());
}
private JsExpression generateTypeTable() {
- JsArrayLiteral arrayLit = new JsArrayLiteral();
+ JsArrayLiteral arrayLit = new JsArrayLiteral(
+ jsProgram.createSourceInfoSynthetic(GenerateJavaScriptAST.class,
+ "Type table"));
for (int i = 0; i < program.getJsonTypeTable().size(); ++i) {
JsonObject jsonObject = program.getJsonTypeTable().get(i);
accept(jsonObject);
@@ -1459,12 +1608,16 @@
private void generateVTables(JClassType x, List<JsStatement> globalStmts) {
for (int i = 0; i < x.methods.size(); ++i) {
JMethod method = x.methods.get(i);
+ SourceInfo sourceInfo = method.getSourceInfo().makeChild(
+ GenerateJavaScriptVisitor.class, "vtable assignment");
if (!method.isStatic() && !method.isAbstract()) {
- JsNameRef lhs = polymorphicNames.get(method).makeRef();
- lhs.setQualifier(globalTemp.makeRef());
- JsNameRef rhs = names.get(method).makeRef();
+ JsNameRef lhs = polymorphicNames.get(method).makeRef(sourceInfo);
+ lhs.setQualifier(globalTemp.makeRef(sourceInfo));
+ JsNameRef rhs = names.get(method).makeRef(sourceInfo);
JsExpression asg = createAssignment(lhs, rhs);
- globalStmts.add(new JsExprStmt(asg));
+ JsExprStmt asgStat = new JsExprStmt(x.getSourceInfo(), asg);
+ globalStmts.add(asgStat);
+ vtableInitForMethodMap.put(asgStat, method);
}
}
}
@@ -1473,9 +1626,11 @@
clinitFunc.setExecuteOnce(true);
clinitFunc.setImpliedExecute(superClinit);
List<JsStatement> statements = clinitFunc.getBody().getStatements();
+ SourceInfo sourceInfo = clinitFunc.getSourceInfo().makeChild(
+ GenerateJavaScriptVisitor.class, "clinit reassignment");
// self-assign to the null method immediately (to prevent reentrancy)
- JsExpression asg = createAssignment(clinitFunc.getName().makeRef(),
- nullMethodName.makeRef());
+ JsExpression asg = createAssignment(clinitFunc.getName().makeRef(
+ sourceInfo), nullMethodName.makeRef(sourceInfo));
statements.add(0, asg.makeStmt());
}
@@ -1488,11 +1643,15 @@
if (!typeOracle.checkClinit(currentMethod.getEnclosingType(),
enclosingType)) {
return null;
+ } else if (enclosingType.equals(program.getTypeClassLiteralHolder())) {
+ return null;
}
JMethod clinitMethod = enclosingType.methods.get(0);
- JsInvocation jsInvocation = new JsInvocation();
- jsInvocation.setQualifier(names.get(clinitMethod).makeRef());
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ GenerateJavaScriptVisitor.class, "clinit invocation");
+ JsInvocation jsInvocation = new JsInvocation(sourceInfo);
+ jsInvocation.setQualifier(names.get(clinitMethod).makeRef(sourceInfo));
return jsInvocation;
}
@@ -1513,8 +1672,10 @@
}
JMethod clinitMethod = enclosingType.methods.get(0);
- JsInvocation jsInvocation = new JsInvocation();
- jsInvocation.setQualifier(names.get(clinitMethod).makeRef());
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ GenerateJavaScriptVisitor.class, "clinit call");
+ JsInvocation jsInvocation = new JsInvocation(sourceInfo);
+ jsInvocation.setQualifier(names.get(clinitMethod).makeRef(sourceInfo));
return jsInvocation;
}
}
@@ -1634,16 +1795,18 @@
@Override
public void endVisit(JProgram x, Context ctx) {
- Collections.sort(x.entryMethods, hasNameSort);
+ for (List<JMethod> methods : x.entryMethods) {
+ Collections.sort(methods, hasNameSort);
+ }
Collections.sort(x.getDeclaredTypes(), hasNameSort);
}
}
- public static void exec(JProgram program, JsProgram jsProgram,
- JsOutputOption output) {
+ public static JavaToJavaScriptMap exec(JProgram program, JsProgram jsProgram,
+ JsOutputOption output, Map<String, JsName> symbolTable) {
GenerateJavaScriptAST generateJavaScriptAST = new GenerateJavaScriptAST(
- program, jsProgram, output);
- generateJavaScriptAST.execImpl();
+ program, jsProgram, output, symbolTable);
+ return generateJavaScriptAST.execImpl();
}
private final Map<JBlock, JsCatch> catchMap = new IdentityHashMap<JBlock, JsCatch>();
@@ -1655,6 +1818,7 @@
* clinit).
*/
private Set<JMethod> crossClassTargets = new HashSet<JMethod>();
+
/**
* Contains JsNames for all interface methods. A special scope is needed so
* that independent classes will obfuscate their interface implementation
@@ -1668,7 +1832,6 @@
* Sorted to avoid nondeterministic iteration.
*/
private final Map<Long, JsName> longLits = new TreeMap<Long, JsName>();
-
private final Map<JsName, JsExpression> longObjects = new IdentityHashMap<JsName, JsExpression>();
private final Map<JAbstractMethodBody, JsFunction> methodBodyMap = new IdentityHashMap<JAbstractMethodBody, JsFunction>();
private final Map<HasName, JsName> names = new IdentityHashMap<HasName, JsName>();
@@ -1704,10 +1867,20 @@
* Contains JsNames for all globals, such as static fields and methods.
*/
private final JsScope topScope;
+
+ private final Map<JsStatement, JReferenceType> typeForStatMap = new HashMap<JsStatement, JReferenceType>();
+
private final JTypeOracle typeOracle;
+ private final Map<JsStatement, JMethod> vtableInitForMethodMap = new HashMap<JsStatement, JMethod>();
+
+ /**
+ * Maps JsNames to machine-usable identifiers.
+ */
+ private final Map<String, JsName> symbolTable;
+
private GenerateJavaScriptAST(JProgram program, JsProgram jsProgram,
- JsOutputOption output) {
+ JsOutputOption output, Map<String, JsName> symbolTable) {
this.program = program;
typeOracle = program.typeOracle;
this.jsProgram = jsProgram;
@@ -1715,6 +1888,7 @@
objectScope = jsProgram.getObjectScope();
interfaceScope = new JsScope(objectScope, "Interfaces");
this.output = output;
+ this.symbolTable = symbolTable;
/*
* Because we modify String's prototype, all fields and polymorphic methods
@@ -1833,7 +2007,7 @@
throw new InternalCompilerException("Unknown output mode");
}
- private void execImpl() {
+ private JavaToJavaScriptMap execImpl() {
SortVisitor sorter = new SortVisitor();
sorter.accept(program);
RecordCrossClassCalls recorder = new RecordCrossClassCalls();
@@ -1842,6 +2016,64 @@
creator.accept(program);
GenerateJavaScriptVisitor generator = new GenerateJavaScriptVisitor();
generator.accept(program);
- }
+ final Map<JsName, JMethod> nameToMethodMap = new HashMap<JsName, JMethod>();
+ final HashMap<JsName, JField> nameToFieldMap = new HashMap<JsName, JField>();
+ final HashMap<JsName, JReferenceType> constructorNameToTypeMap = new HashMap<JsName, JReferenceType>();
+ for (JReferenceType type : program.getDeclaredTypes()) {
+ JsName typeName = names.get(type);
+ if (typeName != null) {
+ constructorNameToTypeMap.put(typeName, type);
+ }
+ for (JField field : type.fields) {
+ if (field.isStatic()) {
+ JsName fieldName = names.get(field);
+ if (fieldName != null) {
+ nameToFieldMap.put(fieldName, field);
+ }
+ }
+ }
+ for (JMethod method : type.methods) {
+ JsName methodName = names.get(method);
+ if (methodName != null) {
+ nameToMethodMap.put(methodName, method);
+ }
+ }
+ }
+ // TODO(spoon): Instead of gathering the information here, get it via
+ // SourceInfo
+ return new JavaToJavaScriptMap() {
+ public JsName nameForMethod(JMethod method) {
+ return names.get(method);
+ }
+
+ public JsName nameForType(JReferenceType type) {
+ return names.get(type);
+ }
+
+ public JField nameToField(JsName name) {
+ return nameToFieldMap.get(name);
+ }
+
+ public JMethod nameToMethod(JsName name) {
+ return nameToMethodMap.get(name);
+ }
+
+ public String stringLiteralForName(JsName var) {
+ /*
+ * This method will be supplied non-trivially elsewhere.
+ * GenerateJavaScriptAST doesn't have the information to implement it.
+ */
+ return null;
+ }
+
+ public JReferenceType typeForStatement(JsStatement stat) {
+ return typeForStatMap.get(stat);
+ }
+
+ public JMethod vtableInitToMethod(JsStatement stat) {
+ return vtableInitForMethodMap.get(stat);
+ }
+ };
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java
index 2fb1574..0e4a148 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.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
@@ -58,30 +58,32 @@
@Override
public final void endVisit(JCharLiteral x, Context ctx) {
- push(program.getNumberLiteral(x.getValue()));
+ push(program.getNumberLiteral(x.getSourceInfo(), x.getValue()));
}
@Override
public final void endVisit(JDoubleLiteral x, Context ctx) {
- push(program.getNumberLiteral(x.getValue()));
+ push(program.getNumberLiteral(x.getSourceInfo(), x.getValue()));
}
@Override
public final void endVisit(JFloatLiteral x, Context ctx) {
- push(program.getNumberLiteral(x.getValue()));
+ push(program.getNumberLiteral(x.getSourceInfo(), x.getValue()));
}
@Override
public final void endVisit(JIntLiteral x, Context ctx) {
- push(program.getNumberLiteral(x.getValue()));
+ push(program.getNumberLiteral(x.getSourceInfo(), x.getValue()));
}
@Override
public void endVisit(JLongLiteral x, Context ctx) {
- JsArrayLiteral arrayLit = new JsArrayLiteral();
+ JsArrayLiteral arrayLit = new JsArrayLiteral(x.getSourceInfo());
double[] doubleArray = LongLib.typeChange(x.getValue());
- arrayLit.getExpressions().add(program.getNumberLiteral(doubleArray[0]));
- arrayLit.getExpressions().add(program.getNumberLiteral(doubleArray[1]));
+ arrayLit.getExpressions().add(
+ program.getNumberLiteral(x.getSourceInfo(), doubleArray[0]));
+ arrayLit.getExpressions().add(
+ program.getNumberLiteral(x.getSourceInfo(), doubleArray[1]));
push(arrayLit);
}
@@ -92,7 +94,7 @@
@Override
public final void endVisit(JStringLiteral x, Context ctx) {
- push(program.getStringLiteral(x.getValue()));
+ push(program.getStringLiteral(x.getSourceInfo(), x.getValue()));
}
@SuppressWarnings("unchecked")
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaAndJavaScript.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaAndJavaScript.java
new file mode 100644
index 0000000..7526b14
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaAndJavaScript.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.impl;
+
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.js.ast.JsProgram;
+
+/**
+ * A Java program, a JavaScript program, and a map between them.
+ */
+public class JavaAndJavaScript {
+ public final JProgram jprogram;
+ public final JsProgram jsprogram;
+ public final String[] jscode;
+ public final JavaToJavaScriptMap map;
+
+ public JavaAndJavaScript(JProgram jprogram, JsProgram jsprogram, String[] jscode, JavaToJavaScriptMap map) {
+ this.jprogram = jprogram;
+ this.jsprogram = jsprogram;
+ this.jscode = jscode;
+ this.map = map;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
index 5fc544d..5d14256 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
@@ -15,31 +15,59 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JCastOperation;
import com.google.gwt.dev.jjs.ast.JClassLiteral;
+import com.google.gwt.dev.jjs.ast.JClassType;
+import com.google.gwt.dev.jjs.ast.JConditional;
+import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JInstanceOf;
+import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JLocal;
+import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JMethodBody;
+import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JModVisitor;
import com.google.gwt.dev.jjs.ast.JNewArray;
import com.google.gwt.dev.jjs.ast.JParameter;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
/**
* Replace references to JSO subtypes with JSO itself.
*/
public class JavaScriptObjectNormalizer {
+ private class Collector extends JVisitor {
+ @Override
+ public void endVisit(JClassType x, Context ctx) {
+ if (program.isJavaScriptObject(x)) {
+ for (JInterfaceType intr : x.implments) {
+ if (isTagInterface(intr) && !jsoType.implments.contains(intr)) {
+ jsoType.implments.add(intr);
+ }
+ }
+ }
+ }
+ }
/**
* Map types from JSO subtypes to JSO itself.
*/
private class NormalizeVisitor extends JModVisitor {
+ private final Stack<JMethodBody> currentMethodBody = new Stack<JMethodBody>();
+
@Override
public void endVisit(JCastOperation x, Context ctx) {
JType newType = translate(x.getCastType());
@@ -82,6 +110,74 @@
}
@Override
+ public void endVisit(JMethodBody x, Context ctx) {
+ if (currentMethodBody.pop() != x) {
+ throw new RuntimeException("Unexpected JMethodBody popped");
+ }
+ }
+
+ /**
+ * Polymorphic dispatches to interfaces implemented by both a JSO and a
+ * regular type require special dispatch handling. If the instance is not a
+ * Java-derived object, the method from the single JSO implementation will
+ * be invoked. Otherwise, a polymorphic dispatch to the Java-derived object
+ * is made.
+ */
+ @Override
+ public void endVisit(JMethodCall x, Context ctx) {
+ JType targetClass = x.getTarget().getEnclosingType();
+ if (jsoSingleImpls.containsKey(targetClass)) {
+
+ SourceInfo info = x.getSourceInfo().makeChild(
+ JavaScriptObjectNormalizer.class,
+ "Polymorphic invocation of SingleJsoImpl interface");
+
+ // Find the method in the JSO type
+ JMethod jsoMethod = findJsoMethod(x.getTarget());
+ assert jsoMethod != null;
+
+ if (dualImpl.contains(targetClass)) {
+ /*
+ * This is the special-case code to handle interfaces.
+ */
+ JMultiExpression multi = new JMultiExpression(program, info);
+ JExpression instance = maybeMakeTempAssignment(multi, x.getInstance());
+
+ // instance.method(arg, arg)
+ JMethodCall localCall = new JMethodCall(program, info, instance,
+ x.getTarget());
+ localCall.getArgs().addAll(x.getArgs());
+
+ // We need a second copy of the arguments for the else expression
+ CloneExpressionVisitor cloner = new CloneExpressionVisitor(program);
+
+ // instance.jsoMethod(arg, arg)
+ JMethodCall jsoCall = new JMethodCall(program, info,
+ cloner.cloneExpression(instance), jsoMethod);
+ jsoCall.getArgs().addAll(cloner.cloneExpressions(x.getArgs()));
+
+ // Cast.isJavaScriptObject() ? instance.jsoMethod() :
+ // instance.method();
+ JConditional newExpr = makeIsJsoConditional(info,
+ cloner.cloneExpression(instance), x.getType(), jsoCall, localCall);
+
+ multi.exprs.add(newExpr);
+ // We may only have the ternary operation if there's no side-effect
+ ctx.replaceMe(multi.exprs.size() == 1 ? multi.exprs.get(0) : multi);
+ } else {
+ /*
+ * ... otherwise, if there's only a JSO implementation, we'll just
+ * call that directly.
+ */
+ JMethodCall jsoCall = new JMethodCall(program, info, x.getInstance(),
+ jsoMethod);
+ jsoCall.getArgs().addAll(x.getArgs());
+ ctx.replaceMe(jsoCall);
+ }
+ }
+ }
+
+ @Override
public void endVisit(JNewArray x, Context ctx) {
x.setType(translate(x.getType()));
}
@@ -91,14 +187,74 @@
x.setType(translate(x.getType()));
}
+ @Override
+ public boolean visit(JMethodBody x, Context ctx) {
+ currentMethodBody.push(x);
+ return true;
+ }
+
+ private JMethod findJsoMethod(JMethod interfaceMethod) {
+ JClassType jsoClass = jsoSingleImpls.get(interfaceMethod.getEnclosingType());
+ assert program.isJavaScriptObject(jsoClass);
+ assert jsoClass != null;
+
+ JMethod toReturn = program.typeOracle.findConcreteImplementation(
+ interfaceMethod, jsoClass);
+ assert toReturn != null;
+ assert !toReturn.isAbstract();
+ assert jsoClass.isFinal() || toReturn.isFinal();
+
+ return toReturn;
+ }
+
+ private JConditional makeIsJsoConditional(SourceInfo info,
+ JExpression instance, JType conditionalType, JExpression isJsoExpr,
+ JExpression notJsoExpr) {
+ // Cast.isJavaScriptObjectOrString(instance)
+ JMethod isJavaScriptObjectMethod = program.getIndexedMethod("Cast.isJavaScriptObjectOrString");
+ JMethodCall isJavaScriptObjectExpr = new JMethodCall(program, info, null,
+ isJavaScriptObjectMethod);
+ isJavaScriptObjectExpr.getArgs().add(instance);
+ return new JConditional(program, info, conditionalType,
+ isJavaScriptObjectExpr, isJsoExpr, notJsoExpr);
+ }
+
+ private JExpression maybeMakeTempAssignment(JMultiExpression multi,
+ JExpression instance) {
+ if (instance.hasSideEffects()) {
+ /*
+ * It may be necessary to save off the instance expression into a local
+ * variable if its evaluation would produce side-effects. The
+ * multi-expression is used for this purpose.
+ */
+ SourceInfo info = instance.getSourceInfo().makeChild(
+ JavaScriptObjectNormalizer.class,
+ "Temporary assignment for instance with side-effects");
+ JLocal local = program.createLocal(info,
+ "maybeJsoInvocation".toCharArray(), instance.getType(), true,
+ currentMethodBody.peek());
+ multi.exprs.add(program.createAssignmentStmt(info,
+ new JLocalRef(program, info, local), instance).getExpr());
+
+ instance = new JLocalRef(program, info, local);
+ }
+ return instance;
+ }
+
private JType translate(JType type) {
if (program.isJavaScriptObject(type)) {
return program.getJavaScriptObject();
+
+ } else if (jsoSingleImpls.containsKey(type) && !dualImpl.contains(type)) {
+ // Narrow to JSO when possible
+ return program.getJavaScriptObject();
+
} else if (type instanceof JArrayType) {
JArrayType arrayType = (JArrayType) type;
- if (program.isJavaScriptObject(arrayType.getLeafType())) {
- return program.getTypeArray(program.getJavaScriptObject(),
- arrayType.getDims());
+ JType leafType = arrayType.getLeafType();
+ JType replacement = translate(leafType);
+ if (leafType != replacement) {
+ return program.getTypeArray(replacement, arrayType.getDims());
}
}
return type;
@@ -109,15 +265,53 @@
new JavaScriptObjectNormalizer(program).execImpl();
}
+ /**
+ * Interfaces implemented both by a JSO type and a regular Java type.
+ */
+ private final Set<JInterfaceType> dualImpl;
+
+ /**
+ * Maps SingleJsoImpl interfaces onto the single JSO implementation.
+ */
+ private final Map<JInterfaceType, JClassType> jsoSingleImpls;
+
+ private final JClassType jsoType;
+
private final JProgram program;
private JavaScriptObjectNormalizer(JProgram program) {
this.program = program;
+ dualImpl = program.typeOracle.getInterfacesWithJavaAndJsoImpls();
+ jsoSingleImpls = program.typeOracle.getSingleJsoImpls();
+
+ jsoType = program.getJavaScriptObject();
+ jsoType.implments.addAll(dualImpl);
}
private void execImpl() {
+ new Collector().accept(program);
+
NormalizeVisitor visitor = new NormalizeVisitor();
visitor.accept(program);
}
+ private boolean isTagInterface(JReferenceType intr) {
+ if (!(intr instanceof JInterfaceType)) {
+ return false;
+ }
+
+ if (intr.methods.size() > 1) {
+ assert intr.methods.size() == 0
+ || intr.methods.get(0).getName().equals("$clinit");
+ return false;
+ }
+
+ for (JInterfaceType t : intr.implments) {
+ if (!isTagInterface(t)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaToJavaScriptMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaToJavaScriptMap.java
new file mode 100644
index 0000000..7b21d28
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaToJavaScriptMap.java
@@ -0,0 +1,67 @@
+/*
+ * 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.JField;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.js.ast.JsName;
+import com.google.gwt.dev.js.ast.JsStatement;
+
+/**
+ * A map between chunks of JavaScript to chunks of Java.
+ */
+public interface JavaToJavaScriptMap {
+ /**
+ * Return the JavaScript name corresponding to a Java type.
+ */
+ JsName nameForType(JReferenceType type);
+
+ /**
+ * Return the JavaScript name corresponding to a Java method.
+ */
+ JsName nameForMethod(JMethod method);
+
+ /**
+ * If <code>name</code> is the name of a <code>var<code> that corresponds to a Java
+ * static field, then return that field. Otherwise, return null.
+ */
+ JField nameToField(JsName name);
+
+ /**
+ * If <code>name</code> is the name of a function that corresponds to a Java
+ * method, then return that method. Otherwise, return null.
+ */
+ JMethod nameToMethod(JsName name);
+
+ /**
+ * If <code>var</code> is the name of the variable used to hold an interned
+ * string literal, then return the string it interns. Otherwise, return null.
+ */
+ String stringLiteralForName(JsName var);
+
+ /**
+ * If <code>stat</code> is used to set up the definition of some class,
+ * return that class. Otherwise, return null.
+ */
+ JReferenceType typeForStatement(JsStatement stat);
+
+ /**
+ * If <code>stat</code> is used to set up a vtable entry for a method,
+ * then return that method. Otherwise return null.
+ */
+ JMethod vtableInitToMethod(JsStatement stat);
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
index ff4610e..c2e737e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
@@ -126,15 +126,16 @@
*/
private JMethod createDevirtualMethod(JMethod objectMethod, JMethod jsoImpl) {
JClassType jsoType = program.getJavaScriptObject();
- SourceInfo sourceInfo = null;
+ SourceInfo sourceInfo = jsoType.getSourceInfo();
// Create the new method.
String name = objectMethod.getName() + "__devirtual$";
- JMethod newMethod = program.createMethod(sourceInfo, name.toCharArray(),
+ JMethod newMethod = program.createMethod(sourceInfo.makeChild(
+ JsoDevirtualizer.class, "Devirtualized method"), name.toCharArray(),
jsoType, objectMethod.getType(), false, true, true, false, false);
// Setup parameters.
- JParameter thisParam = program.createParameter(null,
+ JParameter thisParam = program.createParameter(sourceInfo,
"this$static".toCharArray(), program.getTypeJavaLangObject(), true,
true, newMethod);
for (JParameter oldParam : objectMethod.params) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
index 7e5e399..fed1cd4 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
@@ -83,7 +83,8 @@
@Override
public void endVisit(JsThisRef x, JsContext<JsExpression> ctx) {
- ctx.replaceMe(thisParam.makeRef());
+ ctx.replaceMe(thisParam.makeRef(x.getSourceInfo().makeChild(
+ RewriteJsniMethodBody.class, "Devirtualized instance")));
}
@Override
@@ -113,14 +114,16 @@
public void endVisit(JParameterRef x, Context ctx) {
JParameter param = varMap.get(x.getTarget());
JParameterRef paramRef = new JParameterRef(x.getProgram(),
- x.getSourceInfo(), param);
+ x.getSourceInfo().makeChild(RewriteMethodBody.class,
+ "Reference to devirtualized parameter"), param);
ctx.replaceMe(paramRef);
}
@Override
public void endVisit(JThisRef x, Context ctx) {
JParameterRef paramRef = new JParameterRef(x.getProgram(),
- x.getSourceInfo(), thisParam);
+ x.getSourceInfo().makeChild(RewriteMethodBody.class,
+ "Reference to devirtualized instance"), thisParam);
ctx.replaceMe(paramRef);
}
}
@@ -142,11 +145,13 @@
* its enclosing class.
*/
JProgram program = x.getProgram();
- JMethod newMethod = new JMethod(program, sourceInfo, newName,
+ JMethod newMethod = new JMethod(program, sourceInfo.makeChild(
+ CreateStaticImplsVisitor.class, "Devirtualized function"), newName,
enclosingType, returnType, false, true, true, x.isPrivate());
// Setup parameters; map from the old params to the new params
- JParameter thisParam = program.createParameter(null,
+ JParameter thisParam = program.createParameter(sourceInfo.makeChild(
+ CreateStaticImplsVisitor.class, "Instance parameter"),
"this$static".toCharArray(), enclosingType, true, true, newMethod);
Map<JParameter, JParameter> varMap = new IdentityHashMap<JParameter, JParameter>();
for (int i = 0; i < x.params.size(); ++i) {
@@ -168,20 +173,25 @@
newMethod.setBody(movedBody);
// Create a new body for the instance method that delegates to the static
- JMethodBody newBody = new JMethodBody(program, sourceInfo);
+ SourceInfo delegateCallSourceInfo = sourceInfo.makeChild(
+ CreateStaticImplsVisitor.class, "Degelgating to devirtualized method");
+ JMethodBody newBody = new JMethodBody(program, delegateCallSourceInfo);
x.setBody(newBody);
- JMethodCall newCall = new JMethodCall(program, sourceInfo, null,
- newMethod);
- newCall.getArgs().add(program.getExprThisRef(sourceInfo, enclosingType));
+ JMethodCall newCall = new JMethodCall(program, delegateCallSourceInfo,
+ null, newMethod);
+ newCall.getArgs().add(
+ program.getExprThisRef(delegateCallSourceInfo, enclosingType));
for (int i = 0; i < x.params.size(); ++i) {
JParameter param = x.params.get(i);
- newCall.getArgs().add(new JParameterRef(program, sourceInfo, param));
+ newCall.getArgs().add(
+ new JParameterRef(program, delegateCallSourceInfo, param));
}
JStatement statement;
if (returnType == program.getTypeVoid()) {
statement = newCall.makeStatement();
} else {
- statement = new JReturnStatement(program, sourceInfo, newCall);
+ statement = new JReturnStatement(program, delegateCallSourceInfo,
+ newCall);
}
newBody.getStatements().add(statement);
@@ -195,7 +205,10 @@
// TODO: Do we really need to do that in BuildTypeMap?
JsFunction jsFunc = ((JsniMethodBody) movedBody).getFunc();
JsName paramName = jsFunc.getScope().declareName("this$static");
- jsFunc.getParameters().add(0, new JsParameter(paramName));
+ jsFunc.getParameters().add(
+ 0,
+ new JsParameter(sourceInfo.makeChild(
+ CreateStaticImplsVisitor.class, "Static accessor"), paramName));
RewriteJsniMethodBody rewriter = new RewriteJsniMethodBody(paramName);
// Accept the body to avoid the recursion blocker.
rewriter.accept(jsFunc.getBody());
@@ -282,8 +295,9 @@
static JMethodCall makeStaticCall(JMethodCall x, JMethod newMethod) {
// Update the call site
- JMethodCall newCall = new JMethodCall(x.getProgram(), x.getSourceInfo(),
- null, newMethod);
+ JMethodCall newCall = new JMethodCall(x.getProgram(),
+ x.getSourceInfo().makeChild(MakeCallsStatic.class,
+ "Devirtualized function call"), null, newMethod);
// The qualifier becomes the first arg
newCall.getArgs().add(x.getInstance());
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 01b04ba..44b85f4 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
@@ -19,12 +19,8 @@
import com.google.gwt.dev.jjs.ast.CanBeStatic;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.HasEnclosingType;
-import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
-import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
-import com.google.gwt.dev.jjs.ast.JCastOperation;
-import com.google.gwt.dev.jjs.ast.JClassLiteral;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JExpression;
@@ -32,38 +28,26 @@
import com.google.gwt.dev.jjs.ast.JFieldRef;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JLocal;
-import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JModVisitor;
-import com.google.gwt.dev.jjs.ast.JNewArray;
-import com.google.gwt.dev.jjs.ast.JNewInstance;
import com.google.gwt.dev.jjs.ast.JNode;
import com.google.gwt.dev.jjs.ast.JParameter;
-import com.google.gwt.dev.jjs.ast.JParameterRef;
import com.google.gwt.dev.jjs.ast.JPrimitiveType;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
-import com.google.gwt.dev.jjs.ast.JStringLiteral;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.JVariable;
import com.google.gwt.dev.jjs.ast.JVariableRef;
-import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
-import com.google.gwt.dev.js.ast.JsContext;
-import com.google.gwt.dev.js.ast.JsExpression;
import com.google.gwt.dev.js.ast.JsFunction;
-import com.google.gwt.dev.js.ast.JsName;
-import com.google.gwt.dev.js.ast.JsNameRef;
-import com.google.gwt.dev.js.ast.JsVisitor;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -97,13 +81,20 @@
* and null method, and drop assignments to pruned variables.
*/
private class CleanupRefsVisitor extends JModVisitor {
-
private Stack<JExpression> lValues = new Stack<JExpression>();
+ private final Map<JMethod, ArrayList<JParameter>> methodToOriginalParamsMap;
+ private final Set<? extends JNode> referencedNonTypes;
{
// Initialize a sentinel value to avoid having to check for empty stack.
lValues.push(null);
}
+ public CleanupRefsVisitor(Set<? extends JNode> referencedNodes,
+ Map<JMethod, ArrayList<JParameter>> methodToOriginalParamsMap) {
+ this.referencedNonTypes = referencedNodes;
+ this.methodToOriginalParamsMap = methodToOriginalParamsMap;
+ }
+
@Override
public void endVisit(JBinaryOperation x, Context ctx) {
// The LHS of assignments may have been pruned.
@@ -141,11 +132,6 @@
}
if (isPruned(x.getField())) {
- /*
- * We assert that field must be non-static if it's an rvalue, otherwise
- * it would have been rescued.
- */
- assert !x.getField().isStatic();
// The field is gone; replace x by a null field reference.
JFieldRef fieldRef = transformToNullFieldRef(x, program);
ctx.replaceMe(fieldRef);
@@ -312,14 +298,27 @@
* unreferenced methods and fields from their containing classes.
*/
private class PruneVisitor extends JModVisitor {
-
private boolean didChange = false;
+ private final Map<JMethod, ArrayList<JParameter>> methodToOriginalParamsMap = new HashMap<JMethod, ArrayList<JParameter>>();
+ private final Set<? extends JNode> referencedNonTypes;
+
+ private final Set<? extends JReferenceType> referencedTypes;
+
+ public PruneVisitor(Set<? extends JReferenceType> referencedTypes,
+ Set<? extends JNode> referencedNodes) {
+ this.referencedTypes = referencedTypes;
+ this.referencedNonTypes = referencedNodes;
+ }
@Override
public boolean didChange() {
return didChange;
}
+ public Map<JMethod, ArrayList<JParameter>> getMethodToOriginalParamsMap() {
+ return methodToOriginalParamsMap;
+ }
+
@Override
public boolean visit(JClassType type, Context ctx) {
@@ -449,7 +448,7 @@
@Override
public boolean visit(JProgram program, Context ctx) {
- for (JMethod method : program.entryMethods) {
+ for (JMethod method : program.getAllEntryMethods()) {
accept(method);
}
for (Iterator<JReferenceType> it = program.getDeclaredTypes().iterator(); it.hasNext();) {
@@ -496,517 +495,6 @@
}
}
- /**
- * Marks as "referenced" any types, methods, and fields that are reachable.
- * Also marks as "instantiable" any the classes and interfaces that can
- * possibly be instantiated.
- *
- * TODO(later): make RescueVisitor use less stack?
- */
- private class RescueVisitor extends JVisitor {
-
- private final Set<JReferenceType> instantiatedTypes = new HashSet<JReferenceType>();
-
- public void commitInstantiatedTypes() {
- program.typeOracle.setInstantiatedTypes(instantiatedTypes);
- }
-
- @Override
- public boolean visit(JArrayType type, Context ctx) {
- assert (referencedTypes.contains(type));
- boolean isInstantiated = instantiatedTypes.contains(type);
-
- JType leafType = type.getLeafType();
- int dims = type.getDims();
-
- // Rescue my super array type
- if (leafType instanceof JReferenceType) {
- JReferenceType rLeafType = (JReferenceType) leafType;
- if (rLeafType.extnds != null) {
- JArrayType superArray = program.getTypeArray(rLeafType.extnds, dims);
- rescue(superArray, true, isInstantiated);
- }
-
- for (int i = 0; i < rLeafType.implments.size(); ++i) {
- JInterfaceType intfType = rLeafType.implments.get(i);
- JArrayType intfArray = program.getTypeArray(intfType, dims);
- rescue(intfArray, true, isInstantiated);
- }
- }
-
- // Rescue the base Array type
- rescue(program.getIndexedType("Array"), true, isInstantiated);
- return false;
- }
-
- @Override
- public boolean visit(JBinaryOperation x, Context ctx) {
- // special string concat handling
- if ((x.getOp() == JBinaryOperator.ADD || x.getOp() == JBinaryOperator.ASG_ADD)
- && x.getType() == program.getTypeJavaLangString()) {
- rescueByConcat(x.getLhs().getType());
- rescueByConcat(x.getRhs().getType());
- } else if (x.getOp() == JBinaryOperator.ASG) {
- // Don't rescue variables that are merely assigned to and never read
- boolean doSkip = false;
- JExpression lhs = x.getLhs();
- if (lhs.hasSideEffects() || isVolatileField(lhs)) {
- /*
- * If the lhs has side effects, skipping it would lose the side
- * effect. If the lhs is volatile, also keep it. This behavior
- * provides a useful idiom for test cases to prevent code from being
- * pruned.
- */
- } else if (lhs instanceof JLocalRef) {
- // locals are ok to skip
- doSkip = true;
- } else if (lhs instanceof JParameterRef) {
- // parameters are ok to skip
- doSkip = true;
- } else if (lhs instanceof JFieldRef) {
- // fields must rescue the qualifier
- doSkip = true;
- JFieldRef fieldRef = (JFieldRef) lhs;
- JExpression instance = fieldRef.getInstance();
- if (instance != null) {
- accept(instance);
- }
- }
-
- if (doSkip) {
- accept(x.getRhs());
- return false;
- }
- }
- return true;
- }
-
- @Override
- public boolean visit(JCastOperation x, Context ctx) {
- // Rescue any JavaScriptObject type that is the target of a cast.
- JType targetType = x.getCastType();
- if (program.isJavaScriptObject(targetType)) {
- rescue((JReferenceType) targetType, true, true);
- }
- return true;
- }
-
- @Override
- public boolean visit(JClassLiteral x, Context ctx) {
- // Works just like JFieldRef to a static field.
- JField field = x.getField();
- rescue(field.getEnclosingType(), true, false);
- rescue(field);
- return true;
- }
-
- @Override
- public boolean visit(JClassType type, Context ctx) {
- assert (referencedTypes.contains(type));
- boolean isInstantiated = instantiatedTypes.contains(type);
-
- /*
- * SPECIAL: Some classes contain methods used by code generation later.
- * Unless those transforms have already been performed, we must rescue all
- * contained methods for later user.
- */
- if (saveCodeGenTypes && program.codeGenTypes.contains(type)) {
- for (int i = 0; i < type.methods.size(); ++i) {
- JMethod it = type.methods.get(i);
- rescue(it);
- }
- }
-
- // Rescue my super type
- rescue(type.extnds, true, isInstantiated);
-
- // Rescue my clinit (it won't ever be explicitly referenced
- rescue(type.methods.get(0));
-
- // JLS 12.4.1: don't rescue my super interfaces just because I'm rescued.
- // However, if I'm instantiated, let's mark them as instantiated.
- for (int i = 0; i < type.implments.size(); ++i) {
- JInterfaceType intfType = type.implments.get(i);
- rescue(intfType, false, isInstantiated);
- }
-
- return false;
- }
-
- @Override
- public boolean visit(JDeclarationStatement x, Context ctx) {
- /*
- * A declaration by itself doesn't rescue a local (even if it has an
- * initializer). Writes don't count, only reads.
- */
- if (x.getInitializer() != null) {
- accept(x.getInitializer());
- }
-
- // If the lhs is a field ref, we have to visit its qualifier.
- JVariableRef variableRef = x.getVariableRef();
- if (variableRef instanceof JFieldRef) {
- JFieldRef fieldRef = (JFieldRef) variableRef;
- JExpression instance = fieldRef.getInstance();
- if (instance != null) {
- accept(instance);
- }
- }
- return false;
- }
-
- @Override
- public boolean visit(JFieldRef ref, Context ctx) {
- JField target = ref.getField();
-
- // JLS 12.4.1: references to static, non-final, or
- // non-compile-time-constant fields rescue the enclosing class.
- // JDT already folds in compile-time constants as literals, so we must
- // rescue the enclosing types for any static fields that make it here.
- if (target.isStatic()) {
- rescue(target.getEnclosingType(), true, false);
- }
- rescue(target);
- return true;
- }
-
- @Override
- public boolean visit(JInterfaceType type, Context ctx) {
- boolean isReferenced = referencedTypes.contains(type);
- boolean isInstantiated = instantiatedTypes.contains(type);
- assert (isReferenced || isInstantiated);
-
- // Rescue my clinit (it won't ever be explicitly referenced
- rescue(type.methods.get(0));
-
- // JLS 12.4.1: don't rescue my super interfaces just because I'm rescued.
- // However, if I'm instantiated, let's mark them as instantiated.
- if (isInstantiated) {
- for (int i = 0; i < type.implments.size(); ++i) {
- JInterfaceType intfType = type.implments.get(i);
- rescue(intfType, false, true);
- }
- }
-
- // visit any field initializers
- for (int i = 0; i < type.fields.size(); ++i) {
- JField it = type.fields.get(i);
- accept(it);
- }
-
- return false;
- }
-
- @Override
- public boolean visit(JLocalRef ref, Context ctx) {
- JLocal target = ref.getLocal();
- rescue(target);
- return true;
- }
-
- @Override
- public boolean visit(final JMethod x, Context ctx) {
- if (x.isNative()) {
- // Manually rescue native parameter references
- final JsniMethodBody body = (JsniMethodBody) x.getBody();
- final JsFunction func = body.getFunc();
-
- new JsVisitor() {
- @Override
- public void endVisit(JsNameRef nameRef, JsContext<JsExpression> ctx) {
- JsName ident = nameRef.getName();
-
- if (ident != null) {
- // If we're referencing a parameter, rescue the associated
- // JParameter
- int index = func.getParameters().indexOf(ident.getStaticRef());
- if (index != -1) {
- rescue(x.params.get(index));
- }
- }
- }
- }.accept(func);
- }
-
- return true;
- }
-
- @Override
- public boolean visit(JMethodCall call, Context ctx) {
- JMethod target = call.getTarget();
- JReferenceType enclosingType = target.getEnclosingType();
- if (program.isJavaScriptObject(enclosingType)) {
- // Calls to JavaScriptObject types rescue those types.
- boolean instance = !target.isStatic() || program.isStaticImpl(target);
- rescue(enclosingType, true, instance);
- } else if (target.isStatic()) {
- // JLS 12.4.1: references to static methods rescue the enclosing class
- rescue(enclosingType, true, false);
- }
- rescue(target);
- return true;
- }
-
- @Override
- public boolean visit(JNewArray newArray, Context ctx) {
- // rescue and instantiate the array type
- JArrayType arrayType = newArray.getArrayType();
- if (newArray.dims != null) {
- // rescue my type and all the implicitly nested types (with fewer dims)
- int nDims = arrayType.getDims();
- JType leafType = arrayType.getLeafType();
- assert (newArray.dims.size() == nDims);
- for (int i = 0; i < nDims; ++i) {
- if (newArray.dims.get(i) instanceof JAbsentArrayDimension) {
- break;
- }
- rescue(program.getTypeArray(leafType, nDims - i), true, true);
- }
- } else {
- // just rescue my own specific type
- rescue(arrayType, true, true);
- }
- return true;
- }
-
- @Override
- public boolean visit(JNewInstance newInstance, Context ctx) {
- // rescue and instantiate the target class!
- rescue(newInstance.getClassType(), true, true);
- return true;
- }
-
- @Override
- public boolean visit(JParameterRef x, Context ctx) {
- // rescue the parameter for future pruning purposes
- rescue(x.getParameter());
- return true;
- }
-
- @Override
- public boolean visit(JsniFieldRef x, Context ctx) {
- /*
- * SPECIAL: this could be an assignment that passes a value from
- * JavaScript into Java.
- */
- if (x.isLvalue()) {
- maybeRescueJavaScriptObjectPassingIntoJava(x.getField().getType());
- }
- // JsniFieldRef rescues as JFieldRef
- return visit((JFieldRef) x, ctx);
- }
-
- @Override
- public boolean visit(JsniMethodRef x, Context ctx) {
- /*
- * SPECIAL: each argument of the call passes a value from JavaScript into
- * Java.
- */
- ArrayList<JParameter> params = x.getTarget().params;
- for (int i = 0, c = params.size(); i < c; ++i) {
- JParameter param = params.get(i);
- maybeRescueJavaScriptObjectPassingIntoJava(param.getType());
-
- /*
- * Because we're not currently tracking methods through JSNI, we need to
- * assume that it's not safe to prune parameters of a method referenced
- * as such.
- *
- * A better solution would be to perform basic escape analysis to ensure
- * that the function reference never escapes, or at minimum, ensure that
- * the method is immediately called after retrieving the method
- * reference.
- */
- rescue(param);
- }
- // JsniMethodRef rescues as JMethodCall
- return visit((JMethodCall) x, ctx);
- }
-
- @Override
- public boolean visit(JStringLiteral literal, Context ctx) {
- // rescue and instantiate java.lang.String
- rescue(program.getTypeJavaLangString(), true, true);
- return true;
- }
-
- private boolean isVolatileField(JExpression x) {
- if (x instanceof JFieldRef) {
- JFieldRef xFieldRef = (JFieldRef) x;
- if (xFieldRef.getField().isVolatile()) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Subclasses of JavaScriptObject are never instantiated directly. They are
- * created "magically" when a JSNI method passes a reference to an existing
- * JS object into Java code. If any point in the program can pass a value
- * from JS into Java which could potentially be cast to JavaScriptObject, we
- * must rescue JavaScriptObject.
- *
- * @param type The type of the value passing from Java to JavaScript.
- * @see com.google.gwt.core.client.JavaScriptObject
- */
- private void maybeRescueJavaScriptObjectPassingIntoJava(JType type) {
- boolean doIt = false;
- if (program.isJavaScriptObject(type)
- || type == program.getTypeJavaLangString()) {
- doIt = true;
- } else if (type instanceof JArrayType) {
- /*
- * Hackish: in our own JRE we sometimes create "not quite baked" arrays
- * in JavaScript for expediency.
- */
- JArrayType arrayType = (JArrayType) type;
- JType elementType = arrayType.getElementType();
- if (elementType instanceof JPrimitiveType
- || elementType == program.getTypeJavaLangString()
- || program.isJavaScriptObject(elementType)) {
- doIt = true;
- }
- }
- if (doIt) {
- rescue((JReferenceType) type, true, true);
- }
- }
-
- private boolean rescue(JMethod method) {
- if (method != null) {
- if (!referencedNonTypes.contains(method)) {
- referencedNonTypes.add(method);
- accept(method);
- if (method.isNative()) {
- /*
- * SPECIAL: returning from this method passes a value from
- * JavaScript into Java.
- */
- maybeRescueJavaScriptObjectPassingIntoJava(method.getType());
- }
- return true;
- }
- }
- return false;
- }
-
- private void rescue(JReferenceType type, boolean isReferenced,
- boolean isInstantiated) {
- if (type != null) {
-
- boolean doVisit = false;
- if (isInstantiated && !instantiatedTypes.contains(type)) {
- instantiatedTypes.add(type);
- doVisit = true;
- }
-
- if (isReferenced && !referencedTypes.contains(type)) {
- referencedTypes.add(type);
- doVisit = true;
- }
-
- if (doVisit) {
- accept(type);
- }
- }
- }
-
- private void rescue(JVariable var) {
- if (var != null) {
- if (!referencedNonTypes.contains(var)) {
- referencedNonTypes.add(var);
- }
- }
- }
-
- /**
- * Handle special rescues needed implicitly to support concat.
- */
- private void rescueByConcat(JType type) {
- JClassType stringType = program.getTypeJavaLangString();
- JPrimitiveType charType = program.getTypePrimitiveChar();
- if (type instanceof JReferenceType && type != stringType
- && type != program.getTypeNull()) {
- /*
- * Any reference types (except String, which works by default) that take
- * part in a concat must rescue java.lang.Object.toString().
- *
- * TODO: can we narrow the focus by walking up the type hierarchy or
- * doing explicit toString calls?
- */
- JMethod toStringMethod = program.getIndexedMethod("Object.toString");
- rescue(toStringMethod);
- } else if (type == charType) {
- /*
- * Characters must rescue String.valueOf(char)
- */
- if (stringValueOfChar == null) {
- for (int i = 0; i < stringType.methods.size(); ++i) {
- JMethod meth = stringType.methods.get(i);
- if (meth.getName().equals("valueOf")) {
- List<JType> params = meth.getOriginalParamTypes();
- if (params.size() == 1) {
- if (params.get(0) == charType) {
- stringValueOfChar = meth;
- break;
- }
- }
- }
- }
- assert (stringValueOfChar != null);
- }
- rescue(stringValueOfChar);
- }
- }
- }
-
- /**
- * A method that isn't called directly can still be needed, if it overrides or
- * implements any methods that are called.
- */
- private class UpRefVisitor extends JVisitor {
-
- private boolean didRescue = false;
- private final RescueVisitor rescuer;
-
- public UpRefVisitor(RescueVisitor rescuer) {
- this.rescuer = rescuer;
- }
-
- public boolean didRescue() {
- return didRescue;
- }
-
- @Override
- public boolean visit(JClassType x, Context ctx) {
- return rescuer.instantiatedTypes.contains(x);
- }
-
- @Override
- public boolean visit(JMethod x, Context ctx) {
- if (referencedNonTypes.contains(x)) {
- return false;
- }
-
- for (JMethod override : program.typeOracle.getAllOverrides(x)) {
- if (referencedNonTypes.contains(override)) {
- rescuer.rescue(x);
- didRescue = true;
- return false;
- }
- }
- return false;
- }
-
- @Override
- public boolean visit(JProgram x, Context ctx) {
- didRescue = false;
- return true;
- }
- }
-
public static boolean exec(JProgram program, boolean noSpecialTypes) {
return new Pruner(program, noSpecialTypes).execImpl();
}
@@ -1017,6 +505,26 @@
*/
public static JFieldRef transformToNullFieldRef(JFieldRef x, JProgram program) {
JExpression instance = x.getInstance();
+
+ /*
+ * We assert that field must be non-static if it's an rvalue, otherwise it
+ * would have been rescued.
+ */
+ // assert !x.getField().isStatic();
+ /*
+ * HACK HACK HACK: ControlFlowAnalyzer has special hacks for dealing with
+ * ClassLiterals, which causes the body of ClassLiteralHolder's clinit to
+ * never be rescured. This in turn causes invalid references to static
+ * methods, which violates otherwise good assumptions about compiler
+ * operation.
+ *
+ * TODO: Remove this when ControlFlowAnalyzer doesn't special-case
+ * CLH.clinit().
+ */
+ if (x.getField().isStatic() && instance == null) {
+ instance = program.getLiteralNull();
+ }
+
assert instance != null;
if (!instance.hasSideEffects()) {
instance = program.getLiteralNull();
@@ -1040,7 +548,24 @@
instance = args.get(0);
args = args.subList(1, args.size());
} else {
- assert !x.getTarget().isStatic();
+ /*
+ * We assert that method must be non-static, otherwise it would have been
+ * rescued.
+ */
+ // assert !x.getTarget().isStatic();
+ /*
+ * HACK HACK HACK: ControlFlowAnalyzer has special hacks for dealing with
+ * ClassLiterals, which causes the body of ClassLiteralHolder's clinit to
+ * never be rescured. This in turn causes invalid references to static
+ * methods, which violates otherwise good assumptions about compiler
+ * operation.
+ *
+ * TODO: Remove this when ControlFlowAnalyzer doesn't special-case
+ * CLH.clinit().
+ */
+ if (x.getTarget().isStatic() && instance == null) {
+ instance = program.getLiteralNull();
+ }
}
assert (instance != null);
if (!instance.hasSideEffects()) {
@@ -1064,12 +589,8 @@
return program.getTypeNull();
}
- private final Map<JMethod, ArrayList<JParameter>> methodToOriginalParamsMap = new HashMap<JMethod, ArrayList<JParameter>>();
private final JProgram program;
- private final Set<JNode> referencedNonTypes = new HashSet<JNode>();
- private final Set<JReferenceType> referencedTypes = new HashSet<JReferenceType>();
private final boolean saveCodeGenTypes;
- private JMethod stringValueOfChar = null;
private Pruner(JProgram program, boolean saveCodeGenTypes) {
this.program = program;
@@ -1079,35 +600,52 @@
private boolean execImpl() {
boolean madeChanges = false;
while (true) {
- RescueVisitor rescuer = new RescueVisitor();
- for (JReferenceType type : program.codeGenTypes) {
- rescuer.rescue(type, true, saveCodeGenTypes);
+ ControlFlowAnalyzer livenessAnalyzer = new ControlFlowAnalyzer(program);
+ if (saveCodeGenTypes) {
+ /*
+ * SPECIAL: Some classes contain methods used by code generation later.
+ * Unless those transforms have already been performed, we must rescue
+ * all contained methods for later user.
+ */
+ traverseFromCodeGenTypes(livenessAnalyzer);
}
- for (JMethod method : program.entryMethods) {
- rescuer.rescue(method);
+ for (JMethod method : program.getAllEntryMethods()) {
+ livenessAnalyzer.traverseFrom(method);
}
+ livenessAnalyzer.traverseFromLeftoversFragmentHasLoaded();
- UpRefVisitor upRefer = new UpRefVisitor(rescuer);
- do {
- rescuer.commitInstantiatedTypes();
- upRefer.accept(program);
- } while (upRefer.didRescue());
+ program.typeOracle.setInstantiatedTypes(livenessAnalyzer.getInstantiatedTypes());
- PruneVisitor pruner = new PruneVisitor();
+ PruneVisitor pruner = new PruneVisitor(
+ livenessAnalyzer.getReferencedTypes(),
+ livenessAnalyzer.getLiveFieldsAndMethods());
pruner.accept(program);
if (!pruner.didChange()) {
break;
}
- CleanupRefsVisitor cleaner = new CleanupRefsVisitor();
- cleaner.accept(program);
+ CleanupRefsVisitor cleaner = new CleanupRefsVisitor(
+ livenessAnalyzer.getLiveFieldsAndMethods(),
+ pruner.getMethodToOriginalParamsMap());
+ cleaner.accept(program.getDeclaredTypes());
- referencedTypes.clear();
- referencedNonTypes.clear();
- methodToOriginalParamsMap.clear();
madeChanges = true;
}
return madeChanges;
}
+ /**
+ * Traverse from all methods in the program's code-gen types. See
+ * {@link JProgram#CODEGEN_TYPES_SET}.
+ */
+ private void traverseFromCodeGenTypes(ControlFlowAnalyzer livenessAnalyzer) {
+ for (JReferenceType type : program.codeGenTypes) {
+ livenessAnalyzer.traverseFromReferenceTo(type);
+ for (int i = 0; i < type.methods.size(); ++i) {
+ JMethod method = type.methods.get(i);
+ livenessAnalyzer.traverseFrom(method);
+ }
+ }
+ }
+
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
new file mode 100644
index 0000000..ef63635
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
@@ -0,0 +1,156 @@
+/*
+ * 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.core.ext.TreeLogger;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JClassType;
+import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JMethodCall;
+import com.google.gwt.dev.jjs.ast.JModVisitor;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JType;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Replaces calls to
+ * {@link com.google.gwt.core.client.GWT#runAsync(com.google.gwt.core.client.RunAsyncCallback)}"
+ * by calls to a fragment loader.
+ */
+public class ReplaceRunAsyncs {
+ private class AsyncCreateVisitor extends JModVisitor {
+ private JMethod currentMethod;
+ private Map<Integer, String> splitPointMap = new TreeMap<Integer, String>();
+ private Map<String, Integer> methodCount = new HashMap<String, Integer>();
+ private int entryCount = 1;
+
+ @Override
+ public void endVisit(JMethodCall x, Context ctx) {
+ JMethod method = x.getTarget();
+ if (method == program.getIndexedMethod("GWT.runAsync")) {
+ assert (x.getArgs().size() == 1);
+ JExpression asyncCallback = x.getArgs().get(0);
+
+ int entryNumber = entryCount++;
+ logger.log(TreeLogger.DEBUG, "Assigning split point #" + entryNumber
+ + " in method " + fullMethodDescription(currentMethod));
+
+ String methodDescription = fullMethodDescription(currentMethod);
+ if (methodCount.containsKey(methodDescription)) {
+ methodCount.put(methodDescription,
+ methodCount.get(methodDescription) + 1);
+ methodDescription += "#"
+ + Integer.toString(methodCount.get(methodDescription));
+ } else {
+ methodCount.put(methodDescription, 1);
+ }
+ splitPointMap.put(entryNumber, methodDescription);
+
+ JClassType loader = getFragmentLoader(entryNumber);
+ JMethod loadMethod = getRunAsyncMethod(loader);
+ assert loadMethod != null;
+
+ JMethodCall methodCall = new JMethodCall(program, x.getSourceInfo(),
+ null, loadMethod);
+ methodCall.getArgs().add(asyncCallback);
+
+ program.addEntryMethod(getOnLoadMethod(loader), entryNumber);
+
+ ctx.replaceMe(methodCall);
+ }
+ }
+
+ @Override
+ public boolean visit(JMethod x, Context ctx) {
+ currentMethod = x;
+ return true;
+ }
+ }
+
+ public static int exec(TreeLogger logger, JProgram program) {
+ return new ReplaceRunAsyncs(logger, program).execImpl();
+ }
+
+ private static String fullMethodDescription(JMethod method) {
+ return (method.getEnclosingType().getName() + "." + JProgram.getJsniSig(method));
+ }
+
+ private final TreeLogger logger;
+ private JProgram program;
+
+ private ReplaceRunAsyncs(TreeLogger logger, JProgram program) {
+ this.logger = logger.branch(TreeLogger.TRACE,
+ "Replacing GWT.runAsync with island loader calls");
+ this.program = program;
+ }
+
+ private int execImpl() {
+ AsyncCreateVisitor visitor = new AsyncCreateVisitor();
+ visitor.accept(program);
+ setNumEntriesInAsyncFragmentLoader(visitor.entryCount);
+ program.setSplitPointMap(visitor.splitPointMap);
+
+ return visitor.entryCount;
+ }
+
+ private JClassType getFragmentLoader(int fragmentNumber) {
+ String fragmentLoaderClassName = FragmentLoaderCreator.ASYNC_LOADER_PACKAGE
+ + "." + FragmentLoaderCreator.ASYNC_LOADER_CLASS_PREFIX
+ + fragmentNumber;
+ JType result = program.getFromTypeMap(fragmentLoaderClassName);
+ assert (result != null);
+ assert (result instanceof JClassType);
+ return (JClassType) result;
+ }
+
+ private JMethod getOnLoadMethod(JClassType loaderType) {
+ assert loaderType != null;
+ assert loaderType.methods != null;
+ for (JMethod method : loaderType.methods) {
+ if (method.getName().equals("onLoad")) {
+ assert (method.isStatic());
+ assert (method.params.size() == 0);
+ return method;
+ }
+ }
+ assert false;
+ return null;
+ }
+
+ private JMethod getRunAsyncMethod(JClassType loaderType) {
+ assert loaderType != null;
+ assert loaderType.methods != null;
+ for (JMethod method : loaderType.methods) {
+ if (method.getName().equals("runAsync")) {
+ assert (method.isStatic());
+ assert (method.params.size() == 1);
+ assert (method.params.get(0).getType().getName().equals(FragmentLoaderCreator.RUN_ASYNC_CALLBACK));
+ return method;
+ }
+ }
+ return null;
+ }
+
+ private void setNumEntriesInAsyncFragmentLoader(int entryCount) {
+ JField field = program.getIndexedField("AsyncFragmentLoader.numEntries");
+ field.getDeclarationStatement().initializer = program.getLiteralInt(entryCount);
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/SourceGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/SourceGenerationVisitor.java
index fa8e23b..9817428 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/SourceGenerationVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/SourceGenerationVisitor.java
@@ -107,12 +107,6 @@
@Override
public boolean visit(JProgram x, Context ctx) {
- for (int i = 0; i < x.entryMethods.size(); ++i) {
- JMethod method = x.entryMethods.get(i);
- accept(method);
- newline();
- newline();
- }
for (int i = 0; i < x.getDeclaredTypes().size(); ++i) {
JReferenceType type = x.getDeclaredTypes().get(i);
accept(type);
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 836ed93..ac9815c 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
@@ -249,7 +249,9 @@
// Fake an assignment-to-self on all args to prevent tightening
JMethod method = x.getTarget();
for (JParameter param : method.params) {
- addAssignment(param, new JParameterRef(program, null, param));
+ addAssignment(param, new JParameterRef(program,
+ program.createSourceInfoSynthetic(RecordVisitor.class,
+ "Fake assignment"), param));
}
}
@@ -366,8 +368,8 @@
public class TightenTypesVisitor extends JModVisitor {
/**
- * <code>true</code> if this visitor has changed the AST apart from calls
- * to Context.
+ * <code>true</code> if this visitor has changed the AST apart from calls to
+ * Context.
*/
private boolean myDidChange = false;
diff --git a/dev/core/src/com/google/gwt/dev/js/EvalFunctionsAtTopScope.java b/dev/core/src/com/google/gwt/dev/js/EvalFunctionsAtTopScope.java
new file mode 100644
index 0000000..b22a69c
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/js/EvalFunctionsAtTopScope.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2009 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.js;
+
+import com.google.gwt.dev.js.ast.JsBlock;
+import com.google.gwt.dev.js.ast.JsContext;
+import com.google.gwt.dev.js.ast.JsExpression;
+import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsModVisitor;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsProgramFragment;
+import com.google.gwt.dev.js.ast.JsStatement;
+
+import java.util.HashSet;
+import java.util.ListIterator;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Force all functions to be evaluated at the top of the lexical scope in which
+ * they reside. This makes {@link StaticEvalVisitor} simpler in that we no
+ * longer have to worry about function declarations within expressions. After
+ * this runs, only statements can contain declarations. Moved functions will end
+ * up just before the statement in which they presently reside.
+ */
+public class EvalFunctionsAtTopScope extends JsModVisitor {
+
+ public static void exec(JsProgram jsProgram) {
+ EvalFunctionsAtTopScope fev = new EvalFunctionsAtTopScope();
+ fev.accept(jsProgram);
+ }
+
+ private final Set<JsFunction> dontMove = new HashSet<JsFunction>();
+
+ private final Stack<ListIterator<JsStatement>> itrStack = new Stack<ListIterator<JsStatement>>();
+
+ private final Stack<JsBlock> scopeStack = new Stack<JsBlock>();
+
+ @Override
+ public void endVisit(JsFunction x, JsContext<JsExpression> ctx) {
+ scopeStack.pop();
+ }
+
+ @Override
+ public void endVisit(JsProgram x, JsContext<JsProgram> ctx) {
+ scopeStack.pop();
+ }
+
+ @Override
+ public void endVisit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+ scopeStack.pop();
+ }
+
+ @Override
+ public boolean visit(JsBlock x, JsContext<JsStatement> ctx) {
+ if (x == scopeStack.peek()) {
+ ListIterator<JsStatement> itr = x.getStatements().listIterator();
+ itrStack.push(itr);
+ while (itr.hasNext()) {
+ JsStatement stmt = itr.next();
+ JsFunction func = JsStaticEval.isFunctionDecl(stmt);
+ // Already at the top level.
+ if (func != null) {
+ dontMove.add(func);
+ }
+ accept(stmt);
+ if (func != null) {
+ dontMove.remove(func);
+ }
+ }
+ itrStack.pop();
+ // Already visited.
+ return false;
+ } else {
+ // Just do normal visitation.
+ return true;
+ }
+ }
+
+ @Override
+ public boolean visit(JsFunction x, JsContext<JsExpression> ctx) {
+ /*
+ * We do this during visit() to preserve first-to-last evaluation order.
+ */
+ if (x.getName() != null && !dontMove.contains(x)) {
+ /*
+ * Reinsert this function into the statement immediately before the
+ * current statement. The current statement will have already been
+ * returned from the current iterator's next(), so we have to backshuffle
+ * one step to get in front of it.
+ */
+ ListIterator<JsStatement> itr = itrStack.peek();
+ itr.previous();
+ itr.add(x.makeStmt());
+ itr.next();
+ ctx.replaceMe(x.getName().makeRef(
+ x.getSourceInfo().makeChild(EvalFunctionsAtTopScope.class,
+ "Shuffled evaluation order")));
+ }
+
+ // Dive into the function itself.
+ scopeStack.push(x.getBody());
+ return true;
+ }
+
+ @Override
+ public boolean visit(JsProgram x, JsContext<JsProgram> ctx) {
+ scopeStack.push(x.getGlobalBlock());
+ return true;
+ }
+
+ @Override
+ public boolean visit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+ scopeStack.push(x.getGlobalBlock());
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/js/JsConstructExpressionVisitor.java b/dev/core/src/com/google/gwt/dev/js/JsConstructExpressionVisitor.java
index 3d09cba..1ca37e0 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsConstructExpressionVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsConstructExpressionVisitor.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
@@ -26,6 +26,7 @@
import com.google.gwt.dev.js.ast.JsObjectLiteral;
import com.google.gwt.dev.js.ast.JsVisitable;
import com.google.gwt.dev.js.ast.JsVisitor;
+import com.google.gwt.dev.js.ast.SourceInfoJs;
/**
* Searches for method invocations in constructor expressions that would not
@@ -33,7 +34,8 @@
*/
public class JsConstructExpressionVisitor extends JsVisitor {
- private static final int PRECEDENCE_NEW = JsPrecedenceVisitor.exec(new JsNew());
+ private static final int PRECEDENCE_NEW = JsPrecedenceVisitor.exec(new JsNew(
+ SourceInfoJs.INTRINSIC));
public static boolean exec(JsExpression expression) {
if (JsPrecedenceVisitor.exec(expression) < PRECEDENCE_NEW) {
diff --git a/dev/core/src/com/google/gwt/dev/js/JsHoister.java b/dev/core/src/com/google/gwt/dev/js/JsHoister.java
index 33964f2..e5f02ec 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsHoister.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsHoister.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
@@ -60,7 +60,7 @@
@Override
public void endVisit(JsArrayAccess x, JsContext<JsExpression> ctx) {
- JsArrayAccess newExpression = new JsArrayAccess();
+ JsArrayAccess newExpression = new JsArrayAccess(x.getSourceInfo());
newExpression.setIndexExpr(stack.pop());
newExpression.setArrayExpr(stack.pop());
stack.push(newExpression);
@@ -68,7 +68,7 @@
@Override
public void endVisit(JsArrayLiteral x, JsContext<JsExpression> ctx) {
- JsArrayLiteral toReturn = new JsArrayLiteral();
+ JsArrayLiteral toReturn = new JsArrayLiteral(x.getSourceInfo());
List<JsExpression> expressions = toReturn.getExpressions();
for (JsExpression e : x.getExpressions()) {
expressions.add(0, stack.pop());
@@ -78,7 +78,7 @@
@Override
public void endVisit(JsBinaryOperation x, JsContext<JsExpression> ctx) {
- JsBinaryOperation toReturn = new JsBinaryOperation(x.getOperator());
+ JsBinaryOperation toReturn = new JsBinaryOperation(x.getSourceInfo(), x.getOperator());
toReturn.setArg2(stack.pop());
toReturn.setArg1(stack.pop());
stack.push(toReturn);
@@ -91,7 +91,7 @@
@Override
public void endVisit(JsConditional x, JsContext<JsExpression> ctx) {
- JsConditional toReturn = new JsConditional();
+ JsConditional toReturn = new JsConditional(x.getSourceInfo());
toReturn.setElseExpression(stack.pop());
toReturn.setThenExpression(stack.pop());
toReturn.setTestExpression(stack.pop());
@@ -116,7 +116,7 @@
*/
@Override
public void endVisit(JsInvocation x, JsContext<JsExpression> ctx) {
- JsInvocation toReturn = new JsInvocation();
+ JsInvocation toReturn = new JsInvocation(x.getSourceInfo());
List<JsExpression> params = toReturn.getArguments();
for (JsExpression e : x.getArguments()) {
params.add(0, stack.pop());
@@ -132,7 +132,7 @@
*/
@Override
public void endVisit(JsNameRef x, JsContext<JsExpression> ctx) {
- JsNameRef toReturn = new JsNameRef(x.getName());
+ JsNameRef toReturn = new JsNameRef(x.getSourceInfo(), x.getName());
if (x.getQualifier() != null) {
toReturn.setQualifier(stack.pop());
@@ -142,7 +142,7 @@
@Override
public void endVisit(JsNew x, JsContext<JsExpression> ctx) {
- JsNew toReturn = new JsNew();
+ JsNew toReturn = new JsNew(x.getSourceInfo());
List<JsExpression> arguments = toReturn.getArguments();
for (JsExpression a : x.getArguments()) {
@@ -164,7 +164,7 @@
@Override
public void endVisit(JsObjectLiteral x, JsContext<JsExpression> ctx) {
- JsObjectLiteral toReturn = new JsObjectLiteral();
+ JsObjectLiteral toReturn = new JsObjectLiteral(x.getSourceInfo());
List<JsPropertyInitializer> inits = toReturn.getPropertyInitializers();
for (JsPropertyInitializer init : x.getPropertyInitializers()) {
@@ -174,7 +174,7 @@
* rather than expecting it to be on the stack and having to perform
* narrowing casts at all stack.pop() invocations.
*/
- JsPropertyInitializer newInit = new JsPropertyInitializer();
+ JsPropertyInitializer newInit = new JsPropertyInitializer(x.getSourceInfo());
newInit.setValueExpr(stack.pop());
newInit.setLabelExpr(stack.pop());
@@ -185,14 +185,14 @@
@Override
public void endVisit(JsPostfixOperation x, JsContext<JsExpression> ctx) {
- JsPostfixOperation toReturn = new JsPostfixOperation(x.getOperator());
+ JsPostfixOperation toReturn = new JsPostfixOperation(x.getSourceInfo(), x.getOperator());
toReturn.setArg(stack.pop());
stack.push(toReturn);
}
@Override
public void endVisit(JsPrefixOperation x, JsContext<JsExpression> ctx) {
- JsPrefixOperation toReturn = new JsPrefixOperation(x.getOperator());
+ JsPrefixOperation toReturn = new JsPrefixOperation(x.getSourceInfo(), x.getOperator());
toReturn.setArg(stack.pop());
stack.push(toReturn);
}
diff --git a/dev/core/src/com/google/gwt/dev/js/JsIEBlockSizeVisitor.java b/dev/core/src/com/google/gwt/dev/js/JsIEBlockSizeVisitor.java
index 56d6d85..8927798 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsIEBlockSizeVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsIEBlockSizeVisitor.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.js;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.js.ast.JsBlock;
import com.google.gwt.dev.js.ast.JsCase;
import com.google.gwt.dev.js.ast.JsContext;
@@ -51,6 +52,12 @@
*/
private static class BlockVisitor extends JsVisitor {
+ private final JsProgram program;
+
+ public BlockVisitor(JsProgram program) {
+ this.program = program;
+ }
+
@Override
public void endVisit(JsBlock x, JsContext<JsStatement> ctx) {
restructure(x.getStatements());
@@ -71,6 +78,8 @@
* necessary to prevent any given block from exceeding the maximum size.
*/
private void restructure(List<JsStatement> statements) {
+ SourceInfo sourceInfo = program.createSourceInfoSynthetic(
+ JsIEBlockSizeVisitor.class, "Restructured to reduce block size");
// This outer loop will collapse the newly-created block into super-blocks
while (statements.size() > MAX_BLOCK_SIZE) {
ListIterator<JsStatement> i = statements.listIterator();
@@ -82,7 +91,7 @@
if (statementsInNewBlock == null) {
// Replace the current statement with a new block
- JsBlock newBlock = new JsBlock();
+ JsBlock newBlock = new JsBlock(sourceInfo);
statementsInNewBlock = newBlock.getStatements();
i.set(newBlock);
} else {
@@ -118,6 +127,6 @@
* Entry point.
*/
public static void exec(JsProgram program) {
- (new BlockVisitor()).accept(program);
+ (new BlockVisitor(program)).accept(program);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/js/JsInliner.java b/dev/core/src/com/google/gwt/dev/js/JsInliner.java
index 9b4c2b3..faad0bb 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsInliner.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsInliner.java
@@ -15,7 +15,9 @@
*/
package com.google.gwt.dev.js;
+import com.google.gwt.dev.jjs.HasSourceInfo;
import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.js.ast.JsArrayAccess;
import com.google.gwt.dev.js.ast.JsArrayLiteral;
import com.google.gwt.dev.js.ast.JsBinaryOperation;
@@ -45,6 +47,7 @@
import com.google.gwt.dev.js.ast.JsPostfixOperation;
import com.google.gwt.dev.js.ast.JsPrefixOperation;
import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsProgramFragment;
import com.google.gwt.dev.js.ast.JsRegExp;
import com.google.gwt.dev.js.ast.JsReturn;
import com.google.gwt.dev.js.ast.JsScope;
@@ -71,7 +74,7 @@
/**
* Perform inlining optimizations on the JavaScript AST.
*
- * TODO(bobv): remove anything that's duplicating work with {@link JsStaticEval};
+ * TODO(bobv): remove anything that's duplicating work with {@link JsStaticEval}
* migrate other stuff to that class perhaps.
*/
public class JsInliner {
@@ -152,6 +155,12 @@
return op.getOperator().equals(JsBinaryOperator.COMMA) ? op : null;
}
+ private final List<JsName> localVariableNames;
+
+ public CommaNormalizer(List<JsName> localVariableNames) {
+ this.localVariableNames = localVariableNames;
+ }
+
@Override
public void endVisit(JsBinaryOperation x, JsContext<JsExpression> ctx) {
if (isComma(x) == null) {
@@ -177,6 +186,41 @@
x.setArg1(inner.getArg1());
didChange = true;
}
+
+ /*
+ * Eliminate the pattern (localVar = expr, localVar). This tends to
+ * occur when a method interacted with pruned fields or had statements
+ * removed.
+ */
+ JsName assignmentRef = null;
+ JsExpression expr = null;
+ JsName returnRef = null;
+
+ if (x.getArg1() instanceof JsBinaryOperation) {
+ JsBinaryOperation op = (JsBinaryOperation) x.getArg1();
+ if (op.getOperator() == JsBinaryOperator.ASG
+ && op.getArg1() instanceof JsNameRef) {
+ JsNameRef nameRef = (JsNameRef) op.getArg1();
+ if (nameRef.getQualifier() == null) {
+ assignmentRef = nameRef.getName();
+ expr = op.getArg2();
+ }
+ }
+ }
+
+ if (x.getArg2() instanceof JsNameRef) {
+ JsNameRef nameRef = (JsNameRef) x.getArg2();
+ if (nameRef.getQualifier() == null) {
+ returnRef = nameRef.getName();
+ }
+ }
+
+ if (assignmentRef != null && assignmentRef.equals(returnRef)
+ && localVariableNames.contains(assignmentRef)) {
+ assert expr != null;
+ localVariableNames.remove(assignmentRef);
+ ctx.replaceMe(expr);
+ }
return;
}
@@ -189,7 +233,9 @@
* Create a new comma expression with the original LHS and the LHS of the
* nested comma expression.
*/
- JsBinaryOperation newOp = new JsBinaryOperation(JsBinaryOperator.COMMA);
+ JsBinaryOperation newOp = new JsBinaryOperation(
+ x.getSourceInfo().makeChild(CommaNormalizer.class,
+ "Simplifying comma expression"), JsBinaryOperator.COMMA);
newOp.setArg1(x.getArg1());
newOp.setArg2(toUpdate.getArg1());
@@ -593,9 +639,9 @@
* parameters to ensure that an exception does not prevent their evaluation.
*
* In the case of a nested invocation, such as
- * <code>F(r1, r2, G(r3, r4), f1);</code> the evaluation order is
- * guaranteed to be maintained, provided that no required parameters occur
- * after the nested invocation.
+ * <code>F(r1, r2, G(r3, r4), f1);</code> the evaluation order is guaranteed
+ * to be maintained, provided that no required parameters occur after the
+ * nested invocation.
*/
@Override
public void endVisit(JsInvocation x, JsContext<JsExpression> ctx) {
@@ -677,10 +723,14 @@
private final Set<JsFunction> blacklist = new HashSet<JsFunction>();
private final Stack<JsFunction> functionStack = new Stack<JsFunction>();
private final InvocationCountingVisitor invocationCountingVisitor = new InvocationCountingVisitor();
-
private final Stack<List<JsName>> newLocalVariableStack = new Stack<List<JsName>>();
private final JsProgram program;
+ /**
+ * Not a stack because program fragments aren't nested.
+ */
+ private JsFunction programFunction;
+
public InliningVisitor(JsProgram program) {
this.program = program;
invocationCountingVisitor.accept(program);
@@ -727,7 +777,7 @@
* side-effects.
*/
if (op.getArg2().hasSideEffects()) {
- statements.add(0, new JsExprStmt(op.getArg2()));
+ statements.add(0, op.getArg2().makeStmt());
}
e = op.getArg1();
@@ -739,7 +789,7 @@
* side-effects.
*/
if (e.hasSideEffects()) {
- statements.add(0, new JsExprStmt(e));
+ statements.add(0, e.makeStmt());
}
if (statements.size() == 0) {
@@ -760,7 +810,8 @@
* single JsExprStmt with a JsBlock that contains all of the
* statements.
*/
- JsBlock b = new JsBlock();
+ JsBlock b = new JsBlock(x.getSourceInfo().makeChild(
+ InliningVisitor.class, "Block required for control function"));
b.getStatements().addAll(statements);
ctx.replaceMe(b);
return;
@@ -781,31 +832,10 @@
throw new InternalCompilerException("Unexpected function popped");
}
+ JsBlock body = x.getBody();
List<JsName> newLocalVariables = newLocalVariableStack.pop();
- // Nothing to do
- if (newLocalVariables.isEmpty()) {
- return;
- }
-
- List<JsStatement> statements = x.getBody().getStatements();
-
- // The body can't be empty if we have local variables to create
- assert !statements.isEmpty();
-
- // Find or create the JsVars as the first statement
- JsVars vars;
- if (statements.get(0) instanceof JsVars) {
- vars = (JsVars) statements.get(0);
- } else {
- vars = new JsVars();
- statements.add(0, vars);
- }
-
- // Add all variables
- for (JsName name : newLocalVariables) {
- vars.add(new JsVar(name));
- }
+ addVars(x, body, newLocalVariables);
}
@Override
@@ -831,13 +861,22 @@
return;
}
- List<JsName> localVariableNames = new ArrayList<JsName>();
- List<JsStatement> statements = new ArrayList<JsStatement>(
- f.getBody().getStatements());
+ List<JsStatement> statements;
+ if (f.getBody() != null) {
+ statements = new ArrayList<JsStatement>(f.getBody().getStatements());
+ } else {
+ /*
+ * Will see this with certain classes whose clinits are folded into the
+ * main JsProgram body.
+ */
+ statements = Collections.emptyList();
+ }
+
List<JsExpression> hoisted = new ArrayList<JsExpression>(
statements.size());
-
+ List<JsName> localVariableNames = new ArrayList<JsName>();
boolean sawReturnStatement = false;
+
for (JsStatement statement : statements) {
if (sawReturnStatement) {
/*
@@ -869,10 +908,11 @@
return;
}
- hoisted.add(h);
-
if (isReturnStatement(statement)) {
sawReturnStatement = true;
+ hoisted.add(h);
+ } else if (hasSideEffects(Collections.singletonList(h))) {
+ hoisted.add(h);
}
}
@@ -893,10 +933,12 @@
* ensures that this logic will function correctly in the case of a single
* expression.
*/
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ InliningVisitor.class, "Inlined invocation");
ListIterator<JsExpression> i = hoisted.listIterator(hoisted.size());
JsExpression op = i.previous();
while (i.hasPrevious()) {
- JsBinaryOperation outerOp = new JsBinaryOperation(
+ JsBinaryOperation outerOp = new JsBinaryOperation(sourceInfo,
JsBinaryOperator.COMMA);
outerOp.setArg1(i.previous());
outerOp.setArg2(op);
@@ -932,7 +974,7 @@
op = v.accept(op);
// Normalize any nested comma expressions that we may have generated.
- op = (new CommaNormalizer()).accept(op);
+ op = (new CommaNormalizer(localVariableNames)).accept(op);
/*
* Compare the relative complexity of the original invocation versus the
@@ -945,6 +987,12 @@
return;
}
+ if (functionStack.peek() == programFunction
+ && localVariableNames.size() > 0) {
+ // Don't add additional variables to the top-level program.
+ return;
+ }
+
// We've committed to the inlining, ensure the vars are created
newLocalVariableStack.peek().addAll(localVariableNames);
@@ -963,12 +1011,78 @@
}
@Override
+ public void endVisit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+ if (!functionStack.pop().equals(programFunction)) {
+ throw new InternalCompilerException("Unexpected function popped");
+ }
+
+ assert programFunction.getBody().getStatements().size() == 0 : "Should not have moved statements into program";
+
+ List<JsName> newLocalVariables = newLocalVariableStack.pop();
+ assert newLocalVariables.size() == 0 : "Should not have tried to create variables in program";
+ }
+
+ @Override
+ public boolean visit(JsExprStmt x, JsContext<JsStatement> ctx) {
+ if (functionStack.peek() == programFunction) {
+ /* Don't inline top-level invocations. */
+ if (x.getExpression() instanceof JsInvocation) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
public boolean visit(JsFunction x, JsContext<JsExpression> ctx) {
functionStack.push(x);
newLocalVariableStack.push(new ArrayList<JsName>());
return true;
}
+ /**
+ * Create a synthetic context to attempt to simplify statements in the
+ * top-level of the program.
+ */
+ @Override
+ public boolean visit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+ programFunction = new JsFunction(program.getSourceInfo(),
+ program.getScope());
+ programFunction.setBody(new JsBlock(x.getSourceInfo()));
+ functionStack.push(programFunction);
+ newLocalVariableStack.push(new ArrayList<JsName>());
+ return true;
+ }
+
+ private void addVars(HasSourceInfo x, JsBlock body,
+ List<JsName> newLocalVariables) {
+ // Nothing to do
+ if (newLocalVariables.isEmpty()) {
+ return;
+ }
+
+ List<JsStatement> statements = body.getStatements();
+
+ // The body can't be empty if we have local variables to create
+ assert !statements.isEmpty();
+
+ // Find or create the JsVars as the first statement
+ SourceInfo sourceInfo = x.getSourceInfo().makeChild(
+ InliningVisitor.class, "Synthetic locals");
+ JsVars vars;
+ if (statements.get(0) instanceof JsVars) {
+ vars = (JsVars) statements.get(0);
+ } else {
+ vars = new JsVars(sourceInfo);
+ statements.add(0, vars);
+ }
+
+ // Add all variables
+ for (JsName name : newLocalVariables) {
+ vars.add(new JsVar(sourceInfo, name));
+ }
+ }
+
private boolean isInvokedMoreThanOnce(JsFunction f) {
Integer count = invocationCountingVisitor.invocationCount(f);
return count == null || count > 1;
@@ -1008,7 +1122,7 @@
}
/**
- * Like accept(), but remove counts for all invocations in <code>expr</code>.
+ * Like accept(), but remove counts for all invocations in expr.
*/
public void removeCountsFor(JsExpression expr) {
assert (!removingCounts);
@@ -1067,7 +1181,9 @@
return;
}
- JsExpression replacement = tryGetReplacementExpression(x.getName());
+ JsExpression replacement = tryGetReplacementExpression(
+ x.getSourceInfo().makeChild(NameRefReplacerVisitor.class,
+ "Inlined expression"), x.getName());
if (replacement != null) {
ctx.replaceMe(replacement);
@@ -1089,10 +1205,11 @@
/**
* Determine the replacement expression to use in place of a reference to a
- * given name. Returns <code>null</code> if no replacement has been set
- * for the name.
+ * given name. Returns <code>null</code> if no replacement has been set for
+ * the name.
*/
- private JsExpression tryGetReplacementExpression(JsName name) {
+ private JsExpression tryGetReplacementExpression(SourceInfo sourceInfo,
+ JsName name) {
if (paramsToArgsMap.containsKey(name)) {
/*
* TODO if we ever allow mutable JsExpression types to be considered
@@ -1101,7 +1218,7 @@
return paramsToArgsMap.get(name);
} else if (nameReplacements.containsKey(name)) {
- return nameReplacements.get(name).makeRef();
+ return nameReplacements.get(name).makeRef(sourceInfo);
} else {
return null;
@@ -1512,13 +1629,15 @@
// Extract the initialization expression
JsExpression init = var.getInitExpr();
if (init != null) {
- JsBinaryOperation assignment = new JsBinaryOperation(
+ SourceInfo sourceInfo = var.getSourceInfo().makeChild(
+ JsInliner.class, "Hoisted initializer into inline site");
+ JsBinaryOperation assignment = new JsBinaryOperation(sourceInfo,
JsBinaryOperator.ASG);
- assignment.setArg1(var.getName().makeRef());
+ assignment.setArg1(var.getName().makeRef(sourceInfo));
assignment.setArg2(init);
// Multiple initializers go into a comma expression
- JsBinaryOperation comma = new JsBinaryOperation(
+ JsBinaryOperation comma = new JsBinaryOperation(sourceInfo,
JsBinaryOperator.COMMA);
comma.setArg1(expression);
comma.setArg2(assignment);
@@ -1607,7 +1726,6 @@
* are disjoint. This prevents inlining of the following:
*
* static int i; public void add(int a) { i += a; }; add(i++);
- *
*/
if (hasCommonIdents(arguments, toInline, parameterIdents)) {
return false;
diff --git a/dev/core/src/com/google/gwt/dev/js/JsParser.java b/dev/core/src/com/google/gwt/dev/js/JsParser.java
index e28e8e1..750f102 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsParser.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsParser.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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.js;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.js.ast.JsArrayAccess;
import com.google.gwt.dev.js.ast.JsArrayLiteral;
import com.google.gwt.dev.js.ast.JsBinaryOperation;
@@ -78,7 +79,9 @@
public class JsParser {
private JsProgram program;
+ private SourceInfo rootSourceInfo = SourceInfo.UNKNOWN;
private final Stack<JsScope> scopeStack = new Stack<JsScope>();
+ private final Stack<SourceInfo> sourceInfoStack = new Stack<SourceInfo>();
public JsParser() {
// Create a custom error handler so that we can throw our own exceptions.
@@ -114,7 +117,7 @@
// Map the Rhino AST to ours.
//
program = scope.getProgram();
- pushScope(scope);
+ pushScope(scope, rootSourceInfo);
List<JsStatement> stmts = mapStatements(topNode);
popScope();
@@ -133,6 +136,13 @@
}
}
+ /**
+ * Set the base SourceInfo object to use when creating new JS AST nodes.
+ */
+ public void setSourceInfo(SourceInfo sourceInfo) {
+ rootSourceInfo = sourceInfo;
+ }
+
private JsParserException createParserException(String msg, Node offender) {
// TODO: get source info
offender.getLineno();
@@ -143,11 +153,19 @@
return scopeStack.peek();
}
+ private SourceInfo makeSourceInfo(Node node) {
+ SourceInfo parent = sourceInfoStack.peek();
+ SourceInfo toReturn = program.createSourceInfo(node.getLineno()
+ + parent.getStartLine() + 1, parent.getFileName());
+ toReturn.copyMissingCorrelationsFrom(parent);
+ return toReturn;
+ }
+
private JsNode<?> map(Node node) throws JsParserException {
switch (node.getType()) {
case TokenStream.SCRIPT: {
- JsBlock block = new JsBlock();
+ JsBlock block = new JsBlock(makeSourceInfo(node));
mapStatements(block.getStatements(), node);
return block;
}
@@ -223,7 +241,8 @@
return mapName(node);
case TokenStream.STRING:
- return program.getStringLiteral(node.getString());
+ return program.getStringLiteral(sourceInfoStack.peek().makeChild(
+ JsParser.class, "JS String literal"), node.getString());
case TokenStream.NUMBER:
return mapNumber(node);
@@ -320,7 +339,7 @@
}
private JsArrayLiteral mapArrayLit(Node node) throws JsParserException {
- JsArrayLiteral toLit = new JsArrayLiteral();
+ JsArrayLiteral toLit = new JsArrayLiteral(makeSourceInfo(node));
Node from = node.getFirstChild();
while (from != null) {
toLit.getExpressions().add(mapExpression(from));
@@ -341,7 +360,7 @@
if (unknown instanceof JsStringLiteral) {
JsStringLiteral lit = (JsStringLiteral) unknown;
String litName = lit.getValue();
- return new JsNameRef(litName);
+ return new JsNameRef(makeSourceInfo(nameRefNode), litName);
} else {
throw createParserException("Expecting a name reference", nameRefNode);
}
@@ -400,11 +419,11 @@
JsExpression to1 = mapExpression(from1);
JsExpression to2 = mapExpression(from2);
- return new JsBinaryOperation(op, to1, to2);
+ return new JsBinaryOperation(makeSourceInfo(node), op, to1, to2);
}
private JsBlock mapBlock(Node nodeStmts) throws JsParserException {
- JsBlock block = new JsBlock();
+ JsBlock block = new JsBlock(makeSourceInfo(nodeStmts));
mapStatements(block.getStatements(), nodeStmts);
return block;
}
@@ -412,14 +431,14 @@
private JsBreak mapBreak(Node breakNode) {
Node fromLabel = breakNode.getFirstChild();
if (fromLabel != null) {
- return new JsBreak(mapName(fromLabel));
+ return new JsBreak(makeSourceInfo(breakNode), mapName(fromLabel));
} else {
- return new JsBreak();
+ return new JsBreak(makeSourceInfo(breakNode));
}
}
private JsInvocation mapCall(Node callNode) throws JsParserException {
- JsInvocation invocation = new JsInvocation();
+ JsInvocation invocation = new JsInvocation(makeSourceInfo(callNode));
// Map the target expression.
//
@@ -441,7 +460,7 @@
}
private JsExpression mapConditional(Node condNode) throws JsParserException {
- JsConditional toCond = new JsConditional();
+ JsConditional toCond = new JsConditional(makeSourceInfo(condNode));
Node fromTest = condNode.getFirstChild();
toCond.setTestExpression(mapExpression(fromTest));
@@ -458,9 +477,9 @@
private JsContinue mapContinue(Node contNode) {
Node fromLabel = contNode.getFirstChild();
if (fromLabel != null) {
- return new JsContinue(mapName(fromLabel));
+ return new JsContinue(makeSourceInfo(contNode), mapName(fromLabel));
} else {
- return new JsContinue();
+ return new JsContinue(makeSourceInfo(contNode));
}
}
@@ -474,9 +493,11 @@
Node from = node.getFirstChild();
JsExpression to = mapExpression(from);
if (to instanceof JsNameRef) {
- return new JsPrefixOperation(JsUnaryOperator.DELETE, to);
+ return new JsPrefixOperation(makeSourceInfo(node),
+ JsUnaryOperator.DELETE, to);
} else if (to instanceof JsArrayAccess) {
- return new JsPrefixOperation(JsUnaryOperator.DELETE, to);
+ return new JsPrefixOperation(makeSourceInfo(node),
+ JsUnaryOperator.DELETE, to);
} else {
throw createParserException(
"'delete' can only operate on property names and array elements",
@@ -510,9 +531,9 @@
// Create and attach the "while" or "do" statement we're mapping to.
//
if (isWhile) {
- return new JsWhile(toTestExpr, toBody);
+ return new JsWhile(makeSourceInfo(ifNode), toTestExpr, toBody);
} else {
- return new JsDoWhile(toTestExpr, toBody);
+ return new JsDoWhile(makeSourceInfo(ifNode), toTestExpr, toBody);
}
}
@@ -578,7 +599,7 @@
Node fromIterVarName = fromIter.getFirstChild();
String fromName = fromIterVarName.getString();
JsName toName = getScope().declareName(fromName);
- toForIn = new JsForIn(toName);
+ toForIn = new JsForIn(makeSourceInfo(forNode), toName);
Node fromIterInit = fromIterVarName.getFirstChild();
if (fromIterInit != null) {
// That has an initializer expression (useful only for side effects).
@@ -588,7 +609,7 @@
} else {
// An unnamed iterator var.
//
- toForIn = new JsForIn();
+ toForIn = new JsForIn(makeSourceInfo(forNode));
toForIn.setIterExpr(mapExpression(fromIter));
}
toForIn.setObjExpr(mapExpression(fromObjExpr));
@@ -606,7 +627,7 @@
} else {
// Regular ol' for loop.
//
- JsFor toFor = new JsFor();
+ JsFor toFor = new JsFor(makeSourceInfo(forNode));
// The first item is either an expression or a JsVars.
//
@@ -648,18 +669,19 @@
// Create it, and set the params.
//
- JsFunction toFn = new JsFunction(getScope(), toFnName);
+ SourceInfo fnSourceInfo = makeSourceInfo(fnNode);
+ JsFunction toFn = new JsFunction(fnSourceInfo, getScope(), toFnName);
// Creating a function also creates a new scope, which we push onto
// the scope stack.
//
- pushScope(toFn.getScope());
+ pushScope(toFn.getScope(), fnSourceInfo);
while (fromParamNode != null) {
String fromParamName = fromParamNode.getString();
// should this be unique? I think not since you can have dup args.
JsName paramName = toFn.getScope().declareName(fromParamName);
- toFn.getParameters().add(new JsParameter(paramName));
+ toFn.getParameters().add(new JsParameter(fnSourceInfo, paramName));
fromParamNode = fromParamNode.getNext();
}
@@ -682,7 +704,7 @@
JsExpression to1 = mapExpression(from1);
JsExpression to2 = mapExpression(from2);
- return new JsArrayAccess(to1, to2);
+ return new JsArrayAccess(makeSourceInfo(getElemNode), to1, to2);
}
private JsNameRef mapGetProp(Node getPropNode) throws JsParserException {
@@ -698,7 +720,7 @@
//
Object obj = getPropNode.getProp(Node.SPECIAL_PROP_PROP);
assert (obj instanceof String);
- toNameRef = new JsNameRef((String) obj);
+ toNameRef = new JsNameRef(makeSourceInfo(getPropNode), (String) obj);
}
toNameRef.setQualifier(toQualifier);
@@ -715,7 +737,7 @@
// Create the "if" statement we're mapping to.
//
- JsIf toIf = new JsIf();
+ JsIf toIf = new JsIf(makeSourceInfo(ifNode));
// Map the test expression.
//
@@ -752,7 +774,7 @@
String fromName = labelNode.getFirstChild().getString();
JsName toName = getScope().declareName(fromName);
Node fromStmt = labelNode.getFirstChild().getNext();
- JsLabel toLabel = new JsLabel(toName);
+ JsLabel toLabel = new JsLabel(makeSourceInfo(labelNode), toName);
toLabel.setStmt(mapStatement(fromStmt));
return toLabel;
}
@@ -763,12 +785,12 @@
*/
private JsNameRef mapName(Node node) {
String ident = node.getString();
- return new JsNameRef(ident);
+ return new JsNameRef(makeSourceInfo(node), ident);
}
private JsNew mapNew(Node newNode) throws JsParserException {
- JsNew newExpr = new JsNew();
+ JsNew newExpr = new JsNew(makeSourceInfo(newNode));
// Map the constructor expression, which is often just the name of
// some lambda.
@@ -793,7 +815,7 @@
}
private JsExpression mapObjectLit(Node objLitNode) throws JsParserException {
- JsObjectLiteral toLit = new JsObjectLiteral();
+ JsObjectLiteral toLit = new JsObjectLiteral(makeSourceInfo(objLitNode));
Node fromPropInit = objLitNode.getFirstChild();
while (fromPropInit != null) {
@@ -810,8 +832,8 @@
}
JsExpression toValueExpr = mapExpression(fromValueExpr);
- JsPropertyInitializer toPropInit = new JsPropertyInitializer(toLabelExpr,
- toValueExpr);
+ JsPropertyInitializer toPropInit = new JsPropertyInitializer(
+ makeSourceInfo(fromLabelExpr), toLabelExpr, toValueExpr);
toLit.getPropertyInitializers().add(toPropInit);
// Begin the next property initializer, if there is one.
@@ -839,20 +861,20 @@
throws JsParserException {
Node from = node.getFirstChild();
JsExpression to = mapExpression(from);
- return new JsPostfixOperation(op, to);
+ return new JsPostfixOperation(makeSourceInfo(node), op, to);
}
private JsExpression mapPrefixOperation(JsUnaryOperator op, Node node)
throws JsParserException {
Node from = node.getFirstChild();
JsExpression to = mapExpression(from);
- return new JsPrefixOperation(op, to);
+ return new JsPrefixOperation(makeSourceInfo(node), op, to);
}
private JsExpression mapPrimary(Node node) throws JsParserException {
switch (node.getIntDatum()) {
case TokenStream.THIS:
- return new JsThisRef();
+ return new JsThisRef(makeSourceInfo(node));
case TokenStream.TRUE:
return program.getTrueLiteral();
@@ -862,6 +884,9 @@
case TokenStream.NULL:
return program.getNullLiteral();
+
+ case TokenStream.UNDEFINED:
+ return program.getUndefinedLiteral();
default:
throw new JsParserException("Unknown primary: " + node.getIntDatum());
@@ -869,7 +894,7 @@
}
private JsNode<?> mapRegExp(Node regExpNode) {
- JsRegExp toRegExp = new JsRegExp();
+ JsRegExp toRegExp = new JsRegExp(makeSourceInfo(regExpNode));
Node fromPattern = regExpNode.getFirstChild();
toRegExp.setPattern(fromPattern.getString());
@@ -910,7 +935,7 @@
}
private JsReturn mapReturn(Node returnNode) throws JsParserException {
- JsReturn toReturn = new JsReturn();
+ JsReturn toReturn = new JsReturn(makeSourceInfo(returnNode));
Node from = returnNode.getFirstChild();
if (from != null) {
JsExpression to = mapExpression(from);
@@ -930,7 +955,8 @@
Node fromRhs = setElemNode.getFirstChild().getNext().getNext();
JsExpression toRhs = mapExpression(fromRhs);
- return new JsBinaryOperation(JsBinaryOperator.ASG, lhs, toRhs);
+ return new JsBinaryOperation(makeSourceInfo(setElemNode),
+ JsBinaryOperator.ASG, lhs, toRhs);
}
private JsExpression mapSetProp(Node getPropNode) throws JsParserException {
@@ -943,7 +969,8 @@
Node fromRhs = getPropNode.getFirstChild().getNext().getNext();
JsExpression toRhs = mapExpression(fromRhs);
- return new JsBinaryOperation(JsBinaryOperator.ASG, lhs, toRhs);
+ return new JsBinaryOperation(makeSourceInfo(getPropNode),
+ JsBinaryOperator.ASG, lhs, toRhs);
}
private JsExpression mapShiftVariant(Node shiftNode) throws JsParserException {
@@ -1003,7 +1030,7 @@
}
private JsSwitch mapSwitchStatement(Node switchNode) throws JsParserException {
- JsSwitch toSwitch = new JsSwitch();
+ JsSwitch toSwitch = new JsSwitch(makeSourceInfo(switchNode));
// The switch expression.
//
@@ -1015,7 +1042,7 @@
Node fromMember = fromSwitchExpr.getNext();
while (fromMember != null) {
if (fromMember.getType() == TokenStream.CASE) {
- JsCase toCase = new JsCase();
+ JsCase toCase = new JsCase(makeSourceInfo(fromMember));
// Set the case expression. In JS, this can be any expression.
//
@@ -1035,7 +1062,7 @@
// If more than one is present, we keep the last one.
//
assert (fromMember.getType() == TokenStream.DEFAULT);
- JsDefault toDefault = new JsDefault();
+ JsDefault toDefault = new JsDefault(makeSourceInfo(fromMember));
// Set the default statements.
//
@@ -1056,12 +1083,13 @@
// Create, map, and attach.
//
Node fromExpr = throwNode.getFirstChild();
- JsThrow toThrow = new JsThrow(mapExpression(fromExpr));
+ JsThrow toThrow = new JsThrow(makeSourceInfo(throwNode),
+ mapExpression(fromExpr));
return toThrow;
}
private JsTry mapTryStatement(Node tryNode) throws JsParserException {
- JsTry toTry = new JsTry();
+ JsTry toTry = new JsTry(makeSourceInfo(tryNode));
// Map the "try" body.
//
@@ -1077,7 +1105,8 @@
// Map the catch variable.
//
Node fromCatchVarName = fromCatchNode.getFirstChild();
- JsCatch catchBlock = new JsCatch(getScope(), fromCatchVarName.getString());
+ JsCatch catchBlock = new JsCatch(makeSourceInfo(fromCatchNode),
+ getScope(), fromCatchVarName.getString());
// Pre-advance to the next catch block, if any.
// We do this here to decide whether or not this is the last one.
@@ -1104,7 +1133,7 @@
// Map the catch body.
//
Node fromCatchBody = fromCondition.getNext();
- pushScope(catchBlock.getScope());
+ pushScope(catchBlock.getScope(), catchBlock.getSourceInfo());
catchBlock.setBody(mapBlock(fromCatchBody));
popScope();
@@ -1149,7 +1178,7 @@
}
private JsVars mapVar(Node varNode) throws JsParserException {
- JsVars toVars = new JsVars();
+ JsVars toVars = new JsVars(makeSourceInfo(varNode));
Node fromVar = varNode.getFirstChild();
while (fromVar != null) {
// Use a conservative name allocation strategy that allocates all names
@@ -1158,7 +1187,7 @@
//
String fromName = fromVar.getString();
JsName toName = getScope().declareName(fromName);
- JsVars.JsVar toVar = new JsVars.JsVar(toName);
+ JsVars.JsVar toVar = new JsVars.JsVar(makeSourceInfo(fromVar), toName);
Node fromInit = fromVar.getFirstChild();
if (fromInit != null) {
@@ -1186,9 +1215,11 @@
private void popScope() {
scopeStack.pop();
+ sourceInfoStack.pop();
}
- private void pushScope(JsScope scope) {
+ private void pushScope(JsScope scope, SourceInfo sourceInfo) {
scopeStack.push(scope);
+ sourceInfoStack.push(sourceInfo);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/js/JsReportGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/js/JsReportGenerationVisitor.java
new file mode 100644
index 0000000..080a38e
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/js/JsReportGenerationVisitor.java
@@ -0,0 +1,99 @@
+/*
+ * 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.js;
+
+import com.google.gwt.core.ext.soyc.Range;
+import com.google.gwt.dev.jjs.HasSourceInfo;
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.js.ast.JsVisitable;
+import com.google.gwt.dev.util.AbstractTextOutput;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A variation on the standard source generation visitor that records the
+ * locations of SourceInfo objects in the output.
+ */
+public class JsReportGenerationVisitor extends JsSourceGenerationVisitor {
+ /**
+ * A TextOutput that can return the total number of characters that have been
+ * printed.
+ */
+ public static class CountingTextOutput extends AbstractTextOutput {
+ private final StringWriter sw = new StringWriter();
+ private final PrintWriter out = new PrintWriter(sw);
+
+ public CountingTextOutput(boolean compact) {
+ super(compact);
+ setPrintWriter(out);
+ }
+
+ public int getCount() {
+ out.flush();
+ return sw.getBuffer().length();
+ }
+
+ @Override
+ public String toString() {
+ out.flush();
+ return sw.toString();
+ }
+ }
+
+ private final Map<Range, SourceInfo> sourceInfoMap = new HashMap<Range, SourceInfo>();
+ private final CountingTextOutput out;
+
+ public JsReportGenerationVisitor(CountingTextOutput out) {
+ super(out);
+ this.out = out;
+ }
+
+ public Map<Range, SourceInfo> getSourceInfoMap() {
+ return Collections.unmodifiableMap(sourceInfoMap);
+ }
+
+ @Override
+ protected <T extends JsVisitable<T>> T doAccept(T node) {
+ boolean addEntry = node instanceof HasSourceInfo;
+ int start = addEntry ? out.getCount() : 0;
+ T toReturn = super.doAccept(node);
+ if (addEntry) {
+ SourceInfo info = ((HasSourceInfo) node).getSourceInfo();
+ sourceInfoMap.put(new Range(start, out.getCount()), info);
+ }
+ return toReturn;
+ }
+
+ @Override
+ protected <T extends JsVisitable<T>> void doAcceptList(List<T> collection) {
+ for (T t : collection) {
+ doAccept(t);
+ }
+ }
+
+ @Override
+ protected <T extends JsVisitable<T>> void doAcceptWithInsertRemove(
+ List<T> collection) {
+ for (T t : collection) {
+ doAccept(t);
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitor.java
index ad1a780..4a15d4a 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitor.java
@@ -18,6 +18,7 @@
import com.google.gwt.dev.js.ast.JsBlock;
import com.google.gwt.dev.js.ast.JsContext;
import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsProgramFragment;
import com.google.gwt.dev.js.ast.JsStatement;
import com.google.gwt.dev.util.TextOutput;
@@ -30,11 +31,19 @@
super(out);
}
+ @Override
public boolean visit(JsProgram x, JsContext<JsProgram> ctx) {
// Descend naturally.
return true;
}
+ @Override
+ public boolean visit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+ // Descend naturally.
+ return true;
+ }
+
+ @Override
public boolean visit(JsBlock x, JsContext<JsStatement> ctx) {
printJsBlockOptionalTruncate(x, false);
return false;
diff --git a/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java b/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
index 050bc77..12a1d2f 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.js;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.js.ast.CanBooleanEval;
import com.google.gwt.dev.js.ast.JsBinaryOperation;
import com.google.gwt.dev.js.ast.JsBinaryOperator;
@@ -44,9 +45,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
-import java.util.ListIterator;
import java.util.Set;
-import java.util.Stack;
/**
* Removes JsFunctions that are never referenced in the program.
@@ -80,85 +79,6 @@
}
/**
- * Force all functions to be evaluated at the top of the lexical scope in
- * which they reside. This makes {@link StaticEvalVisitor} simpler in that we
- * no longer have to worry about function declarations within expressions.
- * After this runs, only statements can contain declarations. Moved functions
- * will end up just before the statement in which they presently reside.
- */
- private class EvalFunctionsAtTopScope extends JsModVisitor {
- private final Set<JsFunction> dontMove = new HashSet<JsFunction>();
- private final Stack<ListIterator<JsStatement>> itrStack = new Stack<ListIterator<JsStatement>>();
- private final Stack<JsBlock> scopeStack = new Stack<JsBlock>();
-
- @Override
- public void endVisit(JsFunction x, JsContext<JsExpression> ctx) {
- scopeStack.pop();
- }
-
- @Override
- public void endVisit(JsProgram x, JsContext<JsProgram> ctx) {
- scopeStack.pop();
- }
-
- @Override
- public boolean visit(JsBlock x, JsContext<JsStatement> ctx) {
- if (x == scopeStack.peek()) {
- ListIterator<JsStatement> itr = x.getStatements().listIterator();
- itrStack.push(itr);
- while (itr.hasNext()) {
- JsStatement stmt = itr.next();
- JsFunction func = isFunctionDecl(stmt);
- // Already at the top level.
- if (func != null) {
- dontMove.add(func);
- }
- accept(stmt);
- if (func != null) {
- dontMove.remove(func);
- }
- }
- itrStack.pop();
- // Already visited.
- return false;
- } else {
- // Just do normal visitation.
- return true;
- }
- }
-
- @Override
- public boolean visit(JsFunction x, JsContext<JsExpression> ctx) {
- /*
- * We do this during visit() to preserve first-to-last evaluation order.
- */
- if (x.getName() != null && !dontMove.contains(x)) {
- /*
- * Reinsert this function into the statement immediately before the
- * current statement. The current statement will have already been
- * returned from the current iterator's next(), so we have to
- * backshuffle one step to get in front of it.
- */
- ListIterator<JsStatement> itr = itrStack.peek();
- itr.previous();
- itr.add(x.makeStmt());
- itr.next();
- ctx.replaceMe(x.getName().makeRef());
- }
-
- // Dive into the function itself.
- scopeStack.push(x.getBody());
- return true;
- }
-
- @Override
- public boolean visit(JsProgram x, JsContext<JsProgram> ctx) {
- scopeStack.push(x.getGlobalBlock());
- return true;
- }
- }
-
- /**
* Creates a minimalist list of statements that must be run in order to
* achieve the same declaration effect as the visited statements.
*
@@ -186,10 +106,12 @@
@Override
public void endVisit(JsVars x, JsContext<JsStatement> ctx) {
- JsVars strippedVars = new JsVars();
+ JsVars strippedVars = new JsVars(x.getSourceInfo().makeChild(
+ MustExecVisitor.class, "Simplified execution"));
boolean mustReplace = false;
for (JsVar var : x) {
- JsVar strippedVar = new JsVar(var.getName());
+ JsVar strippedVar = new JsVar(var.getSourceInfo().makeChild(
+ MustExecVisitor.class, "Simplified execution"), var.getName());
strippedVars.add(strippedVar);
if (var.getInitExpr() != null) {
mustReplace = true;
@@ -298,12 +220,16 @@
CanBooleanEval condEval = (CanBooleanEval) condExpr;
if (condEval.isBooleanTrue()) {
// e.g. (true() ? then : else) -> true() && then
- JsBinaryOperation binOp = new JsBinaryOperation(JsBinaryOperator.AND,
+ JsBinaryOperation binOp = new JsBinaryOperation(
+ x.getSourceInfo().makeChild(StaticEvalVisitor.class,
+ "Simplified always-true condition"), JsBinaryOperator.AND,
condExpr, thenExpr);
ctx.replaceMe(accept(binOp));
} else if (condEval.isBooleanFalse()) {
// e.g. (false() ? then : else) -> false() || else
- JsBinaryOperation binOp = new JsBinaryOperation(JsBinaryOperator.OR,
+ JsBinaryOperation binOp = new JsBinaryOperation(
+ x.getSourceInfo().makeChild(StaticEvalVisitor.class,
+ "Simplified always-false condition"), JsBinaryOperator.OR,
condExpr, elseExpr);
ctx.replaceMe(accept(binOp));
}
@@ -327,7 +253,8 @@
FindBreakContinueStatementsVisitor visitor = new FindBreakContinueStatementsVisitor();
visitor.accept(x.getBody());
if (!visitor.hasBreakContinueStatements()) {
- JsBlock block = new JsBlock();
+ JsBlock block = new JsBlock(x.getSourceInfo().makeChild(
+ StaticEvalVisitor.class, "Simplified always-false condition"));
block.getStatements().add(x.getBody());
block.getStatements().add(expr.makeStmt());
ctx.replaceMe(accept(block));
@@ -360,7 +287,8 @@
// If false, replace with initializers and condition.
if (cond.isBooleanFalse()) {
- JsBlock block = new JsBlock();
+ JsBlock block = new JsBlock(x.getSourceInfo().makeChild(
+ StaticEvalVisitor.class, "Simplified always-false condition"));
if (x.getInitExpr() != null) {
block.getStatements().add(x.getInitExpr().makeStmt());
}
@@ -387,6 +315,7 @@
JsExpression expr = x.getIfExpr();
JsStatement thenStmt = x.getThenStmt();
JsStatement elseStmt = x.getElseStmt();
+ SourceInfo sourceInfo;
if (expr instanceof CanBooleanEval) {
CanBooleanEval cond = (CanBooleanEval) expr;
JsStatement onlyStmtToExecute;
@@ -394,13 +323,17 @@
if (cond.isBooleanTrue()) {
onlyStmtToExecute = thenStmt;
removed = elseStmt;
+ sourceInfo = x.getSourceInfo().makeChild(StaticEvalVisitor.class,
+ "Simplified always-true condition");
} else if (cond.isBooleanFalse()) {
onlyStmtToExecute = elseStmt;
removed = thenStmt;
+ sourceInfo = x.getSourceInfo().makeChild(StaticEvalVisitor.class,
+ "Simplified always-false condition");
} else {
return;
}
- JsBlock block = new JsBlock();
+ JsBlock block = new JsBlock(sourceInfo);
block.getStatements().add(expr.makeStmt());
if (onlyStmtToExecute != null) {
@@ -452,7 +385,8 @@
// If false, replace with condition.
if (cond.isBooleanFalse()) {
- JsBlock block = new JsBlock();
+ JsBlock block = new JsBlock(x.getSourceInfo().makeChild(
+ StaticEvalVisitor.class, "Simplified always-false condition"));
block.getStatements().add(expr.makeStmt());
JsStatement decls = ensureDeclarations(x.getBody());
if (decls != null) {
@@ -525,7 +459,8 @@
} else if (stmts.size() == 1) {
return stmts.get(0);
} else {
- JsBlock jsBlock = new JsBlock();
+ JsBlock jsBlock = new JsBlock(stmt.getSourceInfo().makeChild(
+ StaticEvalVisitor.class, "Ensuring declarations"));
jsBlock.getStatements().addAll(stmts);
return jsBlock;
}
@@ -656,11 +591,9 @@
}
public boolean execImpl() {
- EvalFunctionsAtTopScope fev = new EvalFunctionsAtTopScope();
- fev.accept(program);
StaticEvalVisitor sev = new StaticEvalVisitor();
sev.accept(program);
- return fev.didChange() || sev.didChange();
+ return sev.didChange();
}
}
diff --git a/dev/core/src/com/google/gwt/dev/js/JsStringInterner.java b/dev/core/src/com/google/gwt/dev/js/JsStringInterner.java
index bc7c92d..4c10370 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsStringInterner.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsStringInterner.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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.js;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.js.ast.JsBinaryOperation;
import com.google.gwt.dev.js.ast.JsBlock;
import com.google.gwt.dev.js.ast.JsContext;
@@ -31,6 +32,7 @@
import com.google.gwt.dev.js.ast.JsVars.JsVar;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -131,7 +133,8 @@
toCreate.put(x, name);
}
- ctx.replaceMe(name.makeRef());
+ ctx.replaceMe(name.makeRef(x.getSourceInfo().makeChild(
+ JsStringInterner.class, "Interned reference")));
return false;
}
@@ -156,20 +159,11 @@
* @param scope the JsScope in which to reserve the new identifiers
* @return <code>true</code> if any changes were made to the block
*/
- public static boolean exec(JsBlock block, JsScope scope) {
+ public static boolean exec(JsProgram program, JsBlock block, JsScope scope) {
StringVisitor v = new StringVisitor(scope);
v.accept(block);
- if (v.toCreate.size() > 0) {
- // Create the pool of variable names.
- JsVars vars = new JsVars();
- for (Map.Entry<JsStringLiteral, JsName> entry : v.toCreate.entrySet()) {
- JsVar var = new JsVar(entry.getValue());
- var.setInitExpr(entry.getKey());
- vars.add(var);
- }
- block.getStatements().add(0, vars);
- }
+ createVars(program, block, v.toCreate);
return v.didChange();
}
@@ -181,10 +175,39 @@
* global block.
*
* @param program the JsProgram
- * @return <code>true</code> if any changes were made to the program
+ * @return a map from each created JsName to the string it is a literal for.
*/
- public static boolean exec(JsProgram program) {
- return exec(program.getGlobalBlock(), program.getScope());
+ public static Map<JsName, String> exec(JsProgram program) {
+ StringVisitor v = new StringVisitor(program.getScope());
+ for (int i = 0; i < program.getFragmentCount(); i++) {
+ v.accept(program.getFragmentBlock(i));
+ }
+
+ Map<JsName, String> map = new HashMap<JsName, String>();
+ for (JsStringLiteral stringLit : v.toCreate.keySet()) {
+ map.put(v.toCreate.get(stringLit), stringLit.getValue());
+ }
+
+ createVars(program, program.getGlobalBlock(), v.toCreate);
+
+ return map;
+ }
+
+ private static void createVars(JsProgram program, JsBlock block,
+ SortedMap<JsStringLiteral, JsName> toCreate) {
+ if (toCreate.size() > 0) {
+ // Create the pool of variable names.
+ JsVars vars = new JsVars(program.createSourceInfoSynthetic(
+ JsStringInterner.class, "Interned string pool"));
+ SourceInfo sourceInfo = program.createSourceInfoSynthetic(
+ JsStringInterner.class, "Interned string assignment");
+ for (Map.Entry<JsStringLiteral, JsName> entry : toCreate.entrySet()) {
+ JsVar var = new JsVar(sourceInfo, entry.getValue());
+ var.setInitExpr(entry.getKey());
+ vars.add(var);
+ }
+ block.getStatements().add(0, vars);
+ }
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/js/JsToStringGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/js/JsToStringGenerationVisitor.java
index 13fb936..f2ce3e9 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsToStringGenerationVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsToStringGenerationVisitor.java
@@ -51,6 +51,7 @@
import com.google.gwt.dev.js.ast.JsPostfixOperation;
import com.google.gwt.dev.js.ast.JsPrefixOperation;
import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsProgramFragment;
import com.google.gwt.dev.js.ast.JsPropertyInitializer;
import com.google.gwt.dev.js.ast.JsRegExp;
import com.google.gwt.dev.js.ast.JsReturn;
@@ -658,6 +659,12 @@
}
@Override
+ public boolean visit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+ p.print("<JsProgramFragment>");
+ return false;
+ }
+
+ @Override
public boolean visit(JsPropertyInitializer x,
JsContext<JsPropertyInitializer> ctx) {
// Since there are separators, we actually print the property init
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsArrayAccess.java b/dev/core/src/com/google/gwt/dev/js/ast/JsArrayAccess.java
index 2628f2e..77f6604 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsArrayAccess.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsArrayAccess.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a javascript expression for array access.
*/
@@ -24,10 +26,13 @@
private JsExpression indexExpr;
- public JsArrayAccess() {
+ public JsArrayAccess(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
- public JsArrayAccess(JsExpression arrayExpr, JsExpression indexExpr) {
+ public JsArrayAccess(SourceInfo sourceInfo, JsExpression arrayExpr,
+ JsExpression indexExpr) {
+ super(sourceInfo);
this.arrayExpr = arrayExpr;
this.indexExpr = indexExpr;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsArrayLiteral.java b/dev/core/src/com/google/gwt/dev/js/ast/JsArrayLiteral.java
index aa2e978..8bcaeb9 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsArrayLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsArrayLiteral.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -25,7 +27,8 @@
private final List<JsExpression> exprs = new ArrayList<JsExpression>();
- public JsArrayLiteral() {
+ public JsArrayLiteral(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public List<JsExpression> getExpressions() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsBinaryOperation.java b/dev/core/src/com/google/gwt/dev/js/ast/JsBinaryOperation.java
index ce14a46..12a8767 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsBinaryOperation.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsBinaryOperation.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript binary operation.
*/
@@ -26,12 +28,13 @@
private final JsBinaryOperator op;
- public JsBinaryOperation(JsBinaryOperator op) {
- this(op, null, null);
+ public JsBinaryOperation(SourceInfo sourceInfo, JsBinaryOperator op) {
+ this(sourceInfo, op, null, null);
}
- public JsBinaryOperation(JsBinaryOperator op, JsExpression arg1,
- JsExpression arg2) {
+ public JsBinaryOperation(SourceInfo sourceInfo, JsBinaryOperator op,
+ JsExpression arg1, JsExpression arg2) {
+ super(sourceInfo);
this.op = op;
this.arg1 = arg1;
this.arg2 = arg2;
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsBlock.java b/dev/core/src/com/google/gwt/dev/js/ast/JsBlock.java
index 10df903..a4a06c8 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsBlock.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsBlock.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -25,7 +27,8 @@
private final List<JsStatement> stmts = new ArrayList<JsStatement>();
- public JsBlock() {
+ public JsBlock(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public List<JsStatement> getStatements() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsBooleanLiteral.java b/dev/core/src/com/google/gwt/dev/js/ast/JsBooleanLiteral.java
index c38b8f0..06d6a0f 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsBooleanLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsBooleanLiteral.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript literal boolean expression.
*/
@@ -23,7 +25,8 @@
private final boolean value;
// Should be interned by JsProgram
- JsBooleanLiteral(boolean value) {
+ JsBooleanLiteral(SourceInfo sourceInfo, boolean value) {
+ super(sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsBreak.java b/dev/core/src/com/google/gwt/dev/js/ast/JsBreak.java
index 204e94d..638029e 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsBreak.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsBreak.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents the JavaScript break statement.
*/
@@ -22,11 +24,12 @@
private final JsNameRef label;
- public JsBreak() {
- this(null);
+ public JsBreak(SourceInfo sourceInfo) {
+ this(sourceInfo, null);
}
- public JsBreak(JsNameRef label) {
+ public JsBreak(SourceInfo sourceInfo, JsNameRef label) {
+ super(sourceInfo);
this.label = label;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsCase.java b/dev/core/src/com/google/gwt/dev/js/ast/JsCase.java
index 979891d..a1c7006 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsCase.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsCase.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents the JavaScript case statement.
*/
@@ -22,7 +24,8 @@
private JsExpression caseExpr;
- public JsCase() {
+ public JsCase(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public JsExpression getCaseExpr() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsCatch.java b/dev/core/src/com/google/gwt/dev/js/ast/JsCatch.java
index 855300b..e1d1cd8 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsCatch.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsCatch.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript catch clause.
*/
@@ -26,12 +28,13 @@
private JsExpression condition;
- private final JsParameter param;
+ private JsParameter param;
- public JsCatch(JsScope parent, String ident) {
+ public JsCatch(SourceInfo sourceInfo, JsScope parent, String ident) {
+ super(sourceInfo);
assert (parent != null);
scope = new JsCatchScope(parent, ident);
- param = new JsParameter(scope.findExistingName(ident));
+ param = new JsParameter(sourceInfo, scope.findExistingName(ident));
}
public JsBlock getBody() {
@@ -60,6 +63,7 @@
public void traverse(JsVisitor v, JsContext<JsCatch> ctx) {
if (v.visit(this, ctx)) {
+ param = v.accept(param);
if (condition != null) {
condition = v.accept(condition);
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsConditional.java b/dev/core/src/com/google/gwt/dev/js/ast/JsConditional.java
index e10127c..abd9d43 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsConditional.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsConditional.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript conditional expression.
*/
@@ -26,11 +28,13 @@
private JsExpression thenExpr;
- public JsConditional() {
+ public JsConditional(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
- public JsConditional(JsExpression testExpr, JsExpression thenExpr,
- JsExpression elseExpr) {
+ public JsConditional(SourceInfo sourceInfo, JsExpression testExpr,
+ JsExpression thenExpr, JsExpression elseExpr) {
+ super(sourceInfo);
this.testExpr = testExpr;
this.thenExpr = thenExpr;
this.elseExpr = elseExpr;
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsContinue.java b/dev/core/src/com/google/gwt/dev/js/ast/JsContinue.java
index 192aecf..8efb802 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsContinue.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsContinue.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents the JavaScript continue statement.
*/
@@ -22,11 +24,12 @@
private final JsNameRef label;
- public JsContinue() {
- this(null);
+ public JsContinue(SourceInfo sourceInfo) {
+ this(sourceInfo, null);
}
- public JsContinue(JsNameRef label) {
+ public JsContinue(SourceInfo sourceInfo, JsNameRef label) {
+ super(sourceInfo);
this.label = label;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsDebugger.java b/dev/core/src/com/google/gwt/dev/js/ast/JsDebugger.java
index 667ffa7..5f0186c 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsDebugger.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsDebugger.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
@@ -15,11 +15,17 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript debugger statement.
*/
public class JsDebugger extends JsStatement {
+ public JsDebugger(SourceInfo sourceInfo) {
+ super(sourceInfo);
+ }
+
public void traverse(JsVisitor v, JsContext<JsStatement> ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsDefault.java b/dev/core/src/com/google/gwt/dev/js/ast/JsDefault.java
index ca9b658..9ff557f 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsDefault.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsDefault.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
@@ -15,12 +15,15 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents the default option in a JavaScript swtich statement.
*/
public final class JsDefault extends JsSwitchMember {
- public JsDefault() {
+ public JsDefault(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public void traverse(JsVisitor v, JsContext<JsSwitchMember> ctx) {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsDoWhile.java b/dev/core/src/com/google/gwt/dev/js/ast/JsDoWhile.java
index cd6d934..4ce7128 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsDoWhile.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsDoWhile.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript do..while statement.
*/
@@ -24,10 +26,13 @@
private JsExpression condition;
- public JsDoWhile() {
+ public JsDoWhile(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
- public JsDoWhile(JsExpression condition, JsStatement body) {
+ public JsDoWhile(SourceInfo sourceInfo, JsExpression condition,
+ JsStatement body) {
+ super(sourceInfo);
this.condition = condition;
this.body = body;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsEmpty.java b/dev/core/src/com/google/gwt/dev/js/ast/JsEmpty.java
index 00379fc..097e31e 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsEmpty.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsEmpty.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
@@ -15,13 +15,16 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents an empty statement in JavaScript.
*/
public class JsEmpty extends JsStatement {
// Interned by JsProgram
- JsEmpty() {
+ JsEmpty(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public void traverse(JsVisitor v, JsContext<JsStatement> ctx) {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsExprStmt.java b/dev/core/src/com/google/gwt/dev/js/ast/JsExprStmt.java
index ec5c33d..b4ddcf0 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsExprStmt.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsExprStmt.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript expression statement.
*/
@@ -22,7 +24,8 @@
private JsExpression expr;
- public JsExprStmt(JsExpression expr) {
+ public JsExprStmt(SourceInfo sourceInfo, JsExpression expr) {
+ super(sourceInfo);
this.expr = expr;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsExpression.java b/dev/core/src/com/google/gwt/dev/js/ast/JsExpression.java
index 3f5b26d..13cf5c4 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsExpression.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsExpression.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
@@ -15,10 +15,16 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* An abstract base class for all JavaScript expressions.
*/
public abstract class JsExpression extends JsNode<JsExpression> {
+
+ protected JsExpression(SourceInfo sourceInfo) {
+ super(sourceInfo);
+ }
/**
* Determines whether the expression can cause side effects.
@@ -47,6 +53,6 @@
}
public JsExprStmt makeStmt() {
- return new JsExprStmt(this);
+ return new JsExprStmt(getSourceInfo(), this);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsFor.java b/dev/core/src/com/google/gwt/dev/js/ast/JsFor.java
index 85fe8c1..c2f002b 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsFor.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsFor.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A <code>for</code> statement. If specified at all, the initializer part is
* either a declaration of one or more variables, in which case
@@ -38,7 +40,8 @@
private JsVars initVars;
- public JsFor() {
+ public JsFor(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public JsStatement getBody() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsForIn.java b/dev/core/src/com/google/gwt/dev/js/ast/JsForIn.java
index feab502..4358782 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsForIn.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsForIn.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript for..in statement.
*/
@@ -29,11 +31,12 @@
private JsExpression objExpr;
- public JsForIn() {
- this(null);
+ public JsForIn(SourceInfo sourceInfo) {
+ this(sourceInfo, null);
}
- public JsForIn(JsName iterVarName) {
+ public JsForIn(SourceInfo sourceInfo, JsName iterVarName) {
+ super(sourceInfo);
this.iterVarName = iterVarName;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsFunction.java b/dev/core/src/com/google/gwt/dev/js/ast/JsFunction.java
index 047ece4..3ae9c2f 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsFunction.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsFunction.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -43,21 +45,23 @@
/**
* Creates an anonymous function.
*/
- public JsFunction(JsScope parent) {
- this(parent, null, false);
+ public JsFunction(SourceInfo sourceInfo, JsScope parent) {
+ this(sourceInfo, parent, null, false);
}
/**
* Creates a function that is not derived from Java source.
*/
- public JsFunction(JsScope parent, JsName name) {
- this(parent, name, false);
+ public JsFunction(SourceInfo sourceInfo, JsScope parent, JsName name) {
+ this(sourceInfo, parent, name, false);
}
/**
* Creates a named function, possibly derived from Java source.
*/
- public JsFunction(JsScope parent, JsName name, boolean fromJava) {
+ public JsFunction(SourceInfo sourceInfo, JsScope parent, JsName name,
+ boolean fromJava) {
+ super(sourceInfo);
assert (parent != null);
this.fromJava = fromJava;
setName(name);
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsGlobalBlock.java b/dev/core/src/com/google/gwt/dev/js/ast/JsGlobalBlock.java
index 883674d..f6dfb25 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsGlobalBlock.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsGlobalBlock.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
@@ -15,14 +15,20 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represnts a JavaScript block in the global scope.
*/
public class JsGlobalBlock extends JsBlock {
+ public JsGlobalBlock(SourceInfo sourceInfo) {
+ super(sourceInfo);
+ }
+
@Override
public boolean isGlobalBlock() {
return true;
}
-
+
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsIf.java b/dev/core/src/com/google/gwt/dev/js/ast/JsIf.java
index fccefae..2440155 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsIf.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsIf.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript if statement.
*/
@@ -26,10 +28,13 @@
private JsStatement elseStmt;
- public JsIf() {
+ public JsIf(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
- public JsIf(JsExpression ifExpr, JsStatement thenStmt, JsStatement elseStmt) {
+ public JsIf(SourceInfo sourceInfo, JsExpression ifExpr, JsStatement thenStmt,
+ JsStatement elseStmt) {
+ super(sourceInfo);
this.ifExpr = ifExpr;
this.thenStmt = thenStmt;
this.elseStmt = elseStmt;
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsInvocation.java b/dev/core/src/com/google/gwt/dev/js/ast/JsInvocation.java
index 2e1838b..ac7fdac 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsInvocation.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsInvocation.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -27,7 +29,8 @@
private JsExpression qualifier;
- public JsInvocation() {
+ public JsInvocation(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public List<JsExpression> getArguments() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsLabel.java b/dev/core/src/com/google/gwt/dev/js/ast/JsLabel.java
index 74af6de..c733b6e 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsLabel.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsLabel.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript label statement.
*/
@@ -24,7 +26,8 @@
private JsStatement stmt;
- public JsLabel(JsName label) {
+ public JsLabel(SourceInfo sourceInfo, JsName label) {
+ super(sourceInfo);
this.label = label;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsLiteral.java b/dev/core/src/com/google/gwt/dev/js/ast/JsLiteral.java
index 6deb149..6fc345d 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsLiteral.java
@@ -15,8 +15,13 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript string literal expression.
*/
public abstract class JsLiteral extends JsExpression implements CanBooleanEval {
+ protected JsLiteral(SourceInfo sourceInfo) {
+ super(sourceInfo);
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsName.java b/dev/core/src/com/google/gwt/dev/js/ast/JsName.java
index 8321727..0b605e9 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsName.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsName.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.io.Serializable;
/**
@@ -62,8 +64,8 @@
return isObfuscatable;
}
- public JsNameRef makeRef() {
- return new JsNameRef(this);
+ public JsNameRef makeRef(SourceInfo sourceInfo) {
+ return new JsNameRef(sourceInfo, this);
}
public void setObfuscatable(boolean isObfuscatable) {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsNameRef.java b/dev/core/src/com/google/gwt/dev/js/ast/JsNameRef.java
index 93d9159..03c3433 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsNameRef.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsNameRef.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
@@ -15,21 +15,27 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript expression that references a name.
*/
public final class JsNameRef extends JsExpression implements CanBooleanEval,
HasName {
+ private boolean hasStaticRef;
private String ident;
private JsName name;
private JsExpression qualifier;
- public JsNameRef(JsName name) {
+ public JsNameRef(SourceInfo sourceInfo, JsName name) {
+ super(sourceInfo.makeChild(JsNameRef.class, "Reference"));
this.name = name;
+ maybeUpdateSourceInfo();
}
- public JsNameRef(String ident) {
+ public JsNameRef(SourceInfo sourceInfo, String ident) {
+ super(sourceInfo);
this.ident = ident;
}
@@ -50,6 +56,11 @@
}
@Override
+ public SourceInfo getSourceInfo() {
+ return maybeUpdateSourceInfo();
+ }
+
+ @Override
public boolean hasSideEffects() {
if (qualifier == null) {
return false;
@@ -113,4 +124,22 @@
}
v.endVisit(this, ctx);
}
+
+ /**
+ * This corrects the JsNameRef's SourceInfo derivation when the JsName is
+ * created with a JsName that has not yet had its static reference set. This
+ * is the case in GenerateJavaScriptAST after the names and scopes visitor has
+ * been run, but before the AST is fully realized.
+ */
+ private SourceInfo maybeUpdateSourceInfo() {
+ SourceInfo toReturn = super.getSourceInfo();
+ if (!hasStaticRef && name != null) {
+ JsNode<?> staticRef = name.getStaticRef();
+ if (staticRef != null) {
+ toReturn.copyMissingCorrelationsFrom(name.getStaticRef().getSourceInfo());
+ hasStaticRef = true;
+ }
+ }
+ return toReturn;
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsNew.java b/dev/core/src/com/google/gwt/dev/js/ast/JsNew.java
index 577ceb8..19f8a51 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsNew.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsNew.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -27,7 +29,8 @@
private JsExpression ctorExpr;
- public JsNew() {
+ public JsNew(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public List<JsExpression> getArguments() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsNode.java b/dev/core/src/com/google/gwt/dev/js/ast/JsNode.java
index 6ca9618..f370ee4 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsNode.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsNode.java
@@ -30,10 +30,16 @@
*/
public abstract class JsNode<T extends JsVisitable<T>> implements
JsVisitable<T>, HasSourceInfo, Serializable {
+
+ private final SourceInfo sourceInfo;
+
+ protected JsNode(SourceInfo sourceInfo) {
+ assert sourceInfo != null : "SourceInfo must be provided for JsNodes";
+ this.sourceInfo = sourceInfo;
+ }
public SourceInfo getSourceInfo() {
- // TODO: make this real
- return null;
+ return sourceInfo;
}
// Causes source generation to delegate to the one visitor
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsNullLiteral.java b/dev/core/src/com/google/gwt/dev/js/ast/JsNullLiteral.java
index 5a63acc..f960539 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsNullLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsNullLiteral.java
@@ -15,13 +15,16 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript null literal.
*/
public final class JsNullLiteral extends JsValueLiteral {
// Should only be instantiated in JsProgram
- JsNullLiteral() {
+ JsNullLiteral(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public boolean isBooleanFalse() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsNumberLiteral.java b/dev/core/src/com/google/gwt/dev/js/ast/JsNumberLiteral.java
index 3de6de8..cef02c6 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsNumberLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsNumberLiteral.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Represents a JavaScript literal decimal expression.
*/
@@ -23,7 +25,8 @@
private final double value;
// Should be interned by JsProgram
- JsNumberLiteral(double value) {
+ JsNumberLiteral(SourceInfo sourceInfo, double value) {
+ super(sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsObjectLiteral.java b/dev/core/src/com/google/gwt/dev/js/ast/JsObjectLiteral.java
index 393fa17..a81377a 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsObjectLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsObjectLiteral.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -25,7 +27,8 @@
private final List<JsPropertyInitializer> props = new ArrayList<JsPropertyInitializer>();
- public JsObjectLiteral() {
+ public JsObjectLiteral(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public List<JsPropertyInitializer> getPropertyInitializers() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsParameter.java b/dev/core/src/com/google/gwt/dev/js/ast/JsParameter.java
index af2e667..b934353 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsParameter.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsParameter.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript parameter.
*/
@@ -22,7 +24,8 @@
private final JsName name;
- public JsParameter(JsName name) {
+ public JsParameter(SourceInfo sourceInfo, JsName name) {
+ super(sourceInfo);
this.name = name;
name.setStaticRef(this);
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsPostfixOperation.java b/dev/core/src/com/google/gwt/dev/js/ast/JsPostfixOperation.java
index ded8be4..b4ec4bf 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsPostfixOperation.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsPostfixOperation.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
@@ -15,17 +15,20 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript postfix operation.
*/
public final class JsPostfixOperation extends JsUnaryOperation {
- public JsPostfixOperation(JsUnaryOperator op) {
- this(op, null);
+ public JsPostfixOperation(SourceInfo sourceInfo, JsUnaryOperator op) {
+ this(sourceInfo, op, null);
}
- public JsPostfixOperation(JsUnaryOperator op, JsExpression arg) {
- super(op, arg);
+ public JsPostfixOperation(SourceInfo sourceInfo, JsUnaryOperator op,
+ JsExpression arg) {
+ super(sourceInfo, op, arg);
}
@Override
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsPrefixOperation.java b/dev/core/src/com/google/gwt/dev/js/ast/JsPrefixOperation.java
index bf5956a..ff41d04 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsPrefixOperation.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsPrefixOperation.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
@@ -15,18 +15,21 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript prefix operation.
*/
public final class JsPrefixOperation extends JsUnaryOperation implements
CanBooleanEval {
- public JsPrefixOperation(JsUnaryOperator op) {
- this(op, null);
+ public JsPrefixOperation(SourceInfo sourceInfo, JsUnaryOperator op) {
+ this(sourceInfo, op, null);
}
- public JsPrefixOperation(JsUnaryOperator op, JsExpression arg) {
- super(op, arg);
+ public JsPrefixOperation(SourceInfo sourceInfo, JsUnaryOperator op,
+ JsExpression arg) {
+ super(sourceInfo, op, arg);
}
public boolean isBooleanFalse() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java b/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java
index 7abc651..33dd57f 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.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
@@ -15,6 +15,11 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.Correlation;
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.Correlation.Axis;
+import com.google.gwt.dev.jjs.Correlation.Literal;
+
import java.util.HashMap;
import java.util.Map;
@@ -22,16 +27,30 @@
* A JavaScript program.
*/
public final class JsProgram extends JsNode<JsProgram> {
+ /**
+ * This method is used to create SourceInfos for fields in JsProgram. This
+ * method always creates a SourceInfo that has collection enabled.
+ */
+ private static SourceInfo createSourceInfoEnabled(String description) {
+ return new SourceInfoJs(-1, -1, 0, JsProgram.class.getName(), true).makeChild(
+ JsProgram.class, description);
+ }
- private final JsStatement debuggerStmt = new JsDebugger();
+ private final JsStatement debuggerStmt = new JsDebugger(
+ createSourceInfoEnabled("debugger statement"));
- private final JsEmpty emptyStmt = new JsEmpty();
+ private final JsEmpty emptyStmt = new JsEmpty(
+ createSourceInfoEnabled("Empty statement"));
- private final JsBooleanLiteral falseLiteral = new JsBooleanLiteral(false);
+ private final boolean enableSourceInfoDescendants;
- private final JsGlobalBlock globalBlock;
+ private final JsBooleanLiteral falseLiteral = new JsBooleanLiteral(
+ createSourceInfoEnabled("false literal"), false);
- private final JsNullLiteral nullLiteral = new JsNullLiteral();
+ private JsProgramFragment[] fragments;
+
+ private final JsNullLiteral nullLiteral = new JsNullLiteral(
+ createSourceInfoEnabled("null literal"));
private final Map<Double, JsNumberLiteral> numberLiteralMap = new HashMap<Double, JsNumberLiteral>();
@@ -41,18 +60,52 @@
private final Map<String, JsStringLiteral> stringLiteralMap = new HashMap<String, JsStringLiteral>();
+ private final SourceInfo stringPoolSourceInfo;
+
private final JsScope topScope;
- private final JsBooleanLiteral trueLiteral = new JsBooleanLiteral(true);
+ private final JsBooleanLiteral trueLiteral = new JsBooleanLiteral(
+ createSourceInfoEnabled("true literal"), true);
+
+ public JsProgram() {
+ this(false);
+ }
/**
* Constructs a JavaScript program object.
+ *
+ * @param soycEnabled Controls whether or not SourceInfo nodes created via the
+ * JsProgram will record descendant information. Enabling this
+ * feature will collect extra data during the compilation cycle, but
+ * at a cost of memory and object allocations.
*/
- public JsProgram() {
+ public JsProgram(boolean soycEnabled) {
+ super(SourceInfoJs.INTRINSIC.makeChild(JsProgram.class,
+ "JavaScript program"));
+ this.enableSourceInfoDescendants = soycEnabled;
+
rootScope = new JsRootScope(this);
- globalBlock = new JsGlobalBlock();
topScope = new JsScope(rootScope, "Global");
objectScope = new JsScope(rootScope, "Object");
+ setFragmentCount(1);
+ falseLiteral.getSourceInfo().addCorrelation(
+ Correlation.by(Literal.JS_BOOLEAN));
+ nullLiteral.getSourceInfo().addCorrelation(Correlation.by(Literal.JS_NULL));
+ trueLiteral.getSourceInfo().addCorrelation(
+ Correlation.by(Literal.JS_BOOLEAN));
+ stringPoolSourceInfo = createSourceInfoSynthetic(JsProgram.class,
+ "String pool");
+ stringPoolSourceInfo.addCorrelation(Correlation.by(Literal.JS_STRING));
+ }
+
+ public SourceInfo createSourceInfo(int lineNumber, String location) {
+ return new SourceInfoJs(-1, -1, lineNumber, location,
+ enableSourceInfoDescendants);
+ }
+
+ public SourceInfo createSourceInfoSynthetic(Class<?> caller,
+ String description) {
+ return createSourceInfo(0, caller.getName()).makeChild(caller, description);
}
public JsBooleanLiteral getBooleanLiteral(boolean truth) {
@@ -80,11 +133,22 @@
return falseLiteral;
}
+ public JsBlock getFragmentBlock(int fragment) {
+ if (fragment < 0 || fragment >= fragments.length) {
+ throw new IllegalArgumentException("Invalid fragment: " + fragment);
+ }
+ return fragments[fragment].getGlobalBlock();
+ }
+
+ public int getFragmentCount() {
+ return this.fragments.length;
+ }
+
/**
* Gets the one and only global block.
*/
public JsBlock getGlobalBlock() {
- return globalBlock;
+ return getFragmentBlock(0);
}
public JsNullLiteral getNullLiteral() {
@@ -92,12 +156,35 @@
}
public JsNumberLiteral getNumberLiteral(double value) {
- JsNumberLiteral lit = numberLiteralMap.get(value);
- if (lit == null) {
- lit = new JsNumberLiteral(value);
- numberLiteralMap.put(value, lit);
+ return getNumberLiteral(null, value);
+ }
+
+ public JsNumberLiteral getNumberLiteral(SourceInfo info, double value) {
+ /*
+ * This method only canonicalizes number literals when we don't have an
+ * incoming SourceInfo so that we can distinguish int-0 from double-0 in the
+ * analysis.
+ */
+ if (info == null) {
+ JsNumberLiteral lit = numberLiteralMap.get(value);
+ if (lit == null) {
+ info = createSourceInfoSynthetic(JsProgram.class, "Number literal "
+ + value);
+ info.addCorrelation(Correlation.by(Literal.JS_NUMBER));
+ lit = new JsNumberLiteral(info, value);
+ numberLiteralMap.put(value, lit);
+ }
+
+ return lit;
+ } else {
+ // Only add a JS_NUMBER if no literal correlation present: e.g. Java int
+ if (info.getPrimaryCorrelation(Axis.LITERAL) == null) {
+ // Don't mutate incoming SourceInfo
+ info = info.makeChild(JsProgram.class, "Number literal " + value);
+ info.addCorrelation(Correlation.by(Literal.JS_NUMBER));
+ }
+ return new JsNumberLiteral(info, value);
}
- return lit;
}
public JsScope getObjectScope() {
@@ -121,12 +208,19 @@
return topScope;
}
- public JsStringLiteral getStringLiteral(String value) {
+ /**
+ * Note: This is currently assumed not to be called after
+ * GenerateJavaScriptAST has finished. If it ever is, then GWT.runAsync needs
+ * to be updated to account for such string literals.
+ */
+ public JsStringLiteral getStringLiteral(SourceInfo sourceInfo, String value) {
JsStringLiteral lit = stringLiteralMap.get(value);
if (lit == null) {
- lit = new JsStringLiteral(value);
+ lit = new JsStringLiteral(stringPoolSourceInfo.makeChild(JsProgram.class,
+ "String literal: " + value), value);
stringLiteralMap.put(value, lit);
}
+ lit.getSourceInfo().merge(sourceInfo);
return lit;
}
@@ -135,12 +229,25 @@
}
public JsNameRef getUndefinedLiteral() {
- return rootScope.findExistingName("undefined").makeRef();
+ SourceInfo info = createSourceInfoSynthetic(JsProgram.class,
+ "undefined reference");
+ info.addCorrelation(Correlation.by(Literal.JS_UNDEFINED));
+ return rootScope.findExistingName("undefined").makeRef(info);
+ }
+
+ public void setFragmentCount(int fragments) {
+ this.fragments = new JsProgramFragment[fragments];
+ for (int i = 0; i < fragments; i++) {
+ this.fragments[i] = new JsProgramFragment(createSourceInfoSynthetic(
+ JsProgram.class, "fragment " + i));
+ }
}
public void traverse(JsVisitor v, JsContext<JsProgram> ctx) {
if (v.visit(this, ctx)) {
- v.accept(globalBlock);
+ for (JsProgramFragment fragment : fragments) {
+ v.accept(fragment);
+ }
}
v.endVisit(this, ctx);
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsProgramFragment.java b/dev/core/src/com/google/gwt/dev/js/ast/JsProgramFragment.java
new file mode 100644
index 0000000..2b685aa
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsProgramFragment.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.js.ast;
+
+import com.google.gwt.dev.jjs.SourceInfo;
+
+/**
+ * One independently loadable fragment of a {@link JsProgram}.
+ */
+public class JsProgramFragment extends JsNode<JsProgramFragment> {
+ private final JsGlobalBlock globalBlock;
+
+ public JsProgramFragment(SourceInfo sourceInfo) {
+ super(sourceInfo);
+ this.globalBlock = new JsGlobalBlock(sourceInfo.makeChild(
+ JsProgramFragment.class, "global block for a fragment"));
+ }
+
+ public JsBlock getGlobalBlock() {
+ return globalBlock;
+ }
+
+ public void traverse(JsVisitor v, JsContext<JsProgramFragment> ctx) {
+ if (v.visit(this, ctx)) {
+ v.accept(globalBlock);
+ }
+ v.endVisit(this, ctx);
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsPropertyInitializer.java b/dev/core/src/com/google/gwt/dev/js/ast/JsPropertyInitializer.java
index 3b429b2..de18cca 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsPropertyInitializer.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsPropertyInitializer.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Used in object literals to specify property values by name.
*/
@@ -24,10 +26,12 @@
private JsExpression valueExpr;
- public JsPropertyInitializer() {
+ public JsPropertyInitializer(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
- public JsPropertyInitializer(JsExpression labelExpr, JsExpression valueExpr) {
+ public JsPropertyInitializer(SourceInfo sourceInfo, JsExpression labelExpr, JsExpression valueExpr) {
+ super(sourceInfo);
this.labelExpr = labelExpr;
this.valueExpr = valueExpr;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsRegExp.java b/dev/core/src/com/google/gwt/dev/js/ast/JsRegExp.java
index 62aec87..c367597 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsRegExp.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsRegExp.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript regular expression.
*/
@@ -24,7 +26,8 @@
private String pattern;
- public JsRegExp() {
+ public JsRegExp(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public String getFlags() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsReturn.java b/dev/core/src/com/google/gwt/dev/js/ast/JsReturn.java
index e9272b4..0176340 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsReturn.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsReturn.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript return statement.
*/
@@ -22,10 +24,12 @@
private JsExpression expr;
- public JsReturn() {
+ public JsReturn(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
- public JsReturn(JsExpression expr) {
+ public JsReturn(SourceInfo sourceInfo, JsExpression expr) {
+ super(sourceInfo);
this.expr = expr;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsStatement.java b/dev/core/src/com/google/gwt/dev/js/ast/JsStatement.java
index e1db178..3043cc1 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsStatement.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsStatement.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
@@ -15,11 +15,17 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* Abstract base class for JavaScript statement objects.
*/
public abstract class JsStatement extends JsNode<JsStatement> {
+ protected JsStatement(SourceInfo sourceInfo) {
+ super(sourceInfo);
+ }
+
/**
* Returns true if this statement definitely causes an abrupt change in flow
* control.
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsStringLiteral.java b/dev/core/src/com/google/gwt/dev/js/ast/JsStringLiteral.java
index 799195f..c553f2c 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsStringLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsStringLiteral.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript string literal expression.
*/
@@ -23,7 +25,8 @@
private final String value;
// These only get created by JsProgram so that they can be interned.
- JsStringLiteral(String value) {
+ JsStringLiteral(SourceInfo sourceInfo, String value) {
+ super(sourceInfo);
this.value = value;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsSwitch.java b/dev/core/src/com/google/gwt/dev/js/ast/JsSwitch.java
index 8d9c521..6e4d038 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsSwitch.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsSwitch.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -27,7 +29,8 @@
private JsExpression expr;
- public JsSwitch() {
+ public JsSwitch(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public List<JsSwitchMember> getCases() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsSwitchMember.java b/dev/core/src/com/google/gwt/dev/js/ast/JsSwitchMember.java
index 1080890..26bee44 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsSwitchMember.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsSwitchMember.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -25,6 +27,10 @@
protected final List<JsStatement> stmts = new ArrayList<JsStatement>();
+ protected JsSwitchMember(SourceInfo sourceInfo) {
+ super(sourceInfo);
+ }
+
public List<JsStatement> getStmts() {
return stmts;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsThisRef.java b/dev/core/src/com/google/gwt/dev/js/ast/JsThisRef.java
index ee5c739..c67af2e 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsThisRef.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsThisRef.java
@@ -15,12 +15,15 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript <code>this</code> reference.
*/
public final class JsThisRef extends JsValueLiteral {
- public JsThisRef() {
+ public JsThisRef(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public boolean isBooleanFalse() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsThrow.java b/dev/core/src/com/google/gwt/dev/js/ast/JsThrow.java
index 010ec10..2f25bd2 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsThrow.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsThrow.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript <code>throw</code> statement.
*/
@@ -22,10 +24,12 @@
private JsExpression expr;
- public JsThrow() {
+ public JsThrow(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
- public JsThrow(JsExpression expr) {
+ public JsThrow(SourceInfo sourceInfo, JsExpression expr) {
+ super(sourceInfo);
this.expr = expr;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsTry.java b/dev/core/src/com/google/gwt/dev/js/ast/JsTry.java
index 737fff0..ae7ec34 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsTry.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsTry.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -29,7 +31,8 @@
private JsBlock tryBlock;
- public JsTry() {
+ public JsTry(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public List<JsCatch> getCatches() {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsUnaryOperation.java b/dev/core/src/com/google/gwt/dev/js/ast/JsUnaryOperation.java
index 6358f15..4feadb6 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsUnaryOperation.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsUnaryOperation.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript prefix or postfix operation.
*/
@@ -24,11 +26,13 @@
private final JsUnaryOperator op;
- public JsUnaryOperation(JsUnaryOperator op) {
- this(op, null);
+ public JsUnaryOperation(SourceInfo sourceInfo, JsUnaryOperator op) {
+ this(sourceInfo, op, null);
}
- public JsUnaryOperation(JsUnaryOperator op, JsExpression arg) {
+ public JsUnaryOperation(SourceInfo sourceInfo, JsUnaryOperator op,
+ JsExpression arg) {
+ super(sourceInfo);
this.op = op;
this.arg = arg;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsValueLiteral.java b/dev/core/src/com/google/gwt/dev/js/ast/JsValueLiteral.java
index f3e4af4..ba6dcd3 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsValueLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsValueLiteral.java
@@ -15,11 +15,17 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript string literal expression.
*/
public abstract class JsValueLiteral extends JsLiteral {
+ protected JsValueLiteral(SourceInfo sourceInfo) {
+ super(sourceInfo);
+ }
+
@Override
public final boolean hasSideEffects() {
return false;
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsVars.java b/dev/core/src/com/google/gwt/dev/js/ast/JsVars.java
index c23e5ff..5b37e06 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsVars.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsVars.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -33,7 +35,8 @@
private final JsName name;
- public JsVar(JsName name) {
+ public JsVar(SourceInfo sourceInfo, JsName name) {
+ super(sourceInfo);
this.name = name;
}
@@ -61,13 +64,18 @@
private final List<JsVar> vars = new ArrayList<JsVar>();
- public JsVars() {
+ public JsVars(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
public void add(JsVar var) {
vars.add(var);
}
+ public int getNumVars() {
+ return vars.size();
+ }
+
public boolean isEmpty() {
return vars.isEmpty();
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java b/dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java
index ffaf3dd..e3151f5 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java
@@ -91,6 +91,8 @@
};
public final <T extends JsVisitable> T accept(T node) {
+ // The following cast to T is needed for javac 1.5.0_13
+ // as shipped on OS X
return (T) doAccept(node);
}
@@ -201,6 +203,9 @@
public void endVisit(JsProgram x, JsContext<JsProgram> ctx) {
}
+ public void endVisit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+ }
+
public void endVisit(JsPropertyInitializer x,
JsContext<JsPropertyInitializer> ctx) {
}
@@ -355,6 +360,10 @@
return true;
}
+ public boolean visit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+ return true;
+ }
+
public boolean visit(JsPropertyInitializer x,
JsContext<JsPropertyInitializer> ctx) {
return true;
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsWhile.java b/dev/core/src/com/google/gwt/dev/js/ast/JsWhile.java
index 799e594..5bed233 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsWhile.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsWhile.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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.js.ast;
+import com.google.gwt.dev.jjs.SourceInfo;
+
/**
* A JavaScript <code>while</code> statement.
*/
@@ -24,10 +26,12 @@
private JsExpression condition;
- public JsWhile() {
+ public JsWhile(SourceInfo sourceInfo) {
+ super(sourceInfo);
}
- public JsWhile(JsExpression condition, JsStatement body) {
+ public JsWhile(SourceInfo sourceInfo, JsExpression condition, JsStatement body) {
+ super(sourceInfo);
this.condition = condition;
this.body = body;
}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/SourceInfoJs.java b/dev/core/src/com/google/gwt/dev/js/ast/SourceInfoJs.java
new file mode 100644
index 0000000..9db902d
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/js/ast/SourceInfoJs.java
@@ -0,0 +1,41 @@
+/*
+ * 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.js.ast;
+
+import com.google.gwt.dev.jjs.SourceInfo;
+
+/**
+ * An implementation of SourceInfo representing SourceInfo nodes derived from
+ * the JavaScript AST. Instances of this class should only be constructed by
+ * JsProgram.
+ */
+public class SourceInfoJs extends SourceInfo {
+ /**
+ * Indicates that an AST element is an intrinsic element of the AST and has no
+ * meaningful source location. This is typically used by singleton AST
+ * elements or for literal values.
+ */
+ public static final SourceInfo INTRINSIC = new Immutable(0, 0, 0,
+ "Js intrinsics", true);
+
+ /**
+ * Called only from JsProgram.
+ */
+ SourceInfoJs(int startPos, int endPos, int startLine, String fileName,
+ boolean createDescendants) {
+ super(startPos, endPos, startLine, fileName, createDescendants);
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/js/rhino/TokenStream.java b/dev/core/src/com/google/gwt/dev/js/rhino/TokenStream.java
index 4a98379..871fec7 100644
--- a/dev/core/src/com/google/gwt/dev/js/rhino/TokenStream.java
+++ b/dev/core/src/com/google/gwt/dev/js/rhino/TokenStream.java
@@ -1506,6 +1506,17 @@
break;
}
}
+
+ // Arrray-type reference
+ while (c == '[') {
+ if (']' == in.peek()) {
+ addToString('[');
+ addToString(in.read());
+ c = in.read();
+ } else {
+ break;
+ }
+ }
// We have a non-ident char to classify.
//
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/DefaultFilters.java b/dev/core/src/com/google/gwt/dev/resource/impl/DefaultFilters.java
new file mode 100644
index 0000000..0fc980c
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/DefaultFilters.java
@@ -0,0 +1,410 @@
+/*
+ * 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.resource.impl;
+
+import org.apache.tools.ant.types.ZipScanner;
+
+import java.util.regex.Pattern;
+
+/**
+ * A singleton class that provides blazingly fast implementation of the default
+ * excludes of Ant's {@link org.apache.tools.ant.DirectoryScanner}, assuming
+ * case-sensitiveness.
+ *
+ * TODO: this class needs to be revisited, when Gwt's Ant is upgraded.
+ *
+ * Currently, we do not go to ant if (a) the filterList is empty, or (b) the
+ * filterList has "common" patterns. Exception: When path ends in '/', we defer
+ * to ant.
+ *
+ * TODO: This code could be made more general and cleaner by removing the
+ * dependency on Ant completely. All ant patterns could be compiled into
+ * reg-exps. That could also make the code faster. Plus, at several places,
+ * Ant's documentation seems to be incomplete. Instead, perhaps, we should
+ * specify our own rules for writing patterns.
+ */
+public class DefaultFilters {
+
+ private static final boolean IS_EXCLUDES = false;
+ private static final boolean IS_INCLUDES = true;
+ private static final boolean NOT_JAVA = false;
+ private static final boolean YES_JAVA = true;
+
+ static ZipScanner getScanner(String[] includeList, String[] excludeList,
+ boolean defaultExcludes, boolean caseSensitive) {
+ /*
+ * Hijack Ant's ZipScanner to handle inclusions/exclusions exactly as Ant
+ * does. We're only using its pattern-matching capabilities; the code path
+ * I'm using never tries to hit the filesystem in Ant 1.6.5.
+ */
+ ZipScanner scanner = new ZipScanner();
+ if (includeList.length > 0) {
+ scanner.setIncludes(includeList);
+ }
+ if (excludeList.length > 0) {
+ scanner.setExcludes(excludeList);
+ }
+ if (defaultExcludes) {
+ scanner.addDefaultExcludes();
+ }
+ scanner.setCaseSensitive(caseSensitive);
+ scanner.init();
+
+ return scanner;
+ }
+
+ /* used when defaultExcludes is true */
+ final ResourceFilter defaultResourceFilter = new ResourceFilter() {
+
+ public boolean allows(String path) {
+ return defaultAntIncludes.allows(path)
+ && !defaultExcludesPattern.matcher(path).matches();
+ }
+ };
+
+ /* used when defaultExcludes is true */
+ final ResourceFilter defaultJavaFilter = new ResourceFilter() {
+
+ public boolean allows(String path) {
+ return justJavaFilter.allows(path)
+ && !defaultJavaExcludesPattern.matcher(path).matches();
+ }
+
+ };
+ /* used when defaultExcludes is false */
+ final ResourceFilter justResourceFilter = new ResourceFilter() {
+
+ public boolean allows(String path) {
+ return defaultAntIncludes.allows(path);
+ }
+ };
+
+ /* used when defaultExcludes is false */
+ final ResourceFilter justJavaFilter = new ResourceFilter() {
+
+ public boolean allows(String path) {
+ return defaultAntIncludes.allows(path) && isJavaFile(path);
+ }
+ };
+
+ private final Pattern defaultExcludesPattern;
+ private final Pattern defaultJavaExcludesPattern;
+ // \w (word character), ., $, /, -, *, ~, #, %
+ private final Pattern antPattern = Pattern.compile("^[\\w\\.\\$/\\-\\*~#%]*$");
+
+ // accepts all but paths starting with '/'. Default include list is '**'
+ private final ResourceFilter defaultAntIncludes = new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.charAt(0) != '/';
+ }
+ };
+
+ private final ResourceFilter rejectAll = new ResourceFilter() {
+ public boolean allows(String path) {
+ return false;
+ }
+ };
+
+ public DefaultFilters() {
+
+ /*
+ * list copied from {@link org.apache.tools.ant.DirectoryScanner}
+ */
+ String defaultExcludes[] = new String[] {
+ // Miscellaneous typical temporary files
+ "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*",
+
+ // CVS
+ "**/CVS", "**/CVS/**",
+ // to not hit the weird formatting error.
+ "**/.cvsignore",
+
+ // SCCS
+ "**/SCCS", "**/SCCS/**",
+
+ // Visual SourceSafe
+ "**/vssver.scc",
+
+ // Subversion
+ "**/.svn", "**/.svn/**",
+
+ // Mac
+ "**/.DS_Store",};
+
+ defaultExcludesPattern = getPatternFromAntStrings(defaultExcludes);
+
+ String defaultExcludesJava[] = new String[] {
+ // Miscellaneous typical temporary files
+ "**/.#*", "**/._*",
+
+ // CVS
+ "**/CVS/**",
+
+ // SCCS
+ "**/SCCS/**",
+
+ // Subversion
+ "**/.svn/**",};
+ defaultJavaExcludesPattern = getPatternFromAntStrings(defaultExcludesJava);
+ }
+
+ public ResourceFilter customJavaFilter(String includeList[],
+ String excludeList[], boolean defaultExcludes, boolean caseSensitive) {
+ return getCustomFilter(includeList, excludeList, defaultExcludes,
+ caseSensitive, YES_JAVA);
+ }
+
+ public ResourceFilter customResourceFilter(String includeList[],
+ String excludeList[], boolean defaultExcludes, boolean caseSensitive) {
+
+ return getCustomFilter(includeList, excludeList, defaultExcludes,
+ caseSensitive, NOT_JAVA);
+ }
+
+ /**
+ * return a customResourceFiter that handles all the argument. If unable to
+ * create a customResourceFilter that handles the arguments, catchAll is used
+ * as the final ResourceFilter.
+ */
+ ResourceFilter customFilterWithCatchAll(final String includeList[],
+ final String excludeList[], final boolean defaultExcludes,
+ final ResourceFilter catchAll, final boolean isJava) {
+
+ assert includeList.length > 0 || excludeList.length > 0;
+
+ final ResourceFilter includeFilter = getFilterPart(includeList, IS_INCLUDES);
+ final ResourceFilter excludeFilter = getFilterPart(excludeList, IS_EXCLUDES);
+
+ if (includeFilter == null || excludeFilter == null) {
+ return catchAll;
+ }
+ // another common-case
+ ResourceFilter filter = new ResourceFilter() {
+ public boolean allows(String path) {
+ // do not handle the case when pattern ends in '/'
+ if (path.endsWith("/")) {
+ return catchAll.allows(path);
+ }
+ return isPathAllowedByDefaults(path, defaultExcludes, isJava)
+ && includeFilter.allows(path) && !excludeFilter.allows(path);
+ }
+
+ private boolean isPathAllowedByDefaults(String path,
+ boolean defaultExcludes, boolean isJava) {
+ if (defaultExcludes) {
+ return isJava ? !defaultJavaExcludesPattern.matcher(path).matches()
+ && isJavaFile(path)
+ : !defaultExcludesPattern.matcher(path).matches();
+ }
+ return isJava ? isJavaFile(path) : true;
+ }
+ };
+ return filter;
+ }
+
+ ResourceFilter getCustomFilter(final String includeList[],
+ final String excludeList[], final boolean defaultExcludes,
+ final boolean caseSensitive, final boolean isJava) {
+ if (includeList.length == 0 && excludeList.length == 0 && caseSensitive) {
+ // optimize for the common case.
+ return getMatchingDefaultFilter(defaultExcludes, isJava);
+ }
+
+ // don't create a catchAll in default cases
+ ResourceFilter catchAll = new ResourceFilter() {
+ ZipScanner scanner = getScanner(includeList, excludeList,
+ defaultExcludes, caseSensitive);
+
+ public boolean allows(String path) {
+ if (isJava) {
+ return isJavaFile(path) && scanner.match(path);
+ }
+ return scanner.match(path);
+ }
+ };
+
+ // for now, don't handle case sensitivity
+ if (!caseSensitive) {
+ return catchAll;
+ }
+ return customFilterWithCatchAll(includeList, excludeList, defaultExcludes,
+ catchAll, isJava);
+ }
+
+ ResourceFilter getFilterPart(final String list[], final boolean defaultValue) {
+ if (list.length == 0) {
+ return defaultValue ? defaultAntIncludes : rejectAll;
+ }
+
+ String patternStrings[] = new String[list.length];
+ int count = 0;
+ for (String antPatternString : list) {
+ String patternString = getPatternFromAntPattern(antPatternString);
+ if (patternString == null) {
+ return null;
+ }
+ patternStrings[count++] = patternString;
+ }
+
+ final Pattern pattern = getPatternFromStrings(patternStrings);
+ return new ResourceFilter() {
+ public boolean allows(String path) {
+ return pattern.matcher(path).matches();
+ }
+ };
+ }
+
+ /**
+ * Returns a pattern string that can be passed in Java Pattern.compile(..).
+ * For spec, see <a href="http://www.jajakarta.org/ant/ant-1.6.1/docs/ja/manual/api/org/apache/tools/ant/DirectoryScanner.html"
+ * >DirectoryScanner</a> From the spec: There is a special case regarding the
+ * use of File.separators at the beginning of the pattern and the string to
+ * match: When a pattern starts with a File.separator, the string to match
+ * must also start with a File.separator. When a pattern does not start with a
+ * File.separator, the string to match may not start with a File.separator.
+ *
+ * </p>
+ *
+ * TODO: This method could accept all ant patterns, but then all characters
+ * that have a special meaning in Java's regular expression would need to be
+ * escaped.
+ *
+ * @param antPatternString the ant pattern String.
+ * @return a pattern string that can be passed in Java's Pattern.compile(..),
+ * null if cannot process the pattern.
+ */
+ String getPatternFromAntPattern(String antPatternString) {
+ if (!antPattern.matcher(antPatternString).matches()) {
+ return null;
+ }
+ // do not handle patterns that have ***
+ if (antPatternString.indexOf("***") != -1) {
+ return null;
+ }
+ if (antPatternString.endsWith("/")) {
+ /*
+ * From the DirectoryScanner.html spec: When a pattern ends with a '/' or
+ * '\', "**" is appended. if ant pattern = testing/, path = testing/foo,
+ * result = true.
+ */
+ antPatternString = antPatternString + "**";
+ }
+ StringBuffer sb = new StringBuffer();
+ int length = antPatternString.length();
+ for (int i = 0; i < length; i++) {
+ char c = antPatternString.charAt(i);
+ switch (c) {
+ case '.':
+ sb.append("\\.");
+ break;
+ case '$':
+ sb.append("\\$");
+ break;
+ case '/':
+ // convert /** to (/[^/]*)* except when / is the first char.
+ if (i != 0 && i + 2 < length && antPatternString.charAt(i + 1) == '*'
+ && antPatternString.charAt(i + 2) == '*') {
+ sb.append("(/[^/]*)*");
+ i += 2; // handled 2 more chars than usual
+ } else {
+ sb.append(c);
+ }
+ break;
+ case '*':
+ // ** to .*
+ if (i + 1 < length && antPatternString.charAt(i + 1) == '*') {
+ if (i + 2 < length && antPatternString.charAt(i + 2) == '/') {
+ if (i == 0) {
+ /*
+ * When a pattern does not start with a File.separator, the
+ * string to match may not start with a File.separator.
+ */
+ sb.append("([^/]+/)*");
+ } else {
+ // convert **/ to ([^/]*/)*
+ sb.append("([^/]*/)*");
+ }
+ i += 2;
+ } else {
+ if (i == 0) {
+ /*
+ * When a pattern does not start with a File.separator, the
+ * string to match may not start with a File.separator.
+ */
+ sb.append("([^/].*)*");
+ } else {
+ sb.append(".*");
+ }
+ i++;
+ }
+ } else {
+ sb.append("[^/]*");
+ }
+ break;
+ default:
+ sb.append(c);
+ break;
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Obtain the appropriate resourceFilter based on defaultExcludes and isJava
+ * values. Assumptions: caseSensitive = true,and the includesList and
+ * excludesList are empty
+ */
+ private ResourceFilter getMatchingDefaultFilter(boolean defaultExcludes,
+ boolean isJava) {
+ if (defaultExcludes) {
+ return isJava ? defaultJavaFilter : defaultResourceFilter;
+ }
+ return isJava ? justJavaFilter : justResourceFilter;
+ }
+
+ private Pattern getPatternFromAntStrings(String... antPatterns) {
+ String patternStrings[] = new String[antPatterns.length];
+ int count = 0;
+ for (String antPatternString : antPatterns) {
+ String patternString = getPatternFromAntPattern(antPatternString);
+ if (patternString == null) {
+ throw new RuntimeException("Unable to convert " + antPatternString
+ + " to java code");
+ }
+ patternStrings[count++] = patternString;
+ }
+ return getPatternFromStrings(patternStrings);
+ }
+
+ private Pattern getPatternFromStrings(String... patterns) {
+ StringBuffer entirePattern = new StringBuffer("^");
+ int length = patterns.length;
+ int count = 0;
+ for (String pattern : patterns) {
+ entirePattern.append("(" + pattern + ")");
+ if (count < length - 1) {
+ entirePattern.append("|");
+ }
+ count++;
+ }
+ entirePattern.append("$");
+ return Pattern.compile(entirePattern.toString());
+ }
+
+ private boolean isJavaFile(String path) {
+ return path.endsWith(".java");
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
index 3629a14..9f0c28e 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
@@ -27,6 +27,7 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -148,6 +149,8 @@
}
}
+ private static final Map<ClassLoader, List<ClassPathEntry>> classPathCache = new HashMap<ClassLoader, List<ClassPathEntry>>();
+
public static ClassPathEntry createEntryForUrl(TreeLogger logger, URL url)
throws URISyntaxException, IOException {
if (url.getProtocol().equals("file")) {
@@ -182,11 +185,16 @@
private static void addAllClassPathEntries(TreeLogger logger,
ClassLoader classLoader, List<ClassPathEntry> classPath) {
+ Set<URL> seenEntries = new HashSet<URL>();
for (; classLoader != null; classLoader = classLoader.getParent()) {
if (classLoader instanceof URLClassLoader) {
URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
URL[] urls = urlClassLoader.getURLs();
for (URL url : urls) {
+ if (seenEntries.contains(url)) {
+ continue;
+ }
+ seenEntries.add(url);
Throwable caught;
try {
ClassPathEntry entry = createEntryForUrl(logger, url);
@@ -194,6 +202,10 @@
classPath.add(entry);
}
continue;
+ } catch (AccessControlException e) {
+ logger.log(TreeLogger.DEBUG,
+ "Skipping URL due to access restrictions: " + url);
+ continue;
} catch (URISyntaxException e) {
caught = e;
} catch (IOException e) {
@@ -206,10 +218,14 @@
}
}
- private static List<ClassPathEntry> getAllClassPathEntries(TreeLogger logger,
- ClassLoader classLoader) {
- ArrayList<ClassPathEntry> classPath = new ArrayList<ClassPathEntry>();
- addAllClassPathEntries(logger, classLoader, classPath);
+ private static synchronized List<ClassPathEntry> getAllClassPathEntries(
+ TreeLogger logger, ClassLoader classLoader) {
+ List<ClassPathEntry> classPath = classPathCache.get(classLoader);
+ if (classPath == null) {
+ classPath = new ArrayList<ClassPathEntry>();
+ addAllClassPathEntries(logger, classLoader, classPath);
+ classPathCache.put(classLoader, classPath);
+ }
return classPath;
}
@@ -361,6 +377,11 @@
this.pathPrefixSet = pathPrefixSet;
}
+ // @VisibleForTesting
+ List<ClassPathEntry> getClassPath() {
+ return classPath;
+ }
+
private boolean shouldUseNewResource(TreeLogger logger, ResourceData oldData,
ResourceData newData) {
AbstractResource newResource = newData.resource;
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
index f7a0420..96f37c9 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
@@ -20,6 +20,7 @@
import java.io.File;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -52,11 +53,21 @@
TreeLogger.DEBUG, "$0");
}
+ private static class ZipFileSnapshot {
+ private final int prefixSetSize;
+ private final Map<AbstractResource, PathPrefix> cachedAnswers;
+
+ ZipFileSnapshot(int prefixSetSize,
+ Map<AbstractResource, PathPrefix> cachedAnswers) {
+ this.prefixSetSize = prefixSetSize;
+ this.cachedAnswers = cachedAnswers;
+ }
+ }
+
private Set<ZipFileResource> allZipFileResources;
- private Map<AbstractResource, PathPrefix> cachedAnswers;
+ private final Map<PathPrefixSet, ZipFileSnapshot> cachedSnapshots = new HashMap<PathPrefixSet, ZipFileSnapshot>(
+ 2); // currently gwt has just 2 ResourceOracles.
private String cachedLocation;
- private PathPrefixSet lastPrefixSet;
- private int lastPrefixSetSize;
private final ZipFile zipFile;
public ZipFileClassPathEntry(ZipFile zipFile) {
@@ -74,13 +85,13 @@
allZipFileResources = buildIndex(logger);
}
- if (cachedAnswers == null || lastPrefixSet != pathPrefixSet
- || lastPrefixSetSize != pathPrefixSet.getSize()) {
- cachedAnswers = computeApplicableResources(logger, pathPrefixSet);
- lastPrefixSet = pathPrefixSet;
- lastPrefixSetSize = pathPrefixSet.getSize();
+ ZipFileSnapshot snapshot = cachedSnapshots.get(pathPrefixSet);
+ if (snapshot == null || snapshot.prefixSetSize != pathPrefixSet.getSize()) {
+ snapshot = new ZipFileSnapshot(pathPrefixSet.getSize(),
+ computeApplicableResources(logger, pathPrefixSet));
+ cachedSnapshots.put(pathPrefixSet, snapshot);
}
- return cachedAnswers;
+ return snapshot.cachedAnswers;
}
@Override
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index 36a197a..f2b240f 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -18,17 +18,20 @@
import com.google.gwt.core.client.GWTBridge;
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.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameter;
+import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
+import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.CompilationUnit;
import com.google.gwt.dev.javac.CompiledClass;
import com.google.gwt.dev.javac.JsniMethod;
+import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter;
import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter.InstanceMethodOracle;
-import com.google.gwt.dev.util.Jsni;
import com.google.gwt.dev.util.JsniRef;
import com.google.gwt.util.tools.Utility;
@@ -40,6 +43,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
@@ -51,6 +55,9 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.SortedMap;
+import java.util.Stack;
+import java.util.TreeMap;
import java.util.regex.Pattern;
/**
@@ -64,7 +71,8 @@
* since they really do not interact with the CompilingClassLoader
* functionality.
*/
-public final class CompilingClassLoader extends ClassLoader {
+public final class CompilingClassLoader extends ClassLoader implements
+ DispatchIdOracle {
/**
* Oracle that can answer questions about {@link DispatchClassInfo
@@ -130,12 +138,31 @@
DispatchClassInfo dispClassInfo = getClassInfoFromClassName(className);
if (dispClassInfo != null) {
String memberName = parsed.memberSignature();
+
+ /*
+ * Disallow the use of JSNI references to SingleJsoImpl interface
+ * methods. This policy is due to web-mode dispatch implementation
+ * details; resolving the JSNI reference wouldn't be just be a name
+ * replacement, instead it would be necessary to significantly alter the
+ * semantics of the hand-written JS.
+ */
+ if (singleJsoImplTypes.contains(canonicalizeClassName(className))) {
+ logger.log(TreeLogger.WARN,
+ "Invalid JSNI reference to SingleJsoImpl interface ("
+ + className + "); consider using a trampoline. "
+ + "Expect subsequent failures.", new NoSuchFieldError(
+ jsniMemberRef));
+ return -1;
+ }
+
int memberId = dispClassInfo.getMemberId(memberName);
if (memberId < 0) {
- logger.log(TreeLogger.WARN, "Member '" + memberName
- + "' in JSNI reference '" + jsniMemberRef
- + "' could not be found; expect subsequent failures",
- new NoSuchFieldError(memberName));
+ if (!className.startsWith("java.")) {
+ logger.log(TreeLogger.WARN, "Member '" + memberName
+ + "' in JSNI reference '" + jsniMemberRef
+ + "' could not be found; expect subsequent failures",
+ new NoSuchFieldError(memberName));
+ }
}
return synthesizeDispId(dispClassInfo.getClassId(), memberId);
@@ -160,7 +187,10 @@
/**
* Returns the {@link java.lang.Class} instance for a given binary class
- * name.
+ * name. It is important to avoid initializing the class because this would
+ * potentially cause initializers to be run in a different order than in web
+ * mode. Moreover, we may not have injected all of the JSNI code required to
+ * initialize the class.
*
* @param binaryClassName the binary name of a class
* @return {@link java.lang.Class} instance or null if the given binary
@@ -168,7 +198,42 @@
*/
private Class<?> getClassFromBinaryName(String binaryClassName) {
try {
- return Class.forName(binaryClassName, true, CompilingClassLoader.this);
+ int dims = 0;
+ while (binaryClassName.endsWith("[]")) {
+ dims++;
+ binaryClassName = binaryClassName.substring(0,
+ binaryClassName.length() - 2);
+ }
+
+ Class<?> clazz;
+ if ("Z".equals(binaryClassName)) {
+ clazz = boolean.class;
+ } else if ("B".equals(binaryClassName)) {
+ clazz = byte.class;
+ } else if ("C".equals(binaryClassName)) {
+ clazz = char.class;
+ } else if ("D".equals(binaryClassName)) {
+ clazz = double.class;
+ } else if ("F".equals(binaryClassName)) {
+ clazz = float.class;
+ } else if ("I".equals(binaryClassName)) {
+ clazz = int.class;
+ } else if ("J".equals(binaryClassName)) {
+ clazz = long.class;
+ } else if ("S".equals(binaryClassName)) {
+ clazz = short.class;
+ } else if ("V".equals(binaryClassName)) {
+ clazz = void.class;
+ } else {
+ clazz = Class.forName(binaryClassName, false,
+ CompilingClassLoader.this);
+ }
+
+ if (dims > 0) {
+ return Array.newInstance(clazz, new int[dims]).getClass();
+ } else {
+ return clazz;
+ }
} catch (ClassNotFoundException e) {
return null;
}
@@ -348,21 +413,22 @@
private static final Class<?>[] BRIDGE_CLASSES = new Class<?>[] {
ShellJavaScriptHost.class, GWTBridge.class};
- private static final boolean CLASS_DUMP = false;
+ private static final boolean CLASS_DUMP = Boolean.getBoolean("gwt.dev.classDump");
- private static final String CLASS_DUMP_PATH = "rewritten-classes";
+ private static final String CLASS_DUMP_PATH = System.getProperty(
+ "gwt.dev.classDumpPath", "rewritten-classes");
private static boolean emmaAvailable = false;
private static EmmaStrategy emmaStrategy;
+ private static final Pattern GENERATED_CLASSNAME_PATTERN = Pattern.compile(".+\\$\\d.*");
+
/**
* Caches the byte code for {@link JavaScriptHost}.
*/
private static byte[] javaScriptHostBytes;
- private static final Pattern GENERATED_CLASSNAME_PATTERN = Pattern.compile(".+\\$\\d.*");
-
static {
for (Class<?> c : BRIDGE_CLASSES) {
BRIDGE_CLASS_NAMES.put(c.getName(), c);
@@ -477,6 +543,11 @@
}
}
+ /**
+ * The set of units whose JSNI has already been injected.
+ */
+ private Set<CompilationUnit> alreadyInjected = new HashSet<CompilationUnit>();
+
private final HostedModeClassRewriter classRewriter;
private CompilationState compilationState;
@@ -485,10 +556,21 @@
private Class<?> gwtClass, javaScriptHostClass;
+ /**
+ * Used by {@link #findClass(String)} to prevent reentrant JSNI injection.
+ */
+ private boolean isInjectingClass = false;
+
private final TreeLogger logger;
private ShellJavaScriptHost shellJavaScriptHost;
+ private final Set<String> singleJsoImplTypes = new HashSet<String>();
+ /**
+ * Used by {@link #findClass(String)} to prevent reentrant JSNI injection.
+ */
+ private Stack<CompilationUnit> toInject = new Stack<CompilationUnit>();
+
private final TypeOracle typeOracle;
@SuppressWarnings("unchecked")
@@ -524,17 +606,28 @@
jsoTypes.add(jsoType);
Set<String> jsoTypeNames = new HashSet<String>();
- Map<String, String> jsoSuperTypes = new HashMap<String, String>();
+ Map<String, List<String>> jsoSuperTypes = new HashMap<String, List<String>>();
for (JClassType type : jsoTypes) {
+ List<String> types = new ArrayList<String>();
+ types.add(getBinaryName(type.getSuperclass()));
+ for (JClassType impl : type.getImplementedInterfaces()) {
+ types.add(getBinaryName(impl));
+ }
+
String binaryName = getBinaryName(type);
jsoTypeNames.add(binaryName);
- jsoSuperTypes.put(binaryName, getBinaryName(type.getSuperclass()));
+ jsoSuperTypes.put(binaryName, types);
}
+ // computeSingleJsoImplData has two out parameters
+ SortedMap<String, com.google.gwt.dev.asm.commons.Method> mangledNamesToImplementations = new TreeMap<String, com.google.gwt.dev.asm.commons.Method>();
+ computeSingleJsoImplData(singleJsoImplTypes,
+ mangledNamesToImplementations);
+
MyInstanceMethodOracle mapper = new MyInstanceMethodOracle(jsoTypes,
typeOracle.getJavaLangObject());
classRewriter = new HostedModeClassRewriter(jsoTypeNames, jsoSuperTypes,
- mapper);
+ mangledNamesToImplementations, singleJsoImplTypes, mapper);
} else {
// If we couldn't find the JSO class, we don't need to do any rewrites.
classRewriter = null;
@@ -626,12 +719,58 @@
throw new ClassNotFoundException(className);
}
+ /*
+ * Prevent reentrant problems where classes that need to be injected have
+ * circular dependencies on one another via JSNI and inheritance. This check
+ * ensures that a class's supertype can refer to the subtype (static
+ * members, etc) via JSNI references by ensuring that the Class for the
+ * subtype will have been defined before injecting the JSNI for the
+ * supertype.
+ */
+ boolean localInjection;
+ if (!isInjectingClass) {
+ localInjection = isInjectingClass = true;
+ } else {
+ localInjection = false;
+ }
+
Class<?> newClass = defineClass(className, classBytes, 0, classBytes.length);
if (className.equals(JavaScriptHost.class.getName())) {
javaScriptHostClass = newClass;
updateJavaScriptHost();
}
+ /*
+ * We have to inject the JSNI code after defining the class, since dispId
+ * assignment is based around reflection on Class objects. Don't inject JSNI
+ * when loading a JSO interface class; just wait until the implementation
+ * class is loaded.
+ */
+ if (!classRewriter.isJsoIntf(className)) {
+ CompilationUnit unit = getUnitForClassName(canonicalizeClassName(className));
+ if (unit != null) {
+ toInject.push(unit);
+ }
+ }
+
+ if (localInjection) {
+ try {
+ /*
+ * Can't use an iterator here because calling injectJsniFor may cause
+ * additional entries to be added.
+ */
+ while (toInject.size() > 0) {
+ CompilationUnit unit = toInject.remove(0);
+ if (!alreadyInjected.contains(unit)) {
+ injectJsniMethods(unit);
+ alreadyInjected.add(unit);
+ }
+ }
+ } finally {
+ isInjectingClass = false;
+ }
+ }
+
if (className.equals("com.google.gwt.core.client.GWT")) {
gwtClass = newClass;
updateGwtClass();
@@ -649,6 +788,123 @@
dispClassInfoOracle.clear();
}
+ /**
+ * Convert a binary class name into a resource-like name.
+ */
+ private String canonicalizeClassName(String className) {
+ String lookupClassName = className.replace('.', '/');
+ // A JSO impl class ends with $, strip it
+ if (classRewriter != null && classRewriter.isJsoImpl(className)) {
+ lookupClassName = lookupClassName.substring(0,
+ lookupClassName.length() - 1);
+ }
+ return lookupClassName;
+ }
+
+ /**
+ * Cook up the data we need to support JSO subtypes that implement interfaces
+ * with methods. This includes the set of SingleJsoImpl interfaces actually
+ * implemented by a JSO type, the mangled method names, and the names of the
+ * Methods that should actually implement the virtual functions.
+ *
+ * Given the current implementation of JSO$ and incremental execution of
+ * rebinds, it's not possible for Generators to produce additional
+ * JavaScriptObject subtypes, so this data can remain static.
+ */
+ private void computeSingleJsoImplData(
+ Set<String> singleJsoImplTypes,
+ SortedMap<String, com.google.gwt.dev.asm.commons.Method> mangledNamesToImplementations) {
+
+ // Loop over all types declared with the SingleJsoImpl annotation
+ typeLoop : for (JClassType type : typeOracle.getSingleJsoImplInterfaces()) {
+ assert type.isInterface() == type : "Expecting interfaces only";
+
+ /*
+ * By preemptively adding all possible mangled names by which a method
+ * could be called, we greatly simplify the logic necessary to rewrite the
+ * call-site.
+ *
+ * interface A {void m();}
+ *
+ * interface B extends A {void z();}
+ *
+ * becomes
+ *
+ * c_g_p_A_m() -> JsoA$.m$()
+ *
+ * c_g_p_B_m() -> JsoA$.m$()
+ *
+ * c_g_p_B_z() -> JsoB$.z$()
+ */
+ for (JMethod m : type.getOverridableMethods()) {
+ assert m.isAbstract() : "Expecting only abstract methods";
+
+ /*
+ * It is necessary to locate the implementing type on a per-method
+ * basis. Consider the case of
+ *
+ * @SingleJsoImpl interface C extends A, B {}
+ *
+ * Methods inherited from interfaces A and B must be dispatched to their
+ * respective JSO implementations.
+ */
+ JClassType implementingType = typeOracle.getSingleJsoImpl(m.getEnclosingType());
+
+ if (implementingType == null) {
+ /*
+ * This means that there is no concrete implementation of the
+ * interface by a JSO. Any implementation that might be created by a
+ * Generator won't be a JSO subtype, so we'll just ignore it as an
+ * actionable type. Were Generators ever able to create new JSO
+ * subtypes, we'd have to speculatively rewrite the callsite.
+ */
+ continue typeLoop;
+ }
+
+ /*
+ * Record the type as being actionable.
+ */
+ singleJsoImplTypes.add(canonicalizeClassName(getBinaryName(type)));
+
+ /*
+ * The mangled name adds the current interface like
+ *
+ * com_foo_Bar_methodName
+ */
+ String mangledName = getBinaryName(type).replace('.', '_') + "_"
+ + m.getName();
+
+ /*
+ * Cook up the a pseudo-method declaration for the concrete type. This
+ * should look something like
+ *
+ * ReturnType method$ (JsoType, ParamType, ParamType)
+ *
+ * This must be kept in sync with the WriteJsoImpl class.
+ */
+ String decl = getBinaryOrPrimitiveName(m.getReturnType()) + " "
+ + m.getName() + "$ (" + getBinaryOrPrimitiveName(implementingType);
+ for (JParameter p : m.getParameters()) {
+ decl += ",";
+ decl += getBinaryOrPrimitiveName(p.getType());
+ }
+ decl += ")";
+
+ com.google.gwt.dev.asm.commons.Method toImplement = com.google.gwt.dev.asm.commons.Method.getMethod(decl);
+
+ mangledNamesToImplementations.put(mangledName, toImplement);
+ }
+ }
+
+ if (logger.isLoggable(Type.SPAM)) {
+ TreeLogger dumpLogger = logger.branch(Type.SPAM,
+ "SingleJsoImpl method mappings");
+ for (Map.Entry<String, com.google.gwt.dev.asm.commons.Method> entry : mangledNamesToImplementations.entrySet()) {
+ dumpLogger.log(Type.SPAM, entry.getKey() + " -> " + entry.getValue());
+ }
+ }
+ }
+
private byte[] findClassBytes(String className) {
if (JavaScriptHost.class.getName().equals(className)) {
// No need to rewrite.
@@ -657,15 +913,15 @@
if (classRewriter != null && classRewriter.isJsoIntf(className)) {
// Generate a synthetic JSO interface class.
- return classRewriter.writeJsoIntf(className);
+ byte[] newBytes = classRewriter.writeJsoIntf(className);
+ if (CLASS_DUMP) {
+ classDump(className, newBytes);
+ }
+ return newBytes;
}
// A JSO impl class needs the class bytes for the original class.
- String lookupClassName = className.replace('.', '/');
- if (classRewriter != null && classRewriter.isJsoImpl(className)) {
- lookupClassName = lookupClassName.substring(0,
- lookupClassName.length() - 1);
- }
+ String lookupClassName = canonicalizeClassName(className);
CompiledClass compiledClass = compilationState.getClassFileMap().get(
lookupClassName);
@@ -722,11 +978,6 @@
}
}
if (classBytes != null && classRewriter != null) {
- /*
- * The injectJsniFor method defines the native methods in the browser. The
- * rewriter does the jsni injection.
- */
- injectJsniMethods(unit);
Map<String, String> anonymousClassMap = Collections.emptyMap();
if (unit != null) {
anonymousClassMap = unit.getAnonymousClassMap();
@@ -749,6 +1000,19 @@
return name;
}
+ private String getBinaryOrPrimitiveName(JType type) {
+ JClassType asClass = type.isClassOrInterface();
+ JPrimitiveType asPrimitive = type.isPrimitive();
+ if (asClass != null) {
+ return getBinaryName(asClass);
+ } else if (asPrimitive != null) {
+ return asPrimitive.getQualifiedSourceName();
+ } else {
+ throw new InternalCompilerException("Cannot create binary name for "
+ + type.getQualifiedSourceName());
+ }
+ }
+
/**
* Returns the compilationUnit corresponding to the className. For nested
* classes, the unit corresponding to the top level type is returned.
@@ -771,15 +1035,7 @@
if (unit == null || unit.getJsniMethods() == null) {
return;
}
- for (JsniMethod jsniMethod : unit.getJsniMethods()) {
- String body = Jsni.getJavaScriptForHostedMode(logger, jsniMethod);
- if (body == null) {
- // The error has been logged; just ignore it for now.
- continue;
- }
- shellJavaScriptHost.createNative(jsniMethod.location(),
- jsniMethod.line(), jsniMethod.name(), jsniMethod.paramNames(), body);
- }
+ shellJavaScriptHost.createNativeMethods(logger, unit.getJsniMethods(), this);
}
private boolean typeHasCompilationUnit(String className) {
diff --git a/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java b/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
index 9b1cbfe..4140d30 100644
--- a/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
+++ b/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
@@ -177,7 +177,6 @@
* or
*
* x.@java.lang.Object::equals(Ljava/lang/Object;)(y)
- *
*/
// Get the methods on this class/interface.
@@ -193,5 +192,8 @@
field.setAccessible(true);
addMember(field, field.getName());
}
+
+ // Add a magic field to access class literals from JSNI
+ addMember(new SyntheticClassMember(targetClass), "class");
}
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/DispatchIdOracle.java b/dev/core/src/com/google/gwt/dev/shell/DispatchIdOracle.java
new file mode 100644
index 0000000..a848445
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/DispatchIdOracle.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 com.google.gwt.dev.shell;
+
+/**
+ * A type that can map JSNI field and method references to dispatch information.
+ */
+public interface DispatchIdOracle {
+
+ /**
+ * Returns the {@link DispatchClassInfo} for a given dispatch id.
+ *
+ * @param dispId dispatch identifier
+ * @return {@link DispatchClassInfo} for a given dispatch id or null if one
+ * does not exist
+ */
+ DispatchClassInfo getClassInfoByDispId(int dispId);
+
+ /**
+ * Returns the dispatch id for a JSNI member reference.
+ *
+ * @param jsniMemberRef a JSNI member reference
+ * @return dispatch id or -1 if the JSNI member reference could not be found
+ */
+ int getDispId(String jsniMemberRef);
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java b/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java
index 52b1d0b..7737996 100644
--- a/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java
+++ b/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java
@@ -61,7 +61,19 @@
* @return the field
*/
public Field getField(int dispId) {
- return (Field) getMember(dispId);
+ Member member = getMember(dispId);
+
+ if (member instanceof SyntheticClassMember) {
+ try {
+ Field f = SyntheticClassMember.class.getDeclaredField("clazz");
+ assert f != null;
+ return f;
+ } catch (SecurityException e) {
+ } catch (NoSuchFieldException e) {
+ }
+ assert false : "Should never get here";
+ }
+ return (Field) member;
}
/**
@@ -70,7 +82,13 @@
* @throws IllegalArgumentException
*/
public Object getFieldValue(int dispId) {
- Field field = (Field) getMember(dispId);
+ Member member = getMember(dispId);
+
+ if (member instanceof SyntheticClassMember) {
+ return member.getDeclaringClass();
+ }
+
+ Field field = (Field) member;
try {
return field.get(target);
} catch (IllegalAccessException e) {
@@ -108,7 +126,8 @@
return false;
}
- return getMember(dispId) instanceof Field;
+ Member member = getMember(dispId);
+ return member instanceof Field || member instanceof SyntheticClassMember;
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
index 10aedbc..8720a1b 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
@@ -47,6 +47,11 @@
sThrownJavaExceptionObject.set(t);
}
+ /**
+ * Create a JavaScriptException object. This must be done reflectively, since
+ * this class will have been loaded from a ClassLoader other than the
+ * session's thread.
+ */
protected static RuntimeException createJavaScriptException(ClassLoader cl,
Object exception) {
Exception caught;
@@ -77,7 +82,44 @@
return threadLocalLogger.get();
}
- private final ModuleSpaceHost host;
+ /**
+ * Get the JavaScriptObject wrapped by a JavaScriptException. We have to do
+ * this reflectively, since the JavaScriptException object is from an
+ * arbitrary classloader. If the object is not a JavaScriptException, or is
+ * not from the given ClassLoader, we'll return null.
+ */
+ static Object getJavaScriptExceptionException(ClassLoader cl,
+ Object javaScriptException) {
+ if (javaScriptException.getClass().getClassLoader() != cl) {
+ return null;
+ }
+
+ Exception caught;
+ try {
+ Class<?> javaScriptExceptionClass = Class.forName(
+ "com.google.gwt.core.client.JavaScriptException", true, cl);
+
+ if (!javaScriptExceptionClass.isInstance(javaScriptException)) {
+ // Not a JavaScriptException
+ return null;
+ }
+ Method getException = javaScriptExceptionClass.getMethod("getException");
+ return getException.invoke(javaScriptException);
+ } catch (NoSuchMethodException e) {
+ caught = e;
+ } catch (ClassNotFoundException e) {
+ caught = e;
+ } catch (IllegalArgumentException e) {
+ caught = e;
+ } catch (IllegalAccessException e) {
+ caught = e;
+ } catch (InvocationTargetException e) {
+ caught = e;
+ }
+ throw new RuntimeException("Error getting exception value", caught);
+ }
+
+ protected final ModuleSpaceHost host;
private final Object key;
@@ -284,9 +326,8 @@
// Make sure we can resolve JSNI references to static Java names.
//
try {
+ createStaticDispatcher(logger);
Object staticDispatch = getStaticDispatcher();
- createNative("initializeStaticDispatcher", 0, "__defineStatic",
- new String[] {"__arg0"}, "window.__static = __arg0;");
invokeNativeVoid("__defineStatic", null, new Class[] {Object.class},
new Object[] {staticDispatch});
} catch (Throwable e) {
@@ -417,6 +458,13 @@
}
/**
+ * Create the __defineStatic method.
+ *
+ * @param logger
+ */
+ protected abstract void createStaticDispatcher(TreeLogger logger);
+
+ /**
* Invokes a native JavaScript function.
*
* @param name the name of the function to invoke
@@ -462,8 +510,7 @@
throw thrown;
}
- protected boolean isExceptionSame(@SuppressWarnings("unused")
- Throwable original, Object exception) {
+ protected boolean isExceptionSame(Throwable original, Object exception) {
// For most platforms, the null exception means we threw it.
// IE overrides this.
return exception == null;
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellJavaScriptHost.java b/dev/core/src/com/google/gwt/dev/shell/ShellJavaScriptHost.java
index 23a8f6d..967de58 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellJavaScriptHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellJavaScriptHost.java
@@ -15,7 +15,11 @@
*/
package com.google.gwt.dev.shell;
+import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.JsniMethod;
+
+import java.util.List;
/**
* This interface contains all of the methods that must be exposed to a hosted
@@ -30,14 +34,15 @@
public interface ShellJavaScriptHost {
/**
- * Defines a new native JavaScript function.
+ * Define one or more JSNI methods.
*
- * @param name the function's name, usually a JSNI signature
- * @param paramNames parameter names
- * @param js the script body
+ * @param logger
+ * @param compiledClass
+ * @param jsniMethods
+ * @param dispatchIdOracle
*/
- void createNative(String file, int line, String name, String[] paramNames,
- String js);
+ void createNativeMethods(TreeLogger logger, List<JsniMethod> jsniMethods,
+ DispatchIdOracle dispatchIdOracle);
/**
* Call this when a JavaScript exception is caught.
diff --git a/dev/core/src/com/google/gwt/dev/shell/SyntheticClassMember.java b/dev/core/src/com/google/gwt/dev/shell/SyntheticClassMember.java
new file mode 100644
index 0000000..a12ae94
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/SyntheticClassMember.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import java.lang.reflect.Member;
+
+/**
+ * This class is used to represent a synthetic field called "class" that allows
+ * JSNI references to class literals.
+ */
+public class SyntheticClassMember implements Member {
+ private final Class<?> clazz;
+
+ public SyntheticClassMember(Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ public Class getDeclaringClass() {
+ return clazz;
+ }
+
+ public int getModifiers() {
+ return Member.PUBLIC;
+ }
+
+ public String getName() {
+ return "class";
+ }
+
+ public boolean isSynthetic() {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java b/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java
index 393c364..7b88173 100644
--- a/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java
+++ b/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java
@@ -19,13 +19,17 @@
import com.google.gwt.dev.asm.ClassVisitor;
import com.google.gwt.dev.asm.ClassWriter;
import com.google.gwt.dev.asm.Opcodes;
+import com.google.gwt.dev.asm.commons.Method;
import com.google.gwt.dev.shell.JsValueGlue;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
+import java.util.SortedMap;
/**
* This class performs any and all byte code rewriting needed to make hosted
@@ -87,7 +91,7 @@
static final String JAVASCRIPTOBJECT_IMPL_DESC = JsValueGlue.JSO_IMPL_CLASS.replace(
'.', '/');
- static final String REFERENCE_FIELD = JsValueGlue.HOSTED_MODE_REFERENCE;;
+ static final String REFERENCE_FIELD = JsValueGlue.HOSTED_MODE_REFERENCE;
static String addSyntheticThisParam(String owner, String methodDescriptor) {
return "(L" + owner + ";" + methodDescriptor.substring(1);
@@ -112,13 +116,17 @@
/**
* Records the superclass of every JSO for generating empty JSO interfaces.
*/
- private final Map<String, String> jsoSuperDescs;
+ private final Map<String, List<String>> jsoSuperDescs;
/**
* Maps methods to the class in which they are declared.
*/
private InstanceMethodOracle mapper;
+ private final SortedMap<String, Method> mangledNamesToImplementations;
+
+ private final Set<String> singleJsoImplTypes;
+
/**
* Creates a new {@link HostedModeClassRewriter} for a specified set of
* subclasses of JavaScriptObject.
@@ -128,21 +136,31 @@
* @param mapper maps methods to the class in which they are declared
*/
public HostedModeClassRewriter(Set<String> jsoSubtypes,
- Map<String, String> jsoSuperTypes, InstanceMethodOracle mapper) {
+ Map<String, List<String>> jsoSuperTypes,
+ SortedMap<String, Method> mangledNamesToImplementations,
+ Set<String> singleJsoImplTypes, InstanceMethodOracle mapper) {
Set<String> buildJsoIntfDescs = new HashSet<String>();
Set<String> buildJsoImplDescs = new HashSet<String>();
- Map<String, String> buildJsoSuperDescs = new HashMap<String, String>();
+ Map<String, List<String>> buildJsoSuperDescs = new HashMap<String, List<String>>();
for (String jsoSubtype : jsoSubtypes) {
String desc = toDescriptor(jsoSubtype);
buildJsoIntfDescs.add(desc);
buildJsoImplDescs.add(desc + "$");
- String superType = jsoSuperTypes.get(jsoSubtype);
- assert (superType != null);
- buildJsoSuperDescs.put(desc, toDescriptor(superType));
+
+ List<String> superTypes = jsoSuperTypes.get(jsoSubtype);
+ assert (superTypes != null);
+ assert (superTypes.size() > 0);
+ for (ListIterator<String> i = superTypes.listIterator(); i.hasNext();) {
+ i.set(toDescriptor(i.next()));
+ }
+ buildJsoSuperDescs.put(desc, Collections.unmodifiableList(superTypes));
}
+
this.jsoIntfDescs = Collections.unmodifiableSet(buildJsoIntfDescs);
this.jsoImplDescs = Collections.unmodifiableSet(buildJsoImplDescs);
this.jsoSuperDescs = Collections.unmodifiableMap(buildJsoSuperDescs);
+ this.mangledNamesToImplementations = Collections.unmodifiableSortedMap(mangledNamesToImplementations);
+ this.singleJsoImplTypes = Collections.unmodifiableSet(singleJsoImplTypes);
this.mapper = mapper;
}
@@ -182,10 +200,14 @@
// v = new CheckClassAdapter(v);
// v = new TraceClassVisitor(v, new PrintWriter(System.out));
+ v = new RewriteSingleJsoImplDispatches(v, singleJsoImplTypes,
+ mangledNamesToImplementations);
+
v = new RewriteRefsToJsoClasses(v, jsoIntfDescs, mapper);
if (jsoImplDescs.contains(desc)) {
- v = new WriteJsoImpl(v, jsoIntfDescs, mapper);
+ v = WriteJsoImpl.create(v, desc, jsoIntfDescs, mapper,
+ mangledNamesToImplementations);
}
v = new RewriteJsniMethods(v, anonymousClassMap);
@@ -202,8 +224,9 @@
String desc = toDescriptor(className);
assert (jsoIntfDescs.contains(desc));
assert (jsoSuperDescs.containsKey(desc));
- String superDesc = jsoSuperDescs.get(desc);
- assert (superDesc != null);
+ List<String> superDescs = jsoSuperDescs.get(desc);
+ assert (superDescs != null);
+ assert (superDescs.size() > 0);
// The ASM model is to chain a bunch of visitors together.
ClassWriter writer = new ClassWriter(0);
@@ -213,10 +236,11 @@
// v = new TraceClassVisitor(v, new PrintWriter(System.out));
String[] interfaces;
- if ("java/lang/Object".equals(superDesc)) {
+ // TODO(bov): something better than linear?
+ if (superDescs.contains("java/lang/Object")) {
interfaces = null;
} else {
- interfaces = new String[] {superDesc};
+ interfaces = superDescs.toArray(new String[superDescs.size()]);
}
v.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE, desc,
null, "java/lang/Object", interfaces);
diff --git a/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteSingleJsoImplDispatches.java b/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteSingleJsoImplDispatches.java
new file mode 100644
index 0000000..b08e667
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteSingleJsoImplDispatches.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell.rewrite;
+
+import com.google.gwt.dev.asm.ClassAdapter;
+import com.google.gwt.dev.asm.ClassVisitor;
+import com.google.gwt.dev.asm.MethodAdapter;
+import com.google.gwt.dev.asm.MethodVisitor;
+import com.google.gwt.dev.asm.Opcodes;
+import com.google.gwt.dev.asm.Type;
+import com.google.gwt.dev.asm.commons.Method;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * Effects the renaming of {@code @SingleJsoImpl} methods from their original
+ * name to their mangled name. Let us call the original method an "unmangled
+ * method" and the new method a "mangled method". There are three steps in this
+ * process:
+ * <ol>
+ * <li>Within {@code @SingleJsoImpl} interfaces rename all unmangled methods to
+ * become mangled methods.</li>
+ * <li>Within non-JSO classes containing a concrete implementation of an
+ * unmangled method, add a mangled method which is implemented as a simple
+ * trampoline to the unmangled method. (We don't do this in JSO classes here
+ * because the one-and-only trampoline lives in JavaScriptObject$ and is emitted
+ * in {@link WriteJsoImpl}).
+ * <li>Update all call sites targeting unmangled methods to target mangled
+ * methods instead, provided the caller is binding to the interface rather than
+ * a concrete type.</li>
+ * </ol>
+ */
+public class RewriteSingleJsoImplDispatches extends ClassAdapter {
+ private class MyMethodVisitor extends MethodAdapter {
+ public MyMethodVisitor(MethodVisitor mv) {
+ super(mv);
+ }
+
+ /*
+ * Implements objective #3: updates call sites to unmangled methods.
+ */
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc) {
+ if (singleJsoImplTypes.contains(owner)) {
+ name = owner.replace('/', '_') + "_" + name;
+ }
+
+ super.visitMethodInsn(opcode, owner, name, desc);
+ }
+ }
+
+ private String currentTypeName;
+ private final Set<String> implementedMethods = new HashSet<String>();
+ private final SortedMap<String, Method> mangledNamesToImplementations;
+ private final Set<String> singleJsoImplTypes;
+ private boolean inSingleJsoImplInterfaceType;
+
+ public RewriteSingleJsoImplDispatches(ClassVisitor v,
+ Set<String> singleJsoImplTypes,
+ SortedMap<String, Method> mangledNamesToImplementations) {
+ super(v);
+ this.singleJsoImplTypes = Collections.unmodifiableSet(singleJsoImplTypes);
+ this.mangledNamesToImplementations = Collections.unmodifiableSortedMap(mangledNamesToImplementations);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature,
+ String superName, String[] interfaces) {
+ assert currentTypeName == null;
+ super.visit(version, access, name, signature, superName, interfaces);
+
+ currentTypeName = name;
+ inSingleJsoImplInterfaceType = singleJsoImplTypes.contains(name);
+
+ /*
+ * Implements objective #2: non-JSO types that implement a SingleJsoImpl
+ * interface don't have their original instance methods altered. Instead, we
+ * add trampoline methods with mangled names that simply call over to the
+ * original methods.
+ */
+ if (interfaces != null && (access & Opcodes.ACC_INTERFACE) == 0) {
+ List<String> toStub = new ArrayList<String>();
+ Collections.addAll(toStub, interfaces);
+ toStub.retainAll(singleJsoImplTypes);
+
+ for (String stubIntr : toStub) {
+ writeTrampoline(stubIntr);
+ }
+ }
+ }
+
+ @Override
+ public void visitEnd() {
+ /*
+ * Add any missing methods that are defined by a super-interface, but that
+ * may be referenced via a more specific interface.
+ */
+ if (inSingleJsoImplInterfaceType) {
+ for (Map.Entry<String, Method> entry : toImplement(currentTypeName).entrySet()) {
+ writeEmptyMethod(entry.getKey(), entry.getValue());
+ }
+ }
+ super.visitEnd();
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+
+ /*
+ * Implements objective #2: Rename unmangled methods in a @SingleJsoImpl
+ * into mangled methods (except for clinit, LOL).
+ */
+ if (inSingleJsoImplInterfaceType && !"<clinit>".equals(name)) {
+ name = currentTypeName.replace('/', '_') + "_" + name;
+ implementedMethods.add(name);
+ }
+
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature,
+ exceptions);
+ if (mv == null) {
+ return null;
+ }
+
+ return new MyMethodVisitor(mv);
+ }
+
+ /**
+ * Given a resource name of a class, find all mangled method names that must
+ * be implemented.
+ */
+ private SortedMap<String, Method> toImplement(String typeName) {
+ String name = typeName.replace('/', '_');
+ String prefix = name + "_";
+ String suffix = name + "`";
+ SortedMap<String, Method> toReturn = new TreeMap<String, Method>(
+ mangledNamesToImplementations.subMap(prefix, suffix));
+ toReturn.keySet().removeAll(implementedMethods);
+ return toReturn;
+ }
+
+ private void writeEmptyMethod(String mangledMethodName, Method method) {
+ assert method.getArgumentTypes().length > 0;
+ // Remove the first argument, which would be the implementing JSO type
+ String descriptor = "("
+ + method.getDescriptor().substring(
+ 1 + method.getArgumentTypes()[0].getDescriptor().length());
+
+ // Create the stub method entry in the interface
+ MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC
+ | Opcodes.ACC_ABSTRACT, mangledMethodName, descriptor, null, null);
+ mv.visitEnd();
+ }
+
+ /**
+ * For regular Java objects that implement a SingleJsoImpl interface, write
+ * instance trampoline dispatchers for mangled method names to the
+ * implementing method.
+ */
+ private void writeTrampoline(String stubIntr) {
+ /*
+ * This is almost the same kind of trampoline as the ones generated in
+ * WriteJsoImpl, however there are enough small differences between the
+ * semantics of the dispatches that would make a common implementation far
+ * more awkward than the duplication of code.
+ */
+ for (Map.Entry<String, Method> entry : toImplement(stubIntr).entrySet()) {
+ String mangledName = entry.getKey();
+ Method method = entry.getValue();
+
+ String descriptor = "("
+ + method.getDescriptor().substring(
+ 1 + method.getArgumentTypes()[0].getDescriptor().length());
+ String localName = method.getName().substring(0,
+ method.getName().length() - 1);
+ Method toCall = new Method(localName, descriptor);
+
+ // Must not be final
+ MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC
+ | Opcodes.ACC_SYNTHETIC, mangledName, descriptor, null, null);
+ if (mv != null) {
+ mv.visitCode();
+
+ /*
+ * It just so happens that the stack and local variable sizes are the
+ * same, but they're kept distinct to aid in clarity should the dispatch
+ * logic change.
+ *
+ * These start at 1 because we need to load "this" onto the stack
+ */
+ int var = 1;
+ int size = 1;
+
+ // load this
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+
+ // then the rest of the arguments
+ for (Type t : toCall.getArgumentTypes()) {
+ size += t.getSize();
+ mv.visitVarInsn(t.getOpcode(Opcodes.ILOAD), var);
+ var += t.getSize();
+ }
+
+ // Make sure there's enough room for the return value
+ size = Math.max(size, toCall.getReturnType().getSize());
+
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, currentTypeName,
+ toCall.getName(), toCall.getDescriptor());
+ mv.visitInsn(toCall.getReturnType().getOpcode(Opcodes.IRETURN));
+ mv.visitMaxs(size, var);
+ mv.visitEnd();
+ }
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoImpl.java b/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoImpl.java
index 54bced6..4adf11c 100644
--- a/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoImpl.java
+++ b/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoImpl.java
@@ -20,36 +20,205 @@
import com.google.gwt.dev.asm.FieldVisitor;
import com.google.gwt.dev.asm.MethodVisitor;
import com.google.gwt.dev.asm.Opcodes;
+import com.google.gwt.dev.asm.Type;
+import com.google.gwt.dev.asm.commons.Method;
import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter.InstanceMethodOracle;
import java.util.ArrayList;
+import java.util.Map;
import java.util.Set;
/**
- * Writes the implementation class for a JSO type.
+ * Writes the implementation classes for JSO and its subtypes.
*
+ * Changes made by the base class:
* <ol>
* <li>The new type has the same name as the old type with a '$' appended.</li>
- * <li>The new type's superclass is Object.</li>
- * <li>All instance methods in the original type become static methods taking
- * an explicit <code>this</code> parameter. Such methods have the same stack
+ * <li>All instance methods in the original type become static methods taking an
+ * explicit <code>this</code> parameter. Such methods have the same stack
* behavior as the original.</li>
- * <li>JavaScriptObject itself gets a new synthetic field to store the
- * underlying hosted mode reference.</li>
* </ol>
*/
-class WriteJsoImpl extends ClassAdapter {
+abstract class WriteJsoImpl extends ClassAdapter {
/**
- * An unmodifiable set of descriptors containing <code>JavaScriptObject</code>
- * and all subclasses.
+ * This type implements JavaScriptObject.
+ *
+ * <ol>
+ * <li>JavaScriptObject itself gets a new synthetic field to store the
+ * underlying hosted mode reference.</li>
+ * <li>Instance methods are added so that JavaScriptObject implements all
+ * SingleJsoImpl interfaces.</li>
+ * </ol>
+ *
*/
- protected final Set<String> jsoDescriptors;
+ private static class ForJsoDollar extends WriteJsoImpl {
+ /**
+ * An unmodifiable set of descriptors containing
+ * <code>JavaScriptObject</code> and all subclasses.
+ */
+ private final Set<String> jsoDescriptors;
+ private final Map<String, Method> methodsToImplement;
+
+ public ForJsoDollar(ClassVisitor cv, Set<String> jsoDescriptors,
+ InstanceMethodOracle mapper, Map<String, Method> methodsToImplement) {
+ super(cv, mapper);
+ this.jsoDescriptors = jsoDescriptors;
+ this.methodsToImplement = methodsToImplement;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature,
+ String superName, String[] interfaces) {
+
+ ArrayList<String> jsoDescList = new ArrayList<String>();
+ jsoDescList.addAll(jsoDescriptors);
+ interfaces = jsoDescList.toArray(new String[jsoDescList.size()]);
+
+ super.visit(version, access, name, signature, superName, interfaces);
+
+ /*
+ * Generate the synthetic "hostedModeReferece" field to contain the
+ * underlying real reference to the JavaScript object.
+ */
+ FieldVisitor fv = visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC,
+ HostedModeClassRewriter.REFERENCE_FIELD, "Ljava/lang/Object;", null,
+ null);
+ if (fv != null) {
+ fv.visitEnd();
+ }
+
+ // Implement the trampoline methods
+ for (Map.Entry<String, Method> entry : methodsToImplement.entrySet()) {
+ writeTrampoline(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * JSO methods are implemented as flyweight style, with the instance being
+ * passed as the first parameter. This loop create instance methods on JSO$
+ * for all of the mangled SingleJsoImpl interface method names. These
+ * instance methods simply turn around and call the static-dispatch methods.
+ * In Java, it might look like:
+ *
+ * <pre>
+ * public String com_google_Interface_someMethod(int a, double b) {
+ * return com.google.MyJso$.someMethod$(this, a, b);
+ * }
+ * </pre>
+ *
+ * @param mangledName {@code com_google_gwt_sample_hello_client_Interface_a}
+ * @param implementingMethod {@code static final java.lang.String
+ * a$(com.google.gwt.sample.hello.client.Jso, ...);}
+ */
+ private void writeTrampoline(String mangledName, Method implementingMethod) {
+ /*
+ * We derive the local descriptor by simply removing the first argument
+ * from the static method we want to call.
+ */
+ assert implementingMethod.getArgumentTypes().length > 0;
+ String localDescriptor = "("
+ + implementingMethod.getDescriptor().substring(
+ 1 + implementingMethod.getArgumentTypes()[0].getDescriptor().length());
+ Method localMethod = new Method(mangledName, localDescriptor);
+
+ /*
+ * We also use the first argument to know which type to statically
+ * dispatch to.
+ */
+ Type implementingType = Type.getType("L"
+ + implementingMethod.getArgumentTypes()[0].getInternalName() + "$;");
+
+ // Maybe create the method. This is marked final as a sanity check
+ MethodVisitor mv = visitMethodNoRewrite(Opcodes.ACC_PUBLIC
+ | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC, localMethod.getName(),
+ localMethod.getDescriptor(), null, null);
+
+ if (mv != null) {
+ mv.visitCode();
+
+ /*
+ * It just so happens that the stack and local variable sizes are the
+ * same, but they're kept distinct to aid in clarity should the dispatch
+ * logic change.
+ */
+ int var = 0;
+ int size = 0;
+
+ for (Type t : implementingMethod.getArgumentTypes()) {
+ size += t.getSize();
+ mv.visitVarInsn(t.getOpcode(Opcodes.ILOAD), var);
+ var += t.getSize();
+ }
+
+ // Make sure there's enough room for the return value
+ size = Math.max(size, implementingMethod.getReturnType().getSize());
+
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC,
+ implementingType.getInternalName(), implementingMethod.getName(),
+ implementingMethod.getDescriptor());
+ mv.visitInsn(localMethod.getReturnType().getOpcode(Opcodes.IRETURN));
+ mv.visitMaxs(size, var);
+ mv.visitEnd();
+ }
+ }
+ }
+
+ /**
+ * This type is used to implement subtypes of JSO.
+ *
+ * <ol>
+ * <li>The new type's superclass is mangled by adding $.</li>
+ * <li>Constructors are deleted.</li>
+ * </ol>
+ */
+ private static class ForJsoInterface extends WriteJsoImpl {
+ public ForJsoInterface(ClassVisitor cv, InstanceMethodOracle mapper) {
+ super(cv, mapper);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature,
+ String superName, String[] interfaces) {
+ // Reference the old superclass's implementation class.
+ superName += '$';
+ interfaces = null;
+
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ boolean isCtor = isCtor(name);
+ if (isCtor) {
+ // Don't copy over constructors except for JavaScriptObject itself.
+ return null;
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+ }
+
+ /**
+ * Creates a ClassVisitor to implement a JavaScriptObject subtype. This will
+ * select between a simple implementation for user-defined JSO subtypes and
+ * the complex implementation for implementing JavaScriptObject$.
+ */
+ public static ClassVisitor create(ClassVisitor cv, String classDescriptor,
+ Set<String> jsoDescriptors, InstanceMethodOracle mapper,
+ Map<String, Method> methodsToImplement) {
+
+ if (classDescriptor.equals(HostedModeClassRewriter.JAVASCRIPTOBJECT_IMPL_DESC)) {
+ return new ForJsoDollar(cv, jsoDescriptors, mapper, methodsToImplement);
+ } else {
+ return new ForJsoInterface(cv, mapper);
+ }
+ }
/**
* Maps methods to the class in which they are declared.
*/
- private InstanceMethodOracle mapper;
+ private final InstanceMethodOracle mapper;
/**
* The original name of the class being visited.
@@ -64,67 +233,60 @@
* <code>JavaScriptObject</code> and all subclasses
* @param mapper maps methods to the class in which they are declared
*/
- public WriteJsoImpl(ClassVisitor cv, Set<String> jsoDescriptors,
- InstanceMethodOracle mapper) {
+ private WriteJsoImpl(ClassVisitor cv, InstanceMethodOracle mapper) {
super(cv);
- this.jsoDescriptors = jsoDescriptors;
this.mapper = mapper;
}
+ /**
+ * Records the original name and resets access opcodes.
+ */
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
originalName = name;
-
- // JavaScriptObject$ must implement all JSO interface types.
- if (isJavaScriptObject()) {
- ArrayList<String> jsoDescList = new ArrayList<String>();
- jsoDescList.addAll(jsoDescriptors);
- interfaces = jsoDescList.toArray(new String[jsoDescList.size()]);
- } else {
- // Reference the old superclass's implementation class.
- superName += '$';
- interfaces = null;
- }
-
- super.visit(version, access, name + '$', signature, superName, interfaces);
-
- if (isJavaScriptObject()) {
- FieldVisitor fv = visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC,
- HostedModeClassRewriter.REFERENCE_FIELD, "Ljava/lang/Object;", null,
- null);
- if (fv != null) {
- fv.visitEnd();
- }
- }
+ super.visit(version, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC
+ | Opcodes.ACC_SYNTHETIC, name + '$', signature, superName, interfaces);
}
+ /**
+ * Mangle all instance methods declared in JavaScriptObject types.
+ */
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
- boolean isCtor = "<init>".equals(name);
- if (!isJavaScriptObject() && isCtor) {
- // Don't copy over constructors except for JavaScriptObject itself.
- return null;
- }
+ boolean isCtor = isCtor(name);
if (!isCtor && !isStatic(access) && !isObjectMethod(name + desc)) {
access |= Opcodes.ACC_STATIC;
- desc = HostedModeClassRewriter.addSyntheticThisParam(originalName, desc);
+ desc = HostedModeClassRewriter.addSyntheticThisParam(getOriginalName(),
+ desc);
name = name + "$";
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
- private boolean isJavaScriptObject() {
- return originalName.equals(HostedModeClassRewriter.JAVASCRIPTOBJECT_DESC);
+ protected String getOriginalName() {
+ return originalName;
}
- private boolean isObjectMethod(String signature) {
- return "java/lang/Object".equals(mapper.findOriginalDeclaringClass(originalName,
- signature));
+ protected boolean isCtor(String name) {
+ return "<init>".equals(name);
}
- private boolean isStatic(int access) {
+ protected boolean isObjectMethod(String signature) {
+ return "java/lang/Object".equals(mapper.findOriginalDeclaringClass(
+ originalName, signature));
+ }
+
+ protected boolean isStatic(int access) {
return (access & Opcodes.ACC_STATIC) != 0;
}
+
+ /**
+ * Allows access to an unmodified visitMethod call.
+ */
+ protected MethodVisitor visitMethodNoRewrite(int access, String name,
+ String desc, String signature, String[] exceptions) {
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
index 0bccea5..cfa4972 100644
--- a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
+++ b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
@@ -175,6 +175,14 @@
//
String catBase = System.getProperty("catalina.base");
if (catBase == null) {
+ // we (briefly) supported catalina.base.create, so let's not cut support
+ // until the deprecated sunset
+ catBase = System.getProperty("catalina.base.create");
+ if (catBase != null) {
+ logger.log(TreeLogger.WARN, "catalina.base.create is deprecated. " +
+ "Use catalina.base, and it will be created if necessary.");
+ topWorkDir = new File(catBase);
+ }
catBase = generateDefaultCatalinaBase(logger, topWorkDir);
System.setProperty("catalina.base", catBase);
}
diff --git a/dev/core/src/com/google/gwt/dev/util/AbstractTextOutput.java b/dev/core/src/com/google/gwt/dev/util/AbstractTextOutput.java
new file mode 100644
index 0000000..0aa54c2
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/AbstractTextOutput.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.util;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/**
+ * An abstract base type to build TextOutput implementations.
+ */
+public abstract class AbstractTextOutput implements TextOutput {
+ private final boolean compact;
+ private int identLevel = 0;
+ private int indentGranularity = 2;
+ private char[][] indents = new char[][] {new char[0]};
+ private boolean justNewlined;
+ private PrintWriter out;
+
+ protected AbstractTextOutput(boolean compact) {
+ this.compact = compact;
+ }
+
+ public void indentIn() {
+ ++identLevel;
+ if (identLevel >= indents.length) {
+ // Cache a new level of indentation string.
+ //
+ char[] newIndentLevel = new char[identLevel * indentGranularity];
+ Arrays.fill(newIndentLevel, ' ');
+ char[][] newIndents = new char[indents.length + 1][];
+ System.arraycopy(indents, 0, newIndents, 0, indents.length);
+ newIndents[identLevel] = newIndentLevel;
+ indents = newIndents;
+ }
+ }
+
+ public void indentOut() {
+ --identLevel;
+ }
+
+ public void newline() {
+ if (compact) {
+ out.print('\n');
+ } else {
+ out.println();
+ }
+ justNewlined = true;
+ }
+
+ public void newlineOpt() {
+ if (!compact) {
+ out.println();
+ justNewlined = true;
+ }
+ }
+
+ public void print(char c) {
+ maybeIndent();
+ out.print(c);
+ justNewlined = false;
+ }
+
+ public void print(char[] s) {
+ maybeIndent();
+ out.print(s);
+ justNewlined = false;
+ }
+
+ public void print(String s) {
+ maybeIndent();
+ out.print(s);
+ justNewlined = false;
+ }
+
+ public void printOpt(char c) {
+ if (!compact) {
+ maybeIndent();
+ out.print(c);
+ }
+ }
+
+ public void printOpt(char[] s) {
+ if (!compact) {
+ maybeIndent();
+ out.print(s);
+ }
+ }
+
+ public void printOpt(String s) {
+ if (!compact) {
+ maybeIndent();
+ out.print(s);
+ }
+ }
+
+ protected void setPrintWriter(PrintWriter out) {
+ this.out = out;
+ }
+
+ private void maybeIndent() {
+ if (justNewlined && !compact) {
+ out.print(indents[identLevel]);
+ justNewlined = false;
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/DefaultTextOutput.java b/dev/core/src/com/google/gwt/dev/util/DefaultTextOutput.java
index 5f469e6..f57a123 100644
--- a/dev/core/src/com/google/gwt/dev/util/DefaultTextOutput.java
+++ b/dev/core/src/com/google/gwt/dev/util/DefaultTextOutput.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
@@ -17,109 +17,26 @@
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.Arrays;
/**
- * Adapts {@link TextOutput} to a print writer.
+ * Adapts {@link TextOutput} to an internal text buffer.
*/
-public final class DefaultTextOutput implements TextOutput {
+public class DefaultTextOutput extends AbstractTextOutput {
- private final boolean compact;
- private int identLevel = 0;
- private int indentGranularity = 2;
- private char[][] indents = new char[][] {new char[0]};
- private boolean justNewlined;
- private final PrintWriter p;
- private final StringWriter sw;
+ private final StringWriter sw = new StringWriter();
+ private final PrintWriter out;
public DefaultTextOutput(boolean compact) {
- this.compact = compact;
- sw = new StringWriter();
- p = new PrintWriter(sw, false);
- }
-
- public void indentIn() {
- ++identLevel;
- if (identLevel >= indents.length) {
- // Cache a new level of indentation string.
- //
- char[] newIndentLevel = new char[identLevel * indentGranularity];
- Arrays.fill(newIndentLevel, ' ');
- char[][] newIndents = new char[indents.length + 1][];
- System.arraycopy(indents, 0, newIndents, 0, indents.length);
- newIndents[identLevel] = newIndentLevel;
- indents = newIndents;
- }
- }
-
- public void indentOut() {
- --identLevel;
- }
-
- public void newline() {
- if (compact) {
- p.print('\n');
- } else {
- p.println();
- }
- justNewlined = true;
- }
-
- public void newlineOpt() {
- if (!compact) {
- p.println();
- justNewlined = true;
- }
- }
-
- public void print(char c) {
- maybeIndent();
- p.print(c);
- justNewlined = false;
- }
-
- public void print(char[] s) {
- maybeIndent();
- p.print(s);
- justNewlined = false;
- }
-
- public void print(String s) {
- maybeIndent();
- p.print(s);
- justNewlined = false;
- }
-
- public void printOpt(char c) {
- if (!compact) {
- maybeIndent();
- p.print(c);
- }
- }
-
- public void printOpt(char[] s) {
- if (!compact) {
- maybeIndent();
- p.print(s);
- }
- }
-
- public void printOpt(String s) {
- if (!compact) {
- maybeIndent();
- p.print(s);
- }
+ super(compact);
+ setPrintWriter(out = new PrintWriter(sw));
}
public String toString() {
- p.flush();
- return sw.toString();
- }
-
- private void maybeIndent() {
- if (justNewlined && !compact) {
- p.print(indents[identLevel]);
- justNewlined = false;
+ out.flush();
+ if (sw != null) {
+ return sw.toString();
+ } else {
+ return super.toString();
}
}
}
diff --git a/dev/core/src/com/google/gwt/dev/util/FileBackedObject.java b/dev/core/src/com/google/gwt/dev/util/FileBackedObject.java
new file mode 100644
index 0000000..af62425
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/FileBackedObject.java
@@ -0,0 +1,103 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * Represents a File that contains the serialized form of a Serializable object.
+ *
+ * @param <T> the type of object serialized into the file
+ */
+public class FileBackedObject<T extends Serializable> implements Serializable {
+ private final File backingFile;
+ private final Class<T> clazz;
+
+ /**
+ * Constructs an empty FileBackedObject. A temporary File will be used and
+ * this file will be deleted when the JVM exits.
+ *
+ * @param clazz the type of object to be serialized
+ * @throws IOException if the temporary file could not be created
+ */
+ public FileBackedObject(Class<T> clazz) throws IOException {
+ this(clazz, File.createTempFile("fileBackedObject", ".ser"));
+ backingFile.deleteOnExit();
+ }
+
+ /**
+ * Constructs a FileBackedObject using an existing File object.
+ *
+ * @param clazz the type of object to be serialized
+ * @param backingFile the file to read from or write to
+ */
+ public FileBackedObject(Class<T> clazz, File backingFile) {
+ this.clazz = clazz;
+ this.backingFile = backingFile;
+ }
+
+ /**
+ * Returns the underlying File object.
+ */
+ public File getFile() {
+ return backingFile;
+ }
+
+ /**
+ * Construct a new instance of the object stored in the backing file.
+ *
+ * @param logger a sink for error messages
+ * @return a new instance of the object stored in the backing file
+ * @throws UnableToCompleteException if the backing store does not contain an
+ * object of type <code>T</code>
+ */
+ public T newInstance(TreeLogger logger) throws UnableToCompleteException {
+ try {
+ T toReturn = Util.readFileAsObject(backingFile, clazz);
+ if (toReturn == null) {
+ logger.log(TreeLogger.ERROR, "Unable to instantiate object");
+ throw new UnableToCompleteException();
+ }
+ return toReturn;
+ } catch (ClassNotFoundException e) {
+ logger.log(TreeLogger.ERROR, "Missing class definition", e);
+ throw new UnableToCompleteException();
+ }
+ }
+
+ /**
+ * Set the contents of the backing file.
+ *
+ * @param logger a sink for error messages
+ * @param object the object to store
+ * @throws UnableToCompleteException if the object could not be serialized
+ */
+ public void set(TreeLogger logger, T object) throws IllegalStateException,
+ UnableToCompleteException {
+ assert clazz.isInstance(object);
+ Util.writeObjectAsFile(logger, backingFile, object);
+ }
+
+ @Override
+ public String toString() {
+ return backingFile.toString() + "<" + clazz.getName() + ">";
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/HtmlTextOutput.java b/dev/core/src/com/google/gwt/dev/util/HtmlTextOutput.java
new file mode 100644
index 0000000..32b8a2e
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/HtmlTextOutput.java
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+import java.io.PrintWriter;
+
+/**
+ * An implementation of TextOutput that will produce HTML-escaped output.
+ */
+public class HtmlTextOutput extends AbstractTextOutput {
+ public HtmlTextOutput(PrintWriter out, boolean compact) {
+ super(compact);
+ setPrintWriter(out);
+ }
+
+ @Override
+ public void print(char c) {
+ print(String.valueOf(c));
+ }
+
+ @Override
+ public void print(char[] s) {
+ print(String.valueOf(s));
+ }
+
+ @Override
+ public void print(String s) {
+ super.print(Util.escapeXml(s));
+ }
+
+ @Override
+ public void printOpt(char c) {
+ printOpt(String.valueOf(c));
+ }
+
+ @Override
+ public void printOpt(char[] s) {
+ printOpt(String.valueOf(s));
+ }
+
+ @Override
+ public void printOpt(String s) {
+ super.printOpt(Util.escapeXml(s));
+ }
+
+ /**
+ * Print unescaped data into the output.
+ */
+ public void printRaw(String s) {
+ super.print(s);
+ }
+
+ /**
+ * Print unescaped data into the output.
+ */
+ public void printRawOpt(String s) {
+ super.printOpt(s);
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/util/Jsni.java b/dev/core/src/com/google/gwt/dev/util/Jsni.java
index 801a192..fa1dcbb 100644
--- a/dev/core/src/com/google/gwt/dev/util/Jsni.java
+++ b/dev/core/src/com/google/gwt/dev/util/Jsni.java
@@ -23,6 +23,7 @@
import com.google.gwt.dev.js.ast.JsFunction;
import com.google.gwt.dev.js.ast.JsNameRef;
import com.google.gwt.dev.js.ast.JsNode;
+import com.google.gwt.dev.shell.DispatchIdOracle;
import com.google.gwt.dev.shell.JavaScriptHost;
/**
@@ -102,7 +103,7 @@
* injection.
*/
public static String getJavaScriptForHostedMode(TreeLogger logger,
- JsniMethod jsniMethod) {
+ DispatchIdOracle dispatchInfo, JsniMethod jsniMethod) {
/*
* Surround the original JS body statements with a try/catch so that we can
* map JavaScript exceptions back into Java. Note that the method body
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 e0e3f75..dcbd806 100644
--- a/dev/core/src/com/google/gwt/dev/util/Util.java
+++ b/dev/core/src/com/google/gwt/dev/util/Util.java
@@ -45,7 +45,6 @@
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;
@@ -56,6 +55,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
+import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@@ -126,6 +126,16 @@
* formatted for use as a file name
*/
public static String computeStrongName(byte[] content) {
+ return computeStrongName(new byte[][] {content});
+ }
+
+ /**
+ * Computes the MD5 hash of the specified byte arrays.
+ *
+ * @return a big fat string encoding of the MD5 for the content, suitably
+ * formatted for use as a file name
+ */
+ public static String computeStrongName(byte[][] contents) {
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
@@ -133,7 +143,23 @@
throw new RuntimeException("Error initializing MD5", e);
}
- md5.update(content);
+ /*
+ * Include the lengths of the contents components in the hash, so that the
+ * hashed sequence of bytes is in a one-to-one correspondence with the
+ * possible arguments to this method.
+ */
+ ByteBuffer b = ByteBuffer.allocate((contents.length + 1) * 4);
+ b.putInt(contents.length);
+ for (int i = 0; i < contents.length; i++) {
+ b.putInt(contents[i].length);
+ }
+ b.flip();
+ md5.update(b);
+
+ // Now hash the actual contents of the arrays
+ for (int i = 0; i < contents.length; i++) {
+ md5.update(contents[i]);
+ }
return toHexString(md5.digest());
}
@@ -278,8 +304,7 @@
}
/**
- * Returns a String as a byte-array using the default encoding for the
- * compiler.
+ * Returns a byte-array representing the default encoding for a String.
*/
public static byte[] getBytes(String s) {
try {
@@ -291,6 +316,18 @@
}
/**
+ * Returns an array of byte-arrays representing the default encoding for an
+ * array of Strings.
+ */
+ public static byte[][] getBytes(String[] s) {
+ byte[][] bytes = new byte[s.length][];
+ for (int i = 0; i < s.length; i++) {
+ bytes[i] = getBytes(s[i]);
+ }
+ return bytes;
+ }
+
+ /**
* @param cls A class whose name you want.
* @return The base name for the specified class.
*/
@@ -537,6 +574,25 @@
logger.log(TreeLogger.INFO, "Unable to dump source to disk", caught);
}
+ // public static byte[][] readFileAndSplit(File file) {
+ // RandomAccessFile f = null;
+ // try {
+ // f = new RandomAccessFile(file, "r");
+ // int length = f.readInt();
+ // byte[][] results = new byte[length][];
+ // for (int i = 0; i < length; i++) {
+ // int nextLength = f.readInt();
+ // results[i] = new byte[nextLength];
+ // f.read(results[i]);
+ // }
+ // return results;
+ // } catch (IOException e) {
+ // return null;
+ // } finally {
+ // Utility.close(f);
+ // }
+ // }
+
public static byte[] readFileAsBytes(File file) {
FileInputStream fileInputStream = null;
try {
@@ -883,6 +939,14 @@
return toArray(String.class, coll);
}
+ public static String[] toStrings(byte[][] bytes) {
+ String[] strings = new String[bytes.length];
+ for (int i = 0; i < bytes.length; i++) {
+ strings[i] = toString(bytes[i]);
+ }
+ return strings;
+ }
+
public static URL toURL(File f) {
try {
return f.toURI().toURL();
@@ -987,17 +1051,14 @@
*/
public static void writeBytesToFile(TreeLogger logger, File where,
byte[][] what) throws UnableToCompleteException {
- RandomAccessFile f = null;
+ FileOutputStream f = null;
Throwable caught;
try {
where.getParentFile().mkdirs();
- f = new RandomAccessFile(where, "rwd");
- long newLen = 0;
+ f = new FileOutputStream(where);
for (int i = 0; i < what.length; i++) {
- newLen += what[i].length;
f.write(what[i]);
}
- f.setLength(newLen);
return;
} catch (FileNotFoundException e) {
caught = e;
@@ -1099,6 +1160,32 @@
}
}
+ // /**
+ // * Write all of the supplied bytes to the file, in a way that they can be
+ // read
+ // * back by {@link #readFileAndSplit(File).
+ // */
+ // public static boolean writeStringsAsFile(TreeLogger branch,
+ // File makePermFilename, String[] js) {
+ // RandomAccessFile f = null;
+ // try {
+ // makePermFilename.delete();
+ // makePermFilename.getParentFile().mkdirs();
+ // f = new RandomAccessFile(makePermFilename, "rwd");
+ // f.writeInt(js.length);
+ // for (String s : js) {
+ // byte[] b = getBytes(s);
+ // f.writeInt(b.length);
+ // f.write(b);
+ // }
+ // return true;
+ // } catch (IOException e) {
+ // return false;
+ // } finally {
+ // Utility.close(f);
+ // }
+ // }
+
/**
* Reads the specified number of bytes from the {@link InputStream}.
*
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableClassMetadata.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableClassMetadata.java
new file mode 100644
index 0000000..13590a6
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableClassMetadata.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ * An ArgHandler to provide the -disableClassMetadata flag.
+ */
+public class ArgHandlerDisableClassMetadata extends ArgHandlerFlag {
+
+ private final OptionDisableClassMetadata option;
+
+ public ArgHandlerDisableClassMetadata(OptionDisableClassMetadata option) {
+ this.option = option;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "EXPERIMENTAL: Disables some java.lang.Class methods (e.g. getName())";
+ }
+
+ @Override
+ public String getTag() {
+ return "-XdisableClassMetadata";
+ }
+
+ @Override
+ public boolean setFlag() {
+ option.setClassMetadataDisabled(true);
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableRunAsync.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableRunAsync.java
new file mode 100644
index 0000000..581ba32
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableRunAsync.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.ArgHandlerFlag;
+
+/**
+ * An ArgHandler than can be used to disable runAsync code-splitting.
+ */
+public class ArgHandlerDisableRunAsync extends ArgHandlerFlag {
+
+ private final OptionRunAsyncEnabled option;
+
+ public ArgHandlerDisableRunAsync(OptionRunAsyncEnabled option) {
+ this.option = option;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Disable runAsync code-splitting";
+ }
+
+ @Override
+ public String getTag() {
+ return "-XdisableRunAsync";
+ }
+
+ @Override
+ public boolean isUndocumented() {
+ return true;
+ }
+
+ @Override
+ public boolean setFlag() {
+ option.setRunAsyncEnabled(false);
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDraftCompile.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDraftCompile.java
new file mode 100644
index 0000000..20d40cd
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDraftCompile.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ * An ArgHandler to enable draft compiles.
+ */
+public class ArgHandlerDraftCompile extends ArgHandlerFlag {
+
+ private final OptionAggressivelyOptimize optimizeOption;
+ private final OptionDraftCompile draftOption;
+
+ public <T extends OptionDraftCompile & OptionAggressivelyOptimize> ArgHandlerDraftCompile(T option) {
+ this.optimizeOption = option;
+ this.draftOption = option;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Enable faster, but less-optimized, compilations";
+ }
+
+ @Override
+ public String getTag() {
+ return "-draftCompile";
+ }
+
+ @Override
+ public boolean setFlag() {
+ draftOption.setDraftCompile(true);
+ optimizeOption.setAggressivelyOptimize(false);
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerSoyc.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerSoyc.java
new file mode 100644
index 0000000..0bcdabd
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerSoyc.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+/**
+ * An ArgHandler that enables Story Of Your Compile data-collection.
+ */
+public class ArgHandlerSoyc extends ArgHandlerFlag {
+
+ private final OptionSoycEnabled options;
+
+ public ArgHandlerSoyc(OptionSoycEnabled options) {
+ this.options = options;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Enable Story Of Your Compile";
+ }
+
+ @Override
+ public String getTag() {
+ return "-soyc";
+ }
+
+ @Override
+ public boolean setFlag() {
+ options.setSoycEnabled(true);
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionDisableClassMetadata.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionDisableClassMetadata.java
new file mode 100644
index 0000000..eadc103
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionDisableClassMetadata.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ * Encapsulates a compiler option to disable {@link Class#getName()}.
+ */
+public interface OptionDisableClassMetadata {
+ boolean isClassMetadataDisabled();
+
+ void setClassMetadataDisabled(boolean disabled);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionDraftCompile.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionDraftCompile.java
new file mode 100644
index 0000000..8c425e3
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionDraftCompile.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ * An option that indicates that the majority of optimizations are skipped in
+ * favor of a faster compile time.
+ */
+public interface OptionDraftCompile {
+ boolean isDraftCompile();
+
+ void setDraftCompile(boolean draft);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionRunAsyncEnabled.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionRunAsyncEnabled.java
new file mode 100644
index 0000000..78dfc7b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionRunAsyncEnabled.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.dev.util.arg;
+
+/**
+ * An option to control whether or not runAsync code-splitting will be employed
+ * by the compilation.
+ */
+public interface OptionRunAsyncEnabled {
+ boolean isRunAsyncEnabled();
+
+ void setRunAsyncEnabled(boolean enabled);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionSoycEnabled.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionSoycEnabled.java
new file mode 100644
index 0000000..3e81c37
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionSoycEnabled.java
@@ -0,0 +1,25 @@
+/*
+ * 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 for enabling Story Of Your Compile data-collection.
+ */
+public interface OptionSoycEnabled {
+ boolean isSoycEnabled();
+
+ void setSoycEnabled(boolean enabled);
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/log/AbstractTreeLogger.java b/dev/core/src/com/google/gwt/dev/util/log/AbstractTreeLogger.java
index a1b1b2d..2f7de47 100644
--- a/dev/core/src/com/google/gwt/dev/util/log/AbstractTreeLogger.java
+++ b/dev/core/src/com/google/gwt/dev/util/log/AbstractTreeLogger.java
@@ -106,6 +106,7 @@
* Implements branching behavior that supports lazy logging for low-priority
* branched loggers.
*/
+ @Override
public final synchronized TreeLogger branch(TreeLogger.Type type, String msg,
Throwable caught, HelpInfo helpInfo) {
@@ -165,10 +166,15 @@
return indexWithinMyParent;
}
+ public final synchronized TreeLogger.Type getMaxDetail() {
+ return logLevel;
+ }
+
public final AbstractTreeLogger getParentLogger() {
return parent;
}
+ @Override
public final synchronized boolean isLoggable(TreeLogger.Type type) {
return !type.isLowerPriorityThan(logLevel);
}
@@ -178,6 +184,7 @@
* message type and this logger's settings. If the message is loggable, then
* parent branches may be lazily created before the log can take place.
*/
+ @Override
public final synchronized void log(TreeLogger.Type type, String msg,
Throwable caught, HelpInfo helpInfo) {
@@ -210,7 +217,7 @@
}
logLevel = type;
}
-
+
@Override
public String toString() {
return getLoggerId();
@@ -227,7 +234,6 @@
* instead.
*/
@Deprecated
- @SuppressWarnings("unused")
protected final void doCommitBranch(AbstractTreeLogger childBeingCommitted,
TreeLogger.Type type, String msg, Throwable caught) {
}
@@ -246,7 +252,6 @@
* instead.
*/
@Deprecated
- @SuppressWarnings("unused")
protected final void doLog(int indexOfLogEntryWithinParentLogger,
TreeLogger.Type type, String msg, Throwable caught) {
}
diff --git a/dev/core/src/com/google/gwt/util/tools/Utility.java b/dev/core/src/com/google/gwt/util/tools/Utility.java
index a41dbe8..4ed188b 100644
--- a/dev/core/src/com/google/gwt/util/tools/Utility.java
+++ b/dev/core/src/com/google/gwt/util/tools/Utility.java
@@ -26,6 +26,7 @@
import java.io.RandomAccessFile;
import java.io.Reader;
import java.io.Writer;
+import java.net.Socket;
import java.net.URI;
import java.net.URL;
import java.util.Iterator;
@@ -99,6 +100,19 @@
* Helper that ignores exceptions during close, because what are you going to
* do?
*/
+ public static void close(Socket socket) {
+ try {
+ if (socket != null) {
+ socket.close();
+ }
+ } catch (IOException e) {
+ }
+ }
+
+ /**
+ * Helper that ignores exceptions during close, because what are you going to
+ * do?
+ */
public static void close(Writer writer) {
try {
if (writer != null) {
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
index 6e4e378..6310a50 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
@@ -52,6 +52,17 @@
}
/**
+ * Allow a dynamic cast to an object, always succeeding if it's a JSO.
+ */
+ static Object dynamicCastAllowJso(Object src, int dstId) {
+ if (src != null && !isJavaScriptObject(src) &&
+ !canCastUnsafe(Util.getTypeId(src), dstId)) {
+ throw new ClassCastException();
+ }
+ return src;
+ }
+
+ /**
* Allow a cast to JSO only if there's no type ID.
*/
static Object dynamicCastJso(Object src) {
@@ -72,6 +83,15 @@
return (src != null) && isJavaScriptObject(src);
}
+ /**
+ * Returns true if the object is a Java object and can be cast, or if it's a
+ * non-null JSO.
+ */
+ static boolean instanceOfOrJso(Object src, int dstId) {
+ return (src != null) &&
+ (isJavaScriptObject(src) || canCast(Util.getTypeId(src), dstId));
+ }
+
static boolean isJavaObject(Object src) {
return Util.getTypeMarker(src) == getNullMethod() || Util.getTypeId(src) == 2;
}
@@ -80,6 +100,10 @@
return Util.getTypeMarker(src) != getNullMethod() && Util.getTypeId(src) != 2;
}
+ static boolean isJavaScriptObjectOrString(Object src) {
+ return Util.getTypeMarker(src) != getNullMethod();
+ }
+
/**
* Uses the not operator to perform a null-check; do NOT use on anything that
* could be a String.
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/EntryMethodHolder.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/EntryMethodHolder.java
new file mode 100644
index 0000000..8464c59
--- /dev/null
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/EntryMethodHolder.java
@@ -0,0 +1,23 @@
+/*
+ * 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.lang;
+
+/**
+ * This class holds the boot strap entry method that the compiler generates.
+ */
+public class EntryMethodHolder {
+
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
index b8eb521..34acec3 100644
--- a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
@@ -20,8 +20,19 @@
import junit.framework.TestCase;
+/**
+ * Tests the JSORestrictionsChecker.
+ */
public class JSORestrictionsTest extends TestCase {
+ static {
+ // Mac -XstartOnFirstThread bug
+ if (Thread.currentThread().getContextClassLoader() == null) {
+ Thread.currentThread().setContextClassLoader(
+ JSORestrictionsTest.class.getClassLoader());
+ }
+ }
+
public void testFinalClass() {
StringBuffer code = new StringBuffer();
code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
@@ -33,6 +44,30 @@
shouldGenerateNoError(code);
}
+ public void testImplementsInterfaces() {
+ StringBuffer goodCode = new StringBuffer();
+ goodCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ goodCode.append("public class Buggy {\n");
+ goodCode.append(" static interface Squeaks {\n");
+ goodCode.append(" public void squeak();\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static interface Squeaks2 extends Squeaks {\n");
+ goodCode.append(" public void squeak();\n");
+ goodCode.append(" public void squeak2();\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static class Squeaker extends JavaScriptObject implements Squeaks {\n");
+ goodCode.append(" public final void squeak() { }\n");
+ goodCode.append(" protected Squeaker() { }\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static class Squeaker2 extends Squeaker implements Squeaks, Squeaks2 {\n");
+ goodCode.append(" public final void squeak2() { }\n");
+ goodCode.append(" protected Squeaker2() { }\n");
+ goodCode.append(" }\n");
+ goodCode.append("}\n");
+
+ shouldGenerateNoError(goodCode);
+ }
+
public void testInstanceField() {
StringBuffer buggyCode = new StringBuffer();
buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
@@ -56,6 +91,30 @@
+ JSORestrictionsChecker.ERR_CONSTRUCTOR_WITH_PARAMETERS);
}
+ public void testMultipleImplementations() {
+ StringBuffer buggyCode = new StringBuffer();
+ buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ buggyCode.append("public class Buggy {\n");
+ buggyCode.append(" static interface Squeaks {\n");
+ buggyCode.append(" public void squeak();\n");
+ buggyCode.append(" }\n");
+ buggyCode.append(" static class Squeaker extends JavaScriptObject implements Squeaks {\n");
+ buggyCode.append(" public final void squeak() { }\n");
+ buggyCode.append(" protected Squeaker() { }\n");
+ buggyCode.append(" }\n");
+ buggyCode.append(" static class Squeaker2 extends JavaScriptObject implements Squeaks {\n");
+ buggyCode.append(" public final void squeak() { }\n");
+ buggyCode.append(" protected Squeaker2() { }\n");
+ buggyCode.append(" }\n");
+ buggyCode.append("}\n");
+
+ shouldGenerateError(buggyCode, "Line 6: "
+ + JSORestrictionsChecker.errAlreadyImplemented("Buggy$Squeaks",
+ "Buggy$Squeaker", "Buggy$Squeaker2"), "Line 10: "
+ + JSORestrictionsChecker.errAlreadyImplemented("Buggy$Squeaks",
+ "Buggy$Squeaker", "Buggy$Squeaker2"));
+ }
+
public void testNew() {
StringBuffer buggyCode = new StringBuffer();
buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
@@ -70,6 +129,20 @@
+ JSORestrictionsChecker.ERR_NEW_JSO);
}
+ public void testNoAnnotationOnInterfaceSubtype() {
+ StringBuffer goodCode = new StringBuffer();
+ goodCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ goodCode.append("public class Buggy {\n");
+ goodCode.append(" static interface Squeaks {\n");
+ goodCode.append(" public void squeak();\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static interface Sub extends Squeaks {\n");
+ goodCode.append(" }\n");
+ goodCode.append("}\n");
+
+ shouldGenerateNoError(goodCode);
+ }
+
public void testNoConstructor() {
StringBuffer buggyCode = new StringBuffer();
buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
@@ -81,23 +154,6 @@
+ JSORestrictionsChecker.ERR_NONPROTECTED_CONSTRUCTOR);
}
- public void testNoInterfaces() {
- StringBuffer buggyCode = new StringBuffer();
- buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
- buggyCode.append("public class Buggy {\n");
- buggyCode.append(" static interface Squeaks {\n");
- buggyCode.append(" public void squeak();\n");
- buggyCode.append(" }\n");
- buggyCode.append(" static class Squeaker extends JavaScriptObject implements Squeaks {\n");
- buggyCode.append(" public final void squeak() { }\n");
- buggyCode.append(" protected Squeaker() { }\n");
- buggyCode.append(" }\n");
- buggyCode.append("}\n");
-
- shouldGenerateError(buggyCode, "Line 6: "
- + JSORestrictionsChecker.errInterfaceWithMethods("Buggy.Squeaks"));
- }
-
public void testNonEmptyConstructor() {
StringBuffer buggyCode = new StringBuffer();
buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
@@ -121,6 +177,30 @@
+ JSORestrictionsChecker.ERR_INSTANCE_METHOD_NONFINAL);
}
+ public void testNonJsoInterfaceExtension() {
+ StringBuffer goodCode = new StringBuffer();
+ goodCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ goodCode.append("public class Buggy {\n");
+ goodCode.append(" static interface Squeaks {\n");
+ goodCode.append(" public void squeak();\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static interface Squeaks2 extends Squeaks {\n");
+ goodCode.append(" public void squeak2();\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static class JsoSqueaker extends JavaScriptObject implements Squeaks {\n");
+ goodCode.append(" protected JsoSqueaker() {}\n");
+ goodCode.append(" public final void squeak() {}\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static class JavaSqueaker2 implements Squeaks2 {\n");
+ goodCode.append(" protected JavaSqueaker2() {}\n");
+ goodCode.append(" public void squeak() {}\n");
+ goodCode.append(" public void squeak2() {}\n");
+ goodCode.append(" }\n");
+ goodCode.append("}\n");
+
+ shouldGenerateNoError(goodCode);
+ }
+
public void testNonProtectedConstructor() {
StringBuffer buggyCode = new StringBuffer();
buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
@@ -168,18 +248,46 @@
shouldGenerateNoError(code);
}
+ public void testTagInterfaces() {
+ StringBuffer goodCode = new StringBuffer();
+ goodCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ goodCode.append("public class Buggy {\n");
+ goodCode.append(" static interface Tag {}\n");
+ goodCode.append(" static interface Tag2 extends Tag {}\n");
+ goodCode.append(" static interface IntrExtendsTag extends Tag2 {\n");
+ goodCode.append(" public void intrExtendsTag();\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static class Squeaker3 extends JavaScriptObject implements Tag {\n");
+ goodCode.append(" public final void squeak() { }\n");
+ goodCode.append(" protected Squeaker3() { }\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static class Squeaker4 extends JavaScriptObject implements Tag2 {\n");
+ goodCode.append(" public final void squeak() { }\n");
+ goodCode.append(" protected Squeaker4() { }\n");
+ goodCode.append(" }\n");
+ goodCode.append(" static class Squeaker5 extends JavaScriptObject implements IntrExtendsTag {\n");
+ goodCode.append(" public final void intrExtendsTag() { }\n");
+ goodCode.append(" protected Squeaker5() { }\n");
+ goodCode.append(" }\n");
+ goodCode.append("}\n");
+
+ shouldGenerateNoError(goodCode);
+ }
+
/**
* Test that when compiling buggyCode, the TypeOracleBuilder emits
* expectedError somewhere in its output. The code should define a class named
* Buggy.
*/
private void shouldGenerateError(CharSequence buggyCode,
- final String expectedError) {
+ String... expectedErrors) {
UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
builder.setLowestLogLevel(TreeLogger.ERROR);
- if (expectedError != null) {
+ if (expectedErrors != null) {
builder.expectError("Errors in \'/mock/Buggy\'", null);
- builder.expectError(expectedError, null);
+ for (String e : expectedErrors) {
+ builder.expectError(e, null);
+ }
}
UnitTestTreeLogger logger = builder.createLogger();
CompilationUnit buggyCup = new MockCompilationUnit("Buggy",
@@ -189,6 +297,6 @@
}
private void shouldGenerateNoError(StringBuffer buggyCode) {
- shouldGenerateError(buggyCode, null);
+ shouldGenerateError(buggyCode, (String[]) null);
}
}
diff --git a/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
index 42ea2bc..2a63336 100644
--- a/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
+++ b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
@@ -17,7 +17,6 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.javac.CompilationUnit.State;
import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
import java.util.Collections;
@@ -59,7 +58,8 @@
}
}
JdtCompiler.compile(units);
- CompilationUnitInvalidator.validateCompilationUnits(units,
+ CompilationUnitInvalidator.InvalidatorState state = new CompilationUnitInvalidator.InvalidatorState();
+ CompilationUnitInvalidator.validateCompilationUnits(state, units,
validBinaryTypeNames);
if (CompilationUnitInvalidator.invalidateUnitsWithErrors(logger, units)) {
CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(logger, units);
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
index 29c9feb..c42d98e 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
@@ -154,8 +154,7 @@
}
protected File findJarFile(String name) throws URISyntaxException {
- ClassLoader classLoader = getClass().getClassLoader();
- URL url = classLoader.getResource(name);
+ URL url = findJarUrl(name);
assertNotNull(
"Expecting on the classpath: "
+ name
@@ -166,6 +165,15 @@
return file;
}
+ /**
+ * @param name
+ * @return
+ */
+ protected URL findJarUrl(String name) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ return classLoader.getResource(name);
+ }
+
protected Resource findResourceWithPath(Set<AbstractResource> resources,
String path) {
for (Resource r : resources) {
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/DefaultFiltersTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/DefaultFiltersTest.java
new file mode 100644
index 0000000..d2fccd7
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/DefaultFiltersTest.java
@@ -0,0 +1,458 @@
+/*
+ * 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.resource.impl;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.types.ZipScanner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * An implementation for DefaultExcludesFilterTest.
+ *
+ * Tests:
+ *
+ * 1. The filter conversion from ant to Java regex. Which cases can we handle,
+ * and confirm that we perform correctly in all cases.
+ *
+ * 2. checking the 4 defaultFilters, one for each combination of defaultExcludes
+ * and isJava.
+ *
+ * 3. Checking whether customFilter work correctly, both in presence and absence
+ * of Ant.
+ *
+ * TODO (amitmanjhi): clean up this test code.
+ */
+public class DefaultFiltersTest extends TestCase {
+
+ static class AdvancedPaths {
+ String baseIncluded[] = {
+ "Baz", "test/foo/Foo", "test/bar/Bar", "test/baz/Foo"};
+
+ String baseExcludedTesting[] = {"foo/testing/Baz"};
+ String baseExcludedExact[] = {"Foo", "Bar",};
+ String baseExcludedDoubleStar[] = {"fooz/Baz", "barz/hello/Baz"};
+ String baseExcluded[] = mergeArrays(baseExcludedTesting, baseExcludedExact,
+ baseExcludedDoubleStar);
+
+ void testAdvancedJavaPath(ResourceFilterString expected,
+ ResourceFilterString actual) {
+ for (String path : mergeArrays(baseIncluded, baseExcluded, getMiscPaths(
+ "testing", false).toArray(EMPTY_ARRAY),
+ getMiscPaths("a/bc/de", false).toArray(EMPTY_ARRAY))) {
+ assertEquals(path + ".java", expected, actual);
+ }
+ }
+
+ void testAdvancedJavaPathAnt(ResourceFilterString expected,
+ ResourceFilterString actual) {
+ for (String path : mergeArrays(baseIncluded, baseExcluded, getMiscPaths(
+ "testing", true).toArray(EMPTY_ARRAY),
+ getMiscPaths("a/bc/de", true).toArray(EMPTY_ARRAY))) {
+ assertEquals(excludedChars + path + excludedChars + javaSuffix,
+ expected, actual);
+ assertEquals(path + excludedChars + javaSuffix, expected, actual);
+ assertEquals(path + javaSuffix, expected, actual);
+ }
+ testAdvancedJavaPath(expected, actual);
+ new BasicPaths().testBasicJavaPath(expected, actual);
+ }
+
+ void testAdvancedPath(ResourceFilterString expected,
+ ResourceFilterString actual) {
+ for (String path : mergeArrays(baseIncluded, baseExcluded, getMiscPaths(
+ "testing", false).toArray(EMPTY_ARRAY),
+ getMiscPaths("a/bc/de", false).toArray(EMPTY_ARRAY))) {
+ assertEquals(path, expected, actual);
+ }
+ }
+
+ void testAdvancedPathAnt(ResourceFilterString expected,
+ ResourceFilterString actual) {
+ for (String path : mergeArrays(baseIncluded, baseExcluded, getMiscPaths(
+ "testing", true).toArray(EMPTY_ARRAY),
+ getMiscPaths("a/bc/de", true).toArray(EMPTY_ARRAY))) {
+ assertEquals(path, expected, actual);
+ assertEquals(path + excludedChars, expected, actual);
+ assertEquals(excludedChars + path + excludedChars, expected, actual);
+ }
+ testAdvancedPath(expected, actual);
+ new BasicPaths().testBasicPath(expected, actual);
+ }
+ }
+
+ static class BasicPaths {
+ String baseIncluded[] = {
+ "foo", "/foo", "foo/bar", "/foo/bar", "/foo/bar", "/foo$/$", "/foo-_",
+ "123FOO123", "cvs", "cvs/cvs/svn", ".foo_bar$", "foo/asvn"};
+ String baseExcluded[] = {"foo/CVS/bar", "foo/.svn/bar", "foo/SCCS/bar",};
+ String baseSuffixExcluded[] = {
+ "foo/.cvsignore", "foo/CVS", "foo/.svn", "foo/SCCS",
+ "foo/bar/vssver.scc", "/foo/bar/.DS_Store"};
+
+ void testBasicJavaPath(ResourceFilterString expected,
+ ResourceFilterString actual) {
+ for (String str : mergeArrays(baseIncluded, baseExcluded,
+ baseSuffixExcluded,
+ getMiscPaths("testing", true).toArray(EMPTY_ARRAY), getMiscPaths(
+ "a/bc/de", true).toArray(EMPTY_ARRAY))) {
+ assertEquals(str, expected, actual);
+ assertEquals(str + javaSuffix, expected, actual);
+ assertEquals(excludedChars + str, expected, actual);
+ assertEquals(excludedChars + str + excludedChars, expected, actual);
+ assertEquals(excludedChars + str + javaSuffix, expected, actual);
+ assertEquals(excludedChars + str + excludedChars + javaSuffix,
+ expected, actual);
+ }
+ }
+
+ void testBasicPath(ResourceFilterString expected,
+ ResourceFilterString actual) {
+ for (String str : mergeArrays(baseIncluded, baseExcluded,
+ baseSuffixExcluded,
+ getMiscPaths("testing", true).toArray(EMPTY_ARRAY), getMiscPaths(
+ "a/bc/de", true).toArray(EMPTY_ARRAY))) {
+ assertEquals(str, expected, actual);
+ assertEquals(excludedChars + str, expected, actual);
+ assertEquals(excludedChars + str + excludedChars, expected, actual);
+ }
+ }
+ }
+
+ /*
+ * Sole purpose of this class is to get a useful debug message.
+ */
+ private static class ResourceFilterString {
+ final ResourceFilter filter;
+ final String stringRepresentation;
+
+ ResourceFilterString(ResourceFilter filter, String stringRepresentation) {
+ this.filter = filter;
+ this.stringRepresentation = stringRepresentation;
+ }
+
+ }
+
+ private static final String EMPTY_ARRAY[] = new String[0];
+ private static final boolean DEFAULT_EXCLUDES = true;
+ private static final boolean DEFAULT_INCLUDES = false;
+ private static final boolean NOT_JAVA = false;
+ private static final boolean YES_JAVA = true;
+
+ private static final String mergedPatterns[] = {
+ "**/testing/**", "Foo", "Bar", "fooz/**", "barz/hello/**"};
+
+ // careful that the pattern is still permitted by ant.
+ private static final String excludedChars = "#~%*";
+
+ private static final String javaSuffix = ".java";
+
+ private static void assertEquals(String path, ResourceFilterString expected,
+ ResourceFilterString actual) {
+ boolean scanResult = expected.filter.allows(path);
+ assertEquals("String to be matched = " + path + ", actual filter = "
+ + actual.stringRepresentation + " should yied " + scanResult
+ + ", expected Filter = " + expected.stringRepresentation, scanResult,
+ actual.filter.allows(path));
+ }
+
+ private static List<String> getMiscPaths(String middleString,
+ boolean endInSlash) {
+ List<String> testPaths = new ArrayList<String>();
+ testPaths.addAll(Arrays.asList(new String[] {
+ "Foo", "Bar", "foo/xyz", "afoo/xyz-_$", "b/foo/x",
+ "foo/BarTestabc.java", "foo/xyz/BarTestabc.java", "a/b/testing/c/d",
+ "a/testing/b/c/FooBazBarTest.java", "a/testing/b/Foo/BazBar.java",
+ "a/testing/b/Foo$-_$Bar.class", "a/testing/b/Foo$/$.class"}));
+
+ String pathPrefixes[] = {"", "/", "foo/", "/foo/", "bar/foo/", "/bar/foo/"};
+ List<String> pathSuffixes = new ArrayList<String>();
+ if (endInSlash) {
+ // special handling because currently we don't handle paths that end in /
+ pathSuffixes.addAll(Arrays.asList(new String[] {
+ "", "/", "/foo", "/foo/", "/foo/bar", "/foo/bar/"}));
+ } else {
+ pathSuffixes.addAll(Arrays.asList(new String[] {"", "/foo", "/foo/bar",}));
+ }
+ for (String pathPrefix : pathPrefixes) {
+ for (String pathSuffix : pathSuffixes) {
+ testPaths.add(pathPrefix + middleString + pathSuffix);
+ }
+ }
+ return testPaths;
+ }
+
+ private static String[] mergeArrays(String[]... baseArrays) {
+ int count = 0;
+ for (String arrayElement[] : baseArrays) {
+ count += arrayElement.length;
+ }
+ String retArray[] = new String[count];
+ count = 0;
+ for (String arrayElement[] : baseArrays) {
+ for (String element : arrayElement) {
+ retArray[count++] = element;
+ }
+ }
+ return retArray;
+ }
+
+ public void testEmptyFilters() {
+ BasicPaths basicPaths = new BasicPaths();
+ DefaultFilters defaultFilters = new DefaultFilters();
+
+ // first arg: ant filter, second arg: our custom filter
+ basicPaths.testBasicPath(getAntFilter(EMPTY_ARRAY, EMPTY_ARRAY,
+ DEFAULT_EXCLUDES, NOT_JAVA, "antDefaultFilter"),
+ new ResourceFilterString(defaultFilters.defaultResourceFilter,
+ "defaultFilter"));
+ basicPaths.testBasicPath(getAntFilter(EMPTY_ARRAY, EMPTY_ARRAY,
+ DEFAULT_INCLUDES, NOT_JAVA, "antDefaultIncludesFilter"),
+ new ResourceFilterString(defaultFilters.justResourceFilter,
+ "defaultIncludesFilter"));
+
+ basicPaths.testBasicJavaPath(getAntFilter(EMPTY_ARRAY, EMPTY_ARRAY,
+ DEFAULT_EXCLUDES, YES_JAVA, "antDefaultJavaFilter"),
+ new ResourceFilterString(defaultFilters.defaultJavaFilter,
+ "defaultJavaFilter"));
+ basicPaths.testBasicJavaPath(getAntFilter(EMPTY_ARRAY, EMPTY_ARRAY,
+ DEFAULT_INCLUDES, YES_JAVA, "antJustJavaFilter"),
+ new ResourceFilterString(defaultFilters.justJavaFilter,
+ "justJavaFilter"));
+ }
+
+ /**
+ * (a) test that filters are correctly converted to non-null and null
+ * patterns. (b) test that filters match the same String.
+ */
+ public void testFilterConversion() {
+ List<String> nullFilters = Arrays.asList(new String[] {
+ "***/testing/**", "**/{/**", "**/}/**", "**/+/**",});
+ List<String> okayFilters = new ArrayList<String>();
+ okayFilters.addAll(Arrays.asList(new String[] {
+ "**/#/**", "**/~/**", "Foo", "Bar", "foo/**", "foo/*Test*java",
+ "**/testing/**", "**/testing/**/Foo*Bar*.java",
+ "**/testing/**/Foo$*r.class",}));
+ String doubleStarPrefixes[] = {"", "/", "**/", "/**/", "foo**/", "/foo**/"};
+ String doubleStarSuffixes[] = {"", "/", "/**", "/**/", "/**foo", "/**foo/"};
+ String middleString = "testing";
+ for (String doubleStarPrefix : doubleStarPrefixes) {
+ for (String doubleStarSuffix : doubleStarSuffixes) {
+ okayFilters.add(doubleStarPrefix + middleString + doubleStarSuffix);
+ }
+ }
+
+ List<String> testPaths = getMiscPaths("testing", false);
+ DefaultFilters filters = new DefaultFilters();
+ for (String filter : nullFilters) {
+ assertNull(filter + " conversion should be null",
+ filters.getPatternFromAntPattern(filter));
+ }
+
+ for (String filter : okayFilters) {
+ String pattern = filters.getPatternFromAntPattern(filter);
+ assertNotNull(filter + " conversion should be non-null", pattern);
+
+ ResourceFilterString antFilterString = getAntFilter(
+ new String[] {filter}, EMPTY_ARRAY, DEFAULT_EXCLUDES, NOT_JAVA,
+ "ant_" + filter);
+ ResourceFilterString customFilterString = new ResourceFilterString(
+ filters.customFilterWithCatchAll(new String[] {filter}, EMPTY_ARRAY,
+ true, null, NOT_JAVA), "custom_" + pattern);
+ for (String path : testPaths) {
+ assertEquals(path, antFilterString, customFilterString);
+ }
+ }
+ }
+
+ public void testFilterParts() {
+ AdvancedPaths advancedPaths = new AdvancedPaths();
+ ResourceFilter filter = null;
+
+ // everything except those starting with '/' should be included
+ filter = new DefaultFilters().getFilterPart(EMPTY_ARRAY, true);
+ advancedPaths.testAdvancedPath(getAntFilter(EMPTY_ARRAY, EMPTY_ARRAY,
+ DEFAULT_INCLUDES, NOT_JAVA, "antDefaultFilter"),
+ new ResourceFilterString(filter, "defaultFilter"));
+
+ // everything should be excluded
+ filter = new DefaultFilters().getFilterPart(EMPTY_ARRAY, false);
+ advancedPaths.testAdvancedPath(getAntFilter(new String[] {"a/1/2/3"},
+ new String[] {"**", "/**"}, DEFAULT_INCLUDES, NOT_JAVA,
+ "antDefaultFilter"), new ResourceFilterString(filter, "defaultFilter"));
+
+ filter = new DefaultFilters().getFilterPart(mergedPatterns, true);
+ advancedPaths.testAdvancedPath(getAntFilter(mergedPatterns, EMPTY_ARRAY,
+ DEFAULT_INCLUDES, NOT_JAVA, "antMergedPatterns"),
+ new ResourceFilterString(filter, "customMergedPatterns"));
+ }
+
+ // no ant, catchAll filter is null
+ public void testNonEmptyFilters() {
+ AdvancedPaths advancedPaths = new AdvancedPaths();
+
+ ResourceFilter filter = null;
+ // pass empty includeArray. Matches everything that is not excluded.
+ filter = getFilterWithoutCatchAll(EMPTY_ARRAY, mergedPatterns, NOT_JAVA);
+ advancedPaths.testAdvancedPath(getAntFilter(EMPTY_ARRAY, mergedPatterns,
+ DEFAULT_EXCLUDES, NOT_JAVA, "ant_emptyArray_mergedPatterns"),
+ new ResourceFilterString(filter, "custom_emptyArray_mergedPatterns"));
+
+ // pass empty excludeArray. Matches everything that is included.
+ filter = getFilterWithoutCatchAll(mergedPatterns, EMPTY_ARRAY, NOT_JAVA);
+ advancedPaths.testAdvancedPath(getAntFilter(mergedPatterns, EMPTY_ARRAY,
+ DEFAULT_EXCLUDES, NOT_JAVA, "ant_mergedPatterns_emptyArray"),
+ new ResourceFilterString(filter, "custom_mergedPatterns_emptyArray"));
+
+ // pass non-empty include and exclude array. Matches nothing
+ filter = getFilterWithoutCatchAll(mergedPatterns, mergedPatterns, NOT_JAVA);
+ advancedPaths.testAdvancedPath(
+ getAntFilter(mergedPatterns, mergedPatterns, DEFAULT_EXCLUDES,
+ NOT_JAVA, "ant_mergedPatterns_mergedPatterns"),
+ new ResourceFilterString(filter, "custom_mergedPatterns_mergedPatterns"));
+ }
+
+ // finish, catchAll filter is not-null
+ public void testNonEmptyFiltersAnt() {
+ AdvancedPaths advancedPaths = new AdvancedPaths();
+
+ ResourceFilter filter = null;
+ // pass empty includeArray. Matches everything that is not excluded.
+ filter = getFilterWithCatchAll(EMPTY_ARRAY, mergedPatterns, NOT_JAVA);
+ advancedPaths.testAdvancedPathAnt(getAntFilter(EMPTY_ARRAY, mergedPatterns,
+ DEFAULT_EXCLUDES, NOT_JAVA, "ant_emptyArray_mergedPatterns"),
+ new ResourceFilterString(filter, "custom_emptyArray_mergedPatterns"));
+
+ // pass empty excludeArray. Matches everything that is included.
+ filter = getFilterWithCatchAll(mergedPatterns, EMPTY_ARRAY, NOT_JAVA);
+ advancedPaths.testAdvancedPathAnt(getAntFilter(mergedPatterns, EMPTY_ARRAY,
+ DEFAULT_EXCLUDES, NOT_JAVA, "ant_emptyArray_mergedPatterns"),
+ new ResourceFilterString(filter, "custom_emptyArray_mergedPatterns"));
+
+ // pass non-empty include and exclude array. Matches nothing
+ filter = getFilterWithCatchAll(mergedPatterns, mergedPatterns, NOT_JAVA);
+ advancedPaths.testAdvancedPathAnt(getAntFilter(mergedPatterns,
+ mergedPatterns, DEFAULT_EXCLUDES, NOT_JAVA,
+ "ant_mergedPatterns_mergedPatterns"), new ResourceFilterString(filter,
+ "custom_mergedPatterns_mergedPatterns"));
+ }
+
+ // no ant, catchAll filter is null
+ public void testNonEmptyJavaFilters() {
+ AdvancedPaths advancedPaths = new AdvancedPaths();
+
+ String newMergedPatterns[] = new String[mergedPatterns.length];
+ for (int i = 0; i < mergedPatterns.length; i++) {
+ if (mergedPatterns[i].endsWith("*")) {
+ newMergedPatterns[i] = mergedPatterns[i];
+ } else {
+ newMergedPatterns[i] = mergedPatterns[i] + ".java";
+ }
+ }
+ ResourceFilter filter = null;
+ // pass empty includeArray. Means catch all
+ filter = getFilterWithoutCatchAll(EMPTY_ARRAY, newMergedPatterns, YES_JAVA);
+ advancedPaths.testAdvancedJavaPath(getAntFilter(EMPTY_ARRAY,
+ newMergedPatterns, DEFAULT_EXCLUDES, YES_JAVA,
+ "ant_emptyArray_newMergedPatterns"), new ResourceFilterString(filter,
+ "custom_emptyArray_newMergedPatterns"));
+
+ // pass empty excludeArray. Means catch only the pattern
+ filter = getFilterWithoutCatchAll(newMergedPatterns, EMPTY_ARRAY, YES_JAVA);
+ advancedPaths.testAdvancedJavaPath(getAntFilter(newMergedPatterns,
+ EMPTY_ARRAY, DEFAULT_EXCLUDES, YES_JAVA,
+ "ant_newMergedPatterns_emptyArray"), new ResourceFilterString(filter,
+ "custom_newMergedPatterns_emptyArray"));
+
+ // pass non-empty include and exclude array.
+ filter = getFilterWithoutCatchAll(newMergedPatterns, newMergedPatterns,
+ YES_JAVA);
+ advancedPaths.testAdvancedJavaPath(getAntFilter(newMergedPatterns,
+ newMergedPatterns, DEFAULT_EXCLUDES, YES_JAVA,
+ "ant_newMergedPatterns_newMergedPatterns"), new ResourceFilterString(
+ filter, "custom_newMergedPatterns_newMergedPatterns"));
+ }
+
+ public void testNonEmptyJavaFiltersAnt() {
+ AdvancedPaths advancedPaths = new AdvancedPaths();
+
+ String newMergedPatterns[] = new String[mergedPatterns.length];
+ for (int i = 0; i < mergedPatterns.length; i++) {
+ if (mergedPatterns[i].endsWith("*")) {
+ newMergedPatterns[i] = mergedPatterns[i];
+ } else {
+ newMergedPatterns[i] = mergedPatterns[i] + ".java";
+ }
+ }
+ ResourceFilter filter = null;
+ // pass empty includeArray. Means catch all
+ filter = getFilterWithCatchAll(EMPTY_ARRAY, newMergedPatterns, YES_JAVA);
+ advancedPaths.testAdvancedJavaPathAnt(getAntFilter(EMPTY_ARRAY,
+ newMergedPatterns, DEFAULT_EXCLUDES, YES_JAVA,
+ "ant_emptyArray_newMergedPatterns"), new ResourceFilterString(filter,
+ "custom_emptyArray_newMergedPatterns"));
+
+ // pass empty excludeArray. Means catch only the pattern
+ filter = getFilterWithCatchAll(newMergedPatterns, EMPTY_ARRAY, YES_JAVA);
+ advancedPaths.testAdvancedJavaPathAnt(getAntFilter(newMergedPatterns,
+ EMPTY_ARRAY, DEFAULT_EXCLUDES, YES_JAVA,
+ "ant_newMergedPatterns_emptyArray"), new ResourceFilterString(filter,
+ "custom_newMergedPatterns_emptyArray"));
+
+ // pass non-empty include and exclude array.
+ filter = getFilterWithCatchAll(newMergedPatterns, newMergedPatterns,
+ YES_JAVA);
+ advancedPaths.testAdvancedJavaPathAnt(getAntFilter(newMergedPatterns,
+ newMergedPatterns, DEFAULT_EXCLUDES, YES_JAVA,
+ "ant_newMergedPatterns_newMergedPatterns"), new ResourceFilterString(
+ filter, "custom_newMergedPatterns_newMergedPatterns"));
+ }
+
+ private ResourceFilterString getAntFilter(String includes[],
+ String excludes[], boolean defaultExcludes, final boolean isJava,
+ String tag) {
+ final ZipScanner scanner = DefaultFilters.getScanner(includes, excludes,
+ defaultExcludes, true);
+ return new ResourceFilterString(new ResourceFilter() {
+ public boolean allows(String path) {
+ if (isJava && !path.endsWith(".java")) {
+ return false;
+ }
+ return scanner.match(path);
+ }
+ }, tag != null ? tag : "includes: " + includes + ", excludes: " + excludes);
+ }
+
+ private ResourceFilter getFilterWithCatchAll(String includesList[],
+ String excludesList[], boolean isJava) {
+ if (isJava) {
+ return new DefaultFilters().customJavaFilter(includesList, excludesList,
+ true, true);
+ }
+ return new DefaultFilters().customResourceFilter(includesList,
+ excludesList, true, true);
+ }
+
+ // caseSensitive and excludeDefaults are set
+ private ResourceFilter getFilterWithoutCatchAll(String includesList[],
+ String excludesList[], boolean isJava) {
+ return new DefaultFilters().customFilterWithCatchAll(includesList,
+ excludesList, true, null, isJava);
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
index 5473026..788449a 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
@@ -23,12 +23,16 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.net.MalformedURLException;
import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.jar.JarFile;
/**
* Tests {@link ResourceOracleImpl}.
@@ -128,6 +132,37 @@
}
}
+ public void testCachingOfJarResources() throws IOException,
+ URISyntaxException {
+ TreeLogger logger = createTestTreeLogger();
+ ClassPathEntry cpe1jar = new ZipFileClassPathEntry(new JarFile(
+ findJarFile("com/google/gwt/dev/resource/impl/testdata/cpe1.jar")));
+
+ // test basic caching
+ PathPrefixSet pps1 = new PathPrefixSet();
+ pps1.add(new PathPrefix("com/google/gwt", null, false));
+ Map<AbstractResource, PathPrefix> resourceMap1 = cpe1jar.findApplicableResources(
+ logger, pps1);
+ assertSame(resourceMap1, cpe1jar.findApplicableResources(logger, pps1));
+
+ // test that cache is invalidated if PathPrefixSet is modified.
+ pps1.add(new PathPrefix("com/google/gwt/user", null, false));
+ Map<AbstractResource, PathPrefix> resourceMap2 = cpe1jar.findApplicableResources(
+ logger, pps1);
+ assertNotSame(resourceMap1, resourceMap2);
+
+ PathPrefixSet pps2 = new PathPrefixSet();
+ pps2.add(new PathPrefix("org/example/bar", null, false));
+ Map<AbstractResource, PathPrefix> resourceMap3 = cpe1jar.findApplicableResources(
+ logger, pps2);
+ // check that the entry did go in the cache
+ assertSame(resourceMap3, cpe1jar.findApplicableResources(logger, pps2));
+
+ // check that the cache does not thrash
+ assertSame(resourceMap2, cpe1jar.findApplicableResources(logger, pps1));
+ assertSame(resourceMap3, cpe1jar.findApplicableResources(logger, pps2));
+ }
+
/**
* Test that ResourceOracleImpl preserves the order in which the same logical
* resource is occurs in multiple ClassPathEntries.
@@ -218,6 +253,32 @@
testReadingResource(cpe1dir, cpe2dir);
}
+ /**
+ * Verify that duplicate entries are removed from the classpath, and that
+ * multiple ResourceOracleImpls created from the same classloader return the
+ * same list of ClassPathEntries.
+ *
+ * @throws MalformedURLException
+ */
+ public void testRemoveDuplicates() throws MalformedURLException {
+ TreeLogger logger = createTestTreeLogger();
+ URL cpe1 = findJarUrl("com/google/gwt/dev/resource/impl/testdata/cpe1.jar");
+ URL cpe2 = findJarUrl("com/google/gwt/dev/resource/impl/testdata/cpe2.jar");
+ URLClassLoader classLoader = new URLClassLoader(new URL[] {
+ cpe1, cpe2, cpe2, cpe1, cpe2,}, null);
+ ResourceOracleImpl oracle = new ResourceOracleImpl(logger, classLoader);
+ List<ClassPathEntry> classPath = oracle.getClassPath();
+ assertEquals(2, classPath.size());
+ assertJarEntry(classPath.get(0), "cpe1.jar");
+ assertJarEntry(classPath.get(1), "cpe2.jar");
+ oracle = new ResourceOracleImpl(logger, classLoader);
+ List<ClassPathEntry> classPath2 = oracle.getClassPath();
+ assertEquals(2, classPath2.size());
+ for (int i = 0; i < 2; ++i) {
+ assertSame(classPath.get(i), classPath2.get(i));
+ }
+ }
+
public void testResourceAddition() throws IOException, URISyntaxException {
ClassPathEntry cpe1mock = getClassPathEntry1AsMock();
ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
@@ -333,6 +394,18 @@
}
/**
+ * @param classPathEntry
+ * @param string
+ */
+ private void assertJarEntry(ClassPathEntry classPathEntry, String expected) {
+ assertTrue("Should be instance of ZipFileClassPathEntry",
+ classPathEntry instanceof ZipFileClassPathEntry);
+ ZipFileClassPathEntry zipCPE = (ZipFileClassPathEntry) classPathEntry;
+ String jar = zipCPE.getLocation();
+ assertTrue("URL should contain " + expected, jar.contains(expected));
+ }
+
+ /**
* Creates an array of class path entries, setting up each one with a
* well-known set of client prefixes.
*/
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/ModuleSpaceMoz.java b/dev/linux/src/com/google/gwt/dev/shell/moz/ModuleSpaceMoz.java
index 6ee992e..2b608f4 100644
--- a/dev/linux/src/com/google/gwt/dev/shell/moz/ModuleSpaceMoz.java
+++ b/dev/linux/src/com/google/gwt/dev/shell/moz/ModuleSpaceMoz.java
@@ -16,11 +16,16 @@
package com.google.gwt.dev.shell.moz;
import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.javac.JsniMethod;
import com.google.gwt.dev.shell.CompilingClassLoader;
+import com.google.gwt.dev.shell.DispatchIdOracle;
import com.google.gwt.dev.shell.JsValue;
import com.google.gwt.dev.shell.JsValueGlue;
import com.google.gwt.dev.shell.ModuleSpace;
import com.google.gwt.dev.shell.ModuleSpaceHost;
+import com.google.gwt.dev.util.Jsni;
+
+import java.util.List;
/**
* An implementation of {@link com.google.gwt.dev.shell.ModuleSpace} for
@@ -43,19 +48,24 @@
SwtGeckoGlue.addRefInt(window);
}
- /*
- * (non-Javadoc)
+ /**
+ * Define one or more JSNI methods.
*
- * @see com.google.gwt.dev.shell.ShellJavaScriptHost#createNative(java.lang.String,
- * int, java.lang.String, java.lang.String[], java.lang.String)
+ * @param logger
+ * @param jsniMethods
*/
- public void createNative(String file, int line, String jsniSignature,
- String[] paramNames, String js) {
- // Execute the function definition within the browser, which will define
- // a new top-level function.
- //
- String newScript = createNativeMethodInjector(jsniSignature, paramNames, js);
- LowLevelMoz.executeScriptWithInfo(window, newScript, file, line);
+ public void createNativeMethods(TreeLogger logger,
+ List<JsniMethod> jsniMethods, DispatchIdOracle dispatchIdOracle) {
+ for (JsniMethod jsniMethod : jsniMethods) {
+ String body = Jsni.getJavaScriptForHostedMode(logger, dispatchIdOracle,
+ jsniMethod);
+ if (body == null) {
+ // The error has been logged; just ignore it for now.
+ continue;
+ }
+ createNative(jsniMethod.location(), jsniMethod.line(), jsniMethod.name(),
+ jsniMethod.paramNames(), body);
+ }
}
/*
@@ -69,6 +79,12 @@
super.dispose();
}
+ @Override
+ protected void createStaticDispatcher(TreeLogger logger) {
+ createNative("initializeStaticDispatcher", 0, "__defineStatic",
+ new String[] {"__arg0"}, "window.__static = __arg0;");
+ }
+
/**
* Invokes a native JavaScript function.
*
@@ -105,4 +121,20 @@
protected Object getStaticDispatcher() {
return new GeckoDispatchAdapter(getIsolatedClassLoader());
}
+
+ /**
+ * Defines a new native JavaScript function.
+ *
+ * @param name the function's name, usually a JSNI signature
+ * @param paramNames parameter names
+ * @param js the script body
+ */
+ private void createNative(String file, int line, String jsniSignature,
+ String[] paramNames, String js) {
+ // Execute the function definition within the browser, which will define
+ // a new top-level function.
+ //
+ String newScript = createNativeMethodInjector(jsniSignature, paramNames, js);
+ LowLevelMoz.executeScriptWithInfo(window, newScript, file, line);
+ }
}
diff --git a/dev/mac/src/com/google/gwt/dev/shell/mac/ModuleSpaceSaf.java b/dev/mac/src/com/google/gwt/dev/shell/mac/ModuleSpaceSaf.java
index d4eaa4a..036edc6 100644
--- a/dev/mac/src/com/google/gwt/dev/shell/mac/ModuleSpaceSaf.java
+++ b/dev/mac/src/com/google/gwt/dev/shell/mac/ModuleSpaceSaf.java
@@ -16,11 +16,16 @@
package com.google.gwt.dev.shell.mac;
import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.javac.JsniMethod;
import com.google.gwt.dev.shell.CompilingClassLoader;
+import com.google.gwt.dev.shell.DispatchIdOracle;
import com.google.gwt.dev.shell.JsValue;
import com.google.gwt.dev.shell.JsValueGlue;
import com.google.gwt.dev.shell.ModuleSpace;
import com.google.gwt.dev.shell.ModuleSpaceHost;
+import com.google.gwt.dev.util.Jsni;
+
+import java.util.List;
/**
* An implementation of {@link com.google.gwt.dev.shell.ModuleSpace} for Safari.
@@ -50,13 +55,18 @@
LowLevelSaf.retainJsGlobalContext(scriptGlobalContext);
}
- public void createNative(String file, int line, String jsniSignature,
- String[] paramNames, String js) {
- // Execute the function definition within the browser, which will define
- // a new top-level function.
- //
- String newScript = createNativeMethodInjector(jsniSignature, paramNames, js);
- LowLevelSaf.executeScriptWithInfo(globalContext, newScript, file, line);
+ public void createNativeMethods(TreeLogger logger,
+ List<JsniMethod> jsniMethods, DispatchIdOracle dispatchIdOracle) {
+ for (JsniMethod jsniMethod : jsniMethods) {
+ String body = Jsni.getJavaScriptForHostedMode(logger, dispatchIdOracle,
+ jsniMethod);
+ if (body == null) {
+ // The error has been logged; just ignore it for now.
+ continue;
+ }
+ createNative(jsniMethod.location(), jsniMethod.line(), jsniMethod.name(),
+ jsniMethod.paramNames(), body);
+ }
}
@Override
@@ -66,6 +76,12 @@
super.dispose();
}
+ @Override
+ protected void createStaticDispatcher(TreeLogger logger) {
+ createNative("initializeStaticDispatcher", 0, "__defineStatic",
+ new String[] {"__arg0"}, "window.__static = __arg0;");
+ }
+
/**
* Invokes a native JavaScript function.
*
@@ -106,4 +122,13 @@
protected Object getStaticDispatcher() {
return new WebKitDispatchAdapter(getIsolatedClassLoader());
}
+
+ private void createNative(String file, int line, String jsniSignature,
+ String[] paramNames, String js) {
+ // Execute the function definition within the browser, which will define
+ // a new top-level function.
+ //
+ String newScript = createNativeMethodInjector(jsniSignature, paramNames, js);
+ LowLevelSaf.executeScriptWithInfo(globalContext, newScript, file, line);
+ }
}
diff --git a/dev/oophm/build.xml b/dev/oophm/build.xml
new file mode 100755
index 0000000..5cff13b
--- /dev/null
+++ b/dev/oophm/build.xml
@@ -0,0 +1,41 @@
+<project name="dev-oophm" default="build" basedir=".">
+ <property name="gwt.root" location="../.." />
+ <property name="project.tail" value="dev/oophm" />
+ <import file="${gwt.root}/common.ant.xml" />
+
+ <property.ensure name="gwt.core.root" location="../core" />
+ <property.ensure name="gwt.core.build" location="${project.build}/../core" />
+
+ <target name="compile" description="Compile all java files">
+ <mkdir dir="${javac.out}" />
+ <!-- TODO: merge into gwc.java rule? -->
+ <javac destdir="${javac.out}" debug="${javac.debug}" debuglevel="${javac.debuglevel}" source="${javac.source}" target="${javac.target}" nowarn="${javac.nowarn}" encoding="${javac.encoding}" >
+ <src path="src" />
+ <src path="overlay" />
+ <classpath>
+ <pathelement location="${gwt.tools.lib}/sun/swingworker/swing-worker-1.1.jar" />
+ <pathelement location="${gwt.core.build}/bin" />
+ <pathelement location="${gwt.core.build}/alldeps.jar" />
+ </classpath>
+ </javac>
+ </target>
+
+ <target name="build" depends="compile" description="Build and package this project">
+ <mkdir dir="${gwt.build.lib}" />
+ <gwt.jar>
+ <fileset dir="src" excludes="**/package.html"/>
+ <fileset dir="overlay" excludes="**/package.html"/>
+ <fileset dir="${javac.out}" />
+ <zipfileset src="${gwt.tools.lib}/sun/swingworker/swing-worker-1.1.jar" />
+ <manifest>
+ <attribute name="Main-Class" value="com.google.gwt.dev.GWTMain" />
+ </manifest>
+ </gwt.jar>
+ </target>
+
+ <target name="clean" description="Cleans this project's intermediate and output files">
+ <delete dir="${project.build}" failonerror="false" />
+ <delete file="${project.lib}" failonerror="false" />
+ </target>
+
+</project>
diff --git a/dev/oophm/overlay/com/google/gwt/dev/BootStrapPlatform.java b/dev/oophm/overlay/com/google/gwt/dev/BootStrapPlatform.java
new file mode 100644
index 0000000..04af8bc
--- /dev/null
+++ b/dev/oophm/overlay/com/google/gwt/dev/BootStrapPlatform.java
@@ -0,0 +1,78 @@
+/*
+ * 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 java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
+
+/**
+ * Initializes platform stuff.
+ */
+public class BootStrapPlatform {
+
+ public static void applyPlatformHacks() {
+ if (isMac()) {
+ setSystemProperties();
+ fixContextClassLoaderOnMainThread();
+ }
+ }
+
+ /**
+ * This method allows the compiler to have a tree logger in an AWT window and
+ * allow generators to use AWT for image generation.
+ */
+ public static void initGui() {
+ if (isMac() && !GraphicsEnvironment.isHeadless()) {
+ GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
+ Toolkit.getDefaultToolkit();
+ }
+ }
+
+ public static void initHostedMode() {
+ // nothing required
+ }
+
+ /**
+ * This works around apple radr:5569300. When -XstartOnFirstThread is passed
+ * as a jvm argument, the main thread returns null for
+ * {@link Thread#getContextClassLoader()}.
+ */
+ private static void fixContextClassLoaderOnMainThread() {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ if (classLoader == null) {
+ Thread.currentThread().setContextClassLoader(
+ BootStrapPlatform.class.getClassLoader());
+ }
+ }
+
+ /**
+ * Return true if we are running on a Mac.
+ */
+ private static boolean isMac() {
+ String lcOSName = System.getProperty("os.name").toLowerCase();
+ return lcOSName.startsWith("mac ");
+ }
+
+ /**
+ * Sets platform specific system properties. Currently, this disables
+ * CocoaComponent CompatibilityMode.
+ */
+ private static void setSystemProperties() {
+ // Disable CocoaComponent compatibility mode.
+ System.setProperty("com.apple.eawt.CocoaComponent.CompatibilityMode",
+ "false");
+ }
+}
diff --git a/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java b/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java
new file mode 100644
index 0000000..eb3df67
--- /dev/null
+++ b/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java
@@ -0,0 +1,659 @@
+/*
+ * 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.TreeLogger.Type;
+import com.google.gwt.core.ext.linker.ArtifactSet;
+import com.google.gwt.core.ext.linker.EmittedArtifact;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.GWTCompiler.GWTCompilerOptionsImpl;
+import com.google.gwt.dev.cfg.ModuleDef;
+import com.google.gwt.dev.cfg.ModuleDefLoader;
+import com.google.gwt.dev.shell.ArtifactAcceptor;
+import com.google.gwt.dev.shell.BrowserListener;
+import com.google.gwt.dev.shell.BrowserWidget;
+import com.google.gwt.dev.shell.BrowserWidgetHost;
+import com.google.gwt.dev.shell.ModuleSpaceHost;
+import com.google.gwt.dev.shell.OophmSessionHandler;
+import com.google.gwt.dev.shell.ShellMainWindow;
+import com.google.gwt.dev.shell.ShellModuleSpaceHost;
+import com.google.gwt.dev.shell.WorkDirs;
+import com.google.gwt.dev.shell.tomcat.EmbeddedTomcatServer;
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
+import com.google.gwt.dev.util.log.AbstractTreeLogger;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.util.tools.ArgHandlerExtra;
+import com.google.gwt.util.tools.ArgHandlerString;
+
+import java.awt.Cursor;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JTabbedPane;
+import javax.swing.WindowConstants;
+
+/**
+ * The main executable class for the hosted mode shell.
+ */
+@SuppressWarnings("deprecation")
+@Deprecated
+public class GWTShell extends HostedModeBase {
+
+ /**
+ * Handles the -portHosted command line flag.
+ */
+ protected static class ArgHandlerPortHosted extends ArgHandlerString {
+
+ private final OptionPortHosted options;
+
+ public ArgHandlerPortHosted(OptionPortHosted options) {
+ this.options = options;
+ }
+
+ @Override
+ public String[] getDefaultArgs() {
+ return new String[] {"-portHosted", "9997"};
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Listens on the specified port for hosted mode connections";
+ }
+
+ @Override
+ public String getTag() {
+ return "-portHosted";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"port-number | \"auto\""};
+ }
+
+ @Override
+ public boolean setString(String value) {
+ if (value.equals("auto")) {
+ options.setPortHosted(0);
+ } else {
+ try {
+ options.setPortHosted(Integer.parseInt(value));
+ } catch (NumberFormatException e) {
+ System.err.println("A port must be an integer or \"auto\"");
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Handles the list of startup urls that can be passed at the end of the
+ * command line.
+ */
+ protected static class ArgHandlerStartupURLsExtra extends ArgHandlerExtra {
+
+ private final OptionStartupURLs options;
+
+ public ArgHandlerStartupURLsExtra(OptionStartupURLs options) {
+ this.options = options;
+ }
+
+ @Override
+ public boolean addExtraArg(String arg) {
+ options.addStartupURL(arg);
+ return true;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Automatically launches the specified URL";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"url"};
+ }
+ }
+
+ /**
+ * The GWTShell argument processor.
+ */
+ protected static class ArgProcessor extends HostedModeBase.ArgProcessor {
+ public ArgProcessor(ShellOptionsImpl options, boolean forceServer,
+ boolean noURLs) {
+ super(options, forceServer);
+ if (!noURLs) {
+ registerHandler(new ArgHandlerStartupURLsExtra(options));
+ }
+ registerHandler(new ArgHandlerOutDir(options));
+ registerHandler(new ArgHandlerPortHosted(options));
+ }
+
+ @Override
+ protected String getName() {
+ return GWTShell.class.getName();
+ }
+ }
+
+ interface OptionPortHosted {
+ int getPortHosted();
+
+ void setPortHosted(int portHosted);
+ }
+
+ /**
+ * Concrete class to implement all shell options.
+ */
+ static class ShellOptionsImpl extends HostedModeBaseOptionsImpl implements
+ HostedModeBaseOptions, WorkDirs, LegacyCompilerOptions, OptionPortHosted {
+ private int localWorkers;
+ private File outDir;
+ private int portHosted;
+
+ public File getCompilerOutputDir(ModuleDef moduleDef) {
+ return new File(getOutDir(), moduleDef.getName());
+ }
+
+ public int getLocalWorkers() {
+ return localWorkers;
+ }
+
+ public File getOutDir() {
+ return outDir;
+ }
+
+ public int getPortHosted() {
+ return portHosted;
+ }
+
+ public File getShellPublicGenDir(ModuleDef moduleDef) {
+ return new File(getShellBaseWorkDir(moduleDef), "public");
+ }
+
+ @Override
+ public File getWorkDir() {
+ return new File(getOutDir(), ".gwt-tmp");
+ }
+
+ public void setLocalWorkers(int localWorkers) {
+ this.localWorkers = localWorkers;
+ }
+
+ public void setOutDir(File outDir) {
+ this.outDir = outDir;
+ }
+
+ public void setPortHosted(int port) {
+ portHosted = port;
+ }
+ }
+
+ private class BrowserWidgetHostImpl implements BrowserWidgetHost {
+ private TreeLogger logger;
+ private Map<ModuleSpaceHost, ModulePanel> moduleTabs = new IdentityHashMap<ModuleSpaceHost, ModulePanel>();
+
+ public BrowserWidgetHostImpl() {
+ }
+
+ public void compile(ModuleDef moduleDef) throws UnableToCompleteException {
+ GWTShell.this.compile(getLogger(), moduleDef);
+ }
+
+ public void compile(String[] moduleNames) throws UnableToCompleteException {
+ for (int i = 0; i < moduleNames.length; i++) {
+ String moduleName = moduleNames[i];
+ ModuleDef moduleDef = loadModule(moduleName, getLogger());
+ compile(moduleDef);
+ }
+ }
+
+ public ModuleSpaceHost createModuleSpaceHost(BrowserWidget widget,
+ String moduleName) throws UnableToCompleteException {
+ // TODO(jat): implement method createModuleSpaceHost
+ return null;
+ }
+
+ public ModuleSpaceHost createModuleSpaceHost(TreeLogger mainLogger,
+ String moduleName, String userAgent, String remoteSocket)
+ throws UnableToCompleteException {
+ logger = mainLogger;
+ TreeLogger.Type maxLevel = TreeLogger.INFO;
+ if (mainLogger instanceof AbstractTreeLogger) {
+ maxLevel = ((AbstractTreeLogger) mainLogger).getMaxDetail();
+ }
+
+ ModulePanel tab;
+ if (!isHeadless()) {
+ tab = new ModulePanel(maxLevel, moduleName, userAgent, remoteSocket,
+ tabs);
+ logger = tab.getLogger();
+
+ // Switch to a wait cursor.
+ frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ } else {
+ tab = null;
+ }
+
+ try {
+ // Try to find an existing loaded version of the module def.
+ ModuleDef moduleDef = loadModule(moduleName, logger);
+ assert (moduleDef != null);
+
+ // Create a sandbox for the module.
+ // TODO(jat): consider multiple instances of the same module open at
+ // once
+ TypeOracle typeOracle = moduleDef.getTypeOracle(logger);
+ ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(logger,
+ typeOracle, moduleDef);
+
+ if (tab != null) {
+ moduleTabs.put(host, tab);
+ }
+ return host;
+ } catch (RuntimeException e) {
+ logger.log(TreeLogger.ERROR, "Exception initializing module", e);
+ throw e;
+ } finally {
+ if (!isHeadless()) {
+ frame.setCursor(Cursor.getDefaultCursor());
+ }
+ }
+ }
+
+ public TreeLogger getLogger() {
+ return logger;
+ }
+
+ public String normalizeURL(String whatTheUserTyped) {
+ return GWTShell.this.normalizeURL(whatTheUserTyped);
+ }
+
+ public BrowserWidget openNewBrowserWindow()
+ throws UnableToCompleteException {
+ // TODO(jat): is this ok?
+ throw new UnableToCompleteException();
+ }
+
+ public void unloadModule(ModuleSpaceHost moduleSpaceHost) {
+ ModulePanel tab = moduleTabs.remove(moduleSpaceHost);
+ if (tab != null) {
+ tab.disconnect();
+ }
+ }
+
+ /**
+ * Load a module.
+ *
+ * @param moduleName name of the module to load
+ * @param logger TreeLogger to use
+ * @return the loaded module
+ * @throws UnableToCompleteException
+ */
+ private ModuleDef loadModule(String moduleName, TreeLogger logger)
+ throws UnableToCompleteException {
+ // TODO(jat): consider multithreading issues dealing with ModuleDefs
+ boolean assumeFresh = !alreadySeenModules.contains(moduleName);
+ ModuleDef moduleDef = ModuleDefLoader.loadFromClassPath(logger,
+ moduleName, !assumeFresh);
+ alreadySeenModules.add(moduleName);
+ assert (moduleDef != null) : "Required module state is absent";
+ return moduleDef;
+ }
+ }
+
+ public static final String GWT_SHELL_PATH = ".gwt-tmp" + File.separator
+ + "shell";
+
+ private static final String PACKAGE_PATH = GWTShell.class.getPackage().getName().replace(
+ '.', '/').concat("/shell/");
+
+ public static String checkHost(String hostUnderConsideration,
+ Set<String> hosts) {
+ hostUnderConsideration = hostUnderConsideration.toLowerCase();
+ for (String rule : hosts) {
+ // match on lowercased regex
+ if (hostUnderConsideration.matches(".*" + rule + ".*")) {
+ return rule;
+ }
+ }
+ return null;
+ }
+
+ public static String computeHostRegex(String url) {
+ // the entire URL up to the first slash not prefixed by a slash or colon.
+ String raw = url.split("(?<![:/])/")[0];
+ // escape the dots and put a begin line specifier on the result
+ return "^" + raw.replaceAll("[.]", "[.]");
+ }
+
+ public static String formatRules(Set<String> invalidHttpHosts) {
+ StringBuffer out = new StringBuffer();
+ for (String rule : invalidHttpHosts) {
+ out.append(rule);
+ out.append(" ");
+ }
+ return out.toString();
+ }
+
+ 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.
+ */
+ GWTShell gwtShell = new GWTShell();
+ ArgProcessor argProcessor = new ArgProcessor(gwtShell.options, false, false);
+ if (argProcessor.processArgs(args)) {
+ gwtShell.run();
+ // Exit w/ success code.
+ System.exit(0);
+ }
+ // Exit w/ non-success code.
+ System.exit(-1);
+ }
+
+ /**
+ * Loads an image from the classpath in this package.
+ */
+ static ImageIcon loadImageIcon(String name) {
+ ClassLoader cl = GWTShell.class.getClassLoader();
+ URL url = cl.getResource(PACKAGE_PATH + name);
+ if (url != null) {
+ ImageIcon image = new ImageIcon(url);
+ return image;
+ } else {
+ // Bad image.
+ return new ImageIcon();
+ }
+ }
+
+ protected BrowserListener listener;
+
+ /**
+ * Hiding super field because it's actually the same object, just with a
+ * stronger type.
+ */
+ @SuppressWarnings("hiding")
+ protected final ShellOptionsImpl options = (ShellOptionsImpl) super.options;
+
+ 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
+ * prevents a double-refresh on startup. Subsequent refreshes will trigger a
+ * real refresh.
+ */
+ private Set<String> alreadySeenModules = new HashSet<String>();
+
+ private BrowserWidgetHostImpl browserHost = new BrowserWidgetHostImpl();
+
+ private JFrame frame;
+
+ private volatile boolean mainWindowClosed;
+
+ private ShellMainWindow mainWnd;
+
+ private JTabbedPane tabs;
+
+ private AbstractTreeLogger topLogger;
+
+ private WebServerPanel webServerLog;
+
+ @Override
+ public void closeAllBrowserWindows() {
+ }
+
+ @Override
+ public TreeLogger getTopLogger() {
+ return topLogger;
+ }
+
+ @Override
+ public boolean hasBrowserWindowsOpen() {
+ return false;
+ }
+
+ public WebServerRestart hasWebServer() {
+ return WebServerRestart.NONE;
+ }
+
+ /**
+ * Launch the arguments as Urls in separate windows.
+ */
+ @Override
+ public void launchStartupUrls(final TreeLogger logger) {
+ ensureOophmListener();
+ String startupURL = "";
+ try {
+ for (String prenormalized : options.getStartupURLs()) {
+ startupURL = normalizeURL(prenormalized);
+ logger.log(TreeLogger.INFO, "Starting URL: " + startupURL, null);
+ launchURL(startupURL);
+ }
+ } catch (UnableToCompleteException e) {
+ logger.log(TreeLogger.ERROR,
+ "Unable to open new window for startup URL: " + startupURL, null);
+ }
+ }
+
+ public void launchURL(String url) throws UnableToCompleteException {
+ /*
+ * TODO(jat): properly support launching arbitrary browsers; waiting on
+ * Freeland's work with BrowserScanner and the trunk merge to get it.
+ */
+ String separator;
+ if (url.contains("?")) {
+ separator = "&";
+ } else {
+ separator = "?";
+ }
+ url += separator + "gwt.hosted=" + listener.getEndpointIdentifier();
+ TreeLogger branch = getTopLogger().branch(TreeLogger.INFO,
+ "Launching firefox with " + url, null);
+ try {
+ Process browser = Runtime.getRuntime().exec("firefox " + url + "&");
+ int exitCode = browser.waitFor();
+ if (exitCode != 0) {
+ branch.log(TreeLogger.ERROR, "Exit code " + exitCode, null);
+ }
+ } catch (IOException e) {
+ branch.log(TreeLogger.ERROR, "Error starting browser", e);
+ } catch (InterruptedException e) {
+ branch.log(TreeLogger.ERROR, "Error starting browser", e);
+ }
+ }
+
+ public BrowserWidget openNewBrowserWindow() throws UnableToCompleteException {
+ throw new UnableToCompleteException();
+ }
+
+ public void restartServer(TreeLogger logger) throws UnableToCompleteException {
+ // Unimplemented.
+ }
+
+ @Override
+ protected void compile(TreeLogger logger) throws UnableToCompleteException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Compiles a logical module def. The caller can modify the specified module
+ * def programmatically in some cases (this is needed for JUnit support, for
+ * example).
+ */
+ @Override
+ protected void compile(TreeLogger logger, ModuleDef moduleDef)
+ throws UnableToCompleteException {
+ LegacyCompilerOptions newOptions = new GWTCompilerOptionsImpl(options);
+ if (!new GWTCompiler(newOptions).run(logger, moduleDef)) {
+ // TODO(jat): error dialog?
+ }
+ }
+
+ @Override
+ protected HostedModeBaseOptions createOptions() {
+ return new ShellOptionsImpl();
+ }
+
+ @Override
+ protected ArtifactAcceptor doCreateArtifactAcceptor(final ModuleDef module) {
+ return new ArtifactAcceptor() {
+ public void accept(TreeLogger logger, ArtifactSet artifacts)
+ throws UnableToCompleteException {
+
+ /*
+ * Copied from StandardLinkerContext.produceOutputDirectory() for legacy
+ * GWTShellServlet support.
+ */
+ for (EmittedArtifact artifact : artifacts.find(EmittedArtifact.class)) {
+ if (!artifact.isPrivate()) {
+ File outFile = new File(options.getShellPublicGenDir(module),
+ artifact.getPartialPath());
+ Util.copy(logger, artifact.getContents(logger), outFile);
+ }
+ }
+ }
+ };
+ }
+
+ /**
+ * Can be override to change the default log level in subclasses. JUnit does
+ * this for example.
+ */
+ protected Type doGetDefaultLogLevel() {
+ return Type.INFO;
+ }
+
+ @Override
+ protected void doShutDownServer() {
+ // Stop the HTTP server.
+ //
+ EmbeddedTomcatServer.stop();
+ }
+
+ @Override
+ protected boolean doStartup() {
+ if (super.doStartup()) {
+ // Accept connections from OOPHM clients
+ ensureOophmListener();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected int doStartUpServer() {
+ // TODO(bruce): make tomcat work in terms of the modular launcher
+ String whyFailed = EmbeddedTomcatServer.start(isHeadless() ? getTopLogger()
+ : webServerLog.getLogger(), getPort(), options);
+
+ // TODO(bruce): test that we can remove this old approach in favor of
+ // a better, logger-based error reporting
+ if (whyFailed != null) {
+ System.err.println(whyFailed);
+ return -1;
+ }
+ return EmbeddedTomcatServer.getPort();
+ }
+
+ @Override
+ protected void initializeLogger() {
+ if (mainWnd != null) {
+ topLogger = mainWnd.getLogger();
+ } else {
+ topLogger = new PrintWriterTreeLogger(new PrintWriter(System.out));
+ }
+ topLogger.setMaxDetail(options.getLogLevel());
+ }
+
+ @Override
+ protected boolean initModule(String moduleName) {
+ /*
+ * Not used in legacy mode due to GWTShellServlet playing this role.
+ *
+ * TODO: something smarter here and actually make GWTShellServlet less
+ * magic?
+ */
+ return false;
+ }
+
+ @Override
+ protected void loadRequiredNativeLibs() {
+ // no native libraries are needed with OOPHM
+ }
+
+ @Override
+ protected synchronized boolean notDone() {
+ return !mainWindowClosed;
+ }
+
+ @Override
+ protected void openAppWindow() {
+ ImageIcon gwtIcon = loadImageIcon("icon24.png");
+ frame = new JFrame("GWT Hosted Mode");
+ tabs = new JTabbedPane();
+ mainWnd = new ShellMainWindow(this, options.getLogLevel());
+ tabs.addTab("Hosted Mode", gwtIcon, mainWnd, "GWT Hosted-mode");
+ if (!options.isNoServer()) {
+ ImageIcon tomcatIcon = loadImageIcon("tomcat24.png");
+ webServerLog = new WebServerPanel(getPort(), options.getLogLevel());
+ tabs.addTab("Tomcat", tomcatIcon, webServerLog);
+ }
+ frame.getContentPane().add(tabs);
+ frame.setSize(950, 700);
+ frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ setMainWindowClosed();
+ }
+ });
+ frame.setIconImage(loadImageIcon("icon16.png").getImage());
+ frame.setVisible(true);
+ }
+
+ @Override
+ protected void processEvents() throws Exception {
+ Thread.sleep(10);
+ }
+
+ private void ensureOophmListener() {
+ if (listener == null) {
+ listener = new BrowserListener(getTopLogger(), options.getPortHosted(),
+ new OophmSessionHandler(browserHost));
+ listener.start();
+ }
+ }
+
+ private synchronized void setMainWindowClosed() {
+ mainWindowClosed = true;
+ }
+}
diff --git a/dev/oophm/overlay/com/google/gwt/dev/shell/BrowserWidgetHost.java b/dev/oophm/overlay/com/google/gwt/dev/shell/BrowserWidgetHost.java
new file mode 100644
index 0000000..703f90d
--- /dev/null
+++ b/dev/oophm/overlay/com/google/gwt/dev/shell/BrowserWidgetHost.java
@@ -0,0 +1,39 @@
+/*
+ * 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.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.cfg.ModuleDef;
+
+/**
+ * Interface that unifies access to the <code>BrowserWidget</code>,
+ * <code>ModuleSpaceHost</code>, and the compiler.
+ */
+public interface BrowserWidgetHost {
+ void compile(String[] modules) throws UnableToCompleteException;
+
+ void compile(ModuleDef module) throws UnableToCompleteException;
+
+ ModuleSpaceHost createModuleSpaceHost(TreeLogger logger, String moduleName, String userAgent,
+ String remoteEndpoint) throws UnableToCompleteException;
+
+ TreeLogger getLogger();
+
+ String normalizeURL(String whatTheUserTyped);
+
+ void unloadModule(ModuleSpaceHost moduleSpaceHost);
+}
diff --git a/dev/oophm/overlay/com/google/gwt/dev/shell/JsValue.java b/dev/oophm/overlay/com/google/gwt/dev/shell/JsValue.java
new file mode 100644
index 0000000..3ba91bb
--- /dev/null
+++ b/dev/oophm/overlay/com/google/gwt/dev/shell/JsValue.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+/**
+ * Represents a JavaScript value.
+ *
+ * Note that in general the various get*() methods will return
+ * platform-independent values only if the corresponding is*() method returns
+ * true. In some cases, an IllegalStateException may be thrown if the JavaScript
+ * value is not of the appropriate type or bogus values may be returned. Note
+ * that getString will try very hard to return a reasonable result for any
+ * value, but it is intended only for human consumption and the exact format for
+ * anything besides a string value cannot be relied upon.
+ */
+public abstract class JsValue {
+
+ /**
+ * Provides interface for methods to be exposed on JavaScript side.
+ */
+ public interface DispatchMethod {
+ boolean invoke(JsValue jsthis, JsValue[] jsargs, JsValue returnValue);
+ }
+
+ /**
+ * Provides interface for objects to be exposed on JavaScript side.
+ */
+ public interface DispatchObject {
+ JsValue getField(int dispatchId);
+
+ JsValue getField(String name);
+
+ int getFieldId(String name);
+
+ Object getTarget();
+
+ void setField(int dispatchId, JsValue value);
+
+ void setField(String name, JsValue value);
+ }
+
+ /**
+ * The main thread should call this from time to time to release hosted-mode
+ * objects that Java is no longer referencing.
+ */
+ public static void mainThreadCleanup() {
+ // Do nothing in OOPHM.
+ }
+
+ /**
+ * Get the value of the object as a boolean. May attempt to convert the value
+ * to a boolean if it is not a boolean.
+ *
+ * @return the value of the underlying object as a boolean
+ */
+ public abstract boolean getBoolean();
+
+ /**
+ * Get the value of the object as an integer. May attempt to convert the value
+ * to an integer if it is not an integer.
+ *
+ * @return the value of the underlying object as an int
+ */
+ public abstract int getInt();
+
+ /**
+ * Get the wrapper object for a wrapped Java object. Only valid if
+ * isWrappedJavaObject() is true.
+ *
+ * @return the Java object wrapper
+ */
+ public abstract DispatchObject getJavaObjectWrapper();
+
+ /**
+ * Returns a unique value corresponding to the underlying JavaScript object.
+ * In general, two different JsValues will return the same value IFF the
+ * underlying JavaScript objects are identical (===).
+ *
+ * @return a unique number corresponding to the underlying object, or
+ * <code>0</code> if {@link #isJavaScriptObject()} is
+ * <code>false</code>
+ */
+ public abstract int getJavaScriptObjectPointer();
+
+ /**
+ * Get the value of the object as a double. May attempt to convert the value
+ * to a double if it is not a double.
+ *
+ * @return the value of the underlying object as a double
+ */
+ public abstract double getNumber();
+
+ /**
+ * Get the value of the object as a string. Will coerce the underlying type to
+ * a string, but stable cross-platform behavior is only guaranteed when
+ * {@link #isString()} is <code>true</code>.
+ *
+ * @return the value of the underlying object as a string
+ */
+ public abstract String getString();
+
+ /**
+ * Returns a human-readable string describing the type of the JS object. This
+ * is intended only for human consumption and may vary across platforms.
+ */
+ public abstract String getTypeString();
+
+ /**
+ * Returns a wrapped Java method.
+ */
+ public abstract DispatchMethod getWrappedJavaFunction();
+
+ /**
+ * Unwrap a wrapped Java object.
+ *
+ * @return the original Java object wrapped in this JS object
+ */
+ public abstract Object getWrappedJavaObject();
+
+ /**
+ * Returns true if the JS value is a boolean.
+ */
+ public abstract boolean isBoolean();
+
+ /**
+ * Returns true if getInt() can be used on this value.
+ */
+ public abstract boolean isInt();
+
+ /**
+ * Returns true if the JS value is a native JS object.
+ */
+ public abstract boolean isJavaScriptObject();
+
+ /**
+ * Returns true if the JS value is null.
+ */
+ public abstract boolean isNull();
+
+ /**
+ * Returns true if the JS value is a numeric type.
+ */
+ public abstract boolean isNumber();
+
+ /**
+ * Returns true if the JS value is a string.
+ */
+ public abstract boolean isString();
+
+ /**
+ * Returns true if the JS value is undefined (void).
+ */
+ public abstract boolean isUndefined();
+
+ /**
+ * Returns true if the JS value contains a wrapped Java method.
+ */
+ public abstract boolean isWrappedJavaFunction();
+
+ /**
+ * Returns true if the JS value is a wrapped Java object.
+ */
+ public abstract boolean isWrappedJavaObject();
+
+ /**
+ * Sets the JS object to be a boolean value.
+ *
+ * @param val the boolean value to set
+ */
+ public abstract void setBoolean(boolean val);
+
+ /**
+ * Sets the JS object to be a number, passed as an byte.
+ *
+ * @param val the value to store
+ */
+ public abstract void setByte(byte val);
+
+ /**
+ * Sets the JS object to be a number, passed as a char.
+ *
+ * @param val the value to store
+ */
+ public abstract void setChar(char val);
+
+ /**
+ * Sets the JS object to be a number, passed as a double.
+ *
+ * @param val the value to store
+ */
+ public abstract void setDouble(double val);
+
+ /**
+ * Sets the JS object to be a number, passed as an int.
+ *
+ * @param val the value to store
+ */
+ public abstract void setInt(int val);
+
+ /**
+ * Set the JS object to be null.
+ *
+ * @throws com.google.gwt.dev.shell.HostedModeException
+ */
+ public abstract void setNull();
+
+ /**
+ * Sets the JS object to be a number, passed as a short.
+ *
+ * @param val the value to store
+ */
+ public abstract void setShort(short val);
+
+ /**
+ * Set the JS object to the supplied string.
+ *
+ * @param val the string to put in the JS object
+ * @throws HostedModeException on JS allocation failures
+ */
+ public abstract void setString(String val);
+
+ /**
+ * Set the JS object to be undefined (void).
+ *
+ * @throws HostedModeException on JS allocation failures
+ */
+ public abstract void setUndefined();
+
+ /**
+ * Make this JsValue refer to the same underlying object as another JsValue.
+ *
+ * @param other JsValue to copy JS object from
+ */
+ public abstract void setValue(JsValue other);
+
+ /**
+ * Set the JS object to the supplied object, which will be wrapped in a
+ * platform-dependent JavaScript class.
+ *
+ * @param <T> the type of the Java object to wrap
+ * @param cl the classloader to create the wrapper object with
+ * @param val the Java object to wrap
+ * @throws HostedModeException
+ */
+ public abstract <T> void setWrappedJavaObject(CompilingClassLoader cl, T val);
+
+ /**
+ * Produce a string representation of the JsValue.
+ */
+ @Override
+ public String toString() {
+ if (isUndefined()) {
+ return "void";
+ } else if (isNull()) {
+ return "null";
+ } else if (isBoolean()) {
+ return "bool: " + (getBoolean() ? "true" : "false");
+ } else if (isInt()) {
+ return "int: " + Integer.toString(getInt());
+ } else if (isNumber()) {
+ return "double: " + Double.toString(getNumber());
+ } else if (isWrappedJavaObject()) {
+ Object wrappedObject = getWrappedJavaObject();
+ if (wrappedObject == null) {
+ return "Java static dispatch";
+ }
+ // avoid calling toString on the wrapped object, as this can be expensive
+ return "Java object: " + wrappedObject.getClass().getName() + '@'
+ + System.identityHashCode(wrappedObject);
+ } else if (isJavaScriptObject()) {
+ return getTypeString();
+ } else if (isString()) {
+ return "string: '" + getString() + "'";
+ } else if (isWrappedJavaFunction()) {
+ return "Java method: " + getWrappedJavaFunction().toString();
+ }
+ return getTypeString();
+ }
+}
diff --git a/dev/oophm/overlay/com/google/gwt/dev/shell/JsValueGlue.java b/dev/oophm/overlay/com/google/gwt/dev/shell/JsValueGlue.java
new file mode 100644
index 0000000..2d3f953
--- /dev/null
+++ b/dev/oophm/overlay/com/google/gwt/dev/shell/JsValueGlue.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.util.TypeInfo;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Glue layer that performs GWT-specific operations on JsValues. Used to isolate
+ * HostedModeExceptions/etc from JsValue code
+ */
+public final class JsValueGlue {
+ public static final String HOSTED_MODE_REFERENCE = "hostedModeReference";
+ public static final String JSO_CLASS = "com.google.gwt.core.client.JavaScriptObject";
+ public static final String JSO_IMPL_CLASS = "com.google.gwt.core.client.JavaScriptObject$";
+
+ /**
+ * Create a JavaScriptObject instance referring to this JavaScript object.
+ *
+ * @param classLoader the classLoader to create from
+ * @return the constructed JavaScriptObject
+ */
+ public static Object createJavaScriptObject(JsValue value,
+ CompilingClassLoader classLoader) {
+ Throwable caught;
+ try {
+ // See if there's already a wrapper object (assures identity comparison).
+ Object jso = classLoader.getCachedJso(value.getJavaScriptObjectPointer());
+ if (jso != null) {
+ return jso;
+ }
+
+ // Instantiate the JSO class.
+ Class<?> jsoType = Class.forName(JSO_IMPL_CLASS, true, classLoader);
+ Constructor<?> ctor = jsoType.getDeclaredConstructor();
+ ctor.setAccessible(true);
+ jso = ctor.newInstance();
+
+ // Set the reference field to this JsValue using reflection.
+ Field referenceField = jsoType.getField(HOSTED_MODE_REFERENCE);
+ referenceField.set(jso, value);
+
+ classLoader.putCachedJso(value.getJavaScriptObjectPointer(), jso);
+ return jso;
+ } catch (InstantiationException e) {
+ caught = e;
+ } catch (IllegalAccessException e) {
+ caught = e;
+ } catch (SecurityException e) {
+ caught = e;
+ } catch (NoSuchMethodException e) {
+ caught = e;
+ } catch (IllegalArgumentException e) {
+ caught = e;
+ } catch (InvocationTargetException e) {
+ caught = e;
+ } catch (ClassNotFoundException e) {
+ caught = e;
+ } catch (NoSuchFieldException e) {
+ caught = e;
+ }
+ throw new RuntimeException("Error creating JavaScript object", caught);
+ }
+
+ /**
+ * Return an object containing the value JavaScript object as a specified
+ * type.
+ *
+ * @param value the JavaScript value
+ * @param type expected type of the returned object
+ * @param msgPrefix a prefix for error/warning messages
+ * @return the object reference
+ * @throws com.google.gwt.dev.shell.HostedModeException if the JavaScript
+ * object is not assignable to the supplied type.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T get(JsValue value, CompilingClassLoader cl,
+ Class<T> type, String msgPrefix) {
+
+ if (type.isPrimitive()) {
+ if (type == Boolean.TYPE) {
+ if (!value.isBoolean()) {
+ throw new HostedModeException(msgPrefix + ": JS value of type "
+ + value.getTypeString() + ", expected boolean");
+ }
+ return (T) Boolean.valueOf(value.getBoolean());
+ } else if (type == Byte.TYPE) {
+ return (T) Byte.valueOf((byte) getIntRange(value, Byte.MIN_VALUE,
+ Byte.MAX_VALUE, "byte", msgPrefix));
+ } else if (type == Character.TYPE) {
+ return (T) Character.valueOf((char) getIntRange(value,
+ Character.MIN_VALUE, Character.MAX_VALUE, "char", msgPrefix));
+ } else if (type == Double.TYPE) {
+ if (!value.isNumber()) {
+ throw new HostedModeException(msgPrefix + ": JS value of type "
+ + value.getTypeString() + ", expected double");
+ }
+ return (T) Double.valueOf(value.getNumber());
+ } else if (type == Float.TYPE) {
+ if (!value.isNumber()) {
+ throw new HostedModeException(msgPrefix + ": JS value of type "
+ + value.getTypeString() + ", expected float");
+ }
+ double doubleVal = value.getNumber();
+
+ // Check for small changes near MIN_VALUE and replace with the
+ // actual end point value, in case it is being used as a sentinel
+ // value. This test works by the subtraction result rounding off to
+ // zero if the delta is not representable in a float.
+ // TODO(jat): add similar test for MAX_VALUE if we have a JS
+ // platform that alters the value while converting to/from strings.
+ if ((float) (doubleVal - Float.MIN_VALUE) == 0.0f) {
+ doubleVal = Float.MIN_VALUE;
+ }
+
+ float floatVal = (float) doubleVal;
+ if (Float.isInfinite(floatVal) && !Double.isInfinite(doubleVal)) {
+ // in this case we had overflow from the double value which was
+ // outside the range of supported float values, and the cast
+ // converted it to infinity. Since this lost data, we treat this
+ // as an error in hosted mode.
+ throw new HostedModeException(msgPrefix + ": JS value " + doubleVal
+ + " out of range for a float");
+ }
+ return (T) Float.valueOf(floatVal);
+ } else if (type == Integer.TYPE) {
+ return (T) Integer.valueOf(getIntRange(value, Integer.MIN_VALUE,
+ Integer.MAX_VALUE, "int", msgPrefix));
+ } else if (type == Long.TYPE) {
+ if (!value.isWrappedJavaObject()) {
+ throw new HostedModeException(msgPrefix + ": JS value of type "
+ + value.getTypeString() + ", expected Java long");
+ }
+ JavaLong javaLong = (JavaLong) value.getWrappedJavaObject();
+ return (T) Long.valueOf(javaLong.longValue());
+ } else if (type == Short.TYPE) {
+ return (T) Short.valueOf((short) getIntRange(value, Short.MIN_VALUE,
+ Short.MAX_VALUE, "short", msgPrefix));
+ }
+ }
+
+ if (value.isNull() || value.isUndefined()) {
+ return null;
+ }
+ if (value.isWrappedJavaObject()) {
+ return type.cast(value.getWrappedJavaObject());
+ }
+ if (value.isString()) {
+ return type.cast(value.getString());
+ }
+ if (value.isJavaScriptObject()) {
+ return type.cast(createJavaScriptObject(value, cl));
+ }
+
+ // Just don't know what do to with this.
+ throw new HostedModeException(msgPrefix + ": JS value of type "
+ + value.getTypeString() + ", expected "
+ + TypeInfo.getSourceRepresentation(type));
+ }
+
+ /**
+ * Set the underlying value.
+ *
+ * @param value JsValue to set
+ * @param type static type of the object
+ * @param obj the object to store in the JS value
+ */
+ public static void set(JsValue value, CompilingClassLoader cl, Class<?> type,
+ Object obj) {
+ if (type.isPrimitive()) {
+ if (type == Boolean.TYPE) {
+ value.setBoolean(((Boolean) obj).booleanValue());
+ } else if (type == Byte.TYPE) {
+ value.setInt(((Byte) obj).byteValue());
+ } else if (type == Character.TYPE) {
+ value.setInt(((Character) obj).charValue());
+ } else if (type == Double.TYPE) {
+ value.setDouble(((Double) obj).doubleValue());
+ } else if (type == Float.TYPE) {
+ value.setDouble(((Float) obj).floatValue());
+ } else if (type == Integer.TYPE) {
+ value.setInt(((Integer) obj).intValue());
+ } else if (type == Long.TYPE) {
+ long longVal = ((Long) obj).longValue();
+ value.setWrappedJavaObject(cl, new JavaLong(longVal));
+ } else if (type == Short.TYPE) {
+ value.setInt(((Short) obj).shortValue());
+ } else if (type == Void.TYPE) {
+ value.setUndefined();
+ } else {
+ throw new HostedModeException("Cannot marshal primitive type " + type);
+ }
+ } else if (obj == null) {
+ value.setNull();
+ } else {
+ // not a boxed primitive
+ try {
+ Class<?> jsoType = Class.forName(JSO_IMPL_CLASS, false, cl);
+ if (jsoType == obj.getClass()) {
+ JsValue jsObject = getUnderlyingObject(obj);
+ value.setValue(jsObject);
+ return;
+ }
+ } catch (ClassNotFoundException e) {
+ // Ignore the exception, if we can't find the class then obviously we
+ // don't have to worry about o being one
+ }
+
+ // Fall through case: Object.
+ if (!type.isInstance(obj)) {
+ throw new HostedModeException("object is of type "
+ + obj.getClass().getName() + ", expected " + type.getName());
+ }
+ if (obj instanceof String) {
+ value.setString((String) obj);
+ } else {
+ value.setWrappedJavaObject(cl, obj);
+ }
+ }
+ }
+
+ private static int getIntRange(JsValue value, int low, int high,
+ String typeName, String msgPrefix) {
+ int intVal;
+ if (value.isInt()) {
+ intVal = value.getInt();
+ if (intVal < low || intVal > high) {
+ throw new HostedModeException(msgPrefix + ": JS int value " + intVal
+ + " out of range for a " + typeName);
+ }
+ } else if (value.isNumber()) {
+ double doubleVal = value.getNumber();
+ if (doubleVal < low || doubleVal > high) {
+ throw new HostedModeException(msgPrefix + ": JS double value "
+ + doubleVal + " out of range for a " + typeName);
+ }
+ intVal = (int) doubleVal;
+ if (intVal != doubleVal) {
+ ModuleSpace.getLogger().log(TreeLogger.WARN,
+ msgPrefix + ": Rounding double (" + doubleVal + ") to int for "
+ + typeName, null);
+ }
+ } else {
+ throw new HostedModeException(msgPrefix + ": JS value of type "
+ + value.getTypeString() + ", expected " + typeName);
+ }
+ return intVal;
+ }
+
+ /**
+ * Returns the underlying JsValue from a JavaScriptObject instance.
+ *
+ * The tricky part is that it is in a different ClassLoader so therefore can't
+ * be specified directly. The type is specified as Object, and reflection is
+ * used to retrieve the reference field.
+ *
+ * @param jso the instance of JavaScriptObject to retrieve the JsValue from.
+ * @return the JsValue representing the JavaScript object
+ */
+ private static JsValue getUnderlyingObject(Object jso) {
+ Throwable caught;
+ try {
+ Field referenceField = jso.getClass().getField(HOSTED_MODE_REFERENCE);
+ referenceField.setAccessible(true);
+ return (JsValue) referenceField.get(jso);
+ } catch (IllegalAccessException e) {
+ caught = e;
+ } catch (SecurityException e) {
+ caught = e;
+ } catch (NoSuchFieldException e) {
+ caught = e;
+ }
+ throw new RuntimeException("Error reading " + HOSTED_MODE_REFERENCE, caught);
+ }
+
+ private JsValueGlue() {
+ }
+}
diff --git a/dev/oophm/overlay/com/google/gwt/dev/shell/PlatformSpecific.java b/dev/oophm/overlay/com/google/gwt/dev/shell/PlatformSpecific.java
new file mode 100644
index 0000000..09bf046
--- /dev/null
+++ b/dev/oophm/overlay/com/google/gwt/dev/shell/PlatformSpecific.java
@@ -0,0 +1,138 @@
+/*
+ * 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.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.TreeLogger.HelpInfo;
+import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
+
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Performs platform-specific class selection.
+ */
+public class PlatformSpecific {
+
+ /**
+ * All of these classes must extend CheckForUpdates. Note that currently only
+ * IE has a custom implementation (to handle proxies) and that CheckForUpdates
+ * must be the last one in the list.
+ */
+ private static final String[] updaterClassNames = new String[] {
+ "com.google.gwt.dev.shell.ie.CheckForUpdatesIE6",
+ "com.google.gwt.dev.shell.CheckForUpdates"};
+
+ public static FutureTask<UpdateResult> checkForUpdatesInBackgroundThread(
+ final TreeLogger logger, final long minCheckMillis) {
+ final String entryPoint = PlatformSpecific.computeEntryPoint();
+ FutureTask<UpdateResult> task = new FutureTask<UpdateResult>(
+ new Callable<UpdateResult>() {
+ public UpdateResult call() throws Exception {
+ final CheckForUpdates updateChecker = createUpdateChecker(logger,
+ entryPoint);
+ return updateChecker == null ? null
+ : updateChecker.check(minCheckMillis);
+ }
+ });
+ Thread checkerThread = new Thread(task, "GWT Update Checker");
+ checkerThread.setDaemon(true);
+ checkerThread.start();
+ return task;
+ }
+
+ /**
+ * Find the first method named "main" on the call stack and use its class as
+ * the entry point.
+ */
+ public static String computeEntryPoint() {
+ Throwable t = new Throwable();
+ for (StackTraceElement stackTrace : t.getStackTrace()) {
+ if (stackTrace.getMethodName().equals("main")) {
+ // Strip package name from main's class
+ String className = stackTrace.getClassName();
+ int i = className.lastIndexOf('.');
+ if (i >= 0) {
+ return className.substring(i + 1);
+ }
+ return className;
+ }
+ }
+ return null;
+ }
+
+ public static CheckForUpdates createUpdateChecker(TreeLogger logger) {
+ return createUpdateChecker(logger, computeEntryPoint());
+ }
+
+ public static CheckForUpdates createUpdateChecker(TreeLogger logger,
+ String entryPoint) {
+ try {
+ for (int i = 0; i < updaterClassNames.length; i++) {
+ try {
+ Class<? extends CheckForUpdates> clazz = Class.forName(
+ updaterClassNames[i]).asSubclass(CheckForUpdates.class);
+ Constructor<? extends CheckForUpdates> ctor = clazz.getDeclaredConstructor(new Class[] {
+ TreeLogger.class, String.class});
+ CheckForUpdates checker = ctor.newInstance(new Object[] {
+ logger, entryPoint});
+ return checker;
+ } catch (Exception e) {
+ // Other exceptions can occur besides ClassNotFoundException,
+ // so ignore them all so we can find a functional updater.
+ }
+ }
+ } catch (Throwable e) {
+ // silently ignore any errors
+ }
+ return null;
+ }
+
+ public static void logUpdateAvailable(TreeLogger logger,
+ FutureTask<UpdateResult> updater) {
+ if (updater != null && updater.isDone()) {
+ UpdateResult result = null;
+ try {
+ result = updater.get(0, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // Silently ignore exception
+ } catch (ExecutionException e) {
+ // Silently ignore exception
+ } catch (TimeoutException e) {
+ // Silently ignore exception
+ }
+ logUpdateAvailable(logger, result);
+ }
+ }
+
+ public static void logUpdateAvailable(TreeLogger logger, UpdateResult result) {
+ if (result != null) {
+ final URL url = result.getURL();
+ logger.log(TreeLogger.WARN, "A new version of GWT ("
+ + result.getNewVersion() + ") is available", null, new HelpInfo() {
+ @Override
+ public URL getURL() {
+ return url;
+ }
+ });
+ }
+ }
+}
diff --git a/dev/oophm/overlay/com/google/gwt/dev/shell/ShellMainWindow.java b/dev/oophm/overlay/com/google/gwt/dev/shell/ShellMainWindow.java
new file mode 100644
index 0000000..57ab665
--- /dev/null
+++ b/dev/oophm/overlay/com/google/gwt/dev/shell/ShellMainWindow.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.GWTShell;
+import com.google.gwt.dev.util.log.AbstractTreeLogger;
+import com.google.gwt.dev.util.log.SwingLoggerPanel;
+
+import java.awt.BorderLayout;
+import java.awt.GridLayout;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+/**
+ */
+@SuppressWarnings("deprecation")
+public class ShellMainWindow extends JPanel {
+
+ private SwingLoggerPanel logWindow;
+
+ public ShellMainWindow(GWTShell shell, TreeLogger.Type maxLevel) {
+ super(new BorderLayout());
+ JPanel panel = new JPanel(new GridLayout(2, 1));
+ JPanel optionPanel = new JPanel();
+ optionPanel.setBorder(BorderFactory.createTitledBorder("Options"));
+ optionPanel.add(new JLabel("Miscellaneous options here"));
+ panel.add(optionPanel);
+ JPanel launchPanel = new JPanel();
+ launchPanel.setBorder(BorderFactory.createTitledBorder("Launch GWT Module"));
+ launchPanel.add(new JLabel("Selections for launching a new module on a selected browser"));
+ panel.add(launchPanel);
+ add(panel, BorderLayout.NORTH);
+ logWindow = new SwingLoggerPanel(maxLevel);
+ add(logWindow);
+ }
+
+ /**
+ * @return
+ */
+ public AbstractTreeLogger getLogger() {
+ return logWindow.getLogger();
+ }
+}
diff --git a/dev/oophm/overlay/com/google/gwt/dev/util/Jsni.java b/dev/oophm/overlay/com/google/gwt/dev/util/Jsni.java
new file mode 100644
index 0000000..2df7d42
--- /dev/null
+++ b/dev/oophm/overlay/com/google/gwt/dev/util/Jsni.java
@@ -0,0 +1,259 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.javac.JsniMethod;
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.js.JsSourceGenerationVisitor;
+import com.google.gwt.dev.js.ast.JsContext;
+import com.google.gwt.dev.js.ast.JsExpression;
+import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsInvocation;
+import com.google.gwt.dev.js.ast.JsNameRef;
+import com.google.gwt.dev.js.ast.JsNode;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.shell.DispatchIdOracle;
+import com.google.gwt.dev.shell.JavaScriptHost;
+import com.google.gwt.dev.shell.SyntheticClassMember;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * Helper methods working with JSNI.
+ */
+public class Jsni {
+
+ /**
+ * Generate source code, fixing up any JSNI references for hosted mode.
+ *
+ * <p/><table>
+ * <tr>
+ * <td>Original</td>
+ * <td>Becomes</td>
+ * </tr>
+ * <tr>
+ * <td><code>obj.@class::method(params)(args)</code></td>
+ *
+ * <td><code>__gwt_makeJavaInvoke(paramCount)(obj, dispId, args)</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>@class::method(params)(args)</code></td>
+ *
+ * <td><code>__gwt_makeJavaInvoke(paramCount)(null, dispId, args)</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>obj.@class::method(params)</code></td>
+ *
+ * <td><code>__gwt_makeTearOff(obj, dispId, paramCount)</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>@class::method(params)</code></td>
+ *
+ * <td><code>__gwt_makeTearOff(null, dispId, paramCount)</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>obj.@class::field</code></td>
+ *
+ * <td><code>obj[dispId]</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>@class::field</code></td>
+ *
+ * <td><code>__static[dispId]</code></td>
+ * </tr>
+ * </table>
+ */
+ private static class JsSourceGenWithJsniIdentFixup extends
+ JsSourceGenerationVisitor {
+ private final DispatchIdOracle dispatchInfo;
+ private final TextOutput out;
+ private final JsProgram program;
+
+ public JsSourceGenWithJsniIdentFixup(TextOutput out, DispatchIdOracle ccl,
+ JsProgram program) {
+ super(out);
+ this.dispatchInfo = ccl;
+ this.out = out;
+ this.program = program;
+ }
+
+ /**
+ * This will handle references to fields or tear-offs of Java methods.
+ */
+ @Override
+ public boolean visit(JsNameRef x, JsContext<JsExpression> ctx) {
+ String ident = x.getIdent();
+ JsExpression q = x.getQualifier();
+ if (ident.startsWith("@")) {
+ int dispId = dispatchInfo.getDispId(ident);
+
+ Member member;
+ if (dispId < 0) {
+ // We've already emitted a warning from getDispId; just fake the jsni
+ member = null;
+ } else {
+ member = dispatchInfo.getClassInfoByDispId(dispId).getMember(dispId);
+ }
+
+ if (member == null || member instanceof Field
+ || member instanceof SyntheticClassMember) {
+ if (q != null) {
+ accept(q);
+ out.print("[");
+ out.print(String.valueOf(dispId));
+ out.print("]");
+ } else {
+ out.print("__static[");
+ out.print(String.valueOf(dispId));
+ out.print("]");
+ }
+
+ return false;
+ }
+
+ int paramCount = 0;
+ if (member instanceof Method) {
+ paramCount = ((Method) member).getParameterTypes().length;
+ } else if (member instanceof Constructor) {
+ paramCount = ((Constructor<?>) member).getParameterTypes().length;
+ }
+
+ // Use a clone instead of modifying the original JSNI
+ // __gwt_makeTearOff(obj, dispId, paramCount)
+ JsInvocation rewritten = new JsInvocation(SourceInfo.UNKNOWN);
+ rewritten.setQualifier(new JsNameRef(SourceInfo.UNKNOWN,
+ "__gwt_makeTearOff"));
+
+ List<JsExpression> arguments = rewritten.getArguments();
+ if (q == null) {
+ q = program.getNullLiteral();
+ }
+ arguments.add(q);
+ arguments.add(program.getNumberLiteral(dispId));
+ arguments.add(program.getNumberLiteral(paramCount));
+
+ accept(rewritten);
+ return false;
+ }
+ return super.visit(x, ctx);
+ }
+
+ /**
+ * Handles immediate invocations of JSNI method references. This has to be
+ * done through a wonky method "__gwt_makeJavaInvoke" to handle exceptions
+ * correctly on some browsers.
+ */
+ @Override
+ public boolean visit(JsInvocation x, JsContext<JsExpression> ctx) {
+ if (x.getQualifier() instanceof JsNameRef) {
+ JsNameRef ref = (JsNameRef) x.getQualifier();
+ String ident = ref.getIdent();
+ if (ident.startsWith("@")) {
+ int dispId = dispatchInfo.getDispId(ident);
+
+ Member member;
+ if (dispId < 0) {
+ member = null;
+ } else {
+ member = dispatchInfo.getClassInfoByDispId(dispId).getMember(dispId);
+ }
+
+ /*
+ * Make sure the ident is a reference to a method or constructor and
+ * not a reference to a field whose contents (e.g. a Function) we
+ * intend to immediately invoke.
+ *
+ * p.C::method()(); versus p.C::field();
+ *
+ * Also, if the reference was to a non-existent field, we'll go ahead
+ * and rewrite the call site as though -1 is a valid dispid.
+ */
+ if (member == null || member instanceof Method
+ || member instanceof Constructor) {
+
+ // Use a clone instead of modifying the original JSNI
+ // __gwt_makeJavaInvoke(paramCount)(obj, dispId, args)
+ int paramCount = 0;
+ if (member instanceof Method) {
+ paramCount = ((Method) member).getParameterTypes().length;
+ } else if (member instanceof Constructor) {
+ paramCount = ((Constructor<?>) member).getParameterTypes().length;
+ }
+
+ JsInvocation inner = new JsInvocation(SourceInfo.UNKNOWN);
+ inner.setQualifier(new JsNameRef(SourceInfo.UNKNOWN,
+ "__gwt_makeJavaInvoke"));
+ inner.getArguments().add(program.getNumberLiteral(paramCount));
+
+ JsInvocation outer = new JsInvocation(SourceInfo.UNKNOWN);
+ outer.setQualifier(inner);
+ JsExpression q = ref.getQualifier();
+ if (q == null) {
+ q = program.getNullLiteral();
+ }
+ List<JsExpression> arguments = outer.getArguments();
+ arguments.add(q);
+ arguments.add(program.getNumberLiteral(dispId));
+ arguments.addAll(x.getArguments());
+
+ accept(outer);
+ return false;
+ }
+ }
+ }
+ return super.visit(x, ctx);
+ }
+ }
+
+ public static final String JAVASCRIPTHOST_NAME = JavaScriptHost.class.getName();
+
+ public static final String JSNI_BLOCK_END = "}-*/";
+
+ public static final String JSNI_BLOCK_START = "/*-{";
+
+ /**
+ * Gets the body of a JSNI method, with Java refs escaped for hosted mode
+ * injection.
+ */
+ public static String getJavaScriptForHostedMode(TreeLogger logger,
+ DispatchIdOracle dispatchInfo, JsniMethod jsniMethod) {
+ JsFunction func = jsniMethod.function(logger);
+ if (func == null) {
+ return null;
+ }
+ return generateJavaScriptForHostedMode(dispatchInfo, jsniMethod.program(),
+ func.getBody());
+ }
+
+ /**
+ * Returns a string representing the source output of the JsNode, where all
+ * JSNI idents have been replaced with legal JavaScript for hosted mode.
+ */
+ private static String generateJavaScriptForHostedMode(
+ DispatchIdOracle dispatchInfo, JsProgram program, JsNode<?> node) {
+ DefaultTextOutput out = new DefaultTextOutput(false);
+ JsSourceGenWithJsniIdentFixup vi = new JsSourceGenWithJsniIdentFixup(out,
+ dispatchInfo, program);
+ vi.accept(node);
+ return out.toString();
+ }
+
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/ModulePanel.java b/dev/oophm/src/com/google/gwt/dev/ModulePanel.java
new file mode 100644
index 0000000..3fd457c
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/ModulePanel.java
@@ -0,0 +1,137 @@
+/**
+ * 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.TreeLogger.Type;
+import com.google.gwt.dev.util.log.AbstractTreeLogger;
+import com.google.gwt.dev.util.log.SwingLoggerPanel;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+
+/**
+ */
+public class ModulePanel extends JPanel {
+
+ /**
+ * A tab component with a close button, derived from Swing
+ * TabComponentsDemoProject.
+ */
+ private class ClosedTabComponent extends JPanel {
+
+ public ClosedTabComponent() {
+ super(new FlowLayout(FlowLayout.LEFT, 0, 0));
+ setOpaque(false);
+ JButton button = new JButton(closeIcon);
+ button.setBorderPainted(false);
+ button.setPreferredSize(new Dimension(closeIcon.getIconWidth(),
+ closeIcon.getIconHeight()));
+ button.setToolTipText("Close this tab");
+ add(button);
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ synchronized (tabs) {
+ tabs.remove(ModulePanel.this);
+ }
+ }
+ });
+ }
+ }
+
+ private static ImageIcon firefoxIcon = GWTShell.loadImageIcon("firefox24.png");
+
+ private static ImageIcon ieIcon = GWTShell.loadImageIcon("ie24.png");
+
+ private static ImageIcon safariIcon = GWTShell.loadImageIcon("safari24.png");
+
+ private static ImageIcon closeIcon = GWTShell.loadImageIcon("close.png");
+
+ private SwingLoggerPanel loggerPanel;
+
+ private final JTabbedPane tabs;
+
+ private JPanel topPanel;
+
+ public ModulePanel(Type maxLevel, String moduleName, String userAgent,
+ String remoteSocket, final JTabbedPane tabs) {
+ super(new BorderLayout());
+ this.tabs = tabs;
+ topPanel = new JPanel();
+ topPanel.add(new JLabel(moduleName));
+ JButton compileButton = new JButton("Compile (not yet implemented)");
+ compileButton.setEnabled(false);
+ compileButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ JOptionPane.showMessageDialog(null, "Compiling not implemented yet",
+ "Alert: Not Implemented", JOptionPane.INFORMATION_MESSAGE);
+ }
+ });
+ topPanel.add(compileButton);
+ add(topPanel, BorderLayout.NORTH);
+ loggerPanel = new SwingLoggerPanel(maxLevel);
+ add(loggerPanel);
+ AbstractTreeLogger logger = loggerPanel.getLogger();
+ ImageIcon browserIcon = null;
+ String lcAgent = userAgent.toLowerCase();
+ if (lcAgent.contains("msie")) {
+ browserIcon = ieIcon;
+ } else if (lcAgent.contains("webkit") || lcAgent.contains("safari")) {
+ browserIcon = safariIcon;
+ } else if (lcAgent.contains("firefox")) {
+ browserIcon = firefoxIcon;
+ }
+ String shortModuleName = moduleName;
+ int lastDot = shortModuleName.lastIndexOf('.');
+ if (lastDot >= 0) {
+ shortModuleName = shortModuleName.substring(lastDot + 1);
+ }
+ synchronized (tabs) {
+ tabs.addTab(shortModuleName, browserIcon, this, moduleName + " from "
+ + remoteSocket + " on " + userAgent);
+ }
+ TreeLogger branch = logger.branch(TreeLogger.INFO, "Request for module "
+ + moduleName);
+ branch.log(TreeLogger.INFO, "User agent: " + userAgent);
+ branch.log(TreeLogger.INFO, "Remote host: " + remoteSocket);
+ }
+
+ public void disconnect() {
+ topPanel.add(new ClosedTabComponent());
+ synchronized (tabs) {
+ int index = tabs.indexOfComponent(this);
+ if (index > -1) {
+ tabs.setTitleAt(index, "Disconnected");
+ tabs.setIconAt(index, null);
+ }
+ }
+ loggerPanel.disconnected();
+ }
+
+ public AbstractTreeLogger getLogger() {
+ return loggerPanel.getLogger();
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/WebServerPanel.java b/dev/oophm/src/com/google/gwt/dev/WebServerPanel.java
new file mode 100644
index 0000000..0b3ec1e
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/WebServerPanel.java
@@ -0,0 +1,39 @@
+/**
+ * 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.dev.util.log.SwingLoggerPanel;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JPanel;
+
+/**
+ */
+public class WebServerPanel extends JPanel {
+ private SwingLoggerPanel logWindow;
+
+ public WebServerPanel(int serverPort, TreeLogger.Type maxLevel) {
+ super(new BorderLayout());
+ logWindow = new SwingLoggerPanel(maxLevel);
+ add(logWindow);
+ }
+
+ public TreeLogger getLogger() {
+ return logWindow.getLogger();
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java
new file mode 100644
index 0000000..325bb64
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java
@@ -0,0 +1,1306 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.shell.BrowserChannel.SessionHandler.ReturnOrException;
+import com.google.gwt.dev.shell.BrowserChannel.SessionHandler.SpecialDispatchId;
+import com.google.gwt.dev.shell.BrowserChannel.Value.ValueType;
+import com.google.gwt.util.tools.Utility;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.net.Socket;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ *
+ */
+public abstract class BrowserChannel {
+
+ /**
+ * Class representing a reference to a Java object.
+ */
+ public static class JavaObjectRef {
+ private int refId;
+
+ public JavaObjectRef(int refId) {
+ this.refId = refId;
+ }
+
+ public int getRefid() {
+ return Math.abs(refId);
+ }
+
+ @Override
+ public String toString() {
+ return "JavaObjectRef(ref=" + refId + ")";
+ }
+ }
+
+ /**
+ * Class representing a reference to a JS object.
+ */
+ public static class JsObjectRef {
+ private int refId;
+
+ public JsObjectRef(int refId) {
+ assert !JSOBJECT_ID_MAP.get().containsKey(refId)
+ || (JSOBJECT_ID_MAP.get().get(refId).get() == null);
+ this.refId = refId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof JsObjectRef) && ((JsObjectRef) o).refId == refId;
+ }
+
+ public int getRefid() {
+ // exceptions are negative, so we get the absolute value
+ return Math.abs(refId);
+ }
+
+ @Override
+ public int hashCode() {
+ return refId;
+ }
+
+ public boolean isException() {
+ return refId < 0;
+ }
+
+ @Override
+ public String toString() {
+ return "JsObjectRef(" + refId + ")";
+ }
+ }
+
+ /**
+ * Enumeration of message type ids.
+ */
+ public enum MessageType {
+ Invoke, Return, LoadModule, Quit, LoadJsni, InvokeSpecial, FreeValue;
+ }
+
+ /**
+ * Hook interface for responding to messages.
+ */
+ public abstract static class SessionHandler {
+
+ /**
+ * Wrapper to return both a return value/exception and a flag as to whether
+ * an exception was thrown or not.
+ */
+ public static class ReturnOrException {
+ private final boolean isException;
+ private final Value returnValue;
+
+ public ReturnOrException(boolean isException, Value returnValue) {
+ this.isException = isException;
+ this.returnValue = returnValue;
+ }
+
+ public Value getReturnValue() {
+ return returnValue;
+ }
+
+ public boolean isException() {
+ return isException;
+ }
+ }
+
+ /**
+ * Enumeration of dispatch IDs on object 0 (the ServerMethods object).
+ *
+ * TODO: hasMethod/hasProperty no longer used, remove them!
+ */
+ public enum SpecialDispatchId {
+ HasMethod, HasProperty, GetProperty, SetProperty,
+ }
+
+ public abstract void freeValue(BrowserChannel channel, int[] ids);
+
+ public abstract ReturnOrException getProperty(BrowserChannel channel,
+ int refId, int dispId);
+
+ public abstract ReturnOrException invoke(BrowserChannel channel,
+ Value thisObj, int dispId, Value[] args);
+
+ public abstract TreeLogger loadModule(TreeLogger logger,
+ BrowserChannel channel, String moduleName, String userAgent);
+
+ public abstract ReturnOrException setProperty(BrowserChannel channel,
+ int refId, int dispId, Value newValue);
+
+ public abstract void unloadModule(BrowserChannel channel, String moduleName);
+ }
+
+ /**
+ * Represents a value for BrowserChannel.
+ */
+ public static class Value {
+ /**
+ * Enum of type tags sent across the wire.
+ */
+ public enum ValueType {
+ /**
+ * Primitive values.
+ */
+ NULL, BOOLEAN, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, STRING,
+
+ /**
+ * Representations of Java or JS objects, sent as an index into a table
+ * kept on the side holding the actual object.
+ */
+ JAVA_OBJECT, JS_OBJECT,
+
+ /**
+ * A Javascript undef value, also used for void returns.
+ */
+ UNDEFINED;
+
+ ValueType() {
+ }
+
+ byte getTag() {
+ return (byte) this.ordinal();
+ }
+ }
+
+ /**
+ * Type tag value.
+ */
+ private ValueType type = ValueType.UNDEFINED;
+
+ /**
+ * Represents a value sent/received across the wire.
+ */
+ private Object value = null;
+
+ public Value() {
+ }
+
+ public Value(Object obj) {
+ convertFromJavaValue(obj);
+ }
+
+ /**
+ * Convert a Java object to a value. Objects must be primitive wrappers,
+ * Strings, or JsObjectRef/JavaObjectRef instances.
+ *
+ * @param obj value to convert.
+ */
+ public void convertFromJavaValue(Object obj) {
+ if (obj == null) {
+ type = ValueType.NULL;
+ } else if (obj instanceof Boolean) {
+ type = ValueType.BOOLEAN;
+ } else if (obj instanceof Byte) {
+ type = ValueType.BYTE;
+ } else if (obj instanceof Character) {
+ type = ValueType.CHAR;
+ } else if (obj instanceof Double) {
+ type = ValueType.DOUBLE;
+ } else if (obj instanceof Float) {
+ type = ValueType.FLOAT;
+ } else if (obj instanceof Integer) {
+ type = ValueType.INT;
+ } else if (obj instanceof Long) {
+ type = ValueType.LONG;
+ } else if (obj instanceof Short) {
+ type = ValueType.SHORT;
+ } else if (obj instanceof String) {
+ type = ValueType.STRING;
+ } else if (obj instanceof JsObjectRef) {
+ // TODO: exception handling?
+ type = ValueType.JS_OBJECT;
+ } else if (obj instanceof JavaObjectRef) {
+ // TODO: exception handling?
+ type = ValueType.JAVA_OBJECT;
+ } else {
+ throw new RuntimeException(
+ "Unexpected Java type in convertFromJavaValue: " + obj);
+ }
+ value = obj;
+ }
+
+ /**
+ * Convert a value to the requested Java type.
+ *
+ * @param reqType type to convert to
+ * @return value as that type.
+ */
+ public Object convertToJavaType(Class<?> reqType) {
+ if (reqType.isArray()) {
+ // TODO(jat): handle arrays?
+ }
+ if (reqType.equals(Boolean.class)) {
+ assert type == ValueType.BOOLEAN;
+ return value;
+ } else if (reqType.equals(Byte.class) || reqType.equals(byte.class)) {
+ assert isNumber();
+ return Byte.valueOf(((Number) value).byteValue());
+ } else if (reqType.equals(Character.class) || reqType.equals(char.class)) {
+ if (type == ValueType.CHAR) {
+ return value;
+ } else {
+ assert isNumber();
+ return Character.valueOf((char) ((Number) value).shortValue());
+ }
+ } else if (reqType.equals(Double.class) || reqType.equals(double.class)) {
+ assert isNumber();
+ return Double.valueOf(((Number) value).doubleValue());
+ } else if (reqType.equals(Float.class) || reqType.equals(float.class)) {
+ assert isNumber();
+ return Float.valueOf(((Number) value).floatValue());
+ } else if (reqType.equals(Integer.class) || reqType.equals(int.class)) {
+ assert isNumber();
+ return Integer.valueOf(((Number) value).intValue());
+ } else if (reqType.equals(Long.class) || reqType.equals(long.class)) {
+ assert isNumber();
+ return Long.valueOf(((Number) value).longValue());
+ } else if (reqType.equals(Short.class) || reqType.equals(short.class)) {
+ assert isNumber();
+ return Short.valueOf(((Number) value).shortValue());
+ } else if (reqType.equals(String.class)) {
+ assert type == ValueType.STRING;
+ return value;
+ } else {
+ // Wants an object, caller must deal with object references.
+ return value;
+ }
+ }
+
+ public boolean getBoolean() {
+ assert type == ValueType.BOOLEAN;
+ return ((Boolean) value).booleanValue();
+ }
+
+ public byte getByte() {
+ assert type == ValueType.BYTE;
+ return ((Byte) value).byteValue();
+ }
+
+ public char getChar() {
+ assert type == ValueType.CHAR;
+ return ((Character) value).charValue();
+ }
+
+ public double getDouble() {
+ assert type == ValueType.DOUBLE;
+ return ((Double) value).doubleValue();
+ }
+
+ public float getFloat() {
+ assert type == ValueType.FLOAT;
+ return ((Float) value).floatValue();
+ }
+
+ public int getInt() {
+ assert type == ValueType.INT;
+ return ((Integer) value).intValue();
+ }
+
+ public JavaObjectRef getJavaObject() {
+ assert type == ValueType.JAVA_OBJECT;
+ return (JavaObjectRef) value;
+ }
+
+ public JsObjectRef getJsObject() {
+ assert type == ValueType.JS_OBJECT;
+ return (JsObjectRef) value;
+ }
+
+ public long getLong() {
+ assert type == ValueType.LONG;
+ return ((Long) value).longValue();
+ }
+
+ public short getShort() {
+ assert type == ValueType.SHORT;
+ return ((Short) value).shortValue();
+ }
+
+ public String getString() {
+ assert type == ValueType.STRING;
+ return (String) value;
+ }
+
+ public ValueType getType() {
+ return type;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public boolean isBoolean() {
+ return type == ValueType.BOOLEAN;
+ }
+
+ public boolean isByte() {
+ return type == ValueType.BYTE;
+ }
+
+ public boolean isChar() {
+ return type == ValueType.CHAR;
+ }
+
+ public boolean isDouble() {
+ return type == ValueType.DOUBLE;
+ }
+
+ public boolean isFloat() {
+ return type == ValueType.FLOAT;
+ }
+
+ public boolean isInt() {
+ return type == ValueType.INT;
+ }
+
+ public boolean isJavaObject() {
+ return type == ValueType.JAVA_OBJECT;
+ }
+
+ public boolean isJsObject() {
+ return type == ValueType.JS_OBJECT;
+ }
+
+ public boolean isLong() {
+ return type == ValueType.LONG;
+ }
+
+ public boolean isNull() {
+ return type == ValueType.NULL;
+ }
+
+ public boolean isNumber() {
+ switch (type) {
+ case BYTE:
+ case CHAR:
+ case DOUBLE:
+ case FLOAT:
+ case INT:
+ case LONG:
+ case SHORT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean isPrimitive() {
+ switch (type) {
+ case BOOLEAN:
+ case BYTE:
+ case CHAR:
+ case DOUBLE:
+ case FLOAT:
+ case INT:
+ case LONG:
+ case SHORT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean isShort() {
+ return type == ValueType.SHORT;
+ }
+
+ public boolean isString() {
+ return type == ValueType.STRING;
+ }
+
+ public boolean isUndefined() {
+ return type == ValueType.UNDEFINED;
+ }
+
+ public void setBoolean(boolean val) {
+ type = ValueType.BOOLEAN;
+ value = Boolean.valueOf(val);
+ }
+
+ public void setByte(byte val) {
+ type = ValueType.BYTE;
+ value = Byte.valueOf(val);
+ }
+
+ public void setChar(char val) {
+ type = ValueType.CHAR;
+ value = Character.valueOf(val);
+ }
+
+ public void setDouble(double val) {
+ type = ValueType.DOUBLE;
+ value = Double.valueOf(val);
+ }
+
+ public void setFloat(float val) {
+ type = ValueType.FLOAT;
+ value = Float.valueOf(val);
+ }
+
+ public void setInt(int val) {
+ type = ValueType.INT;
+ value = Integer.valueOf(val);
+ }
+
+ public void setJavaObject(JavaObjectRef val) {
+ type = ValueType.JAVA_OBJECT;
+ value = val;
+ }
+
+ public void setJsObject(JsObjectRef val) {
+ type = ValueType.JS_OBJECT;
+ value = val;
+ }
+
+ public void setLong(long val) {
+ type = ValueType.BOOLEAN;
+ value = Long.valueOf(val);
+ }
+
+ public void setNull() {
+ type = ValueType.NULL;
+ value = null;
+ }
+
+ public void setShort(short val) {
+ type = ValueType.SHORT;
+ value = Short.valueOf(val);
+ }
+
+ public void setString(String val) {
+ type = ValueType.STRING;
+ value = val;
+ }
+
+ public void setUndefined() {
+ type = ValueType.UNDEFINED;
+ value = null;
+ }
+
+ @Override
+ public String toString() {
+ return type + ": " + value;
+ }
+ }
+
+ /**
+ * A message asking the other side to free object references. Note that there
+ * is no response to this message, and this must only be sent immediately
+ * before an Invoke or Return message.
+ */
+ protected static class FreeMessage extends Message {
+ public static FreeMessage receive(BrowserChannel channel)
+ throws IOException {
+ DataInputStream stream = channel.getStreamFromOtherSide();
+ int numIds = stream.readInt();
+ // TODO: sanity check id count
+ int ids[] = new int[numIds];
+ for (int i = 0; i < numIds; ++i) {
+ ids[i] = stream.readInt();
+ }
+ return new FreeMessage(channel, ids);
+ }
+
+ public static void send(BrowserChannel channel, int[] ids)
+ throws IOException {
+ DataOutputStream stream = channel.getStreamToOtherSide();
+ stream.writeByte(MessageType.FreeValue.ordinal());
+ stream.writeInt(ids.length);
+ for (int id : ids) {
+ stream.writeInt(id);
+ }
+ stream.flush();
+ }
+
+ private final int ids[];
+
+ public FreeMessage(BrowserChannel channel, int[] ids) {
+ super(channel);
+ this.ids = ids;
+ }
+
+ public int[] getIds() {
+ return ids;
+ }
+
+ @Override
+ public boolean isAsynchronous() {
+ return true;
+ }
+
+ @Override
+ public void send() throws IOException {
+ send(getBrowserChannel(), ids);
+ }
+ }
+
+ /**
+ * A request from the to invoke a function on the other side.
+ */
+ protected static class InvokeMessage extends Message {
+ public static InvokeMessage receive(BrowserChannel channel)
+ throws IOException {
+ final DataInputStream stream = channel.getStreamFromOtherSide();
+ // NOTE: Tag has already been read.
+ final int methodDispatchId = stream.readInt();
+ final Value thisRef = readValue(stream);
+ final int argLen = stream.readInt();
+ final Value[] args = new Value[argLen];
+ for (int i = 0; i < argLen; i++) {
+ args[i] = readValue(stream);
+ }
+ return new InvokeMessage(channel, methodDispatchId, thisRef, args);
+ }
+
+ private final int methodDispatchId;
+ private final String methodName;
+
+ private final Value thisRef;
+ private final Value[] args;
+
+ public InvokeMessage(BrowserChannel channel, int methodDispatchId,
+ Value thisRef, Value[] args) {
+ super(channel);
+ this.thisRef = thisRef;
+ this.methodName = null;
+ this.methodDispatchId = methodDispatchId;
+ this.args = args;
+ }
+
+ public InvokeMessage(BrowserChannel channel, String methodName,
+ Value thisRef, Value[] args) {
+ super(channel);
+ this.thisRef = thisRef;
+ this.methodName = methodName;
+ this.methodDispatchId = -1;
+ this.args = args;
+ }
+
+ public Value[] getArgs() {
+ return args;
+ }
+
+ public int getMethodDispatchId() {
+ return methodDispatchId;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public Value getThis() {
+ return thisRef;
+ }
+
+ @Override
+ public void send() throws IOException {
+ final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+
+ stream.writeByte(MessageType.Invoke.ordinal());
+ writeUntaggedString(stream, methodName);
+ writeValue(stream, thisRef);
+ stream.writeInt(args.length);
+ for (int i = 0; i < args.length; i++) {
+ writeValue(stream, args[i]);
+ }
+ stream.flush();
+ }
+ }
+
+ /**
+ * A request from the to invoke a function on the other side.
+ */
+ protected static class InvokeSpecialMessage extends Message {
+ public static InvokeSpecialMessage receive(BrowserChannel channel)
+ throws IOException, BrowserChannelException {
+ final DataInputStream stream = channel.getStreamFromOtherSide();
+ // NOTE: Tag has already been read.
+ final int specialMethodInt = stream.readByte();
+ SpecialDispatchId[] ids = SpecialDispatchId.values();
+ if (specialMethodInt < 0 || specialMethodInt >= ids.length) {
+ throw new BrowserChannelException("Invalid dispatch id "
+ + specialMethodInt);
+ }
+ final SpecialDispatchId dispatchId = ids[specialMethodInt];
+ final int argLen = stream.readInt();
+ final Value[] args = new Value[argLen];
+ for (int i = 0; i < argLen; i++) {
+ args[i] = readValue(stream);
+ }
+ return new InvokeSpecialMessage(channel, dispatchId, args);
+ }
+
+ private final SpecialDispatchId dispatchId;
+ private final Value[] args;
+
+ public InvokeSpecialMessage(BrowserChannel channel,
+ SpecialDispatchId dispatchId, Value[] args) {
+ super(channel);
+ this.dispatchId = dispatchId;
+ this.args = args;
+ }
+
+ public Value[] getArgs() {
+ return args;
+ }
+
+ public SpecialDispatchId getDispatchId() {
+ return dispatchId;
+ }
+
+ @Override
+ public void send() throws IOException {
+ final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+
+ stream.writeByte(MessageType.InvokeSpecial.ordinal());
+ stream.writeByte(dispatchId.ordinal());
+ stream.writeInt(args.length);
+ for (int i = 0; i < args.length; i++) {
+ writeValue(stream, args[i]);
+ }
+ stream.flush();
+ }
+ }
+
+ /**
+ * A message sending JSNI code to be evaluated. Note that there is no response
+ * to this message, and this must only be sent immediately before an Invoke or
+ * Return message.
+ */
+ protected static class LoadJsniMessage extends Message {
+ public static LoadJsniMessage receive(BrowserChannel channel)
+ throws IOException {
+ DataInputStream stream = channel.getStreamFromOtherSide();
+ String js = stream.readUTF();
+ return new LoadJsniMessage(channel, js);
+ }
+
+ public static void send(BrowserChannel channel, String js)
+ throws IOException {
+ DataOutputStream stream = channel.getStreamToOtherSide();
+ stream.write(MessageType.LoadJsni.ordinal());
+ writeUntaggedString(stream, js);
+ stream.flush();
+ }
+
+ private final String js;
+
+ public LoadJsniMessage(BrowserChannel channel, String js) {
+ super(channel);
+ this.js = js;
+ }
+
+ @Override
+ public boolean isAsynchronous() {
+ return true;
+ }
+
+ @Override
+ public void send() throws IOException {
+ send(getBrowserChannel(), js);
+ }
+ }
+
+ /**
+ * A request from the client that the server load and initialize a given
+ * module.
+ */
+ protected static class LoadModuleMessage extends Message {
+ public static LoadModuleMessage receive(BrowserChannel channel)
+ throws IOException, BrowserChannelException {
+ final DataInputStream stream = channel.getStreamFromOtherSide();
+ final int version = stream.readInt();
+ checkProtocolVersion(version);
+ final String moduleName = readUtf8String(stream);
+ final String userAgent = readUtf8String(stream);
+ return new LoadModuleMessage(channel, version, moduleName, userAgent);
+ }
+
+ private static void checkProtocolVersion(int version)
+ throws BrowserChannelException {
+ if (version != BROWSERCHANNEL_PROTOCOL_VERSION) {
+ throw new BrowserChannelException(
+ "Incompatible client version: server="
+ + BROWSERCHANNEL_PROTOCOL_VERSION + ", client=" + version);
+ }
+ }
+
+ private final String moduleName;
+
+ private final String userAgent;
+
+ private final int protocolVersion;
+
+ public LoadModuleMessage(BrowserChannel channel, int protocolVersion,
+ String moduleName, String userAgent) {
+ super(channel);
+ this.moduleName = moduleName;
+ this.userAgent = userAgent;
+ this.protocolVersion = protocolVersion;
+ }
+
+ public String getModuleName() {
+ return moduleName;
+ }
+
+ public int getProtocolVersion() {
+ return protocolVersion;
+ }
+
+ public String getUserAgent() {
+ return userAgent;
+ }
+
+ @Override
+ public void send() throws IOException {
+ final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+ stream.writeByte(MessageType.LoadModule.ordinal());
+ stream.writeInt(protocolVersion);
+ writeUntaggedString(stream, moduleName);
+ writeUntaggedString(stream, userAgent);
+ stream.flush();
+ }
+ }
+
+ /**
+ * Abstract base class of OOPHM messages.
+ */
+ protected abstract static class Message {
+ public static MessageType readMessageType(DataInputStream stream)
+ throws IOException, BrowserChannelException {
+ stream.mark(1);
+ int type = stream.readByte();
+ MessageType[] types = MessageType.values();
+ if (type < 0 || type >= types.length) {
+ stream.reset();
+ throw new BrowserChannelException("Invalid message type " + type);
+ }
+ return types[type];
+ }
+
+ private final BrowserChannel channel;
+
+ public Message(BrowserChannel channel) {
+ this.channel = channel;
+ }
+
+ public final BrowserChannel getBrowserChannel() {
+ return channel;
+ }
+
+ /**
+ * @return true if this message type is asynchronous and does not expect a
+ * return message.
+ */
+ public boolean isAsynchronous() {
+ return false;
+ }
+
+ // IOException thrown by subclasses
+ public void send() throws IOException {
+ throw new UnsupportedOperationException(getClass().getName()
+ + " is a message format that can only be received.");
+ }
+ }
+
+ /**
+ * A message signifying a soft close of the communications channel.
+ */
+ protected static class QuitMessage extends Message {
+ public static QuitMessage receive(BrowserChannel channel) {
+ return new QuitMessage(channel);
+ }
+
+ public static void send(BrowserChannel channel) throws IOException {
+ final DataOutputStream stream = channel.getStreamToOtherSide();
+ stream.writeByte(MessageType.Quit.ordinal());
+ stream.flush();
+ }
+
+ public QuitMessage(BrowserChannel channel) {
+ super(channel);
+ }
+
+ @Override
+ public void send() throws IOException {
+ send(getBrowserChannel());
+ }
+ }
+
+ /**
+ * Signifies a return from a previous invoke.
+ */
+ protected static class ReturnMessage extends Message {
+ public static ReturnMessage receive(BrowserChannel channel)
+ throws IOException {
+ final DataInputStream stream = channel.getStreamFromOtherSide();
+ final boolean isException = stream.readBoolean();
+ final Value returnValue = readValue(stream);
+ return new ReturnMessage(channel, isException, returnValue);
+ }
+
+ public static void send(BrowserChannel channel, boolean isException,
+ Value returnValue) throws IOException {
+ final DataOutputStream stream = channel.getStreamToOtherSide();
+ stream.writeByte(MessageType.Return.ordinal());
+ stream.writeBoolean(isException);
+ writeValue(stream, returnValue);
+ stream.flush();
+ }
+
+ public static void send(BrowserChannel channel,
+ ReturnOrException returnOrException) throws IOException {
+ send(channel, returnOrException.isException(),
+ returnOrException.getReturnValue());
+ }
+
+ private final Value returnValue;
+ private final boolean isException;
+
+ public ReturnMessage(BrowserChannel channel, boolean isException,
+ Value returnValue) {
+ super(channel);
+ this.returnValue = returnValue;
+ this.isException = isException;
+ }
+
+ public Value getReturnValue() {
+ return returnValue;
+ }
+
+ public boolean isException() {
+ return isException;
+ }
+
+ @Override
+ public void send() throws IOException {
+ send(getBrowserChannel(), isException, returnValue);
+ }
+ }
+
+ public static final int BROWSERCHANNEL_PROTOCOL_VERSION = 1;
+
+ public static final int SPECIAL_CLIENTMETHODS_OBJECT = 0;
+
+ public static final int SPECIAL_SERVERMETHODS_OBJECT = 0;
+
+ /**
+ * This accumulates JsObjectRefs that are no longer referenced in the JVM.
+ */
+ private static final ThreadLocal<ReferenceQueue<JsObjectRef>> JSOBJECT_REF_QUEUE = new ThreadLocal<ReferenceQueue<JsObjectRef>>() {
+ @Override
+ protected ReferenceQueue<JsObjectRef> initialValue() {
+ return new ReferenceQueue<JsObjectRef>();
+ }
+ };
+
+ /**
+ * This map associates a JS reference id with a Reference to the JSObjectRef
+ * that currently represents that id.
+ */
+ private static final ThreadLocal<Map<Integer, Reference<JsObjectRef>>> JSOBJECT_ID_MAP = new ThreadLocal<Map<Integer, Reference<JsObjectRef>>>() {
+ @Override
+ protected Map<Integer, Reference<JsObjectRef>> initialValue() {
+ return new TreeMap<Integer, Reference<JsObjectRef>>();
+ }
+ };
+
+ /**
+ * This maps References to JsObjectRefs back to the original refId. Because we
+ * need the refId of the JsValueRef after it's been garbage-collected, this
+ * state must be stored externally.
+ */
+ private static final ThreadLocal<Map<Reference<JsObjectRef>, Integer>> REFERENCE_ID_MAP = new ThreadLocal<Map<Reference<JsObjectRef>, Integer>>() {
+ @Override
+ protected Map<Reference<JsObjectRef>, Integer> initialValue() {
+ return new IdentityHashMap<Reference<JsObjectRef>, Integer>();
+ }
+ };
+
+ /**
+ * Obtain the JsObjectRef that is currently in use to act as a proxy for the
+ * given JS object id.
+ */
+ protected static JsObjectRef getJsObjectRef(int refId) {
+ // Access is implicitly synchronous due to ThreadLocal
+ Map<Integer, Reference<JsObjectRef>> map = JSOBJECT_ID_MAP.get();
+ if (map.containsKey(refId)) {
+ Reference<JsObjectRef> ref = map.get(refId);
+ JsObjectRef toReturn = ref.get();
+ if (toReturn != null) {
+ return toReturn;
+ }
+ }
+
+ JsObjectRef toReturn = new JsObjectRef(refId);
+ Reference<JsObjectRef> ref = new WeakReference<JsObjectRef>(toReturn,
+ JSOBJECT_REF_QUEUE.get());
+ map.put(refId, ref);
+ REFERENCE_ID_MAP.get().put(ref, refId);
+ return toReturn;
+ }
+
+ protected static String readUtf8String(DataInputStream stream)
+ throws IOException {
+ final int len = stream.readInt();
+ final byte[] data = new byte[len];
+ stream.readFully(data);
+ return new String(data, "UTF8");
+ }
+
+ protected static Value readValue(DataInputStream stream) throws IOException {
+ ValueType tag;
+ try {
+ tag = readValueType(stream);
+ } catch (BrowserChannelException e) {
+ IOException ee = new IOException();
+ ee.initCause(e);
+ throw ee;
+ }
+ Value value = new Value();
+ switch (tag) {
+ case NULL:
+ value.setNull();
+ break;
+ case UNDEFINED:
+ value.setUndefined();
+ break;
+ case BOOLEAN:
+ value.setBoolean(stream.readByte() != 0);
+ break;
+ case BYTE:
+ value.setByte(stream.readByte());
+ break;
+ case CHAR:
+ value.setChar(stream.readChar());
+ break;
+ case FLOAT:
+ value.setFloat(stream.readFloat());
+ break;
+ case INT:
+ value.setInt(stream.readInt());
+ break;
+ case LONG:
+ value.setLong(stream.readLong());
+ break;
+ case DOUBLE:
+ value.setDouble(stream.readDouble());
+ break;
+ case SHORT:
+ value.setShort(stream.readShort());
+ break;
+ case STRING:
+ value.setString(readUtf8String(stream));
+ break;
+ case JS_OBJECT:
+ value.setJsObject(getJsObjectRef(stream.readInt()));
+ break;
+ case JAVA_OBJECT:
+ value.setJavaObject(new JavaObjectRef(stream.readInt()));
+ break;
+ }
+ return value;
+ }
+
+ protected static ValueType readValueType(DataInputStream stream)
+ throws IOException, BrowserChannelException {
+ int type = stream.readByte();
+ ValueType[] types = ValueType.values();
+ if (type < 0 || type >= types.length) {
+ throw new BrowserChannelException("Invalid value type " + type);
+ }
+ return types[type];
+ }
+
+ protected static void writeBoolean(DataOutputStream stream, boolean value)
+ throws IOException {
+ stream.writeByte(ValueType.BOOLEAN.getTag());
+ stream.writeBoolean(value);
+ }
+
+ protected static void writeByte(DataOutputStream stream, byte value)
+ throws IOException {
+ stream.writeByte(ValueType.BYTE.getTag());
+ stream.writeByte(value);
+ }
+
+ protected static void writeChar(DataOutputStream stream, char value)
+ throws IOException {
+ stream.writeByte(ValueType.CHAR.getTag());
+ stream.writeChar(value);
+ }
+
+ protected static void writeDouble(DataOutputStream stream, double value)
+ throws IOException {
+ stream.writeByte(ValueType.DOUBLE.getTag());
+ stream.writeDouble(value);
+ }
+
+ protected static void writeFloat(DataOutputStream stream, float value)
+ throws IOException {
+ stream.writeByte(ValueType.FLOAT.getTag());
+ stream.writeFloat(value);
+ }
+
+ protected static void writeInt(DataOutputStream stream, int value)
+ throws IOException {
+ stream.writeByte(ValueType.INT.getTag());
+ stream.writeInt(value);
+ }
+
+ protected static void writeJavaObject(DataOutputStream stream,
+ JavaObjectRef value) throws IOException {
+ stream.writeByte(ValueType.JAVA_OBJECT.getTag());
+ stream.writeInt(value.getRefid());
+ }
+
+ protected static void writeJsObject(DataOutputStream stream, JsObjectRef value)
+ throws IOException {
+ stream.writeByte(ValueType.JS_OBJECT.getTag());
+ stream.writeInt(value.getRefid());
+ }
+
+ protected static void writeNull(DataOutputStream stream) throws IOException {
+ stream.writeByte(ValueType.NULL.getTag());
+ }
+
+ protected static void writeShort(DataOutputStream stream, short value)
+ throws IOException {
+ stream.writeByte(ValueType.SHORT.getTag());
+ stream.writeShort(value);
+ }
+
+ protected static void writeUntaggedString(DataOutputStream stream, String data)
+ throws IOException {
+ try {
+ final byte[] bytes = data.getBytes("UTF8");
+ stream.writeInt(bytes.length);
+ stream.write(bytes);
+ } catch (UnsupportedEncodingException e) {
+ // TODO: Add description.
+ throw new RuntimeException();
+ }
+ }
+
+ protected static void writeUtf8String(DataOutputStream stream, String data)
+ throws IOException {
+ stream.writeByte(ValueType.STRING.getTag());
+ writeUntaggedString(stream, data);
+ }
+
+ protected static void writeValue(DataOutputStream stream, Value value)
+ throws IOException {
+ if (value.isNull()) {
+ writeNull(stream);
+ } else if (value.isUndefined()) {
+ writeUndefined(stream);
+ } else if (value.isJsObject()) {
+ writeJsObject(stream, value.getJsObject());
+ } else if (value.isJavaObject()) {
+ writeJavaObject(stream, value.getJavaObject());
+ } else if (value.isBoolean()) {
+ writeBoolean(stream, value.getBoolean());
+ } else if (value.isByte()) {
+ writeByte(stream, value.getByte());
+ } else if (value.isChar()) {
+ writeChar(stream, value.getChar());
+ } else if (value.isShort()) {
+ writeShort(stream, value.getShort());
+ } else if (value.isDouble()) {
+ writeDouble(stream, value.getDouble());
+ } else if (value.isFloat()) {
+ writeFloat(stream, value.getFloat());
+ } else if (value.isInt()) {
+ writeInt(stream, value.getInt());
+ } else if (value.isString()) {
+ writeUtf8String(stream, value.getString());
+ } else {
+ assert false;
+ }
+ }
+
+ private static void writeUndefined(DataOutputStream stream)
+ throws IOException {
+ stream.writeByte(ValueType.UNDEFINED.getTag());
+ }
+
+ private final DataInputStream streamFromOtherSide;
+
+ private final DataOutputStream streamToOtherSide;
+
+ private Socket socket;
+
+ public BrowserChannel(Socket socket) throws IOException {
+ streamFromOtherSide = new DataInputStream(new BufferedInputStream(
+ socket.getInputStream()));
+ streamToOtherSide = new DataOutputStream(new BufferedOutputStream(
+ socket.getOutputStream()));
+ this.socket = socket;
+ }
+
+ public void endSession() {
+ Utility.close(streamFromOtherSide);
+ Utility.close(streamToOtherSide);
+ Utility.close(socket);
+ }
+
+ public Set<Integer> getRefIdsForCleanup() {
+ // Access to these objects is inherently synchronous
+ Map<Integer, Reference<JsObjectRef>> objectMap = JSOBJECT_ID_MAP.get();
+ Map<Reference<JsObjectRef>, Integer> refIdMap = REFERENCE_ID_MAP.get();
+ ReferenceQueue<JsObjectRef> q = JSOBJECT_REF_QUEUE.get();
+ Set<Integer> toReturn = new HashSet<Integer>();
+
+ // Find all refIds associated with previous garbage collection cycles
+ Reference<? extends JsObjectRef> ref;
+ while ((ref = q.poll()) != null) {
+ Integer i = refIdMap.remove(ref);
+ assert i != null;
+ toReturn.add(i);
+ }
+
+ /*
+ * Check for liveness. This is necessary because the last reference to a
+ * JsObjectRef could have been cleared and a new reference to that refId
+ * created before this method has been called.
+ */
+ for (Iterator<Integer> i = toReturn.iterator(); i.hasNext();) {
+ Integer refId = i.next();
+ if (objectMap.containsKey(refId)) {
+ if (objectMap.get(refId).get() != null) {
+ i.remove();
+ } else {
+ objectMap.remove(refId);
+ }
+ }
+ }
+
+ return toReturn;
+ }
+
+ public String getRemoteEndpoint() {
+ return socket.getInetAddress().getCanonicalHostName() + ":"
+ + socket.getPort();
+ }
+
+ public Value invoke(String methodName, Value vthis, Value[] vargs,
+ SessionHandler handler) throws IOException, BrowserChannelException {
+ new InvokeMessage(this, methodName, vthis, vargs).send();
+ final ReturnMessage msg = reactToMessagesWhileWaitingForReturn(handler);
+ return msg.returnValue;
+ }
+
+ public void reactToMessages(SessionHandler handler) throws IOException,
+ BrowserChannelException {
+ do {
+ getStreamToOtherSide().flush();
+ MessageType messageType = Message.readMessageType(getStreamFromOtherSide());
+ switch (messageType) {
+ case FreeValue:
+ final FreeMessage freeMsg = FreeMessage.receive(this);
+ handler.freeValue(this, freeMsg.getIds());
+ break;
+ case Invoke:
+ final InvokeMessage imsg = InvokeMessage.receive(this);
+ ReturnMessage.send(this, handler.invoke(this, imsg.getThis(),
+ imsg.getMethodDispatchId(), imsg.getArgs()));
+ break;
+ case InvokeSpecial:
+ handleInvokeSpecial(handler);
+ break;
+ case Quit:
+ return;
+ default:
+ throw new BrowserChannelException("Invalid message type "
+ + messageType);
+ }
+ } while (true);
+ }
+
+ public ReturnMessage reactToMessagesWhileWaitingForReturn(
+ SessionHandler handler) throws IOException, BrowserChannelException {
+ do {
+ getStreamToOtherSide().flush();
+ MessageType messageType = Message.readMessageType(getStreamFromOtherSide());
+ switch (messageType) {
+ case FreeValue:
+ final FreeMessage freeMsg = FreeMessage.receive(this);
+ handler.freeValue(this, freeMsg.getIds());
+ break;
+ case Return:
+ return ReturnMessage.receive(this);
+ case Invoke:
+ final InvokeMessage imsg = InvokeMessage.receive(this);
+ ReturnMessage.send(this, handler.invoke(this, imsg.getThis(),
+ imsg.getMethodDispatchId(), imsg.getArgs()));
+ break;
+ case InvokeSpecial:
+ handleInvokeSpecial(handler);
+ break;
+ default:
+ throw new BrowserChannelException("Invalid message type "
+ + messageType + " received waiting for return.");
+ }
+ } while (true);
+ }
+
+ protected DataInputStream getStreamFromOtherSide() {
+ return streamFromOtherSide;
+ }
+
+ protected DataOutputStream getStreamToOtherSide() {
+ return streamToOtherSide;
+ }
+
+ private void handleInvokeSpecial(SessionHandler handler) throws IOException,
+ BrowserChannelException {
+ final InvokeSpecialMessage ismsg = InvokeSpecialMessage.receive(this);
+ Value[] args = ismsg.getArgs();
+ ReturnOrException retExc = null;
+ switch (ismsg.getDispatchId()) {
+ case GetProperty:
+ assert args.length == 2;
+ retExc = handler.getProperty(this, args[0].getInt(), args[1].getInt());
+ break;
+ case SetProperty:
+ assert args.length == 3;
+ retExc = handler.setProperty(this, args[0].getInt(), args[1].getInt(),
+ args[2]);
+ break;
+ default:
+ throw new HostedModeException("Unexpected InvokeSpecial method "
+ + ismsg.getDispatchId());
+ }
+ ReturnMessage.send(this, retExc);
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelException.java b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelException.java
new file mode 100644
index 0000000..d100469
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+/**
+ *
+ */
+public class BrowserChannelException extends Exception {
+ private static final long serialVersionUID = -8003262630951385484L;
+
+ public BrowserChannelException(String message) {
+ super(message);
+ }
+
+ public BrowserChannelException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.java b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.java
new file mode 100644
index 0000000..13fc1ac
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.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.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.shell.JsValue.DispatchObject;
+
+import java.io.IOException;
+import java.net.Socket;
+
+/**
+ *
+ */
+public class BrowserChannelServer extends BrowserChannel implements Runnable {
+
+ public static final String JSO_CLASS = "com.google.gwt.core.client.JavaScriptObject";
+
+ private SessionHandler handler;
+
+ private final ObjectsTable javaObjectsInBrowser = new ObjectsTable();
+
+ private TreeLogger logger;
+
+ private String moduleName;
+
+ private String userAgent;
+
+ public BrowserChannelServer(TreeLogger initialLogger, Socket socket,
+ SessionHandler handler) throws IOException {
+ super(socket);
+ this.handler = handler;
+ this.logger = initialLogger;
+ Thread thread = new Thread(this);
+ thread.setDaemon(true);
+ thread.setName("Hosted mode worker");
+ thread.start();
+ }
+
+ public void freeJsValue(int[] ids) {
+ try {
+ new FreeMessage(this, ids).send();
+ } catch (IOException e) {
+ // TODO(jat): error handling?
+ e.printStackTrace();
+ throw new HostedModeException("I/O error communicating with client");
+ }
+ }
+
+ public ObjectsTable getJavaObjectsExposedInBrowser() {
+ return javaObjectsInBrowser;
+ }
+
+ /**
+ * @param ccl
+ * @param jsthis
+ * @param methodName
+ * @param args
+ * @param returnJsValue
+ * @throws Throwable
+ */
+ public void invokeJavascript(CompilingClassLoader ccl, JsValueOOPHM jsthis,
+ String methodName, JsValueOOPHM[] args, JsValueOOPHM returnJsValue)
+ throws Throwable {
+ final ObjectsTable remoteObjects = getJavaObjectsExposedInBrowser();
+ Value vthis = convertFromJsValue(remoteObjects, jsthis);
+ Value[] vargs = new Value[args.length];
+ for (int i = 0; i < args.length; ++i) {
+ vargs[i] = convertFromJsValue(remoteObjects, args[i]);
+ }
+ try {
+ InvokeMessage invokeMessage = new InvokeMessage(this, methodName, vthis,
+ vargs);
+ invokeMessage.send();
+ final ReturnMessage msg = reactToMessagesWhileWaitingForReturn(handler);
+ Value returnValue = msg.getReturnValue();
+ convertToJsValue(ccl, remoteObjects, returnValue, returnJsValue);
+ if (msg.isException()) {
+ if (returnValue.isNull() || returnValue.isUndefined()) {
+ throw ModuleSpace.createJavaScriptException(ccl, null);
+
+ } else if (returnValue.isString()) {
+ throw ModuleSpace.createJavaScriptException(ccl,
+ returnValue.getString());
+
+ } else if (returnValue.isJsObject()) {
+ Object jso = JsValueGlue.createJavaScriptObject(returnJsValue, ccl);
+ throw ModuleSpace.createJavaScriptException(ccl, jso);
+
+ } else if (returnValue.isJavaObject()) {
+ Object object = remoteObjects.get(returnValue.getJavaObject().getRefid());
+ Object target = ((JsValueOOPHM.DispatchObjectOOPHM) object).getTarget();
+ if (target instanceof Throwable) {
+ throw (Throwable) (target);
+ } else {
+ // JS throwing random Java Objects, which we'll wrap is JSException
+ throw ModuleSpace.createJavaScriptException(ccl, target);
+ }
+ }
+ // JS throwing random primitives, which we'll wrap is JSException
+ throw ModuleSpace.createJavaScriptException(ccl,
+ returnValue.getValue().toString());
+ }
+ } catch (IOException e) {
+ // TODO(jat): error handling?
+ e.printStackTrace();
+ throw new HostedModeException("I/O error communicating with client");
+ } catch (BrowserChannelException e) {
+ // TODO(jat): error handling?
+ e.printStackTrace();
+ throw new HostedModeException("I/O error communicating with client");
+ }
+ }
+
+ public void loadJsni(String jsni) {
+ try {
+ LoadJsniMessage jsniMessage = new LoadJsniMessage(this, jsni);
+ jsniMessage.send();
+ // we do not wait for a return value
+ } catch (IOException e) {
+ // TODO(jat): error handling?
+ e.printStackTrace();
+ throw new HostedModeException("I/O error communicating with client");
+ }
+ }
+
+ public void run() {
+ try {
+ MessageType type = Message.readMessageType(getStreamFromOtherSide());
+ assert type == MessageType.LoadModule;
+ LoadModuleMessage message = LoadModuleMessage.receive(this);
+ moduleName = message.getModuleName();
+ userAgent = message.getUserAgent();
+ Thread.currentThread().setName(
+ "Hosting " + moduleName + " for " + userAgent);
+ logger = handler.loadModule(logger, this, moduleName, userAgent);
+ try {
+ // send LoadModule response
+ ReturnMessage.send(this, false, new Value());
+ reactToMessages(handler);
+ } finally {
+ handler.unloadModule(this, moduleName);
+ }
+ } catch (IOException e) {
+ logger.log(TreeLogger.WARN, "Client connection lost", e);
+ } catch (BrowserChannelException e) {
+ logger.log(TreeLogger.ERROR,
+ "Unrecognized command for client; closing connection", e);
+ } finally {
+ try {
+ shutdown();
+ } catch (IOException ignored) {
+ }
+ endSession();
+ }
+ }
+
+ public void shutdown() throws IOException {
+ QuitMessage.send(this);
+ }
+
+ /**
+ * Convert a JsValue into a BrowserChannel Value.
+ *
+ * @param localObjects lookup table for local objects -- may be null if jsval
+ * is known to be a primitive (including String).
+ * @param jsval value to convert
+ * @return jsval as a Value object.
+ */
+ Value convertFromJsValue(ObjectsTable localObjects, JsValueOOPHM jsval) {
+ Value value = new Value();
+ if (jsval.isNull()) {
+ value.setNull();
+ } else if (jsval.isUndefined()) {
+ value.setUndefined();
+ } else if (jsval.isBoolean()) {
+ value.setBoolean(jsval.getBoolean());
+ } else if (jsval.isInt()) {
+ value.setInt(jsval.getInt());
+ } else if (jsval.isNumber()) {
+ value.setDouble(jsval.getNumber());
+ } else if (jsval.isString()) {
+ value.setString(jsval.getString());
+ } else if (jsval.isJavaScriptObject()) {
+ value.setJsObject(jsval.getJavascriptObject());
+ } else if (jsval.isWrappedJavaObject()) {
+ assert localObjects != null;
+ DispatchObject javaObj = jsval.getJavaObjectWrapper();
+ value.setJavaObject(new JavaObjectRef(localObjects.add(javaObj)));
+ } else if (jsval.isWrappedJavaFunction()) {
+ assert localObjects != null;
+ value.setJavaObject(new JavaObjectRef(
+ localObjects.add(jsval.getWrappedJavaFunction())));
+ } else {
+ throw new RuntimeException("Unknown JsValue type " + jsval);
+ }
+ return value;
+ }
+
+ /**
+ * Convert a BrowserChannel Value into a JsValue.
+ *
+ * @param ccl Compiling class loader, may be null if val is known to not be a
+ * Java object or exception.
+ * @param localObjects table of Java objects, may be null as above.
+ * @param val Value to convert
+ * @param jsval JsValue object to receive converted value.
+ */
+ void convertToJsValue(CompilingClassLoader ccl, ObjectsTable localObjects,
+ Value val, JsValueOOPHM jsval) {
+ switch (val.getType()) {
+ case NULL:
+ jsval.setNull();
+ break;
+ case BOOLEAN:
+ jsval.setBoolean(val.getBoolean());
+ break;
+ case BYTE:
+ jsval.setByte(val.getByte());
+ break;
+ case CHAR:
+ jsval.setChar(val.getChar());
+ break;
+ case DOUBLE:
+ jsval.setDouble(val.getDouble());
+ break;
+ case FLOAT:
+ jsval.setDouble(val.getFloat());
+ break;
+ case INT:
+ jsval.setInt(val.getInt());
+ break;
+ case LONG:
+ jsval.setDouble(val.getLong());
+ break;
+ case SHORT:
+ jsval.setShort(val.getShort());
+ break;
+ case STRING:
+ jsval.setString(val.getString());
+ break;
+ case UNDEFINED:
+ jsval.setUndefined();
+ break;
+ case JS_OBJECT:
+ jsval.setJavascriptObject(val.getJsObject());
+ break;
+ case JAVA_OBJECT:
+ assert ccl != null && localObjects != null;
+ jsval.setWrappedJavaObject(ccl,
+ localObjects.get(val.getJavaObject().getRefid()));
+ break;
+ }
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/BrowserListener.java b/dev/oophm/src/com/google/gwt/dev/shell/BrowserListener.java
new file mode 100644
index 0000000..b06c46a
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/BrowserListener.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.shell.BrowserChannel.SessionHandler;
+
+import java.io.IOException;
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+/**
+ * Listens for connections from OOPHM clients.
+ */
+public class BrowserListener {
+
+ private ServerSocket listenSocket;
+
+ private Thread listenThread;
+
+ /**
+ * Listens for new connections from browsers.
+ */
+ public BrowserListener(final TreeLogger logger, int port,
+ final SessionHandler handler) {
+ try {
+ listenSocket = new ServerSocket(port);
+ logger.log(TreeLogger.INFO, "Listening at: "
+ + listenSocket.getLocalSocketAddress(), null);
+ listenThread = new Thread() {
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ Socket sock = listenSocket.accept();
+ TreeLogger branch = logger.branch(TreeLogger.INFO,
+ "Connection received from "
+ + sock.getInetAddress().getCanonicalHostName() + ":"
+ + sock.getPort());
+ try {
+ sock.setTcpNoDelay(true);
+ sock.setKeepAlive(true);
+ sock.setReuseAddress(true);
+ } catch (SocketException e) {
+ // Ignore non-critical errors.
+ }
+
+ BrowserChannelServer server = new BrowserChannelServer(branch,
+ sock, handler);
+ /*
+ * This object is special-cased by the SessionHandler, used for
+ * methods needed by the client like hasMethod/hasProperty/etc.
+ * handler is used for this object just to make sure it doesn't
+ * conflict with some real object exposed to the client.
+ */
+ int id = server.getJavaObjectsExposedInBrowser().add(server);
+ assert id == BrowserChannel.SPECIAL_SERVERMETHODS_OBJECT;
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Communications error", e);
+ }
+ }
+ }
+ };
+ listenThread.setName("Hosted mode listener");
+ listenThread.setDaemon(true);
+ } catch (BindException e) {
+ logger.log(TreeLogger.ERROR, "Unable to bind socket on port " + port
+ + " -- is another session active?", e);
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Communications error", e);
+ }
+ }
+
+ public String getEndpointIdentifier() {
+ try {
+ return InetAddress.getLocalHost().getHostAddress() + ":"
+ + listenSocket.getLocalPort();
+ } catch (UnknownHostException e) {
+ throw new RuntimeException("Unable to determine my ip", e);
+ }
+ }
+
+ public void start() {
+ if (listenThread != null) {
+ listenThread.start();
+ }
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/JsValueOOPHM.java b/dev/oophm/src/com/google/gwt/dev/shell/JsValueOOPHM.java
new file mode 100644
index 0000000..4ab0c77
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/JsValueOOPHM.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.dev.shell.BrowserChannel.JsObjectRef;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+/**
+ * Represents a JavaScript value in OOPHM.
+ */
+public class JsValueOOPHM extends JsValue {
+ /**
+ * OOPHM implementation of the DispatchObject interface.
+ */
+ static class DispatchObjectOOPHM implements DispatchObject {
+
+ private final CompilingClassLoader classLoader;
+
+ private final JavaDispatchImpl javaDispatch;
+
+ public DispatchObjectOOPHM(CompilingClassLoader ccl) {
+ javaDispatch = new JavaDispatchImpl(ccl);
+ classLoader = ccl;
+ }
+
+ public DispatchObjectOOPHM(CompilingClassLoader ccl, Object val) {
+ javaDispatch = new JavaDispatchImpl(ccl, val);
+ classLoader = ccl;
+ }
+
+ public JsValue getField(int dispId) {
+ JsValueOOPHM jsValue = new JsValueOOPHM();
+ if (javaDispatch.isField(dispId)) {
+ Field field = javaDispatch.getField(dispId);
+ JsValueGlue.set(jsValue, classLoader, field.getType(),
+ javaDispatch.getFieldValue(dispId));
+ } else {
+ MethodAdaptor method = javaDispatch.getMethod(dispId);
+ AccessibleObject obj = method.getUnderlyingObject();
+ DispatchMethod dispMethod = (DispatchMethod) classLoader.getWrapperForObject(obj);
+ if (dispMethod == null) {
+ dispMethod = new MethodDispatch(classLoader, method);
+ classLoader.putWrapperForObject(obj, dispMethod);
+ }
+ jsValue.setWrappedFunction(method.toString(), dispMethod);
+ }
+ return jsValue;
+ }
+
+ public JsValue getField(String name) {
+ int dispId = getFieldId(name);
+ if (dispId < 0) {
+ // no field by that name, return undefined
+ return new JsValueOOPHM();
+ }
+ return getField(dispId);
+ }
+
+ public int getFieldId(String name) {
+ return classLoader.getDispId(name);
+ }
+
+ public Object getTarget() {
+ return javaDispatch.getTarget();
+ }
+
+ public void setField(int dispId, JsValue jsValue) {
+ if (javaDispatch.isMethod(dispId)) {
+ throw new RuntimeException("Cannot reassign method "
+ + javaDispatch.getMethod(dispId).getName());
+ }
+ Field field = javaDispatch.getField(dispId);
+ Object val = JsValueGlue.get(jsValue, classLoader, field.getType(),
+ "setField");
+ javaDispatch.setFieldValue(dispId, val);
+ }
+
+ public void setField(String name, JsValue jsValue) {
+ int dispId = getFieldId(name);
+ if (dispId < 0) {
+ // no field by that name, and we do not support expands on Java objects
+ throw new RuntimeException("No such field " + name);
+ }
+ setField(dispId, jsValue);
+ }
+ }
+
+ /**
+ * Class used to identify a JavaScript undefined value.
+ */
+ private static class UndefinedValue {
+ }
+
+ public static final String JSE_CLASS = "com.google.gwt.core.client.JavaScriptException";
+
+ private static final ThreadLocal<Map<Object, DispatchObject>> dispatchObjectCache = new ThreadLocal<Map<Object, DispatchObject>>();
+
+ private static final UndefinedValue undefValue = new UndefinedValue();
+
+ /**
+ * Underlying value.
+ *
+ * This may be one of:
+ *
+ * <pre>
+ * - Boolean instance
+ * - Integer instance
+ * - Double instance
+ * - String instance
+ * - null
+ * - undefValue
+ * </pre>
+ */
+ private Object value;
+
+ /**
+ * Create a JsValueMoz object representing the undefined value.
+ */
+ public JsValueOOPHM() {
+ this.value = undefValue;
+ }
+
+ /**
+ * Create a JsValueOOPHM object wrapping a JS object given the object
+ * reference id.
+ *
+ * @param jsRefId pointer to underlying JsRootedValue as an integer.
+ */
+ public JsValueOOPHM(int jsRefId) {
+ this.value = new JsObjectRef(jsRefId);
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param other JsValueMoz instance to copy
+ */
+ public JsValueOOPHM(JsValueOOPHM other) {
+ value = other.value;
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return (Boolean) value;
+ }
+
+ @Override
+ public int getInt() {
+ return (Integer) value;
+ }
+
+ @Override
+ public DispatchObject getJavaObjectWrapper() {
+ return (DispatchObject) value;
+ }
+
+ /**
+ * @return the value as a JsObjectRef.
+ *
+ * Fails if isJavascriptObject() is false.
+ */
+ public JsObjectRef getJavascriptObject() {
+ return (JsObjectRef) value;
+ }
+
+ @Override
+ public int getJavaScriptObjectPointer() {
+ assert isJavaScriptObject();
+ return ((JsObjectRef) value).getRefid();
+ }
+
+ @Override
+ public double getNumber() {
+ return ((Number) value).doubleValue();
+ }
+
+ @Override
+ public String getString() {
+ return (String) value;
+ }
+
+ @Override
+ public String getTypeString() {
+ if (isBoolean()) {
+ return "boolean";
+ } else if (isInt()) {
+ return "int";
+ } else if (isJavaScriptObject()) {
+ JsObjectRef objRef = (JsObjectRef) value;
+ return "JavaScript object(" + objRef.getRefid() + ")";
+ } else if (isNull()) {
+ return "null";
+ } else if (isNumber()) {
+ return "number";
+ } else if (isString()) {
+ return "string";
+ } else if (isUndefined()) {
+ return "undefined";
+ } else if (isWrappedJavaFunction()) {
+ return "Java Method";
+ } else if (isWrappedJavaObject()) {
+ return "Java Object " + value.getClass().getName();
+ }
+ return "unexpected value type";
+ }
+
+ @Override
+ public DispatchMethod getWrappedJavaFunction() {
+ return (DispatchMethod) value;
+ }
+
+ @Override
+ public Object getWrappedJavaObject() {
+ return ((DispatchObject) value).getTarget();
+ }
+
+ @Override
+ public boolean isBoolean() {
+ return value instanceof Boolean;
+ }
+
+ @Override
+ public boolean isInt() {
+ return value instanceof Integer;
+ }
+
+ @Override
+ public boolean isJavaScriptObject() {
+ return value instanceof JsObjectRef;
+ }
+
+ @Override
+ public boolean isNull() {
+ return value == null;
+ }
+
+ @Override
+ public boolean isNumber() {
+ return value instanceof Number;
+ }
+
+ @Override
+ public boolean isString() {
+ return value instanceof String;
+ }
+
+ @Override
+ public boolean isUndefined() {
+ return value == undefValue;
+ }
+
+ @Override
+ public boolean isWrappedJavaFunction() {
+ return value instanceof DispatchMethod;
+ }
+
+ @Override
+ public boolean isWrappedJavaObject() {
+ return value instanceof DispatchObject;
+ }
+
+ @Override
+ public void setBoolean(boolean val) {
+ value = Boolean.valueOf(val);
+ }
+
+ /*
+ * TODO(jat): remove this method
+ */
+ @Override
+ public void setByte(byte val) {
+ value = Integer.valueOf(val);
+ }
+
+ /*
+ * TODO(jat): remove this method
+ */
+ @Override
+ public void setChar(char val) {
+ value = Integer.valueOf(val);
+ }
+
+ @Override
+ public void setDouble(double val) {
+ value = Double.valueOf(val);
+ }
+
+ @Override
+ public void setInt(int val) {
+ value = Integer.valueOf(val);
+ }
+
+ public void setJavascriptObject(JsObjectRef jsObject) {
+ value = jsObject;
+ }
+
+ @Override
+ public void setNull() {
+ value = null;
+ }
+
+ /*
+ * TODO(jat): remove this method
+ */
+ @Override
+ public void setShort(short val) {
+ value = Integer.valueOf(val);
+ }
+
+ @Override
+ public void setString(String val) {
+ value = val;
+ }
+
+ @Override
+ public void setUndefined() {
+ value = undefValue;
+ }
+
+ @Override
+ public void setValue(JsValue other) {
+ value = ((JsValueOOPHM) other).value;
+ }
+
+ /**
+ * Wrap a function call to a Java method in this JavaScript value.
+ *
+ * @param methodName the name of the method to invoke
+ * @param dispatchMethod the wrapper object
+ */
+ public void setWrappedFunction(String methodName,
+ DispatchMethod dispatchMethod) {
+ value = dispatchMethod;
+ }
+
+ @Override
+ public <T> void setWrappedJavaObject(CompilingClassLoader cl, T val) {
+ if (val == null) {
+ setNull();
+ return;
+ }
+ if (val instanceof DispatchObject) {
+ value = val;
+ } else {
+ Map<Object, DispatchObject> cache = dispatchObjectCache.get();
+ if (cache == null) {
+ cache = new IdentityHashMap<Object, DispatchObject>();
+ dispatchObjectCache.set(cache);
+ }
+ DispatchObject dispObj = cache.get(val);
+ if (dispObj == null) {
+ dispObj = new DispatchObjectOOPHM(cl, val);
+ cache.put(val, dispObj);
+ }
+ value = dispObj;
+ }
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/MethodDispatch.java b/dev/oophm/src/com/google/gwt/dev/shell/MethodDispatch.java
new file mode 100644
index 0000000..4e2b327
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/MethodDispatch.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.dev.shell.JsValue.DispatchMethod;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Wraps an arbitrary Java Method as a Dispatchable component. The class was
+ * motivated by the need to expose Java objects into JavaScript.
+ */
+class MethodDispatch implements DispatchMethod {
+
+ private final CompilingClassLoader classLoader;
+
+ private final MethodAdaptor method;
+
+ public MethodDispatch(CompilingClassLoader classLoader, MethodAdaptor method) {
+ this.classLoader = classLoader;
+ this.method = method;
+ }
+
+ /**
+ * Invoke a Java method from JavaScript. This is called solely from native
+ * code.
+ *
+ * @param jsthis JavaScript reference to Java object
+ * @param jsargs array of JavaScript values for parameters
+ * @param returnValue JavaScript value to return result in
+ * @return <code>true</code> if an exception was thrown
+ * @throws RuntimeException if improper arguments are supplied
+ */
+ public boolean invoke(JsValue jsthis, JsValue[] jsargs, JsValue returnValue) {
+ Class<?>[] paramTypes = method.getParameterTypes();
+ int argc = paramTypes.length;
+ Object args[] = new Object[argc];
+ // too many arguments are ok: the extra will be silently ignored
+ if (jsargs.length < argc) {
+ throw new RuntimeException("Not enough arguments to " + method);
+ }
+ Object jthis = null;
+ if (method.needsThis()) {
+ jthis = JsValueGlue.get(jsthis, classLoader, method.getDeclaringClass(),
+ "invoke this");
+ }
+ for (int i = 0; i < argc; ++i) {
+ args[i] = JsValueGlue.get(jsargs[i], classLoader, paramTypes[i],
+ "invoke arguments");
+ }
+ try {
+ Object result;
+ try {
+ result = method.invoke(jthis, args);
+ } catch (IllegalAccessException e) {
+ // should never, ever happen
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ JsValueGlue.set(returnValue, classLoader, method.getReturnType(), result);
+ return false;
+ } catch (InstantiationException e) {
+ // If we get here, it means an exception is being thrown from
+ // Java back into JavaScript
+ wrapException(returnValue, e.getCause());
+ return true;
+
+ } catch (InvocationTargetException e) {
+ // If we get here, it means an exception is being thrown from
+ // Java back into JavaScript
+ wrapException(returnValue, e.getTargetException());
+ return true;
+
+ } catch (IllegalArgumentException e) {
+ // TODO(jat): log to treelogger instead? If so, how do I get to it?
+ System.err.println("MethodDispatch.invoke, method=" + method.toString()
+ + ": argument mismatch");
+ for (int i = 0; i < argc; ++i) {
+ System.err.println(" param " + i + " type is "
+ + paramTypes[i].toString() + " value is type "
+ + jsargs[i].getTypeString() + " = " + args[i].toString());
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return method.toString();
+ }
+
+ /**
+ * Send an exception back to the client. This will either wrap a Java
+ * Throwable as a Java Object to be sent over the wire, or if the exception is
+ * a JavaScriptObject unwinding through the stack, send the JSO instead.
+ */
+ private void wrapException(JsValue returnValue, Throwable t) {
+ ModuleSpace.setThrownJavaException(t);
+
+ // See if we're in the process of throwing a JavaScriptObject; remove
+ // it from the JavaScriptException object and throw the JS object instead
+ Object jsoException = ModuleSpace.getJavaScriptExceptionException(
+ classLoader, t);
+
+ if (jsoException != null) {
+ JsValueGlue.set(returnValue, classLoader, jsoException.getClass(),
+ jsoException);
+ } else {
+ JsValueGlue.set(returnValue, classLoader, t.getClass(), t);
+ }
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java b/dev/oophm/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
new file mode 100644
index 0000000..2df0a69
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.javac.JsniMethod;
+import com.google.gwt.dev.shell.JsValue.DispatchObject;
+import com.google.gwt.dev.util.Jsni;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ */
+public class ModuleSpaceOOPHM extends ModuleSpace {
+
+ private BrowserChannelServer channel;
+
+ public ModuleSpaceOOPHM(ModuleSpaceHost msh, String moduleName,
+ BrowserChannelServer channel) {
+ super(msh.getLogger(), msh, moduleName, moduleName);
+ this.channel = channel;
+ msh.getLogger().log(TreeLogger.DEBUG,
+ "Created ModuleSpaceOOPHM for " + moduleName, null);
+ }
+
+ public void createNativeMethods(TreeLogger logger,
+ List<JsniMethod> jsniMethods, DispatchIdOracle dispatchIdOracle) {
+ if (jsniMethods.isEmpty()) {
+ return;
+ }
+ StringBuilder jsni = new StringBuilder();
+ for (JsniMethod jsniMethod : jsniMethods) {
+ String body = Jsni.getJavaScriptForHostedMode(logger, dispatchIdOracle,
+ jsniMethod);
+ if (body == null) {
+ // The error has been logged; just ignore it for now.
+ continue;
+ }
+ jsni.append("// " + jsniMethod.location() + ":" + jsniMethod.line()
+ + "\n");
+ jsni.append("this[\"" + jsniMethod.name() + "\"] = function(");
+ String[] paramNames = jsniMethod.paramNames();
+ for (int i = 0; i < paramNames.length; ++i) {
+ if (i > 0) {
+ jsni.append(", ");
+ }
+ jsni.append(paramNames[i]);
+ }
+ jsni.append(") ");
+ jsni.append(body);
+ jsni.append(";\n\n");
+ }
+ channel.loadJsni(jsni.toString());
+ }
+
+ // @Override
+ protected void cleanupJsValues() {
+ Set<Integer> refIdsForCleanup = channel.getRefIdsForCleanup();
+ if (refIdsForCleanup.isEmpty()) {
+ // nothing to do
+ return;
+ }
+ int[] ids = new int[refIdsForCleanup.size()];
+ int i = 0;
+ for (Integer id : refIdsForCleanup) {
+ ids[i++] = id;
+ }
+ channel.freeJsValue(ids);
+ }
+
+ /**
+ *
+ */
+ @Override
+ protected void createStaticDispatcher(TreeLogger logger) {
+ channel.loadJsni("function __defineStatic(__arg0) { window.__static = __arg0; }");
+ }
+
+ /**
+ * Invoke a JS method and return its value.
+ *
+ * @param name method name to invoke
+ * @param jthis object to invoke method on, null if static method
+ * @param types argument types
+ * @param args argument values
+ */
+ @Override
+ protected JsValue doInvoke(String name, Object jthis, Class<?>[] types,
+ Object[] args) throws Throwable {
+ TreeLogger branch = host.getLogger().branch(TreeLogger.DEBUG,
+ "Invoke native method " + name, null);
+ CompilingClassLoader isolatedClassLoader = getIsolatedClassLoader();
+ JsValueOOPHM jsthis = new JsValueOOPHM();
+ Class<?> jthisType = (jthis == null) ? Object.class : jthis.getClass();
+ JsValueGlue.set(jsthis, isolatedClassLoader, jthisType, jthis);
+ branch.log(TreeLogger.SPAM, " this=" + jsthis);
+
+ int argc = args.length;
+ JsValueOOPHM argv[] = new JsValueOOPHM[argc];
+ for (int i = 0; i < argc; ++i) {
+ argv[i] = new JsValueOOPHM();
+ JsValueGlue.set(argv[i], isolatedClassLoader, types[i], args[i]);
+ branch.log(TreeLogger.SPAM, " arg[" + i + "]=" + argv[i]);
+ }
+ JsValueOOPHM returnVal = new JsValueOOPHM();
+ try {
+ channel.invokeJavascript(isolatedClassLoader, jsthis, name, argv,
+ returnVal);
+ branch.log(TreeLogger.SPAM, " returned " + returnVal);
+ } catch (Throwable t) {
+ branch.log(TreeLogger.DEBUG, "exception thrown", t);
+ throw t;
+ }
+ return returnVal;
+ }
+
+ @Override
+ protected DispatchObject getStaticDispatcher() {
+ return new JsValueOOPHM.DispatchObjectOOPHM(getIsolatedClassLoader());
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/ObjectsTable.java b/dev/oophm/src/com/google/gwt/dev/shell/ObjectsTable.java
new file mode 100644
index 0000000..1d33104
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/ObjectsTable.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A class that keeps track of Java objects which have been exposed to the other
+ * side and assigns unique ids.
+ */
+public class ObjectsTable {
+
+ /**
+ * A type that records the next-available free id slot to use, without itself
+ * being a valid return type.
+ */
+ private static class Tombstone {
+ private final int nextFree;
+
+ public Tombstone(int nextFree) {
+ this.nextFree = nextFree;
+ }
+ }
+
+ private int nextFree = -1;
+ private int nextId = 0;
+ private final Map<Integer, Object> objects = new TreeMap<Integer, Object>();
+ private final Map<Object, Integer> refMap = new IdentityHashMap<Object, Integer>();
+
+ public int add(Object obj) {
+ int id = find(obj);
+ if (id >= 0) {
+ return id;
+ }
+ if (nextFree >= 0) {
+ id = nextFree;
+ nextFree = ((Tombstone) objects.get(id)).nextFree;
+ } else {
+ id = nextId++;
+ }
+ objects.put(id, obj);
+ refMap.put(obj, id);
+ return id;
+ }
+
+ public int find(Object obj) {
+ Integer objId = refMap.get(obj);
+ return objId != null ? objId.intValue() : -1;
+ }
+
+ public void free(int id) {
+ assert objects.get(id) != null : "Trying to free never-used id " + id;
+ assert !(objects.get(id) instanceof Tombstone) : "Duplicate free " + id;
+ refMap.remove(objects.get(id));
+ objects.put(id, new Tombstone(nextFree));
+ nextFree = id;
+ }
+
+ public Object get(int id) {
+ Object toReturn = objects.get(id);
+ assert !(toReturn instanceof Tombstone) : id + " is not an active id";
+ return toReturn;
+ }
+}
\ No newline at end of file
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/OophmSessionHandler.java b/dev/oophm/src/com/google/gwt/dev/shell/OophmSessionHandler.java
new file mode 100644
index 0000000..2c1896b
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/OophmSessionHandler.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.shell.BrowserChannel.SessionHandler;
+import com.google.gwt.dev.shell.BrowserChannel.Value;
+import com.google.gwt.dev.shell.JsValue.DispatchMethod;
+import com.google.gwt.dev.shell.JsValue.DispatchObject;
+
+import java.lang.reflect.Member;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+public class OophmSessionHandler extends SessionHandler {
+
+ private BrowserWidgetHost host;
+
+ private TreeLogger logger;
+
+ private Map<BrowserChannelServer, ModuleSpace> moduleMap = Collections.synchronizedMap(new HashMap<BrowserChannelServer, ModuleSpace>());
+
+ /**
+ * Listens for new connections from browsers.
+ */
+ public OophmSessionHandler(BrowserWidgetHost host) {
+ this.host = host;
+ logger = host.getLogger();
+ }
+
+ @Override
+ public void freeValue(BrowserChannel channel, int[] ids) {
+ BrowserChannelServer serverChannel = (BrowserChannelServer) channel;
+ ObjectsTable localObjects = serverChannel.getJavaObjectsExposedInBrowser();
+ for (int id : ids) {
+ localObjects.free(id);
+ }
+ }
+
+ @Override
+ public ReturnOrException getProperty(BrowserChannel channel, int refId,
+ int dispId) {
+ BrowserChannelServer serverChannel = (BrowserChannelServer) channel;
+ ModuleSpace moduleSpace = moduleMap.get(serverChannel);
+ assert moduleSpace != null;
+ ObjectsTable localObjects = serverChannel.getJavaObjectsExposedInBrowser();
+ try {
+ JsValueOOPHM obj = new JsValueOOPHM();
+ DispatchObject dispObj;
+ CompilingClassLoader ccl = moduleSpace.getIsolatedClassLoader();
+ obj.setWrappedJavaObject(ccl, localObjects.get(refId));
+ dispObj = obj.getJavaObjectWrapper();
+ TreeLogger branch = logger.branch(TreeLogger.SPAM,
+ "Client special invoke of getProperty(" + dispId + " ["
+ + ccl.getClassInfoByDispId(dispId).getMember(dispId) + "]) on "
+ + obj.toString(), null);
+ JsValueOOPHM jsval = (JsValueOOPHM) dispObj.getField(dispId);
+ Value retVal = serverChannel.convertFromJsValue(localObjects, jsval);
+ branch.log(TreeLogger.SPAM, "result is " + retVal, null);
+ return new ReturnOrException(false, retVal);
+ } catch (Throwable t) {
+ JsValueOOPHM jsval = new JsValueOOPHM();
+ JsValueGlue.set(jsval, moduleSpace.getIsolatedClassLoader(),
+ t.getClass(), t);
+ Value retVal = serverChannel.convertFromJsValue(localObjects, jsval);
+ return new ReturnOrException(true, retVal);
+ }
+ }
+
+ /**
+ * Invoke a method on a server object in from client code.
+ */
+ @Override
+ public ReturnOrException invoke(BrowserChannel channel, Value thisVal,
+ int methodDispatchId, Value[] args) {
+ BrowserChannelServer serverChannel = (BrowserChannelServer) channel;
+ ObjectsTable localObjects = serverChannel.getJavaObjectsExposedInBrowser();
+ ModuleSpace moduleSpace = moduleMap.get(serverChannel);
+ assert moduleSpace != null;
+ CompilingClassLoader cl = moduleSpace.getIsolatedClassLoader();
+
+ // Treat dispatch id 0 as toString()
+ if (methodDispatchId == 0) {
+ methodDispatchId = cl.getDispId("java.lang.Object::toString()");
+ }
+
+ JsValueOOPHM jsThis = new JsValueOOPHM();
+ serverChannel.convertToJsValue(cl, localObjects, thisVal, jsThis);
+
+ TreeLogger branch = TreeLogger.NULL;
+ if (logger.isLoggable(TreeLogger.DEBUG)) {
+ StringBuffer logMsg = new StringBuffer();
+ logMsg.append("Client invoke of ");
+ logMsg.append(methodDispatchId);
+ DispatchClassInfo classInfo = cl.getClassInfoByDispId(methodDispatchId);
+ if (classInfo != null) {
+ Member member = classInfo.getMember(methodDispatchId);
+ if (member != null) {
+ logMsg.append(" (");
+ logMsg.append(member.getName());
+ logMsg.append(")");
+ }
+ }
+ logMsg.append(" on ");
+ logMsg.append(jsThis.toString());
+ branch = logger.branch(TreeLogger.DEBUG, logMsg.toString(), null);
+ }
+ JsValueOOPHM[] jsArgs = new JsValueOOPHM[args.length];
+ for (int i = 0; i < args.length; ++i) {
+ jsArgs[i] = new JsValueOOPHM();
+ serverChannel.convertToJsValue(cl, localObjects, args[i], jsArgs[i]);
+ branch.log(TreeLogger.DEBUG, " arg " + i + " = " + jsArgs[i].toString(),
+ null);
+ }
+ JsValueOOPHM jsRetVal = new JsValueOOPHM();
+ JsValueOOPHM jsMethod;
+ DispatchObject dispObj;
+ if (jsThis.isWrappedJavaObject()) {
+ // If this is a wrapped object, get get the method off it.
+ dispObj = jsThis.getJavaObjectWrapper();
+ } else {
+ // Look it up on the static dispatcher.
+ dispObj = (DispatchObject) moduleSpace.getStaticDispatcher();
+ }
+ jsMethod = (JsValueOOPHM) dispObj.getField(methodDispatchId);
+ DispatchMethod dispMethod = jsMethod.getWrappedJavaFunction();
+ boolean exception;
+ try {
+ exception = dispMethod.invoke(jsThis, jsArgs, jsRetVal);
+ } catch (Throwable t) {
+ exception = true;
+ JsValueGlue.set(jsRetVal, moduleSpace.getIsolatedClassLoader(),
+ t.getClass(), t);
+ }
+ Value retVal = serverChannel.convertFromJsValue(localObjects, jsRetVal);
+ return new ReturnOrException(exception, retVal);
+ }
+
+ @Override
+ public TreeLogger loadModule(TreeLogger logger, BrowserChannel channel,
+ String moduleName, String userAgent) {
+ try {
+ // Attach a new ModuleSpace to make it programmable.
+ //
+ BrowserChannelServer serverChannel = (BrowserChannelServer) channel;
+ ModuleSpaceHost msh = host.createModuleSpaceHost(logger, moduleName,
+ userAgent, channel.getRemoteEndpoint());
+ this.logger = logger = msh.getLogger();
+ ModuleSpace moduleSpace = new ModuleSpaceOOPHM(msh, moduleName,
+ serverChannel);
+ moduleMap.put(serverChannel, moduleSpace);
+ moduleSpace.onLoad(logger);
+ } catch (Throwable e) {
+ // We do catch Throwable intentionally because there are a ton of things
+ // that can go wrong trying to load a module, including Error-derived
+ // things like NoClassDefFoundError.
+ //
+ logger.log(TreeLogger.ERROR, "Failed to load module '" + moduleName
+ + "' from user agent '" + userAgent + "' at "
+ + channel.getRemoteEndpoint(), e);
+ }
+ return logger;
+ }
+
+ @Override
+ public ReturnOrException setProperty(BrowserChannel channel, int refId,
+ int dispId, Value newValue) {
+ BrowserChannelServer serverChannel = (BrowserChannelServer) channel;
+ ModuleSpace moduleSpace = moduleMap.get(serverChannel);
+ assert moduleSpace != null;
+ ObjectsTable localObjects = serverChannel.getJavaObjectsExposedInBrowser();
+ try {
+ JsValueOOPHM obj = new JsValueOOPHM();
+ DispatchObject dispObj;
+ obj.setWrappedJavaObject(moduleSpace.getIsolatedClassLoader(),
+ localObjects.get(refId));
+ dispObj = obj.getJavaObjectWrapper();
+ logger.log(TreeLogger.SPAM, "Client special invoke of setProperty(id="
+ + dispId + ", newValue=" + newValue + ") on " + obj.toString(), null);
+ JsValueOOPHM jsval = new JsValueOOPHM();
+ serverChannel.convertToJsValue(moduleSpace.getIsolatedClassLoader(),
+ localObjects, newValue, jsval);
+ dispObj.setField(dispId, jsval);
+ return new ReturnOrException(false, newValue);
+ } catch (Throwable t) {
+ JsValueOOPHM jsval = new JsValueOOPHM();
+ JsValueGlue.set(jsval, moduleSpace.getIsolatedClassLoader(),
+ t.getClass(), t);
+ Value retVal = serverChannel.convertFromJsValue(localObjects, jsval);
+ return new ReturnOrException(true, retVal);
+ }
+ }
+
+ @Override
+ public void unloadModule(BrowserChannel channel, String moduleName) {
+ BrowserChannelServer serverChannel = (BrowserChannelServer) channel;
+ ModuleSpace moduleSpace = moduleMap.get(serverChannel);
+ if (moduleSpace == null) {
+ logger.log(TreeLogger.ERROR, "Unload request without a module loaded",
+ null);
+ return;
+ }
+ logger.log(TreeLogger.INFO, "Unloading module "
+ + moduleSpace.getModuleName() + " (" + moduleName + ")", null);
+ host.unloadModule(moduleSpace.host);
+ moduleSpace.dispose();
+ moduleMap.remove(serverChannel);
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/close.png b/dev/oophm/src/com/google/gwt/dev/shell/close.png
new file mode 100644
index 0000000..3e8fe3a
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/close.png
Binary files differ
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/firefox24.png b/dev/oophm/src/com/google/gwt/dev/shell/firefox24.png
new file mode 100644
index 0000000..29bcab5
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/firefox24.png
Binary files differ
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/ie24.png b/dev/oophm/src/com/google/gwt/dev/shell/ie24.png
new file mode 100644
index 0000000..b1b51cb
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/ie24.png
Binary files differ
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/safari24.png b/dev/oophm/src/com/google/gwt/dev/shell/safari24.png
new file mode 100644
index 0000000..8d9764b
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/safari24.png
Binary files differ
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/tomcat24.png b/dev/oophm/src/com/google/gwt/dev/shell/tomcat24.png
new file mode 100644
index 0000000..6983c54
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/shell/tomcat24.png
Binary files differ
diff --git a/dev/oophm/src/com/google/gwt/dev/util/log/SwingLoggerPanel.java b/dev/oophm/src/com/google/gwt/dev/util/log/SwingLoggerPanel.java
new file mode 100644
index 0000000..0de63a0
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/util/log/SwingLoggerPanel.java
@@ -0,0 +1,565 @@
+/*
+ * 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.log;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.dev.util.log.SwingTreeLogger.LogEvent;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.HeadlessException;
+import java.awt.Point;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextField;
+import javax.swing.JTree;
+import javax.swing.KeyStroke;
+import javax.swing.Popup;
+import javax.swing.PopupFactory;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+/**
+ * Swing widget containing a tree logger.
+ */
+public class SwingLoggerPanel extends JPanel implements TreeSelectionListener {
+
+ private class FindBox extends JPanel {
+
+ private JTextField searchField;
+ private JLabel searchStatus;
+
+ private Popup findPopup;
+
+ private String lastSearch;
+ private int matchNumber;
+ private ArrayList<DefaultMutableTreeNode> matches;
+
+ public FindBox() {
+ super(new BorderLayout());
+ JPanel top = new JPanel(new FlowLayout());
+ searchField = new JTextField(20);
+ top.add(searchField);
+ JButton nextButton = new JButton("+");
+ top.add(nextButton);
+ nextButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ nextMatch();
+ }
+ });
+ JButton prevButton = new JButton("-");
+ top.add(prevButton);
+ prevButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ prevMatch();
+ }
+ });
+ JButton closeButton = new JButton(closeIcon);
+ closeButton.setBorderPainted(false);
+ closeButton.setPreferredSize(new Dimension(closeIcon.getIconWidth(),
+ closeIcon.getIconHeight()));
+ closeButton.setToolTipText("Close this search box");
+ top.add(closeButton);
+ KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+ getInputMap(WHEN_IN_FOCUSED_WINDOW).put(key, "find-cancel");
+ key = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
+ getInputMap(WHEN_IN_FOCUSED_WINDOW).put(key, "find-search");
+ getActionMap().put("find-search", new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ lastSearch = searchField.getText();
+ matches = doFind(lastSearch);
+ matchNumber = 0;
+ updateSearchResult();
+ }
+ });
+ AbstractAction closeFindBox = new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ hideFindBox();
+ }
+ };
+ getActionMap().put("find-cancel", closeFindBox);
+ closeButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ hideFindBox();
+ }
+ });
+ add(top, BorderLayout.NORTH);
+ searchStatus = new JLabel("Type search text and press Enter");
+ searchStatus.setBorder(BorderFactory.createEmptyBorder(0, 2, 2, 0));
+ add(searchStatus, BorderLayout.SOUTH);
+ }
+
+ public void hideBox() {
+ if (findPopup != null) {
+ findPopup.hide();
+ findPopup = null;
+ }
+ }
+
+ public void nextMatch() {
+ if (matches != null && matches.size() > 0) {
+ matchNumber = (matchNumber + 1) % matches.size();
+ updateSearchResult();
+ }
+ }
+
+ public void prevMatch() {
+ if (matches != null) {
+ int n = matches.size();
+ if (n > 0) {
+ matchNumber = (matchNumber + n - 1) % n;
+ updateSearchResult();
+ }
+ }
+ }
+
+ public void showBox() {
+ Point loggerOrigin = details.getLocationOnScreen();
+ Dimension dim = details.getSize();
+ if (findPopup != null) {
+ findPopup.hide();
+ }
+ // have to display once to get the correct size
+ int width = findBox.getWidth();
+ boolean needsRelocate = (width <= 0);
+ int x = loggerOrigin.x + dim.width - width;
+ int y = loggerOrigin.y + dim.height - findBox.getHeight();
+ PopupFactory popupFactory = PopupFactory.getSharedInstance();
+ // TODO(jat): need to track window resize?
+ findPopup = popupFactory.getPopup(SwingLoggerPanel.this, findBox, x, y);
+ findPopup.show();
+ if (needsRelocate) {
+ x = loggerOrigin.x + dim.width - findBox.getWidth();
+ y = loggerOrigin.y + dim.height - findBox.getHeight();
+ findPopup.hide();
+ findPopup = popupFactory.getPopup(SwingLoggerPanel.this, findBox, x, y);
+ findPopup.show();
+ }
+ searchField.requestFocusInWindow();
+ }
+
+ /**
+ *
+ */
+ private void updateSearchResult() {
+ int n = matches.size();
+ if (n == 0) {
+ searchStatus.setText("No matches");
+ } else {
+ searchStatus.setText(String.valueOf(matchNumber + 1) + " of "
+ + n + " matches");
+ showFindResult(matches.get(matchNumber), lastSearch);
+ }
+ }
+ }
+
+ private static class TreeRenderer extends DefaultTreeCellRenderer {
+ @Override
+ public Component getTreeCellRendererComponent(JTree tree, Object value,
+ boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+ super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row,
+ hasFocus);
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
+ Object userObject = node.getUserObject();
+ if (userObject instanceof LogEvent) {
+ LogEvent event = (LogEvent) userObject;
+ event.setDisplayProperties(this);
+ }
+ return this;
+ }
+ }
+
+ private static ImageIcon closeIcon = SwingTreeLogger.tryLoadImage("icon-close.png");
+
+ private static final Color DISCONNECTED_COLOR = Color.decode("0xFFDDDD");
+
+ // package protected for SwingTreeLogger to access
+
+ final JTree tree;
+
+ DefaultTreeModel treeModel;
+
+ Type levelFilter;
+
+ String regexFilter;
+
+ private boolean autoScroll;
+
+ private final JEditorPane details;
+
+ private final AbstractTreeLogger logger;
+
+ private DefaultMutableTreeNode root;
+
+ private JTextField regexField;
+
+ private JComboBox levelComboBox;
+
+ private JPanel topPanel;
+
+ private FindBox findBox;
+
+ private JScrollPane treeView;
+
+ public SwingLoggerPanel(TreeLogger.Type maxLevel) {
+ super(new BorderLayout());
+ regexFilter = "";
+ levelFilter = maxLevel;
+ // TODO(jat): how to make the topPanel properly layout items
+ // when the window is resized
+ topPanel = new JPanel();
+ JButton expandButton = new JButton("Expand All");
+ expandButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ expandAll();
+ }
+ });
+ topPanel.add(expandButton);
+ JButton collapsButton = new JButton("Collapse All");
+ collapsButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ collapseAll();
+ }
+ });
+ topPanel.add(collapsButton);
+ if (true) {
+ // temporarily avoid showing parts that aren't implemented.
+ topPanel.add(new JLabel("Log filtering controls will go here"));
+ } else {
+ topPanel.add(new JLabel("Filter Log Messages: "));
+ levelComboBox = new JComboBox();
+ for (TreeLogger.Type type : TreeLogger.Type.instances()) {
+ if (type.compareTo(maxLevel) > 0) {
+ break;
+ }
+ levelComboBox.addItem(type);
+ }
+ levelComboBox.setEditable(false);
+ levelComboBox.setSelectedIndex(levelComboBox.getItemCount() - 1);
+ topPanel.add(levelComboBox);
+ levelComboBox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setLevelFilter((TreeLogger.Type) levelComboBox.getSelectedItem());
+ }
+ });
+ regexField = new JTextField(20);
+ topPanel.add(regexField);
+ JButton applyRegexButton = new JButton("Apply Regex");
+ applyRegexButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setRegexFilter(regexField.getText());
+ }
+ });
+ topPanel.add(applyRegexButton);
+ JButton clearRegexButton = new JButton("Clear Regex");
+ clearRegexButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ regexField.setText("");
+ setRegexFilter("");
+ }
+ });
+ topPanel.add(clearRegexButton);
+ }
+ add(topPanel, BorderLayout.NORTH);
+ root = new DefaultMutableTreeNode();
+ treeModel = new DefaultTreeModel(root);
+ tree = new JTree(treeModel);
+ tree.setRootVisible(false);
+ tree.setEditable(false);
+ tree.setExpandsSelectedPaths(true);
+ tree.setShowsRootHandles(true);
+ tree.setCellRenderer(new TreeRenderer());
+ tree.getSelectionModel().setSelectionMode(
+ TreeSelectionModel.SINGLE_TREE_SELECTION);
+ tree.addTreeSelectionListener(this);
+ treeView = new JScrollPane(tree);
+ // TODO(jat): better way to do this
+ details = new JEditorPane() {
+ @Override
+ public boolean getScrollableTracksViewportWidth() {
+ return true;
+ }
+ };
+ details.setEditable(false);
+ details.setContentType("text/html");
+ details.setForeground(Color.BLACK);
+ JScrollPane msgView = new JScrollPane(details);
+ JSplitPane splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+ splitter.setTopComponent(treeView);
+ splitter.setBottomComponent(msgView);
+ Dimension minSize = new Dimension(100, 50);
+ msgView.setMinimumSize(minSize);
+ treeView.setMinimumSize(minSize);
+ splitter.setDividerLocation(0.80);
+ add(splitter);
+ logger = new SwingTreeLogger(this);
+ logger.setMaxDetail(maxLevel);
+ KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F,
+ InputEvent.CTRL_DOWN_MASK);
+ getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(key, "find");
+ getActionMap().put("find", new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ showFindBox();
+ }
+ });
+ key = KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK);
+ tree.getInputMap().put(key, "copy");
+ tree.getActionMap().put("copy", new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ treeCopy();
+ }
+ });
+ findBox = new FindBox();
+ key = KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK);
+ tree.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(key, "findnext");
+ tree.getActionMap().put("findnext", new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ findBox.nextMatch();
+ }
+ });
+ key = KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_DOWN_MASK);
+ tree.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(key, "findprev");
+ tree.getActionMap().put("findprev", new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ findBox.prevMatch();
+ }
+ });
+ }
+
+ @SuppressWarnings("unchecked")
+ public void collapseAll() {
+ Enumeration<DefaultMutableTreeNode> children = root.postorderEnumeration();
+ while (children.hasMoreElements()) {
+ DefaultMutableTreeNode node = children.nextElement();
+ if (node != root) {
+ tree.collapsePath(new TreePath(node.getPath()));
+ }
+ }
+ tree.invalidate();
+ }
+
+ public void disconnected() {
+ tree.setBackground(DISCONNECTED_COLOR);
+ tree.repaint();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void expandAll() {
+ Enumeration<DefaultMutableTreeNode> children = root.postorderEnumeration();
+ while (children.hasMoreElements()) {
+ DefaultMutableTreeNode node = children.nextElement();
+ if (node != root) {
+ tree.expandPath(new TreePath(node.getPath()));
+ }
+ }
+ tree.invalidate();
+ }
+
+ public boolean getAutoScroll() {
+ return autoScroll;
+ }
+
+ public AbstractTreeLogger getLogger() {
+ return logger;
+ }
+
+ public void notifyChange(DefaultMutableTreeNode node) {
+ treeModel.nodeChanged(node);
+ }
+
+ @Override
+ public void removeAll() {
+ tree.removeAll();
+ details.setText("");
+ }
+
+ public void setAutoScroll(boolean autoScroll) {
+ this.autoScroll = autoScroll;
+ }
+
+ public void valueChanged(TreeSelectionEvent e) {
+ if (e.isAddedPath()) {
+ TreePath path = e.getPath();
+ Object treeNode = path.getLastPathComponent();
+ if (treeNode == null) {
+ // handle the case of no selection
+ details.setText("");
+ return;
+ }
+ Object userObject = ((DefaultMutableTreeNode) treeNode).getUserObject();
+ String text = userObject.toString();
+ if (userObject instanceof LogEvent) {
+ LogEvent event = (LogEvent) userObject;
+ text = event.getFullText();
+ }
+ details.setText(text);
+ }
+ }
+
+ protected void alert(String msg) {
+ JOptionPane.showMessageDialog(null, msg, "Alert: Not Implemented",
+ JOptionPane.INFORMATION_MESSAGE);
+ }
+
+ protected ArrayList<DefaultMutableTreeNode> doFind(String search) {
+ @SuppressWarnings("unchecked")
+ Enumeration<DefaultMutableTreeNode> children = root.preorderEnumeration();
+ ArrayList<DefaultMutableTreeNode> matches = new ArrayList<DefaultMutableTreeNode>();
+ while (children.hasMoreElements()) {
+ DefaultMutableTreeNode node = children.nextElement();
+ if (node != root && nodeMatches(node, search)) {
+ matches.add(node);
+ // Make sure our this entry is visible by expanding up to parent
+ TreeNode[] nodePath = node.getPath();
+ if (nodePath.length > 1) {
+ TreeNode[] parentPath = new TreeNode[nodePath.length - 1];
+ System.arraycopy(nodePath, 0, parentPath, 0, parentPath.length);
+ tree.expandPath(new TreePath(parentPath));
+ }
+ }
+ }
+ tree.invalidate();
+ return matches;
+ }
+
+ protected void hideFindBox() {
+ findBox.hideBox();
+ }
+
+ protected void setLevelFilter(Type selectedLevel) {
+ levelFilter = selectedLevel;
+ // TODO(jat): filter current tree
+ alert("Filtering not implemented yet");
+ }
+
+ protected void setRegexFilter(String regex) {
+ regexFilter = regex;
+ // TODO(jat): filter current tree
+ alert("Regex filtering not implemented yet");
+ }
+
+ protected void showFindBox() {
+ findBox.showBox();
+ }
+
+ protected void treeCopy() {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode)
+ tree.getLastSelectedPathComponent();
+ if (node == null) {
+ return;
+ }
+ // is it better to use SwingUtilities2.canAccessSystemClipboard() here?
+ Clipboard clipboard;
+ try {
+ clipboard = tree.getToolkit().getSystemClipboard();
+ } catch (SecurityException e) {
+ return;
+ } catch (HeadlessException e) {
+ return;
+ }
+ if (clipboard == null) {
+ return;
+ }
+ StringBuilder text = new StringBuilder();
+ treeLogTraverse(text, node, 0);
+ StringSelection selection = new StringSelection(text.toString());
+ clipboard.setContents(selection, selection);
+ }
+
+ private String htmlUnescape(String str) {
+ // TODO(jat): real implementation, needs to correspond to
+ // SwingTreeLogger.htmlEscape()
+ return str.replace("<", "<").replace(">", ">").replace("&",
+ "&").replace("<br>", "\n");
+ }
+
+ private boolean nodeMatches(DefaultMutableTreeNode node, String search) {
+ Object userObject = node.getUserObject();
+ if (userObject instanceof LogEvent) {
+ LogEvent event = (LogEvent) userObject;
+ String text = htmlUnescape(event.getFullText());
+ // TODO(jat): should this be more than a substring match, such as regex?
+ if (text.contains(search)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void showFindResult(DefaultMutableTreeNode node, String search) {
+ // TODO(jat): highlight search string
+ TreePath path = new TreePath(node.getPath());
+ tree.scrollPathToVisible(path);
+ tree.setSelectionPath(path);
+ }
+
+ private void treeLogTraverse(StringBuilder buf, TreeNode node,
+ int indent) {
+ for (int i = 0; i < indent; ++i) {
+ buf.append(' ');
+ }
+ if (node instanceof DefaultMutableTreeNode) {
+ DefaultMutableTreeNode mutableNode = (DefaultMutableTreeNode) node;
+ Object userObject = mutableNode.getUserObject();
+ if (userObject instanceof LogEvent) {
+ LogEvent event = (LogEvent) userObject;
+ buf.append(htmlUnescape(event.getFullText()));
+ if (event.isBranchCommit) {
+ SwingTreeLogger childLogger = event.childLogger;
+ DefaultMutableTreeNode parent = childLogger.treeNode;
+ for (int i = 0; i < parent.getChildCount(); ++i) {
+ treeLogTraverse(buf, parent.getChildAt(i), indent + 2);
+ }
+ }
+ } else {
+ buf.append(userObject.toString());
+ buf.append('\n');
+ }
+ } else {
+ buf.append(node.toString());
+ buf.append('\n');
+ }
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/util/log/SwingTreeLogger.java b/dev/oophm/src/com/google/gwt/dev/util/log/SwingTreeLogger.java
new file mode 100644
index 0000000..8248612
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/util/log/SwingTreeLogger.java
@@ -0,0 +1,353 @@
+/*
+ * 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.log;
+
+import com.google.gwt.core.ext.TreeLogger;
+
+import org.jdesktop.swingworker.SwingWorker;
+
+import java.awt.Color;
+import java.net.URL;
+import java.text.NumberFormat;
+import java.util.Date;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+
+/**
+ * Tree logger built on an Swing tree item.
+ */
+public final class SwingTreeLogger extends AbstractTreeLogger {
+
+ /**
+ * Represents an individual log event.
+ */
+ public static class LogEvent {
+
+ private static final Color DEBUG_COLOR = Color.decode("0x007777");
+ private static final Color SPAM_COLOR = Color.decode("0x005500");
+ private static final Color WARN_COLOR = Color.decode("0x888800");
+
+ private static final Date firstLog = new Date();
+ private static NumberFormat minHr = NumberFormat.getIntegerInstance();
+ private static NumberFormat seconds = NumberFormat.getNumberInstance();
+
+ static {
+ seconds.setMinimumFractionDigits(3);
+ seconds.setMaximumFractionDigits(3);
+ seconds.setMinimumIntegerDigits(2);
+ minHr.setMinimumIntegerDigits(2);
+ }
+
+ public final SwingTreeLogger childLogger;
+
+ public final String exceptionDetail;
+
+ public final String exceptionName;
+
+ public final HelpInfo helpInfo;
+
+ public final int index;
+
+ public final boolean isBranchCommit;
+
+ public final String message;
+
+ public final Date timestamp;
+
+ public final TreeLogger.Type type;
+
+ public LogEvent(SwingTreeLogger logger, boolean isBranchCommit, int index,
+ Type type, String message, Throwable caught, HelpInfo helpInfo) {
+ this.childLogger = logger;
+ this.isBranchCommit = isBranchCommit;
+ this.index = index;
+ this.type = type;
+ this.message = message;
+ this.helpInfo = helpInfo;
+ this.timestamp = new Date();
+ this.exceptionDetail = AbstractTreeLogger.getStackTraceAsString(caught);
+ this.exceptionName = AbstractTreeLogger.getExceptionName(caught);
+ }
+
+ /**
+ * @return
+ */
+ public String getFullText() {
+ StringBuffer sb = new StringBuffer();
+
+ formatTimestamp(timestamp.getTime() - firstLog.getTime(), sb);
+ sb.append(" ");
+
+ // Show the message type.
+ //
+ if (type != null) {
+ sb.append("[");
+ sb.append(type.getLabel());
+ sb.append("] ");
+ }
+
+ // Show the item text.
+ //
+ sb.append(htmlEscape(message));
+ sb.append("\n");
+
+ // Show the exception info for anything other than "UnableToComplete".
+ //
+ if (exceptionDetail != null) {
+ sb.append(htmlEscape(exceptionDetail));
+ }
+ if (helpInfo != null) {
+ URL url = helpInfo.getURL();
+ if (url != null) {
+ sb.append("\nMore info: <a href=\"");
+ sb.append(url.toString());
+ sb.append("\">");
+ sb.append(url.toString());
+ sb.append("</a>");
+ sb.append("\n");
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * @param treeRenderer
+ */
+ public void setDisplayProperties(JLabel treeLabel) {
+ Icon image = null;
+ if (type == TreeLogger.ERROR) {
+ treeLabel.setForeground(Color.RED);
+ image = imageError;
+ } else if (type == TreeLogger.WARN) {
+ treeLabel.setForeground(WARN_COLOR);
+ image = imageWarning;
+ } else if (type == TreeLogger.INFO) {
+ treeLabel.setForeground(Color.BLACK);
+ image = imageInfo;
+ } else if (type == TreeLogger.TRACE) {
+ treeLabel.setForeground(Color.DARK_GRAY);
+ image = imageTrace;
+ } else if (type == TreeLogger.DEBUG) {
+ treeLabel.setForeground(DEBUG_COLOR);
+ image = imageDebug;
+ } else if (type == TreeLogger.SPAM) {
+ treeLabel.setForeground(SPAM_COLOR);
+ image = imageSpam;
+ } else {
+ // Messages without icons, ie ALL
+ treeLabel.setForeground(Color.BLACK);
+ }
+ treeLabel.setIcon(image);
+ StringBuffer sb = new StringBuffer();
+
+ formatTimestamp(timestamp.getTime() - firstLog.getTime(), sb);
+ sb.append(" ");
+
+ // Show the message type.
+ //
+ if (type != null) {
+ sb.append("[");
+ sb.append(type.getLabel());
+ sb.append("] ");
+ }
+
+ // Show the item text.
+ //
+ sb.append(message);
+
+ // Show the exception info for anything other than "UnableToComplete".
+ //
+ if (exceptionName != null) {
+ sb.append(" -- exception: " + exceptionName);
+ }
+ treeLabel.setText(sb.toString());
+ }
+
+ @Override
+ public String toString() {
+ String s = "";
+ s += "[logger " + childLogger.toString();
+ s += ", " + (isBranchCommit ? "BRANCH" : "LOG");
+ s += ", index " + index;
+ s += ", type " + type.toString();
+ s += ", msg '" + message + "'";
+ s += "]";
+ return s;
+ }
+
+ private void formatTimestamp(long ts, StringBuffer sb) {
+ sb.append(minHr.format(ts / (1000 * 60 * 60)));
+ sb.append(':');
+ sb.append(minHr.format((ts / (1000 * 60)) % 60));
+ sb.append(':');
+ sb.append(seconds.format((ts % 60000) / 1000.0));
+ }
+
+ private String htmlEscape(String str) {
+ // TODO(jat): call real implementation instead
+ return str.replace("&", "&").replace("<", "<").replace(">", ">").replace(
+ "\n", "<br>");
+ }
+ }
+
+ // These don't get disposed, but they do last for the entire process, so
+ // not a big deal.
+ //
+ private static final ImageIcon imageDebug = tryLoadImage("log-item-debug.gif");
+ private static final ImageIcon imageError = tryLoadImage("log-item-error.gif");
+ private static final ImageIcon imageInfo = tryLoadImage("log-item-info.gif");
+ // private static final ImageIcon imageLink = tryLoadImage("log-link.gif");
+ private static final ImageIcon imageSpam = tryLoadImage("log-item-spam.gif");
+ private static final ImageIcon imageTrace = tryLoadImage("log-item-trace.gif");
+ private static final ImageIcon imageWarning = tryLoadImage("log-item-warning.gif");
+
+ // package protected to allow SwingLoggerPanel access
+ // TODO(jat): reorganize
+ static ImageIcon tryLoadImage(String simpleName) {
+ URL url = SwingTreeLogger.class.getResource(simpleName);
+ if (url != null) {
+ try {
+ ImageIcon image = new ImageIcon(url);
+ return image;
+ } finally {
+ }
+ } else {
+ // Bad image.
+ //
+ return null;
+ }
+ }
+
+ // package protected so SwingLoggerPanel can access
+ DefaultMutableTreeNode treeNode;
+
+ private SwingLoggerPanel panel;
+
+ /**
+ * Constructs the top-level TreeItemLogger.
+ *
+ * @param treePanel
+ */
+ public SwingTreeLogger(SwingLoggerPanel panel) {
+ this.panel = panel;
+ // treeNode gets replaced for branches in doCommitBranch
+ treeNode = (DefaultMutableTreeNode) panel.treeModel.getRoot();
+ }
+
+ @Override
+ protected AbstractTreeLogger doBranch() {
+ SwingTreeLogger newLogger = new SwingTreeLogger(panel);
+ return newLogger;
+ }
+
+ @Override
+ protected void doCommitBranch(AbstractTreeLogger childBeingCommitted,
+ Type type, String msg, Throwable caught, HelpInfo helpInfo) {
+ SwingTreeLogger commitChild = (SwingTreeLogger) childBeingCommitted;
+ LogEvent logEvent = new LogEvent(commitChild, true,
+ commitChild.getBranchedIndex(), type, msg, caught, helpInfo);
+ commitChild.treeNode = new DefaultMutableTreeNode(logEvent);
+ addUpdate(logEvent);
+ }
+
+ @Override
+ protected void doLog(int index, Type type, String msg, Throwable caught,
+ HelpInfo helpInfo) {
+ addUpdate(new LogEvent(this, false, index, type, msg, caught, helpInfo));
+ }
+
+ /**
+ * @param logEvent
+ */
+ private void addUpdate(final LogEvent logEvent) {
+ new SwingWorker<LogEvent, Void>() {
+ @Override
+ protected LogEvent doInBackground() throws Exception {
+ return logEvent;
+ }
+
+ @Override
+ protected void done() {
+ LogEvent event;
+ try {
+ // TODO(jat): apply filter criteria
+ event = get();
+ // TODO(jat): do more of this work in doInBackground()?
+ SwingTreeLogger logger = event.childLogger;
+ DefaultMutableTreeNode node;
+ DefaultMutableTreeNode parent;
+ int idx;
+ if (event.isBranchCommit) {
+ SwingTreeLogger parentLogger = (SwingTreeLogger) logger.getParentLogger();
+ parent = parentLogger.treeNode;
+ idx = logger.indexWithinMyParent;
+ node = logger.treeNode;
+ } else {
+ parent = logger.treeNode;
+ idx = event.index;
+ node = new DefaultMutableTreeNode(event);
+ }
+ int insertIndex = findInsertionPoint(parent, idx);
+ panel.treeModel.insertNodeInto(node, parent, insertIndex);
+ if (parent == panel.treeModel.getRoot()
+ && parent.getChildCount() == 1) {
+ panel.treeModel.reload();
+ }
+ if (event.type.needsAttention()) {
+ panel.tree.makeVisible(new TreePath(node.getPath()));
+ }
+ } catch (InterruptedException e) {
+ // TODO(jat): Auto-generated catch block
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ // TODO(jat): Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private int findInsertionPoint(DefaultMutableTreeNode parent, int index) {
+ int high = parent.getChildCount() - 1;
+ if (high < 0) {
+ return 0;
+ }
+ int low = 0;
+ while (low <= high) {
+ final int mid = low + ((high - low) >> 1);
+ DefaultMutableTreeNode midChild = (DefaultMutableTreeNode) parent.getChildAt(mid);
+ final Object userObject = midChild.getUserObject();
+ int compIdx = -1;
+ if (userObject instanceof LogEvent) {
+ LogEvent event = (LogEvent) userObject;
+ compIdx = event.index;
+ }
+ if (compIdx < index) {
+ low = mid + 1;
+ } else if (compIdx > index) {
+ high = mid - 1;
+ } else {
+ return mid;
+ }
+ }
+ return low;
+ }
+ }.execute();
+ }
+}
diff --git a/dev/oophm/src/com/google/gwt/dev/util/log/icon-close.png b/dev/oophm/src/com/google/gwt/dev/util/log/icon-close.png
new file mode 100644
index 0000000..3e8fe3a
--- /dev/null
+++ b/dev/oophm/src/com/google/gwt/dev/util/log/icon-close.png
Binary files differ
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/ModuleSpaceIE6.java b/dev/windows/src/com/google/gwt/dev/shell/ie/ModuleSpaceIE6.java
index 9a91973..b666b0b 100644
--- a/dev/windows/src/com/google/gwt/dev/shell/ie/ModuleSpaceIE6.java
+++ b/dev/windows/src/com/google/gwt/dev/shell/ie/ModuleSpaceIE6.java
@@ -16,11 +16,14 @@
package com.google.gwt.dev.shell.ie;
import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.javac.JsniMethod;
import com.google.gwt.dev.shell.CompilingClassLoader;
+import com.google.gwt.dev.shell.DispatchIdOracle;
import com.google.gwt.dev.shell.JsValue;
import com.google.gwt.dev.shell.ModuleSpace;
import com.google.gwt.dev.shell.ModuleSpaceHost;
import com.google.gwt.dev.shell.ie.IDispatchImpl.HResultException;
+import com.google.gwt.dev.util.Jsni;
import org.eclipse.swt.internal.ole.win32.IDispatch;
import org.eclipse.swt.ole.win32.OleAutomation;
@@ -28,6 +31,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.List;
/**
* An implementation of {@link com.google.gwt.dev.shell.ModuleSpace} for
@@ -93,22 +97,17 @@
window = new OleAutomation(scriptFrameWindow);
}
- public void createNative(String file, int line, String jsniSignature,
- String[] paramNames, String js) {
- // Execute the function definition within the browser, which will define
- // a new top-level function.
- //
- String newScript = createNativeMethodInjector(jsniSignature, paramNames, js);
- try {
- // TODO: somehow insert file/line info into the script
- Variant result = execute(newScript);
- if (result != null) {
- result.dispose();
+ public void createNativeMethods(TreeLogger logger,
+ List<JsniMethod> jsniMethods, DispatchIdOracle dispatchIdOracle) {
+ for (JsniMethod jsniMethod : jsniMethods) {
+ String body = Jsni.getJavaScriptForHostedMode(logger, dispatchIdOracle,
+ jsniMethod);
+ if (body == null) {
+ // The error has been logged; just ignore it for now.
+ continue;
}
- } catch (RuntimeException e) {
- throw new RuntimeException(file + "(" + line
- + "): Failed to create JSNI method with signature '" + jsniSignature
- + "'", e);
+ createNative(jsniMethod.location(), jsniMethod.line(), jsniMethod.name(),
+ jsniMethod.paramNames(), body);
}
}
@@ -121,6 +120,12 @@
super.dispose();
}
+ @Override
+ protected void createStaticDispatcher(TreeLogger logger) {
+ createNative("initializeStaticDispatcher", 0, "__defineStatic",
+ new String[] {"__arg0"}, "window.__static = __arg0;");
+ }
+
/**
* Invokes a native javascript function.
*
@@ -205,6 +210,25 @@
"Failed to invoke JavaScriptException.getDescription()", caught);
}
+ private void createNative(String file, int line, String jsniSignature,
+ String[] paramNames, String js) {
+ // Execute the function definition within the browser, which will define
+ // a new top-level function.
+ //
+ String newScript = createNativeMethodInjector(jsniSignature, paramNames, js);
+ try {
+ // TODO: somehow insert file/line info into the script
+ Variant result = execute(newScript);
+ if (result != null) {
+ result.dispose();
+ }
+ } catch (RuntimeException e) {
+ throw new RuntimeException(file + "(" + line
+ + "): Failed to create JSNI method with signature '" + jsniSignature
+ + "'", e);
+ }
+ }
+
private Variant execute(String code) {
int[] dispIds = window.getIDsOfNames(new String[] {"execScript", "code"});
Variant[] vArgs = new Variant[1];
diff --git a/distro-source/core/src/doc/helpInfo/jsoRestrictions.html b/distro-source/core/src/doc/helpInfo/jsoRestrictions.html
index aed2d81..b3ef73f 100644
--- a/distro-source/core/src/doc/helpInfo/jsoRestrictions.html
+++ b/distro-source/core/src/doc/helpInfo/jsoRestrictions.html
@@ -4,50 +4,51 @@
<title>Restrictions on subclasses of JavaScriptObject</title>
</head>
<body>
-
-<p>Subclasses of JavaScriptObject represent a view of a JavaScript object
-from Java. Such classes must conform to a number of restrictions so
-that the compiler can implement them. This page lists those restrictions.
-
-<p>In the following, "JSO class" means any subclass of
-<code>JavaScriptObject</code>. Rationales are written <em>like
-this</em>.
-
+<p>Subclasses of JavaScriptObject represent a view of a JavaScript
+object from Java. Such classes must conform to a number of restrictions
+so that the compiler can implement them. This page lists those
+restrictions.</p>
+<p>In the following, "JSO class" means any subclass of <code>JavaScriptObject</code>.
+Rationales are written <em>like this</em>.</p>
<ol>
-
- <li> All instance methods on JSO classes must be one of: explicitly
- final, a member of a final class, or private. <em>Methods of JSO classes
- cannot be overridden, because calls to such methods could require
- dynamic dispatch.</em>
-
- <li> JSO classes cannot implement interfaces that define
- methods. <em>This prevents virtual calls that would arise by
- upcasting to the interface and then calling through the interface.
- The programmer should instead use a wrapper, for example using
- <code>Comparator</code> instead of implementing
- <code>Comparable</code>.</em>
-
- <li> No instance methods on JSO classes may override another
- method. <em>This catches accidents where JSO itself did not finalize
- some method from its superclass.</em>
-
- <li> JSO classes cannot have instance fields. <em>The fields would
- have no place to live in web mode. Programmers should instead make
- an explicit wrapper class and put the fields there.</em>
-
- <li> Nested JSO classes must be static. <em>The implicit
- <code>this</code> fields of a non-static inner class has the same
- problems as an explicit field.</em>
-
- <li> "new" operations cannot be used with JSO classes. <em>This
- avoids ever being able to try to instantiate JSO objects using the
- new keyword. New JSO instances can only come from JSNI, as in
- previous versions of GWT.</em>
-
- <li> Every JSO class must have precisely one constructor, and it must
- be protected, empty, and no-argument.
-
+ <li>All instance methods on JSO classes must be one of:
+ explicitly final, a member of a final class, or private. <em>Methods
+ of JSO classes cannot be overridden, because calls to such methods
+ could require dynamic dispatch.</em></li>
+ <li>An interface type may be implemented by at most one JSO
+ subtype. <em>This ensures that polymorphic dispatch via a
+ "SingleJsoImpl" interface can be statically resolved to exactly one
+ implementing JSO subtype.</em>
+ <ol>
+ <li>A <code>JavaScriptObject</code> that implements a
+ "SingleJsoImpl" interface may be further extended. The subclasses
+ may implement additional "SingleJsoImpl" interfaces. <em>The
+ methods on a JSO must be effectively final, so each "SingleJsoImpl"
+ method still has a 1:1 mapping to a method defined within a JSO
+ subtype.</em></li>
+ <li>It is valid for any number of any non-<code>JavaScriptObject</code>
+ types to implement a "SingleJsoImpl" interface. <em>There is a
+ slight runtime dispatch penalty when a "SingleJsoImpl" interface is
+ implemented by both JSO and non-JSO types.</em></li>
+ </ol>
+ </li>
+ <li>No instance methods on JSO classes may override another
+ method. <em>This catches accidents where JSO itself did not
+ finalize some method from its superclass.</em></li>
+ <li>JSO classes cannot have instance fields. <em>The fields
+ would have no place to live in web mode. Programmers should instead
+ make an explicit wrapper class and put the fields there.</em></li>
+ <li>Nested JSO classes must be static. <em>The implicit <code>this</code>
+ fields of a non-static inner class has the same problems as an
+ explicit field.</em></li>
+ <li>"new" operations cannot be used with JSO classes. <em>This
+ avoids ever being able to try to instantiate JSO objects using the new
+ keyword. New JSO instances can only come from JSNI, as in previous
+ versions of GWT.</em></li>
+ <li>JSNI methods may not refer to instance methods defined within
+ a <code>JavaScriptObject</code>.</li>
+ <li>Every JSO class must have precisely one constructor, and it
+ must be protected, empty, and no-argument.</li>
</ol>
-
</body>
</html>
diff --git a/distro-source/linux/build.xml b/distro-source/linux/build.xml
index fc47fe1..5fde893 100755
--- a/distro-source/linux/build.xml
+++ b/distro-source/linux/build.xml
@@ -9,9 +9,11 @@
<gwt.tgz.cat destfile="${project.dist}" compression="bzip2">
<!-- jars -->
<tarfileset file="${gwt.build.lib}/gwt-dev-${dist.platform}.jar" prefix="${project.distname}" />
+ <tarfileset file="${gwt.build.lib}/gwt-dev-oophm.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-user.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-servlet.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-benchmark-viewer.jar" prefix="${project.distname}" />
+ <tarfileset file="${gwt.build.lib}/gwt-soyc-vis.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-api-checker.jar" prefix="${project.distname}" />
<!-- jni libs-->
diff --git a/distro-source/mac/build.xml b/distro-source/mac/build.xml
index e518fd1..4114eb6 100755
--- a/distro-source/mac/build.xml
+++ b/distro-source/mac/build.xml
@@ -9,9 +9,11 @@
<gwt.tgz.cat destfile="${project.dist}">
<!-- jars -->
<tarfileset file="${gwt.build.lib}/gwt-dev-${dist.platform}.jar" prefix="${project.distname}" />
+ <tarfileset file="${gwt.build.lib}/gwt-dev-oophm.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-user.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-servlet.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-benchmark-viewer.jar" prefix="${project.distname}" />
+ <tarfileset file="${gwt.build.lib}/gwt-soyc-vis.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-api-checker.jar" prefix="${project.distname}" />
<!-- jni libs-->
diff --git a/distro-source/windows/build.xml b/distro-source/windows/build.xml
index 386f37c..6110f07 100755
--- a/distro-source/windows/build.xml
+++ b/distro-source/windows/build.xml
@@ -9,9 +9,11 @@
<zip destfile="${project.dist}">
<!-- jars -->
<zipfileset file="${gwt.build.lib}/gwt-dev-${dist.platform}.jar" prefix="${project.distname}" />
+ <zipfileset file="${gwt.build.lib}/gwt-dev-oophm.jar" prefix="${project.distname}" />
<zipfileset file="${gwt.build.lib}/gwt-user.jar" prefix="${project.distname}" />
<zipfileset file="${gwt.build.lib}/gwt-servlet.jar" prefix="${project.distname}" />
<zipfileset file="${gwt.build.lib}/gwt-benchmark-viewer.jar" prefix="${project.distname}" />
+ <zipfileset file="${gwt.build.lib}/gwt-soyc-vis.jar" prefix="${project.distname}" />
<zipfileset file="${gwt.build.lib}/gwt-api-checker.jar" prefix="${project.distname}" />
<!-- jni libs-->
diff --git a/doc/build.xml b/doc/build.xml
index 622d0cb..5bcc340 100644
--- a/doc/build.xml
+++ b/doc/build.xml
@@ -10,8 +10,7 @@
<property.ensure name="gwt.dev.jar" location="${gwt.build.lib}/gwt-dev-linux.jar" />
<property name="USER_PKGS"
- value="com.google.gwt.animation.client;com.google.gwt.benchmarks.client;com.google.gwt.core.client;com.google.gwt.core.ext;com.google.gwt.core.ext.linker;com.google.gwt.core.ext.typeinfo;com.google.gwt.debug.client;com.google.gwt.dom.client;com.google.gwt.event.dom.client;com.google.gwt.event.logical.shared;com.google.gwt.event.shared;com.google.gwt.http.client;com.google.gwt.i18n.client;com.google.gwt.i18n.rebind.format;com.google.gwt.i18n.rebind.keygen;com.google.gwt.json.client;com.google.gwt.junit.client;com.google.gwt.user.client;com.google.gwt.user.client.rpc;com.google.gwt.user.client.ui;com.google.gwt.user.datepicker.client;com.google.gwt.user.server.rpc;com.google.gwt.xml.client" />
-
+ value="com.google.gwt.animation.client;com.google.gwt.benchmarks.client;com.google.gwt.core.client;com.google.gwt.core.ext;com.google.gwt.core.ext.soyc;com.google.gwt.core.ext.linker;com.google.gwt.core.ext.typeinfo;com.google.gwt.debug.client;com.google.gwt.dom.client;com.google.gwt.event.dom.client;com.google.gwt.event.logical.shared;com.google.gwt.event.shared;com.google.gwt.http.client;com.google.gwt.i18n.client;com.google.gwt.i18n.rebind.format;com.google.gwt.i18n.rebind.keygen;com.google.gwt.json.client;com.google.gwt.junit.client;com.google.gwt.benchmarks.client;com.google.gwt.user.client;com.google.gwt.user.client.rpc;com.google.gwt.user.client.ui;com.google.gwt.user.server.rpc;com.google.gwt.xml.client;com.google.gwt.user.datepicker.client"/>
<property name="LANG_PKGS" value="java.lang;java.lang.annotation;java.util;java.io;java.sql" />
<!-- Individual classes to include when we don't want to
@@ -77,6 +76,7 @@
<sequential>
<echo>Building javadoc</echo>
<java classpathref="DOC_PATH" classname="com.google.doctool.custom.GWTJavaDoclet" fork="yes" failonerror="true">
+ <jvmarg value="-Xmx256M" />
<arg value="-quiet" />
<arg value="-notimestamp" />
<arg value="-source" />
diff --git a/eclipse/dev/oophm/.checkstyle b/eclipse/dev/oophm/.checkstyle
new file mode 100644
index 0000000..51cfb6f
--- /dev/null
+++ b/eclipse/dev/oophm/.checkstyle
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fileset-config file-format-version="1.2.0" simple-config="false">
+ <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/dev/oophm/.classpath b/eclipse/dev/oophm/.classpath
new file mode 100644
index 0000000..7509e13
--- /dev/null
+++ b/eclipse/dev/oophm/.classpath
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry excluding="**/.svn" kind="src" path="oophm/src"/>
+ <classpathentry kind="src" path="oophm/overlay"/>
+ <classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar" sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.1.1-src.zip"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar" sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/ant-launcher-1.6.5.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/catalina-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/catalina-optional-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/commons-beanutils-1.6.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/commons-collections-3.1.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/commons-digester-1.5.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/commons-el-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/commons-logging-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/commons-modeler-1.1.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/jakarta-regexp-1.3.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/jasper-compiler-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/jasper-runtime-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/jsp-api-2.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/mx4j-jmx-1.1.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/naming-common-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/naming-factory-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/naming-java-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/naming-resources-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/servlet-api-2.4.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/servlets-common-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/servlets-default-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/servlets-invoker-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/tomcat-coyote-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/tomcat-http11-1.0.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/tomcat-jk2-2.1.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/tomcat-util-5.1.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/xerces/xerces-2_9_1/xercesImpl.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/xerces/xerces-2_9_1/xml-apis.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/xerces/xerces-2_9_1/serializer.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/sun/swingworker/swing-worker-1.1.jar" sourcepath="/GWT_TOOLS/lib/sun/swingworker/swing-worker-1.1-src.zip"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/gwt-dev-windows"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/eclipse/dev/oophm/.project b/eclipse/dev/oophm/.project
new file mode 100644
index 0000000..d4236b9
--- /dev/null
+++ b/eclipse/dev/oophm/.project
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>gwt-dev-oophm</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>oophm</name>
+ <type>2</type>
+ <locationURI>GWT_ROOT/dev/oophm</locationURI>
+ </link>
+ </linkedResources>
+</projectDescription>
diff --git a/eclipse/samples/Hello/.project b/eclipse/samples/Hello/.project
index 7e40312..45a8900 100644
--- a/eclipse/samples/Hello/.project
+++ b/eclipse/samples/Hello/.project
@@ -24,7 +24,7 @@
<link>
<name>core</name>
<type>2</type>
- <location>GWT_ROOT/samples/hello</location>
+ <locationURI>GWT_ROOT/samples/hello</locationURI>
</link>
</linkedResources>
</projectDescription>
diff --git a/eclipse/samples/Showcase/Showcase-gwtc.launch b/eclipse/samples/Showcase/Showcase-gwtc.launch
index cb428cd..cc73877 100644
--- a/eclipse/samples/Showcase/Showcase-gwtc.launch
+++ b/eclipse/samples/Showcase/Showcase-gwtc.launch
@@ -1,17 +1,17 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<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="Showcase" path="1" type="4"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/Showcase/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="Showcase"/> </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.Compiler"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="com.google.gwt.sample.showcase.Showcase"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Showcase"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=${gwt_devjar}"/>
-</launchConfiguration>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<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="Showcase" path="1" type="4"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/Showcase/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="Showcase"/> </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.Compiler"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="com.google.gwt.sample.showcase.Showcase"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Showcase"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=${gwt_devjar}"/>
+</launchConfiguration>
diff --git a/eclipse/samples/Showcase/Showcase.launch b/eclipse/samples/Showcase/Showcase.launch
index e5f4a9f..7c7f985 100644
--- a/eclipse/samples/Showcase/Showcase.launch
+++ b/eclipse/samples/Showcase/Showcase.launch
@@ -1,17 +1,17 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<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="Showcase" path="1" type="4"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/Showcase/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="Showcase"/> </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.HostedMode"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-startupUrl Showcase.html com.google.gwt.sample.showcase.Showcase"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Showcase"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=${gwt_devjar}"/>
-</launchConfiguration>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<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="Showcase" path="1" type="4"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/Showcase/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="Showcase"/> </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.HostedMode"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-startupUrl Showcase.html com.google.gwt.sample.showcase.Showcase"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Showcase"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=${gwt_devjar}"/>
+</launchConfiguration>
diff --git a/platforms.ant.xml b/platforms.ant.xml
index 6c5e1df..7f8c32e 100755
--- a/platforms.ant.xml
+++ b/platforms.ant.xml
@@ -1,6 +1,10 @@
<project name="platforms">
<import file="${gwt.root}/common.ant.xml" />
+ <condition property="oophm.exists" value="true">
+ <available file="oophm" />
+ </condition>
+
<!-- "build" is the default when subprojects are directly targetted -->
<property name="target" value="build" />
@@ -13,6 +17,11 @@
<gwt.ant dir="linux" />
</target>
+ <target name="oophm" depends="core" description="OOPHM overlay"
+ if="oophm.exists">
+ <gwt.ant dir="oophm" />
+ </target>
+
<target name="windows" depends="core" description="Run windows">
<gwt.ant dir="windows" />
</target>
@@ -21,7 +30,7 @@
<gwt.ant dir="mac" />
</target>
- <target name="-do" depends="linux, windows, mac" description="Run all platforms" />
+ <target name="-do" depends="linux, windows, mac, oophm" description="Run all platforms" />
<target name="build" description="Build each platforms">
<antcall target="-do">
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
index b477076..19bf121 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
@@ -13,7 +13,6 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-
package com.google.gwt.museum.client.defaultmuseum;
import com.google.gwt.core.client.EntryPoint;
@@ -47,6 +46,7 @@
addIssue(new Issue1169());
addIssue(new Issue2392());
addIssue(new Issue2443());
+ addIssue(new Issue2553());
addIssue(new Issue2855());
addIssue(new Issue3172());
}
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue2553.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue2553.java
new file mode 100644
index 0000000..6595534
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue2553.java
@@ -0,0 +1,52 @@
+/*
+ * 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.museum.client.defaultmuseum;
+
+import com.google.gwt.museum.client.common.AbstractIssue;
+import com.google.gwt.user.client.ui.Tree;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Test for http://code.google.com/p/google-web-toolkit/issues/detail?id=2553
+ */
+public class Issue2553 extends AbstractIssue {
+
+ @Override
+ public Widget createIssue() {
+ Tree tree = new Tree();
+ tree.addItem("This is a long text displayed in a tree item");
+ tree.addItem("This is a long text displayed in a tree item and it's longer than the others");
+ tree.addItem("This is a long text displayed in a tree item");
+ return tree;
+ }
+
+ @Override
+ public String getInstructions() {
+ return "resize the browser to a smaller width than the tree's width";
+ }
+
+ @Override
+ public String getSummary() {
+ return "Word wrap of treeitem's text when browser width is too small";
+ }
+
+ @Override
+ public boolean hasCSS() {
+ return false;
+ }
+
+}
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3187.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3187.java
new file mode 100644
index 0000000..162a816
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3187.java
@@ -0,0 +1,56 @@
+/*
+ * 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.museum.client.defaultmuseum;
+
+import com.google.gwt.event.dom.client.ChangeEvent;
+import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.museum.client.common.AbstractIssue;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.FileUpload;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * {@link FileUpload} onChange event fires correctly in all browsers.
+ */
+public class Issue3187 extends AbstractIssue {
+ @Override
+ public Widget createIssue() {
+ FileUpload fileUpload = new FileUpload();
+ fileUpload.addChangeHandler(new ChangeHandler() {
+ public void onChange(ChangeEvent event) {
+ Window.alert("Value Changed");
+ }
+ });
+ return fileUpload;
+ }
+
+ @Override
+ public String getInstructions() {
+ return "Change the file path and verify an alert dialog appears. In "
+ + "Opera, the onChange event should only be fired when the box is "
+ + "blurred.";
+ }
+
+ @Override
+ public String getSummary() {
+ return "FileUpload supports change events";
+ }
+
+ @Override
+ public boolean hasCSS() {
+ return false;
+ }
+}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/Showcase.gwt.xml b/samples/showcase/src/com/google/gwt/sample/showcase/Showcase.gwt.xml
index 4a3b79f..3be6b41 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/Showcase.gwt.xml
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/Showcase.gwt.xml
@@ -3,6 +3,7 @@
<inherits name="com.google.gwt.core.Core"/>
<inherits name='com.google.gwt.user.User'/>
<inherits name="com.google.gwt.i18n.I18N"/>
+ <inherits name="com.google.gwt.i18n.CldrLocales"/>
<inherits name="com.google.gwt.user.theme.standard.StandardResources"/>
<inherits name="com.google.gwt.user.theme.chrome.ChromeResources"/>
<inherits name="com.google.gwt.user.theme.dark.DarkResources"/>
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
index 0995248..ee1f6a2 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
@@ -27,6 +27,8 @@
import com.google.gwt.i18n.client.HasDirection;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.LazyPanel;
@@ -44,9 +46,10 @@
* rules.
* </p>
* <p>
- * This {@link Widget} extends {@link LazyPanel} so that the content is not
- * rendered until the widget first becomes visible. The data in the source and
- * css tabs are loaded using an RPC call to the server.
+ * This {@link Widget} uses a lazy initialization mechanism so that the content
+ * is not rendered until the onInitialize method is called, which happens the
+ * first time the {@link Widget} is added to the page.. The data in the source
+ * and css tabs are loaded using an RPC call to the server.
* </p>
* <h3>CSS Style Rules</h3>
* <ul class="css">
@@ -81,6 +84,11 @@
private static String loadingImage;
/**
+ * The tab bar of options.
+ */
+ protected TabBar tabBar = null;
+
+ /**
* An instance of the constants.
*/
private final CwConstants constants;
@@ -112,11 +120,6 @@
private HTML styleWidget = null;
/**
- * The tab bar of options.
- */
- private TabBar tabBar = null;
-
- /**
* Constructor.
*
* @param constants the constants
@@ -246,6 +249,8 @@
tabBar.selectTab(index);
}
+ protected abstract void asyncOnInitialize(final AsyncCallback<Widget> callback);
+
/**
* Initialize this widget by creating the elements that should be added to the
* page.
@@ -287,12 +292,21 @@
add(styleWidget, constants.contentWidgetStyle());
}
- // Initialize the showcase widget (if any) and add it to the page
- Widget widget = onInitialize();
- if (widget != null) {
- vPanel.add(widget);
- }
- onInitializeComplete();
+ asyncOnInitialize(new AsyncCallback<Widget>() {
+
+ public void onFailure(Throwable caught) {
+ Window.alert("exception: " + caught);
+ }
+
+ public void onSuccess(Widget result) {
+ // Initialize the showcase widget (if any) and add it to the page
+ Widget widget = result;
+ if (widget != null) {
+ vPanel.add(widget);
+ }
+ onInitializeComplete();
+ }
+ });
return deckPanel;
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwConstantsExample.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwConstantsExample.java
index 4892345..42d5ab1 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwConstantsExample.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwConstantsExample.java
@@ -16,6 +16,7 @@
package com.google.gwt.sample.showcase.client.content.i18n;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
@@ -25,6 +26,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseRaw;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
@@ -38,7 +40,7 @@
/**
* Example file.
*/
-@ShowcaseRaw({"ExampleConstants.java", "ExampleConstants.properties"})
+@ShowcaseRaw( {"ExampleConstants.java", "ExampleConstants.properties"})
public class CwConstantsExample extends ContentWidget {
/**
* The constants used in this Content Widget.
@@ -191,6 +193,20 @@
}
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Add a tab to this example to show the messages interface.
*/
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwConstantsWithLookupExample.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwConstantsWithLookupExample.java
index a74c714..574c873 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwConstantsWithLookupExample.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwConstantsWithLookupExample.java
@@ -16,6 +16,7 @@
package com.google.gwt.sample.showcase.client.content.i18n;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
@@ -27,6 +28,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseRaw;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
@@ -39,7 +41,7 @@
/**
* Example file.
*/
-@ShowcaseRaw({"ColorConstants.java", "ColorConstants.properties"})
+@ShowcaseRaw( {"ColorConstants.java", "ColorConstants.properties"})
public class CwConstantsWithLookupExample extends ContentWidget {
/**
* The constants used in this Content Widget.
@@ -213,6 +215,20 @@
}
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Add a tab to this example to show the messages interface.
*/
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwDateTimeFormat.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwDateTimeFormat.java
index 29118ef..677bcb9 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwDateTimeFormat.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwDateTimeFormat.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.i18n;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
@@ -25,6 +27,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Label;
@@ -182,6 +185,20 @@
return layout;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Show an error message. Pass in null to clear the error message.
*
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwDictionaryExample.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwDictionaryExample.java
index a6d78fe..16a02bf 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwDictionaryExample.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwDictionaryExample.java
@@ -15,12 +15,15 @@
*/
package com.google.gwt.sample.showcase.client.content.i18n;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.i18n.client.Dictionary;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.VerticalPanel;
@@ -117,4 +120,18 @@
// Return the layout Widget
return layout;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwMessagesExample.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwMessagesExample.java
index 8b17a70..6e58216 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwMessagesExample.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwMessagesExample.java
@@ -16,6 +16,7 @@
package com.google.gwt.sample.showcase.client.content.i18n;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
@@ -27,6 +28,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseRaw;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
@@ -245,6 +247,20 @@
}
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Add a tab to this example to show the {@link ErrorMessages} source code.
*/
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwNumberFormat.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwNumberFormat.java
index 60f98fb..b90490b 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwNumberFormat.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/i18n/CwNumberFormat.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.i18n;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
@@ -25,6 +27,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
@@ -172,6 +175,20 @@
return layout;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Show an error message. Pass in null to clear the error message.
*
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwListBox.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwListBox.java
index 1b8277a..ed632cc 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwListBox.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwListBox.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.lists;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.i18n.client.Constants;
@@ -22,6 +24,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ListBox;
@@ -132,6 +135,20 @@
return hPanel;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Display the options for a given category in the list box.
*
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwMenuBar.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwMenuBar.java
index 34c48f8..c022dbc 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwMenuBar.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwMenuBar.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.lists;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
@@ -22,6 +24,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.Widget;
@@ -29,7 +32,8 @@
/**
* Example file.
*/
-@ShowcaseStyle({".gwt-MenuBar", ".gwt-MenuBarPopup", "html>body .gwt-MenuBarPopup",
+@ShowcaseStyle( {
+ ".gwt-MenuBar", ".gwt-MenuBarPopup", "html>body .gwt-MenuBarPopup",
"* html .gwt-MenuBarPopup"})
public class CwMenuBar extends ContentWidget {
/**
@@ -161,4 +165,18 @@
menu.ensureDebugId("cwMenuBar");
return menu;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwStackPanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwStackPanel.java
index b570f0c..08050f9 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwStackPanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwStackPanel.java
@@ -16,11 +16,13 @@
package com.google.gwt.sample.showcase.client.content.lists;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -39,7 +41,8 @@
/**
* Example file.
*/
-@ShowcaseStyle({".gwt-DecoratedStackPanel", "html>body .gwt-DecoratedStackPanel",
+@ShowcaseStyle( {
+ ".gwt-DecoratedStackPanel", "html>body .gwt-DecoratedStackPanel",
"* html .gwt-DecoratedStackPanel", ".cw-StackPanelHeader"})
public class CwStackPanel extends ContentWidget {
/**
@@ -165,6 +168,20 @@
return stackPanel;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Create the list of Contacts.
*
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwSuggestBox.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwSuggestBox.java
index 49a850f..1d720be 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwSuggestBox.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwSuggestBox.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.lists;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.SuggestBox;
@@ -29,7 +32,8 @@
/**
* Example file.
*/
-@ShowcaseStyle({".gwt-SuggestBox", ".gwt-SuggestBoxPopup",
+@ShowcaseStyle({
+ ".gwt-SuggestBox", ".gwt-SuggestBoxPopup",
"html>body .gwt-SuggestBoxPopup", "* html .gwt-SuggestBoxPopup"})
public class CwSuggestBox extends ContentWidget {
/**
@@ -96,4 +100,18 @@
// Return the panel
return suggestPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwTree.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwTree.java
index 70f0508..a17ae8a 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwTree.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwTree.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.lists;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.i18n.client.Constants;
@@ -23,6 +25,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
import com.google.gwt.user.client.Random;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
@@ -151,6 +154,20 @@
return grid;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Add a new section of music created by a specific composer.
*
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwAnimation.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwAnimation.java
index 954482a..749d1ba 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwAnimation.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwAnimation.java
@@ -16,11 +16,14 @@
package com.google.gwt.sample.showcase.client.content.other;
import com.google.gwt.animation.client.Animation;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.Showcase;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -239,6 +242,20 @@
return mainLayout;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Create an options panel that allows users to select a widget and reposition
* it.
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwCookies.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwCookies.java
index 4c8d83f..882b712 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwCookies.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwCookies.java
@@ -15,8 +15,12 @@
*/
package com.google.gwt.sample.showcase.client.content.other;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
@@ -25,9 +29,8 @@
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
@@ -194,6 +197,20 @@
return mainLayout;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Refresh the list of existing cookies.
*
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwFrame.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwFrame.java
index 4a5f0c6..2e14568 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwFrame.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwFrame.java
@@ -16,6 +16,7 @@
package com.google.gwt.sample.showcase.client.content.other;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
@@ -25,6 +26,7 @@
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Frame;
import com.google.gwt.user.client.ui.HorizontalPanel;
@@ -124,4 +126,18 @@
vPanel.add(frame);
return vPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwAbsolutePanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwAbsolutePanel.java
index c7a9d18..e385072 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwAbsolutePanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwAbsolutePanel.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
@@ -26,6 +28,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratorPanel;
@@ -192,6 +195,20 @@
});
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Create an options panel that allows users to select a widget and reposition
* it.
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDecoratorPanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDecoratorPanel.java
index efcdaf1..71bb6ee 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDecoratorPanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDecoratorPanel.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
@@ -30,7 +33,9 @@
/**
* Example file.
*/
-@ShowcaseStyle({".gwt-DecoratorPanel", "html>body .gwt-DecoratorPanel", "* html .gwt-DecoratorPanel"})
+@ShowcaseStyle({
+ ".gwt-DecoratorPanel", "html>body .gwt-DecoratorPanel",
+ "* html .gwt-DecoratorPanel"})
public class CwDecoratorPanel extends ContentWidget {
/**
* The constants used in this Content Widget.
@@ -108,4 +113,18 @@
decPanel.setWidget(layout);
return decPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDisclosurePanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDisclosurePanel.java
index 0f89957..4250a27 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDisclosurePanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDisclosurePanel.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.FlexTable;
@@ -103,6 +106,20 @@
return vPanel;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Create a form that contains undisclosed advanced options.
*/
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDockPanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDockPanel.java
index b2f5ba1..60677f0 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDockPanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwDockPanel.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.ScrollPanel;
@@ -112,4 +115,18 @@
dock.ensureDebugId("cwDockPanel");
return dock;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwFlowPanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwFlowPanel.java
index 84b17fa..dd19fa5 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwFlowPanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwFlowPanel.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -88,4 +91,18 @@
// Return the content
return flowPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwHorizontalPanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwHorizontalPanel.java
index c6abae3..2f49674 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwHorizontalPanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwHorizontalPanel.java
@@ -15,10 +15,13 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -90,4 +93,18 @@
hPanel.ensureDebugId("cwHorizontalPanel");
return hPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwHorizontalSplitPanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwHorizontalSplitPanel.java
index 1fc379b..b989453 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwHorizontalSplitPanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwHorizontalSplitPanel.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalSplitPanel;
@@ -96,4 +99,18 @@
// Return the content
return decPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwTabPanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwTabPanel.java
index 356e88b..5c96d24 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwTabPanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwTabPanel.java
@@ -15,12 +15,15 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.Showcase;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DecoratedTabPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.VerticalPanel;
@@ -29,7 +32,8 @@
/**
* Example file.
*/
-@ShowcaseStyle({".gwt-DecoratedTabBar", "html>body .gwt-DecoratedTabBar",
+@ShowcaseStyle({
+ ".gwt-DecoratedTabBar", "html>body .gwt-DecoratedTabBar",
"* html .gwt-DecoratedTabBar", ".gwt-TabPanel"})
public class CwTabPanel extends ContentWidget {
/**
@@ -105,4 +109,18 @@
tabPanel.ensureDebugId("cwTabPanel");
return tabPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwVerticalPanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwVerticalPanel.java
index 8115968..01446bd 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwVerticalPanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwVerticalPanel.java
@@ -15,10 +15,13 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -90,4 +93,18 @@
vPanel.ensureDebugId("cwVerticalPanel");
return vPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwVerticalSplitPanel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwVerticalSplitPanel.java
index d7d0198..0f60296 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwVerticalSplitPanel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/panels/CwVerticalSplitPanel.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.panels;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.VerticalSplitPanel;
@@ -96,4 +99,18 @@
// Return the content
return decPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/popups/CwBasicPopup.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/popups/CwBasicPopup.java
index 01419cd..3223fc1 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/popups/CwBasicPopup.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/popups/CwBasicPopup.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.popups;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.Constants;
@@ -23,6 +25,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratedPopupPanel;
import com.google.gwt.user.client.ui.HTML;
@@ -142,4 +145,18 @@
// Return the panel
return vPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/popups/CwDialogBox.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/popups/CwDialogBox.java
index 0354eee..69ab631 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/popups/CwDialogBox.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/popups/CwDialogBox.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.popups;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.Constants;
@@ -24,6 +26,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
@@ -131,6 +134,20 @@
return vPanel;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Create the dialog box for this example.
*
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/tables/CwFlexTable.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/tables/CwFlexTable.java
index 09ebad2..6d13d72 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/tables/CwFlexTable.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/tables/CwFlexTable.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.tables;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.Constants;
@@ -23,6 +25,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
@@ -131,6 +134,20 @@
return flexTable;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Add a row to the flex table.
*/
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/tables/CwGrid.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/tables/CwGrid.java
index 85df366..2f0d1d8 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/tables/CwGrid.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/tables/CwGrid.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.tables;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.Showcase;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Widget;
@@ -91,4 +94,18 @@
grid.ensureDebugId("cwGrid");
return grid;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java
index 1c5851e..9829e3e 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.text;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
@@ -24,6 +26,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
@@ -130,6 +133,20 @@
return vpanel;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Create a TextBox example that includes the text box and an optional
* handler that updates a Label with the currently selected text.
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwRichText.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwRichText.java
index f582285..2e15e28 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwRichText.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwRichText.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.text;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.Widget;
@@ -27,7 +30,8 @@
/**
* Example file.
*/
-@ShowcaseStyle({".gwt-RichTextArea", ".hasRichTextToolbar", ".gwt-RichTextToolbar",
+@ShowcaseStyle({
+ ".gwt-RichTextArea", ".hasRichTextToolbar", ".gwt-RichTextToolbar",
".cw-RichText"})
public class CwRichText extends ContentWidget {
/**
@@ -88,4 +92,18 @@
grid.setWidget(1, 0, area);
return grid;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwBasicButton.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwBasicButton.java
index a78e31c..1217cd3 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwBasicButton.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwBasicButton.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.widgets;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.Constants;
@@ -23,6 +25,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -104,4 +107,18 @@
// Return the panel
return hPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCheckBox.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCheckBox.java
index ac3813f..1322790 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCheckBox.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCheckBox.java
@@ -20,6 +20,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.VerticalPanel;
@@ -101,4 +102,12 @@
// Return the panel of checkboxes
return vPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ /*
+ * CheckBox is the first demo loaded, so go ahead and load it synchronously.
+ */
+ callback.onSuccess(onInitialize());
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCustomButton.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCustomButton.java
index 60035ec..472d5de 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCustomButton.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCustomButton.java
@@ -15,12 +15,15 @@
*/
package com.google.gwt.sample.showcase.client.content.widgets;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.Showcase;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.PushButton;
@@ -122,4 +125,18 @@
// Return the panel
return vpanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwDatePicker.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwDatePicker.java
index f25df4e..5428f13 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwDatePicker.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwDatePicker.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.showcase.client.content.widgets;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.Constants;
@@ -23,6 +25,7 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
@@ -114,4 +117,18 @@
vPanel.add(dateBox);
return vPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwFileUpload.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwFileUpload.java
index c010ce7..f6b84f7 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwFileUpload.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwFileUpload.java
@@ -15,12 +15,15 @@
*/
package com.google.gwt.sample.showcase.client.content.widgets;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -114,4 +117,18 @@
// Return the layout panel
return vPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java
index a6aa867..2ed3d5a 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java
@@ -15,12 +15,15 @@
*/
package com.google.gwt.sample.showcase.client.content.widgets;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseConstants;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.VerticalPanel;
@@ -97,6 +100,20 @@
return vPanel;
}
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
+
/**
* Get a {@link Hyperlink} to a section based on the name of the
* {@link ContentWidget} example.
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java
index 3d483b5..c59aa79 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.sample.showcase.client.content.widgets;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.VerticalPanel;
@@ -115,4 +118,18 @@
return vPanel;
}
+
+ @Override
+ protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ public void onSuccess() {
+ callback.onSuccess(onInitialize());
+ }
+ });
+ }
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/generator/ShowcaseGenerator.java b/samples/showcase/src/com/google/gwt/sample/showcase/generator/ShowcaseGenerator.java
index 3d6bb38..2d5b079 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/generator/ShowcaseGenerator.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/generator/ShowcaseGenerator.java
@@ -71,7 +71,7 @@
String typeName) throws UnableToCompleteException {
this.logger = logger;
this.context = context;
- this.classLoader = getClass().getClassLoader();
+ this.classLoader = Thread.currentThread().getContextClassLoader();
// Only generate files on the first permutation
if (!isFirstPass()) {
diff --git a/tools/api-checker/config/gwt15_16userApi.conf b/tools/api-checker/config/gwt15_16userApi.conf
index 4c179ec..1df4179c 100644
--- a/tools/api-checker/config/gwt15_16userApi.conf
+++ b/tools/api-checker/config/gwt15_16userApi.conf
@@ -50,6 +50,7 @@
:user/src/com/google/gwt/benchmarks/BenchmarkShell.java\
:user/src/com/google/gwt/benchmarks/client/Benchmark.java\
:user/src/com/google/gwt/benchmarks/rebind\
+:user/src/com/google/gwt/i18n/server\
:user/src/com/google/gwt/i18n/rebind\
:user/src/com/google/gwt/i18n/tools\
:user/src/com/google/gwt/junit/GWTMockUtilities.java\
@@ -89,12 +90,19 @@
##############################################
#Api whitelist
# when adding to the white-list, include comments as to why the addition is
-# being made. This needs to be done for this initial white-list below
+# being made.
-# the api-checker is currently regarding overloadeded methods that can be
-# overriden. TODO(amitmanjhi): Solving this issue correctly in all cases seems
+# the api-checker is currently checking overloadeded methods that can be
+# overriden, and there are multiple overloaded versions of
+# StringBuilder::append(..)
+# TODO(amitmanjhi): Solving this issue correctly in all cases seems
# to be hard. Come back and fix this issue, if more such cases come up.
java.lang.StringBuilder::append(Ljava/lang/StringBuffer;) OVERRIDABLE_METHOD_ARGUMENT_TYPE_CHANGE
com.google.gwt.user.client.ui.Button::Button(Ljava/lang/String;Lcom/google/gwt/user/client/ui/ClickListener;) OVERLOADED_METHOD_CALL
com.google.gwt.user.client.ui.ToggleButton::ToggleButton(Lcom/google/gwt/user/client/ui/Image;Lcom/google/gwt/user/client/ui/Image;Lcom/google/gwt/user/client/ui/ClickListener;) OVERLOADED_METHOD_CALL
com.google.gwt.user.client.ui.Tree::setImageBase(Ljava/lang/String;) MISSING
+com.google.gwt.i18n.client.LocaleInfo::getAvailableLocaleNames() FINAL_ADDED
+com.google.gwt.i18n.client.LocaleInfo::getCurrentLocale() FINAL_ADDED
+com.google.gwt.i18n.client.LocaleInfo::getLocaleName() FINAL_ADDED
+com.google.gwt.i18n.client.LocaleInfo::isRTL() FINAL_ADDED
+
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java
index 2cc58eb..ea1bbe2 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java
@@ -903,4 +903,4 @@
return hashSet;
}
-}
\ No newline at end of file
+}
diff --git a/tools/build.xml b/tools/build.xml
index 3c89a8a..104f13b 100755
--- a/tools/build.xml
+++ b/tools/build.xml
@@ -3,7 +3,7 @@
<property name="project.tail" value="tools" />
<import file="${gwt.root}/common.ant.xml" />
- <!-- "build" is the default when subprojects are directly targetted -->
+ <!-- "build" is the default when subprojects are directly targeted -->
<property name="target" value="build" />
<target name="benchmark-viewer" depends="" description="Run benchmark-viewer">
@@ -13,8 +13,12 @@
<target name="api-checker" depends="" description="Compile api-checker">
<gwt.ant dir="api-checker" />
</target>
-
- <target name="-do" depends="benchmark-viewer,api-checker" description="Run all subfolders" />
+
+ <target name="soyc-vis" depends="" description="Compile SOYC dashboard">
+ <gwt.ant dir="soyc-vis" />
+ </target>
+
+ <target name="-do" depends="benchmark-viewer,api-checker,soyc-vis" description="Run all subfolders" />
<target name="build" description="Build each subfolder">
<antcall target="-do">
diff --git a/tools/soyc-vis/README b/tools/soyc-vis/README
new file mode 100644
index 0000000..a0d7938
--- /dev/null
+++ b/tools/soyc-vis/README
@@ -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.
+ */
+
+This utility presents a dashboard visulization of GWT's Story of Your
+Compile.
+
+To compile:
+ant (in this directory)
+
+To run:
+1. Compile your GWT application with SOYC (flag -soyc), which results in one ore
+more .xml files (depending on your number of permutations), plus a file manifest.xml that maps permutations to .xml files.
+2. Run java -classpath build/classes -Xmx1024M com/google/gwt/soyc/SoycDashboard XmlFileName.xml
diff --git a/tools/soyc-vis/build.xml b/tools/soyc-vis/build.xml
new file mode 100644
index 0000000..c6d929d
--- /dev/null
+++ b/tools/soyc-vis/build.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+
+<project name="soyc-vis" default="build" basedir=".">
+
+ <property name="gwt.root" location="../.." />
+ <property name="project.tail" value="tools/soyc-vis" />
+ <import file="${gwt.root}/common.ant.xml" />
+
+ <target name="clean">
+ <delete dir="build"/>
+ </target>
+
+ <target name="compile">
+ <mkdir dir="${javac.out}"/>
+ <javac srcdir="src" destdir="${javac.out}"/>
+ <mkdir dir="${javac.out}/images"/>
+ <copy todir="${javac.out}/images">
+ <fileset dir="images"/>
+ </copy>
+ <copy file="classLevel.css" tofile="${javac.out}/classLevel.css"/>
+ <copy file="roundedCorners.css" tofile="${javac.out}/roundedCorners.css"/>
+ </target>
+
+ <target name="build" depends="compile">
+ <gwt.jar>
+ <fileset dir="${javac.out}" />
+ <manifest>
+ <attribute name="Main-Class" value="com.google.gwt.soyc.SoycDashboard" />
+ </manifest>
+ </gwt.jar>
+ </target>
+
+ <target name="test"/>
+
+ <target name="checkstyle"/>
+
+</project>
\ No newline at end of file
diff --git a/tools/soyc-vis/classLevel.css b/tools/soyc-vis/classLevel.css
new file mode 100644
index 0000000..5c70a24
--- /dev/null
+++ b/tools/soyc-vis/classLevel.css
@@ -0,0 +1,162 @@
+/* \*/
+* html #tlc, * html #trc {height: 1%;}
+/* */
+
+#tlc, #trc { zoom: 1 }
+
+h2 {background-color: transparent}
+p {background-color: fuchsia}
+ A:link {text-decoration: none; color: blue;}
+A:visited {text-decoration: none; color: blue;}
+A:active {text-decoration: none}
+A:hover {text-decoration: underline; color: maroon;}
+
+body
+ {
+ margin: 0;
+ padding: 0;
+ background-color: #728FCE;
+ font-size: 100.01%;
+ text-align: center;
+ }
+
+.box
+ {
+ position: absolute;
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0;
+ text-align: left;
+ <!--background-color: #eeeeee;-->
+
+ z-index: 1;
+ opacity:0.7;
+ }
+
+.box-right
+ {
+ position: absolute;
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0;
+ text-align: right;
+ <!--background-color: #eeeeee;-->
+ z-index: 2;
+ opacity:0.7;
+ }
+
+
+#content
+ {
+ height:25px;
+ }
+
+
+
+.barlabel {
+
+ position: absolute;
+ font-size: 14px;
+ text-color: maroon;
+ z-index: 2;
+ <!--font-weight: bold;-->
+ text-align: left;
+
+
+}
+
+#content h1
+ {
+ color:#0354c2;
+ font-weight: bold;
+ font-size: 1.2em;
+ font-family: helvetica, geneva, arial, sans-serif;
+ }
+
+#content p
+ {
+ color:#3b3b3b;
+ font-size: 1em;
+ line-height: 1.3em;
+ font-family: arial, helvetica, sans-serif;
+ }
+
+
+
+/* ---=== border code follows ===--- */
+/*
+ tlc = top left corner
+ trc = top right corner
+ blc = bottom left corner
+ brc = bottom right corner
+ lb = left border
+ rb = right border
+ tb = top border
+ bb = bottom border
+*/
+
+#tlc, #trc, #blc, #brc
+ {
+ background-color: transparent;
+ background-repeat: no-repeat;
+ }
+
+#tlc
+ {
+ background-image:url(images/tlc.gif);
+ background-position: 0% 0%;
+ }
+
+#trc
+ {
+ background-image:url(images/trc.gif);
+ background-position: 100% 0%;
+ }
+
+#blc
+ {
+ background-image:url(images/blc.gif);
+ background-position: 0% 100%;
+ }
+
+#brc
+ {
+ background-image:url(images/brc.gif);
+ background-position: 100% 100%;
+ }
+
+#tb, #bb
+ {
+ background-color: transparent;
+ background-repeat: repeat-x;
+ }
+
+#tb
+ {
+ background-image:url(images/tb.gif);
+ background-position: 0% 0%;
+ }
+
+#bb
+ {
+ background-image:url(images/bb.gif);
+ background-position: 50% 100%;
+ }
+
+#rb
+ {
+ background-image:url(images/r.gif);
+ background-position: 100% 0%;
+ background-repeat: repeat-y;
+ }
+
+#lb
+ {
+ background-color: #eeeeee;
+ background-image:url(images/l.gif);
+ background-position: 0% 100%;
+ background-repeat: repeat-y;
+ }
+
diff --git a/tools/soyc-vis/images/1bl.gif b/tools/soyc-vis/images/1bl.gif
new file mode 100644
index 0000000..3183405
--- /dev/null
+++ b/tools/soyc-vis/images/1bl.gif
Binary files differ
diff --git a/tools/soyc-vis/images/1br.gif b/tools/soyc-vis/images/1br.gif
new file mode 100644
index 0000000..8748c10
--- /dev/null
+++ b/tools/soyc-vis/images/1br.gif
Binary files differ
diff --git a/tools/soyc-vis/images/1tl.gif b/tools/soyc-vis/images/1tl.gif
new file mode 100644
index 0000000..2ca18a7
--- /dev/null
+++ b/tools/soyc-vis/images/1tl.gif
Binary files differ
diff --git a/tools/soyc-vis/images/1tr.gif b/tools/soyc-vis/images/1tr.gif
new file mode 100644
index 0000000..e4e2a96
--- /dev/null
+++ b/tools/soyc-vis/images/1tr.gif
Binary files differ
diff --git a/tools/soyc-vis/images/bb.gif b/tools/soyc-vis/images/bb.gif
new file mode 100644
index 0000000..ef7d5a3
--- /dev/null
+++ b/tools/soyc-vis/images/bb.gif
Binary files differ
diff --git a/tools/soyc-vis/images/blc.gif b/tools/soyc-vis/images/blc.gif
new file mode 100644
index 0000000..7b6d57a
--- /dev/null
+++ b/tools/soyc-vis/images/blc.gif
Binary files differ
diff --git a/tools/soyc-vis/images/brc.gif b/tools/soyc-vis/images/brc.gif
new file mode 100644
index 0000000..5afd529
--- /dev/null
+++ b/tools/soyc-vis/images/brc.gif
Binary files differ
diff --git a/tools/soyc-vis/images/l.gif b/tools/soyc-vis/images/l.gif
new file mode 100644
index 0000000..a85da2c
--- /dev/null
+++ b/tools/soyc-vis/images/l.gif
Binary files differ
diff --git a/tools/soyc-vis/images/r.gif b/tools/soyc-vis/images/r.gif
new file mode 100644
index 0000000..4b8f639
--- /dev/null
+++ b/tools/soyc-vis/images/r.gif
Binary files differ
diff --git a/tools/soyc-vis/images/roundedbox_lo.gif b/tools/soyc-vis/images/roundedbox_lo.gif
new file mode 100644
index 0000000..c614467
--- /dev/null
+++ b/tools/soyc-vis/images/roundedbox_lo.gif
Binary files differ
diff --git a/tools/soyc-vis/images/roundedbox_lu.gif b/tools/soyc-vis/images/roundedbox_lu.gif
new file mode 100644
index 0000000..995bf88
--- /dev/null
+++ b/tools/soyc-vis/images/roundedbox_lu.gif
Binary files differ
diff --git a/tools/soyc-vis/images/roundedbox_ro.gif b/tools/soyc-vis/images/roundedbox_ro.gif
new file mode 100644
index 0000000..8124e86
--- /dev/null
+++ b/tools/soyc-vis/images/roundedbox_ro.gif
Binary files differ
diff --git a/tools/soyc-vis/images/roundedbox_ru.gif b/tools/soyc-vis/images/roundedbox_ru.gif
new file mode 100644
index 0000000..55774ef
--- /dev/null
+++ b/tools/soyc-vis/images/roundedbox_ru.gif
Binary files differ
diff --git a/tools/soyc-vis/images/tb.gif b/tools/soyc-vis/images/tb.gif
new file mode 100644
index 0000000..8b9a080
--- /dev/null
+++ b/tools/soyc-vis/images/tb.gif
Binary files differ
diff --git a/tools/soyc-vis/images/tlc.gif b/tools/soyc-vis/images/tlc.gif
new file mode 100644
index 0000000..8c40bf7
--- /dev/null
+++ b/tools/soyc-vis/images/tlc.gif
Binary files differ
diff --git a/tools/soyc-vis/images/trc.gif b/tools/soyc-vis/images/trc.gif
new file mode 100644
index 0000000..2e4ed5a
--- /dev/null
+++ b/tools/soyc-vis/images/trc.gif
Binary files differ
diff --git a/tools/soyc-vis/roundedCorners.css b/tools/soyc-vis/roundedCorners.css
new file mode 100644
index 0000000..567daf1
--- /dev/null
+++ b/tools/soyc-vis/roundedCorners.css
@@ -0,0 +1,146 @@
+/* \*/
+* html #tlc, * html #trc {height: 1%;}
+/* */
+
+#tlc, #trc { zoom: 1 }
+
+h2 {background-color: transparent}
+p {background-color: fuchsia}
+ A:link {text-decoration: none; color: blue;}
+A:visited {text-decoration: none; color: blue;}
+A:active {text-decoration: none}
+A:hover {text-decoration: underline; color: maroon;}
+
+body
+ {
+ margin: 0;
+ padding: 0;
+ background-color: white;
+ font-size: 100.01%;
+ text-align: center;
+ }
+
+#box
+ {
+ position: absolute;
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0;
+ text-align: left;
+ <!--background-color: #eeeeee;-->
+
+ z-index: 1;
+ opacity:0.7;
+ }
+
+#content
+ {
+ height:25px;
+ }
+
+.barlabel {
+
+ position: absolute;
+ font-size: 14px;
+ text-color: maroon;
+ z-index: 2;
+ <!--font-weight: bold;-->
+ text-align: left;
+
+
+}
+
+#content h1
+ {
+ color:#0354c2;
+ font-weight: bold;
+ font-size: 1.2em;
+ font-family: helvetica, geneva, arial, sans-serif;
+ }
+
+#content p
+ {
+ color:#3b3b3b;
+ font-size: 1em;
+ line-height: 1.3em;
+ font-family: arial, helvetica, sans-serif;
+ }
+
+
+
+/* ---=== border code follows ===--- */
+/*
+ tlc = top left corner
+ trc = top right corner
+ blc = bottom left corner
+ brc = bottom right corner
+ lb = left border
+ rb = right border
+ tb = top border
+ bb = bottom border
+*/
+
+#tlc, #trc, #blc, #brc
+ {
+ background-color: transparent;
+ background-repeat: no-repeat;
+ }
+
+#tlc
+ {
+ background-image:url(images/tlc.gif);
+ background-position: 0% 0%;
+ }
+
+#trc
+ {
+ background-image:url(images/trc.gif);
+ background-position: 100% 0%;
+ }
+
+#blc
+ {
+ background-image:url(images/blc.gif);
+ background-position: 0% 100%;
+ }
+
+#brc
+ {
+ background-image:url(images/brc.gif);
+ background-position: 100% 100%;
+ }
+
+#tb, #bb
+ {
+ background-color: transparent;
+ background-repeat: repeat-x;
+ }
+
+#tb
+ {
+ background-image:url(images/tb.gif);
+ background-position: 0% 0%;
+ }
+
+#bb
+ {
+ background-image:url(images/bb.gif);
+ background-position: 50% 100%;
+ }
+
+#rb
+ {
+ background-image:url(images/r.gif);
+ background-position: 100% 0%;
+ background-repeat: repeat-y;
+ }
+
+#lb
+ {
+ background-color: #eeeeee;
+ background-image:url(images/l.gif);
+ background-position: 0% 100%;
+ background-repeat: repeat-y;
+ }
+
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/CodeCollection.java b/tools/soyc-vis/src/com/google/gwt/soyc/CodeCollection.java
new file mode 100644
index 0000000..655b516
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/CodeCollection.java
@@ -0,0 +1,59 @@
+/*
+ * 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.soyc;
+
+import java.util.TreeSet;
+
+public class CodeCollection {
+
+ public String codeType = "";
+ public TreeSet<String> classes = new TreeSet<String>();
+ public TreeSet<String> stories = new TreeSet<String>();
+ public float cumPartialSize = 0f;
+ public int cumSize = 0;
+
+
+ public CodeCollection(String type){
+ codeType = type;
+ }
+
+ public int getCumSize(){
+ cumSize = 0;
+ for (String className : classes){
+ if (! GlobalInformation.classToSize.containsKey(className)){
+ System.err.println("*** NO SIZE FOUND FOR CLASS " + className + " *****");
+ }
+ else{
+ cumSize += GlobalInformation.classToSize.get(className);
+ }
+ }
+ return cumSize;
+ }
+
+ public float getCumPartialSize(){
+ cumPartialSize = 0f;
+ for (String className : classes){
+ if (!GlobalInformation.classToPartialSize.containsKey(className)){
+ System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****");
+ }
+ else{
+ cumPartialSize += GlobalInformation.classToPartialSize.get(className);
+ }
+ }
+ return cumPartialSize;
+ }
+}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java b/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java
new file mode 100644
index 0000000..bdba9be
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java
@@ -0,0 +1,96 @@
+/*
+ * 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.soyc;
+
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.HashSet;
+import java.util.TreeSet;
+
+public class GlobalInformation {
+
+ public static Boolean displayDependencies = false;
+
+ public static int allOtherFragmentsPartialSize = 0;
+ public static HashMap<String, String> classToPackage = new HashMap<String, String>();
+ public static HashMap<String, Float> classToPartialSize = new HashMap<String, Float>();
+ public static HashMap<String, Integer> classToSize = new HashMap<String, Integer>();
+ //TODO(kprobst): not currently used, but will be for dependencies
+ public static HashMap<String, HashSet<String>> classToWhatItDependsOn = new HashMap<String, HashSet<String>>();
+ public static float cumPartialSizeFromPackages = 0f;
+ public static int cumSizeAllCode = 0;
+ public static int cumSizeFromPackages = 0;
+ public static int cumSizeInitialFragment = 0;
+ public static HashMap<Integer, Float> fragmentToPartialSize = new HashMap<Integer, Float>(); //collect only size for exclusive fragments
+ public static HashMap<Integer, HashSet<String>> fragmentToStories = new HashMap<Integer, HashSet<String>>();
+ public static TreeMap<String, LiteralsCollection> nameToLitColl = new TreeMap<String, LiteralsCollection>();
+ public static HashMap<String, CodeCollection> nameToCodeColl = new HashMap<String, CodeCollection>();
+
+
+ public static int nonAttributedBytes = 0;
+ public static HashSet<String> nonAttributedStories = new HashSet<String>();
+ public static int numBytesDoubleCounted = 0;
+ public static int numFragments = 0;
+ public static int numSplitPoints = 0;
+ public static TreeMap<String, TreeSet<String>> packageToClasses = new TreeMap<String, TreeSet<String>>();
+ public static HashMap<String, Float> packageToPartialSize = new HashMap<String, Float>();
+ public static HashMap<String, Integer> packageToSize = new HashMap<String, Integer>();
+ public static HashMap<Integer, String> splitPointToLocation = new HashMap<Integer, String>();
+ public static HashMap<String, HashSet<String>> storiesToCorrClasses = new HashMap<String, HashSet<String>>();
+ public static HashMap<String, HashSet<String>> storiesToCorrClassesAndMethods = new HashMap<String, HashSet<String>>();
+
+ public static HashMap<String, String> storiesToLitType = new HashMap<String, String>();
+
+ public static void computePackageSizes(){
+ cumSizeFromPackages = 0;
+ packageToSize.clear();
+ for (String packageName : packageToClasses.keySet()){
+ packageToSize.put(packageName, 0);
+ for (String className : packageToClasses.get(packageName)){
+ if (! classToSize.containsKey(className)){
+ System.err.println("*** NO SIZE FOUND FOR CLASS " + className + " *****");
+ }
+ else{
+ int curSize = classToSize.get(className);
+ cumSizeFromPackages += curSize;
+ int newSize = curSize + packageToSize.get(packageName);
+ packageToSize.put(packageName, newSize);
+ }
+ }
+ }
+ }
+ public static void computePartialPackageSizes(){
+ cumPartialSizeFromPackages = 0;
+ packageToPartialSize.clear();
+ for (String packageName : packageToClasses.keySet()){
+ packageToPartialSize.put(packageName, 0f);
+ for (String className : packageToClasses.get(packageName)){
+ if (! classToPartialSize.containsKey(className)){
+ System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****");
+ }
+ else{
+ float curSize = classToPartialSize.get(className);
+ cumPartialSizeFromPackages += curSize;
+ float newSize = curSize + packageToPartialSize.get(packageName);
+ packageToPartialSize.put(packageName, newSize);
+ }
+ }
+ }
+ }
+
+}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/LiteralsCollection.java b/tools/soyc-vis/src/com/google/gwt/soyc/LiteralsCollection.java
new file mode 100644
index 0000000..3f71ef1
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/LiteralsCollection.java
@@ -0,0 +1,56 @@
+/*
+ * 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.soyc;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.HashSet;
+import java.util.TreeMap;
+
+public class LiteralsCollection {
+ public int cumSize = 0;
+ public int cumStringSize = 0;
+ public String literalType = "";
+ public Map<String, HashSet<String>> literalToLocations = new TreeMap<String, HashSet<String>>();
+ public Map<String, HashSet<String> > storyToLocations = new HashMap<String, HashSet<String>>();
+ public TreeMap<String, String> stringLiteralToType = new TreeMap<String, String>();
+ public Map<String, Integer> stringTypeToSize = new HashMap<String, Integer>();
+ public Map<String, Integer> stringTypeToCount = new HashMap<String, Integer>();
+
+ /**
+ * constructor
+ */
+ public LiteralsCollection(String type){
+ literalType = type;
+ }
+
+ /**
+ * Utility method
+ */
+ public void printAllStrings(){
+ int iSum = 0;
+ System.out.println("--- now printing strings ---");
+ for (String st : stringLiteralToType.keySet()){
+ int numBytes = st.getBytes().length;
+ iSum += numBytes;
+ System.out.println(st + "[" + numBytes + "]");
+ }
+ System.out.println("sum: " + iSum);
+ System.out.println("--- done printing strings ---");
+ }
+
+}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java b/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
new file mode 100644
index 0000000..7712e0b
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
@@ -0,0 +1,1682 @@
+/*
+ * 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.soyc;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+
+public class MakeTopLevelHtmlForPerm {
+
+ private static void makePackageHtml(String outFileName) throws IOException{
+
+
+ TreeMap<Float, String> sortedPackages = new TreeMap<Float, String>(Collections.reverseOrder());
+ float maxSize = 0f;
+ float sumSize = 0f;
+ for (String packageName : GlobalInformation.packageToPartialSize.keySet()){
+ sortedPackages.put(GlobalInformation.packageToPartialSize.get(packageName), packageName);
+ sumSize += GlobalInformation.packageToPartialSize.get(packageName);
+ if (GlobalInformation.packageToPartialSize.get(packageName) > maxSize){
+ maxSize = GlobalInformation.packageToPartialSize.get(packageName);
+ }
+ }
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+
+ outFile.println("</head>");
+ outFile.println("<body>");
+
+ int yOffset = 0;
+ for (Float size : sortedPackages.keySet()){
+
+ String packageName = sortedPackages.get(size);
+ String drillDownFileName = packageName + "Classes.html";
+
+ float ratio = (size / maxSize) * 79;
+
+ if (ratio < 3){
+ ratio = 3;
+ }
+
+ float perc = (size / sumSize) * 100;
+
+ outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+ outFile.println("<div id=\"lb\">");
+ outFile.println("<div id=\"rb\">");
+ outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+ outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+ outFile.println("<div id=\"content\">");
+ outFile.println("</div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div>");
+
+ int yOffsetText = yOffset+8;
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc);
+ outFile.println("%</div>\n");
+ outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+packageName+"</a></div>");
+
+ yOffset = yOffset + 25;
+
+ }
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+
+ }
+
+ private static void makeFragmentsHtml(String outFileName) throws IOException{
+
+ // TreeMap<Float, Integer> sortedFragments = new TreeMap<Float, Integer>(Collections.reverseOrder());
+ TreeMap<Float, String> sortedSplitPoints = new TreeMap<Float, String>(Collections.reverseOrder());
+ float maxSize = 0f;
+ float sumSize = 0f;
+
+ // initial fragment
+ float initialSize = GlobalInformation.fragmentToPartialSize.get(0);
+ sumSize += initialSize;
+ maxSize = initialSize;
+ sortedSplitPoints.put(initialSize, "initialDownload");
+
+ // all fragments that are not in the initial load order
+ float allOtherFragmentsSize = GlobalInformation.allOtherFragmentsPartialSize;
+ sumSize += allOtherFragmentsSize;
+ if (allOtherFragmentsSize > maxSize){
+ maxSize = allOtherFragmentsSize;
+ }
+ sortedSplitPoints.put(allOtherFragmentsSize, "allOtherFragments");
+
+ // all exclusive fragments
+ System.out.println("");
+ for (Integer splitPointId : GlobalInformation.splitPointToLocation.keySet()){
+ System.out.println("splitPointId is: " + splitPointId);
+ Float sizeOfCurExclusiveFrag = GlobalInformation.fragmentToPartialSize.get(splitPointId);
+ sortedSplitPoints.put(sizeOfCurExclusiveFrag, GlobalInformation.splitPointToLocation.get(splitPointId));
+ sumSize += sizeOfCurExclusiveFrag;
+ if (sizeOfCurExclusiveFrag > maxSize){
+ maxSize = sizeOfCurExclusiveFrag;
+ }
+ }
+
+
+/* for (Integer fragmentName : GlobalInformation.fragmentToPartialSize.keySet()){
+ sortedFragments.put(GlobalInformation.fragmentToPartialSize.get(fragmentName), fragmentName);
+ sumSize += GlobalInformation.fragmentToPartialSize.get(fragmentName);
+ if (GlobalInformation.fragmentToPartialSize.get(fragmentName) > maxSize){
+ maxSize = GlobalInformation.fragmentToPartialSize.get(fragmentName);
+ }
+ }*/
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+ outFile.println("</head>");
+ outFile.println("<body>");
+
+ int yOffset = 0;
+ //for (Float size : sortedFragments.keySet()){
+ for (Float size : sortedSplitPoints.keySet()){
+
+ // Integer fragmentName = sortedFragments.get(size);
+ String splitPointName = sortedSplitPoints.get(size);
+ // String drillDownFileName = "fragment" + Integer.toString(fragmentName) + "Classes.html";
+ String drillDownFileName = "splitPoint" + splitPointName + "Classes.html";
+
+ float ratio = (size / maxSize) * 79;
+
+ if (ratio < 3){
+ ratio = 3;
+ }
+
+ float perc = (size / sumSize) * 100;
+
+ outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+ outFile.println("<div id=\"lb\">");
+ outFile.println("<div id=\"rb\">");
+ outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+ outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+ outFile.println("<div id=\"content\">");
+ outFile.println("</div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div>");
+
+ int yOffsetText = yOffset+8;
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:80px;\">%.1f", perc);
+ outFile.println("%</div>\n");
+ // outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:120px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">fragment"+ Integer.toString(fragmentName) +"</a></div>");
+ outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:120px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+ splitPointName +"</a></div>");
+
+ yOffset = yOffset + 25;
+
+ }
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+
+ }
+
+ private static void makeCodeTypeHtml(String outFileName, HashMap<String, CodeCollection> nameToCodeColl) throws IOException{
+
+
+ float maxSize = 0f;
+ float sumSize = 0f;
+ TreeMap<Float, String> sortedCodeTypes = new TreeMap<Float, String>(Collections.reverseOrder());
+
+ //TODO(kprobst): turn this into a multimap? com.google.common.collect.TreeMultimap
+ for (String codeType : nameToCodeColl.keySet()){
+ float curSize = nameToCodeColl.get(codeType).getCumPartialSize();
+ sumSize += curSize;
+
+ if (curSize != 0f){
+ sortedCodeTypes.put(curSize, codeType);
+ if (curSize > maxSize){
+ maxSize = curSize;
+ }
+ }
+ }
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+ outFile.println("</head>");
+ outFile.println("<body>");
+
+ int yOffset = 0;
+ for (Float size : sortedCodeTypes.keySet()){
+
+ String codeType = sortedCodeTypes.get(size);
+ String drillDownFileName = codeType + "Classes.html";
+
+ float ratio = (size / maxSize) * 79;
+ float perc = (size / sumSize) * 100;
+
+ if (ratio < 3){
+ ratio = 3;
+ }
+
+ outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+ outFile.println("<div id=\"lb\">");
+ outFile.println("<div id=\"rb\">");
+ outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+ outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+ outFile.println("<div id=\"content\">");
+ outFile.println("</div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div>");
+
+ int yOffsetText = yOffset+8;
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc);
+ outFile.println("%</div>\n");
+ outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+codeType+"</a></div>");
+
+ yOffset = yOffset + 25;
+
+ }
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+
+
+ }
+
+ private static void makeLiteralsHtml(String outFileName, TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+
+
+ float maxSize = 0f;
+ float sumSize = 0f;
+ TreeMap<Float, String> sortedLitTypes = new TreeMap<Float, String>(Collections.reverseOrder());
+
+ for (String literal : nameToLitColl.keySet()){
+ float curSize = nameToLitColl.get(literal).cumSize;
+ sumSize += curSize;
+
+ if (curSize != 0f){
+ sortedLitTypes.put(curSize, literal);
+
+ if (curSize > maxSize){
+ maxSize = curSize;
+ }
+ }
+ }
+
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+ outFile.println("</head>");
+ outFile.println("<body>");
+
+ int yOffset = 0;
+ for (Float size : sortedLitTypes.keySet()){
+
+ String literal = sortedLitTypes.get(size);
+ String drillDownFileName = literal + "Lits.html";
+
+ float ratio = (size / maxSize) * 79;
+ float perc = (size / sumSize) * 100;
+
+ if (ratio < 3){
+ ratio = 3;
+ }
+
+ outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+ outFile.println("<div id=\"lb\">");
+ outFile.println("<div id=\"rb\">");
+ outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+ outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+ outFile.println("<div id=\"content\">");
+ outFile.println("</div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div>");
+
+ int yOffsetText = yOffset+8;
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc);
+ outFile.println("%</div>\n");
+ outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+literal+"</a></div>");
+
+ yOffset = yOffset + 25;
+
+ }
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+
+ }
+
+ private static void makeStringLiteralsHtml(String outFileName, TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">");
+ outFile.println("</head>");
+ outFile.println("<body>");
+
+
+ if (nameToLitColl.get("string").stringTypeToSize.size() > 0){
+
+ float maxSize = 0f;
+ float sumSize = 0f;
+ TreeMap<Float, String> sortedStLitTypes = new TreeMap<Float, String>(Collections.reverseOrder());
+
+ for (String stringLiteral : nameToLitColl.get("string").stringTypeToSize.keySet()){
+ float curSize = nameToLitColl.get("string").stringTypeToSize.get(stringLiteral);
+ sumSize += curSize;
+
+ if (curSize != 0f){
+ sortedStLitTypes.put(curSize, stringLiteral);
+
+ if (curSize > maxSize){
+ maxSize = curSize;
+ }
+ }
+ }
+
+
+ int yOffset = 0;
+ for (Float size : sortedStLitTypes.keySet()){
+
+ String stringLiteral = sortedStLitTypes.get(size);
+ String drillDownFileName = stringLiteral + "Strings.html";
+
+ float ratio = (size / maxSize) * 79;
+ float perc = (size / sumSize) * 100;
+
+ if (ratio < 3){
+ ratio = 3;
+ }
+
+ outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">");
+ outFile.println("<div id=\"lb\">");
+ outFile.println("<div id=\"rb\">");
+ outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+ outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+ outFile.println("<div id=\"content\">");
+ outFile.println("</div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div>");
+
+ int yOffsetText = yOffset+8;
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc);
+ outFile.println("%</div>\n");
+ outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+stringLiteral+"</a></div>");
+
+ yOffset = yOffset + 25;
+
+ }
+
+ }
+
+ else{
+ outFile.println("No string literals found for this application.");
+
+ }
+
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+
+
+ public static void copyFileOrDirectoryFromJar(String jarFileName, String inputFileName, File dstPath, boolean isDirectory) throws IOException{
+
+ JarFile jarFile = new JarFile(jarFileName);
+ if (isDirectory){
+ dstPath.mkdir();
+
+ JarInputStream jarFileIS = new JarInputStream(new FileInputStream(jarFileName));
+ JarEntry jarEntry = jarFileIS.getNextJarEntry();
+ while(jarEntry != null){
+ if (! inputFileName.endsWith("/")){
+ inputFileName += "/";
+ }
+ if ((jarEntry.getName().compareTo(inputFileName) != 0)&&(jarEntry.getName().startsWith(inputFileName))){
+ File newDstPath = new File(jarEntry.getName());
+ copyFileOrDirectoryFromJar(jarFileName, jarEntry.getName(), newDstPath, false);
+ }
+ jarEntry = jarFileIS.getNextJarEntry();
+ }
+ jarFileIS.close();
+ }
+
+ else{
+ InputStream in = jarFile.getInputStream(jarFile.getEntry(inputFileName));
+ OutputStream out = new FileOutputStream(dstPath);
+
+ int c;
+ while ((c = in.read()) != -1){
+ out.write(c);
+ }
+ in.close();
+ out.close();
+ jarFile.close();
+ }
+ }
+
+ public static void copyFileOrDirectory(File srcPath, File dstPath, String classPath, String inputFileName, boolean isDirectory) throws IOException{
+ if (srcPath.isDirectory()){
+ if (!dstPath.exists()){
+ dstPath.mkdir();
+ }
+ String files[] = srcPath.list();
+ for(int i = 0; i < files.length; i++){
+ copyFileOrDirectory(new File(srcPath, files[i]), new File(dstPath, files[i]), classPath, inputFileName, isDirectory);
+ }
+ }
+ else{
+ if(!srcPath.exists()){
+ copyFileOrDirectoryFromJar(classPath, inputFileName, dstPath, isDirectory);
+ }
+ else{
+ InputStream in = new FileInputStream(srcPath);
+ OutputStream out = new FileOutputStream(dstPath);
+ // Transfer bytes from in to out
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ in.close();
+ out.close();
+ }
+ }
+ }
+
+ public static String escapeXml(String unescaped) {
+ String escaped = unescaped.replaceAll("\\&", "&");
+ escaped = escaped.replaceAll("\\<", "<");
+ escaped = escaped.replaceAll("\\>", ">");
+ escaped = escaped.replaceAll("\\\"", """);
+ escaped = escaped.replaceAll("\\'", "'");
+ return escaped;
+ }
+
+ public static void makeCodeTypeClassesHtmls(HashMap<String, CodeCollection> nameToCodeColl) throws IOException{
+
+ for (String codeType : nameToCodeColl.keySet()){
+
+ //construct file name
+ String outFileName = codeType + "Classes.html";
+
+
+ float maxSize = 0f;
+ TreeMap<Float, String> sortedClasses = new TreeMap<Float, String>(Collections.reverseOrder());
+ for (String className : nameToCodeColl.get(codeType).classes){
+ if (GlobalInformation.classToPartialSize.containsKey(className)){
+
+ float curSize = 0f;
+ if (! GlobalInformation.classToPartialSize.containsKey(className)){
+ System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****");
+ }
+ else{
+ curSize = GlobalInformation.classToPartialSize.get(className);
+ }
+
+ if (curSize != 0f){
+ sortedClasses.put(curSize, className);
+ if (curSize > maxSize){
+ maxSize = curSize;
+ }
+ }
+ }
+ }
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println("</style>");
+
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<link rel=\"stylesheet\" href=\"classLevel.css\" media=\"screen\">");
+ outFile.println("<title>Classes of type \"" + codeType + "\"</title>");
+ outFile.println("</head>");
+ outFile.println("<body>");
+
+
+
+ outFile.println("<center>");
+ outFile.println("<h2>Classes of type \"" + codeType + "\"</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 90px; left:70px; position:absolute; background-color:white\"");
+
+
+ int yOffset = 0;
+ for (Float size : sortedClasses.keySet()){
+
+ String className = sortedClasses.get(size);
+
+ float ratio = (size / maxSize) * 85;
+
+ if (ratio < 3){
+ ratio = 3;
+ }
+
+ outFile.println("<div class=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 60px;\">");
+ outFile.println("<div id=\"lb\">");
+ outFile.println("<div id=\"rb\">");
+ outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+ outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+ outFile.println("<div id=\"content\">");
+ outFile.println("</div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div>");
+
+ int yOffsetText = yOffset+8;
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+ outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">"+className+"</div>");
+
+ yOffset = yOffset + 25;
+
+ }
+
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+ }
+
+ public static void makeDependenciesTableHtmls() throws IOException{
+
+ for (String className : GlobalInformation.classToWhatItDependsOn.keySet()){
+
+ String outFileName = className + "Deps.html";
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<title>Classes that \"" + className + "\" depends on</title>");
+ outFile.println("</head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println("</style>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h2>Classes that \"" + className + "\" depends on</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<center>");
+ outFile.println("<table border=\"1\" width=\"80%\" style=\"font-size: 11pt;\" bgcolor=\"white\">");
+
+ for (String depClassName : GlobalInformation.classToWhatItDependsOn.get(className)){
+
+ outFile.println("<tr>");
+ outFile.println("<td width=\"80%\">" + depClassName + "</td>");
+ outFile.println("</tr>");
+
+ }
+
+ outFile.println("</table>");
+ outFile.println("<center>");
+
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+ }
+
+ /**
+ * Makes html file for fragment classes.
+ * TODO(kprobst): update this once we have SOYC updated to supply enough information
+ * @throws IOException
+ */
+ public static void makeFragmentClassesHtmls() throws IOException{
+
+
+ for (Integer fragmentName : GlobalInformation.fragmentToStories.keySet()){
+ HashSet<String> alreadyPrintedClasses = new HashSet<String>();
+
+ String outFileName = "fragment" + Integer.toString(fragmentName) + "Classes.html";
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<title>Classes correlated with fragment " + Integer.toString(fragmentName) + " </title>");
+ outFile.println("</head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println(".tablediv {");
+ outFile.println("display: table;");
+ outFile.println("width:100%;");
+ outFile.println("background-color:#eee;");
+ outFile.println("border:1px solid #666666;");
+ outFile.println("border-spacing:5px;");
+ outFile.println("border-collapse:separate;");
+ outFile.println("}");
+ outFile.println(".celldiv {");
+ outFile.println("float:left;");
+ outFile.println("display: table-cell;");
+ outFile.println("width:49.5%;");
+ outFile.println("font-size: 14px;");
+ outFile.println("background-color:white;");
+ outFile.println("}");
+ outFile.println(".rowdiv {");
+ outFile.println("display: table-row;");
+ outFile.println("width:100%;");
+ outFile.println("}");
+ outFile.println("</style>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h2>Classes correlated with fragment " + Integer.toString(fragmentName) + "</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\"");
+ outFile.println("<div class=\"tablediv\">");
+
+ for (String storyName : GlobalInformation.fragmentToStories.get(fragmentName)){
+ if (GlobalInformation.storiesToCorrClasses.containsKey(storyName)){
+ for (String className : GlobalInformation.storiesToCorrClasses.get(storyName)){
+
+ if (! alreadyPrintedClasses.contains(className)){
+ //outFile.println("<div class=\"rowdiv\">");
+ outFile.println("<div class=\"rowdiv\">" + className + "</div>");
+ //outFile.println("</div>");
+ alreadyPrintedClasses.add(className);
+ }
+ }
+ }
+ }
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+ }
+
+ public static void makeHTMLShell(HashMap<String, CodeCollection> nameToCodeColl, TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+ //this will contain the place holder iframes where the actual information is going to go.
+
+ System.out.println("making html shell");
+ // copy from the bin directory to the current directory
+ String classPath = System.getProperty("java.class.path");
+ if (!classPath.endsWith("/")){
+ classPath += "/";
+ }
+ String inputFileName = "roundedCorners.css";
+ File inputFile = new File(classPath + inputFileName);
+ File outputFile = new File("roundedCorners.css");
+ copyFileOrDirectory(inputFile, outputFile, classPath, inputFileName, false);
+
+ inputFileName = "classLevel.css";
+ File inputFile2 = new File(classPath + inputFileName);
+ File outputFile2 = new File("classLevel.css");
+ copyFileOrDirectory(inputFile2, outputFile2, classPath, inputFileName, false);
+
+ inputFileName = "images";
+ File inputDir = new File(classPath + "images");
+ File outputDir = new File("images");
+ copyFileOrDirectory(inputDir, outputDir, classPath, inputFileName, true);
+
+
+ String fileName = "SoycDashboard-index.html";
+
+ final PrintWriter outFile = new PrintWriter(fileName);
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<title>Story of Your Compile - Top Level Dashboard for Permutation</title>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println("</style>");
+ outFile.println("</head>");
+
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h3>Story of Your Compile Dashboard</h3>");
+ outFile.println("<hr>");
+ if (GlobalInformation.fragmentToStories.size() > 1){
+ outFile.println("<b>Full code size: <span style=\"color:maroon\">" + GlobalInformation.cumSizeAllCode + "</span>, Size of Initial Download: <span style=\"color:maroon\">" + GlobalInformation.fragmentToPartialSize.get(0) + "</span></b>");
+ }
+ else{
+ outFile.println("<b>Full code size: <span style=\"color:maroon\">" + GlobalInformation.cumSizeAllCode + "</span></b>");
+ }
+
+ outFile.println("<hr>");
+
+ outFile.println("</center>");
+ outFile.println(" <div style=\"width:50%; float:left; padding-top: 10px;\">");
+ outFile.println("<b>Package breakdown</b>");
+ outFile.println(" </div>");
+ outFile.println(" <div style=\"width:48%; float:right; padding-top: 10px; \">");
+ outFile.println("<b>Code type breakdown</b>");
+ outFile.println(" </div>");
+
+
+ outFile.println(" <div style=\"width:50%; float:left; padding-top: 10px;\">");
+ outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+ outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Package Name</div>");
+ outFile.println(" </div>");
+
+
+ outFile.println(" <div style=\"width:48%; float:right; padding-top: 10px;\">");
+ outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+ outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Code Type</div>");
+ outFile.println(" </div>");
+
+
+
+ outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:left;\">");
+ outFile.println("<iframe src=\"packageBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+ outFile.println(" </div>");
+ makePackageHtml("packageBreakdown.html");
+
+ outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:right;\">");
+ outFile.println("<iframe src=\"codeTypeBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+ outFile.println(" </div>");
+ makeCodeTypeHtml("codeTypeBreakdown.html", nameToCodeColl);
+
+ outFile.println(" <div style=\"width:50%; float:left; padding-top: 10px;\">");
+ outFile.println("<b>Literals breakdown</b>");
+ outFile.println(" </div>");
+ outFile.println(" <div style=\"width:48%; float:right; padding-top: 10px; \">");
+ outFile.println("<b>String literals breakdown</b>");
+ outFile.println(" </div>");
+
+
+ outFile.println(" <div style=\"width:50%; float:left; padding-top: 10px;\">");
+ outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+ outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Literal Type</div>");
+ outFile.println(" </div>");
+
+
+ outFile.println(" <div style=\"width:48%; float:right; padding-top: 10px; \">");
+ outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+ outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">String Literal Type</div>");
+ outFile.println(" </div>");
+
+
+ outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:left;\">");
+ outFile.println("<iframe src=\"literalsBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+ outFile.println("</div>");
+ makeLiteralsHtml("literalsBreakdown.html", nameToLitColl);
+
+ outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:right;\">");
+ outFile.println("<iframe src=\"stringLiteralsBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+ outFile.println(" </div>");
+ makeStringLiteralsHtml("stringLiteralsBreakdown.html", nameToLitColl);
+
+
+ if (GlobalInformation.fragmentToStories.size() > 1){
+ outFile.println(" <div style=\"width:50%; float:left; padding-top: 10px;\">");
+ outFile.println("<b>Breakdown by runAsync split points</b>");
+ outFile.println(" </div>");
+
+ outFile.println(" <div style=\"width:100%; float:left; padding-top: 10px;\">");
+ outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>");
+ outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Fragment Name</div>");
+ outFile.println(" </div>");
+
+ outFile.println("<div style=\"height:35%; width:100%; margin:0 auto; background-color:white; float:left;\">");
+ outFile.println("<iframe src=\"fragmentsBreakdown.html\" width=100% height=100% scrolling=auto></iframe>");
+ outFile.println("</div>");
+ makeFragmentsHtml("fragmentsBreakdown.html");
+ }
+
+ outFile.println(" </body>");
+ outFile.println("</html>");
+ outFile.close();
+
+ }
+
+ public static void makeLiteralsClassesTableHtmls(TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+
+ for (String literalType : nameToLitColl.keySet()){
+
+ String outFileName = literalType + "Lits.html";
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<title>Literals of type \"" + literalType + "\"</title>");
+ outFile.println("</head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println("</style>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h2>Literals of type \"" + literalType + "\"</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<center>");
+ outFile.println("<table border=\"1\" width=\"80%\" style=\"font-size: 11pt;\" bgcolor=\"white\">");
+
+ for (String literal : nameToLitColl.get(literalType).literalToLocations.keySet()){
+
+ if (literal.trim().compareTo("") == 0){
+ literal = "[whitespace only string]";
+ }
+
+
+ String newLiteral = "";
+ if(literal.length() > 80){
+ int i;
+ for (i = 80; i < literal.length(); i=i+80){
+ String part1 = literal.substring(i-80, i);
+ newLiteral = newLiteral + part1 + " ";
+ }
+ if (i-80 > 0){
+ newLiteral = newLiteral + literal.substring(i-80);
+ }
+ }
+ else{
+ newLiteral = literal;
+ }
+
+ String escliteral = escapeXml(newLiteral);
+
+ outFile.println("<tr>");
+ outFile.println("<td width=\"40%\">" + escliteral + "</td>");
+
+
+ int ct = 0;
+ for (String location : nameToLitColl.get(literalType).literalToLocations.get(literal)){
+
+ if (ct > 0){
+ outFile.println("<tr>");
+ outFile.println("<td width=\"40%\"> </td>");
+ }
+
+ String newLocation = "";
+ if(location.length() > 80){
+ int i;
+ for (i = 80; i < location.length(); i=i+80){
+ String part1 = location.substring(i-80, i);
+ newLocation = newLocation + part1 + " ";
+ }
+ if (i-80 > 0){
+ newLocation = newLocation + location.substring(i-80);
+ }
+ }
+ else{
+ newLocation = location;
+ }
+
+
+ outFile.println("<td width=\"40%\">" + newLocation + "</td>");
+
+ if (ct > 0){
+ outFile.println("</tr>");
+ }
+ ct++;
+
+ }
+
+
+ outFile.println("</tr>");
+
+ }
+
+ outFile.println("</table>");
+ outFile.println("<center>");
+
+
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+ }
+
+ public static void makeLiteralsClassesHtmls(TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+
+
+ for (String literalType : nameToLitColl.keySet()){
+
+ String outFileName = literalType + "Lits.html";
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<title>Literals of type \"" + literalType + "\"</title>");
+ outFile.println("</head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println(".tablediv {");
+ outFile.println("display: table;");
+ outFile.println("width:100%;");
+ outFile.println("background-color:#eee;");
+ outFile.println("border:1px solid #666666;");
+ outFile.println("border-spacing:5px;/*cellspacing:poor IE support for this*/");
+ outFile.println("border-collapse:separate;");
+ outFile.println("}");
+ outFile.println(".celldiv {");
+ outFile.println("float:left;/*fix for buggy browsers*/");
+ outFile.println("display: table-cell;");
+ outFile.println("width:50%;");
+ outFile.println("font-size: 14px;");
+ outFile.println("background-color:white;");
+ outFile.println("}");
+ outFile.println(".rowdiv {");
+ outFile.println("display: table-row;");
+ //outFile.println("width:90%;");
+ outFile.println("}");
+ outFile.println("</style>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h2>Literals of type \"" + literalType + "\"</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\"");
+ outFile.println("<div class=\"tablediv\">");
+ for (String literal : nameToLitColl.get(literalType).literalToLocations.keySet()){
+
+ if (literal.trim().compareTo("") == 0){
+ literal = "[whitespace only string]";
+ }
+
+
+ String newLiteral = "";
+ if(literal.length() > 100){
+ int i;
+ for (i = 100; i < literal.length(); i=i+100){
+ String part1 = literal.substring(i-100, i);
+ newLiteral = newLiteral + part1 + " ";
+ }
+ if (i-100 > 0){
+ newLiteral = newLiteral + literal.substring(i-100);
+ }
+ }
+ else{
+ newLiteral = literal;
+ }
+
+ String escliteral = escapeXml(newLiteral);
+ outFile.println("<div class=\"rowdiv\">");
+ outFile.println("<div class=\"celldiv\">" + escliteral + "</div>");
+
+ for (String location : nameToLitColl.get(literalType).literalToLocations.get(literal)){
+
+ String newLocation = "";
+ if(location.length() > 100){
+ int i;
+ for (i = 100; i < location.length(); i=i+100){
+ String part1 = location.substring(i-100, i);
+ newLocation = newLocation + part1 + " ";
+ }
+ if (i-100 > 0){
+ newLocation = newLocation + location.substring(i-100);
+ }
+ }
+ else{
+ newLocation = location;
+ }
+
+ outFile.println("<div class=\"celldiv\">" + newLocation + "</div>");
+ }
+ outFile.println("</div>");
+ }
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+ }
+
+ public static void makePackageClassesHtmls() throws IOException{
+
+ for (String packageName : GlobalInformation.packageToClasses.keySet()){
+
+ String outFileName = packageName + "Classes.html";
+ TreeMap<Float, String> sortedClasses = new TreeMap<Float, String>(Collections.reverseOrder());
+ float maxSize = 0f;
+
+ //TODO(kprobst): not currently used, but will be for dependencies
+ int maxDepCount = 1;
+
+ for (String className : GlobalInformation.packageToClasses.get(packageName)){
+
+ float curSize = 0f;
+ if (! GlobalInformation.classToPartialSize.containsKey(className)){
+ System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****");
+ }
+ else{
+ curSize = GlobalInformation.classToPartialSize.get(className);
+ }
+
+ //TODO(kprobst): not currently used, but will be for dependencies
+ int depCount = 0;
+ if (GlobalInformation.classToWhatItDependsOn.containsKey(className)){
+ depCount = GlobalInformation.classToWhatItDependsOn.get(className).size();
+ }
+
+ if (curSize != 0f){
+
+ sortedClasses.put(curSize, className);
+ if (curSize > maxSize){
+ maxSize = curSize;
+ }
+ //TODO(kprobst): not currently used, but will be for dependencies
+ if (depCount > maxDepCount){
+ maxDepCount = depCount;
+ }
+ }
+ }
+
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<link rel=\"stylesheet\" href=\"classLevel.css\" media=\"screen\">");
+ outFile.println("<title>Classes in package \"" + packageName + "\"</title>");
+ outFile.println("</head>");
+ outFile.println("<body>");
+
+
+ outFile.println("<center>");
+ outFile.println("<h2>Classes in package \"" + packageName + "\"</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 90px; left:70px; position:absolute; background-color:white\"");
+
+
+ int yOffset = 0;
+ for (Float size : sortedClasses.keySet()){
+
+ String className = sortedClasses.get(size);
+
+ //TODO(kprobst): switch out the commented/uncommented lines below when showing dependencies
+ // float ratio = (size / maxSize) * 45;
+ float ratio = (size / maxSize) * 85;
+
+ if (ratio < 3){
+ ratio = 3;
+ }
+
+ //TODO(kprobst): not currently used, but will be for dependencies
+ // get the dependency count
+ int depCount = 0;
+ if (GlobalInformation.classToWhatItDependsOn.containsKey(className)){
+ depCount = GlobalInformation.classToWhatItDependsOn.get(className).size();
+ }
+ float depRatio = ((float)depCount / (float)maxDepCount) * 45f;
+ if (depRatio < 3.0){
+ depRatio = 3;
+ }
+
+ outFile.println("<div class=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 60px;\">");
+ outFile.println("<div id=\"lb\">");
+ outFile.println("<div id=\"rb\">");
+ outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+ outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+ outFile.println("<div id=\"content\">");
+ outFile.println("</div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div>");
+
+
+ //TODO(kprobst): not currently used, but will be for dependencies
+/* outFile.println("<div class=\"box-right\" style=\"width:" + depRatio + "%; top: " + yOffset + "px; left: 50%\">");
+ outFile.println("<div id=\"lb\">");
+ outFile.println("<div id=\"rb\">");
+ outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">");
+ outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">");
+ outFile.println("<div id=\"content\">");
+ outFile.println("</div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div></div></div></div>");
+ outFile.println("</div>");*/
+
+ int yOffsetText = yOffset+8;
+ outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size);
+ outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">"+className+"</div>");
+
+/* //TODO(kprobst) make this a link
+ String drillDownFileName = className + "Deps.html";
+ outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:50%;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">Dependencies: " + depCount + "</a></div>");
+*/
+ yOffset = yOffset + 25;
+
+ }
+
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+ }
+
+ /**
+ * Makes html file for fragment classes.
+ * TODO(kprobst): update this once we have SOYC updated to supply enough information
+ * @throws IOException
+ */
+ public static void makeSplitPointClassesHtmls() throws IOException{
+
+ //for the initial fragment and the fragments in the load order, we can print this immediately
+ // For those fragments *not* in the initial load order, we just collect and then print at the end
+ TreeSet<String> sortedClassesAndMethodsAllOtherFragments = new TreeSet<String>();
+
+ for (Integer fragmentName : GlobalInformation.fragmentToStories.keySet()){
+
+ if ((fragmentName != 0)&&(!GlobalInformation.splitPointToLocation.containsKey(fragmentName))){
+
+ // get the stories from ALL the fragments
+ for (String storyName : GlobalInformation.fragmentToStories.get(fragmentName)){
+ if ((!GlobalInformation.nameToLitColl.get("string").storyToLocations.containsKey(storyName))&&(GlobalInformation.storiesToCorrClassesAndMethods.containsKey(storyName))){
+ for (String className : GlobalInformation.storiesToCorrClassesAndMethods.get(storyName)){
+ sortedClassesAndMethodsAllOtherFragments.add(className);
+ }
+ }
+ }
+ }
+
+// else if ((fragmentName == 0)||(GlobalInformation.splitPointToLocation.containsKey(fragmentName))){
+ else{
+ String curSplitPointLocation;
+
+ if (fragmentName == 0){
+ curSplitPointLocation = "initialDownload";
+ }
+ else{
+ curSplitPointLocation = GlobalInformation.splitPointToLocation.get(fragmentName);
+ }
+
+ String outFileName = "splitPoint" + curSplitPointLocation + "Classes.html";
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<title>Classes and methods in exclusives fragment for runAsync split point \"" + curSplitPointLocation + "\" </title>");
+ outFile.println("</head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println(".tablediv {");
+ outFile.println("display: table;");
+ outFile.println("width:100%;");
+ outFile.println("background-color:#eee;");
+ outFile.println("border:1px solid #666666;");
+ outFile.println("border-spacing:5px;");
+ outFile.println("border-collapse:separate;");
+ outFile.println("}");
+ outFile.println(".celldiv {");
+ outFile.println("float:left;");
+ outFile.println("display: table-cell;");
+ outFile.println("width:49.5%;");
+ outFile.println("font-size: 14px;");
+ outFile.println("background-color:white;");
+ outFile.println("}");
+ outFile.println(".rowdiv {");
+ outFile.println("display: table-row;");
+ outFile.println("width:100%;");
+ outFile.println("}");
+ outFile.println("</style>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h2>Classes and methods in exclusives fragment for runAsync split point \"" + curSplitPointLocation + "\"</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\"");
+ outFile.println("<div class=\"tablediv\">");
+
+ TreeSet<String> sortedClassesAndMethods = new TreeSet<String>();
+ for (String storyName : GlobalInformation.fragmentToStories.get(fragmentName)){
+ if ((!GlobalInformation.nameToLitColl.get("string").storyToLocations.containsKey(storyName))&&(GlobalInformation.storiesToCorrClassesAndMethods.containsKey(storyName))){
+ for (String className : GlobalInformation.storiesToCorrClassesAndMethods.get(storyName)){
+ sortedClassesAndMethods.add(className);
+ }
+ }
+ }
+ for (String classOrMethod : sortedClassesAndMethods){
+
+
+ //if it's a method
+ if ((GlobalInformation.displayDependencies == true)&&(classOrMethod.contains("("))&&(classOrMethod.contains(")"))){
+ //get the package
+ String packageName = classOrMethod;
+ packageName = packageName.replaceAll("\\.\\p{Upper}.*", "");
+
+ String noParamMethod = classOrMethod;
+ noParamMethod = noParamMethod.replaceAll("\\(.*", "");
+
+ outFile.println("<div class=\"rowdiv\"><a href=\"methodDependencies-" + packageName + ".html#"+ noParamMethod + "\">" + classOrMethod + "</a></div>");
+ }
+ else{
+ outFile.println("<div class=\"rowdiv\">" + classOrMethod + "</div>");
+ }
+ }
+
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+ }
+
+
+ //finally, make the file for all the other fragments
+ String outFileName = "splitPointAllOtherFragmentsClasses.html";
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<title>Classes and methods in exclusives fragment for runAsync split point \"allOtherFragments\" </title>");
+ outFile.println("</head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println(".tablediv {");
+ outFile.println("display: table;");
+ outFile.println("width:100%;");
+ outFile.println("background-color:#eee;");
+ outFile.println("border:1px solid #666666;");
+ outFile.println("border-spacing:5px;/*cellspacing:poor IE support for this*/");
+ outFile.println("border-collapse:separate;");
+ outFile.println("}");
+ outFile.println(".celldiv {");
+ outFile.println("float:left;/*fix for buggy browsers*/");
+ outFile.println("display: table-cell;");
+ outFile.println("width:49.5%;");
+ outFile.println("font-size: 14px;");
+ outFile.println("background-color:white;");
+ outFile.println("}");
+ outFile.println(".rowdiv {");
+ outFile.println("display: table-row;");
+ outFile.println("width:100%;");
+ outFile.println("}");
+ outFile.println("</style>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h2>Classes and methods in exclusives fragment for runAsync split point \"allOtherFragments\"</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\"");
+ outFile.println("<div class=\"tablediv\">");
+
+ for (String classOrMethod : sortedClassesAndMethodsAllOtherFragments){
+
+ //if it's a method
+ if ((GlobalInformation.displayDependencies == true)&&(classOrMethod.contains("("))&&(classOrMethod.contains(")"))){
+ //get the package
+ String packageName = classOrMethod;
+ packageName = packageName.replaceAll("\\.\\p{Upper}.*", "");
+
+ String noParamMethod = classOrMethod;
+ noParamMethod = noParamMethod.replaceAll("\\(.*", "");
+
+ outFile.println("<div class=\"rowdiv\"><a href=\"methodDependencies-" + packageName + ".html#"+ noParamMethod + "\">" + classOrMethod + "</a></div>");
+ }
+ else{
+ outFile.println("<div class=\"rowdiv\">" + classOrMethod + "</div>");
+ }
+ }
+
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+
+
+
+ }
+
+ public static void makeStringLiteralsClassesHtmls(TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+
+
+ for (String literalType : nameToLitColl.get("string").stringTypeToSize.keySet()){
+
+ String outFileName = literalType + "Strings.html";
+
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<title>Literals of type \"" + literalType + "\"</title>");
+ outFile.println("</head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println(".tablediv {");
+ outFile.println("display: table;");
+ outFile.println("width:100%;");
+ outFile.println("background-color:#eee;");
+ outFile.println("border:1px solid #666666;");
+ outFile.println("border-spacing:5px;/*cellspacing:poor IE support for this*/");
+ outFile.println("border-collapse:separate;");
+ outFile.println("}");
+ outFile.println(".celldiv {");
+ outFile.println("float:left;/*fix for buggy browsers*/");
+ outFile.println("display: table-cell;");
+ outFile.println("width:49.5%;");
+ outFile.println("font-size: 14px;");
+ outFile.println("background-color:white;");
+ outFile.println("}");
+ outFile.println(".rowdiv {");
+ outFile.println("display: table-row;");
+ outFile.println("width:100%;");
+ outFile.println("}");
+ outFile.println("</style>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h2>Literals of type \"" + literalType + "\"</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\"");
+ outFile.println("<div class=\"tablediv\">");
+
+
+ for (String literal : nameToLitColl.get("string").stringLiteralToType.keySet()){
+
+ if (nameToLitColl.get("string").stringLiteralToType.get(literal).compareTo(literalType) == 0){
+
+
+ if (literal.trim().compareTo("") == 0){
+ literal = "[whitespace only string]";
+ }
+
+ String newLiteral = "";
+ if(literal.length() > 100){
+ int i;
+ for (i = 100; i < literal.length(); i=i+100){
+ String part1 = literal.substring(i-100, i);
+ newLiteral = newLiteral + part1 + " ";
+ }
+ if (i-100 > 0){
+ newLiteral = newLiteral + literal.substring(i-100);
+ }
+ }
+ else{
+ newLiteral = literal;
+ }
+
+ String escliteral = escapeXml(newLiteral);
+ outFile.println("<div class=\"rowdiv\">");
+ outFile.println("<div class=\"celldiv\">" + escliteral + "</div>");
+
+ for (String location : nameToLitColl.get("string").literalToLocations.get(literal)){
+
+ String newLocation = "";
+ if(location.length() > 100){
+ int i;
+ for (i = 100; i < location.length(); i=i+100){
+ String part1 = location.substring(i-100, i);
+ newLocation = newLocation + part1 + " ";
+ }
+ if (i-100 > 0){
+ newLocation = newLocation + location.substring(i-100);
+ }
+ }
+ else{
+ newLocation = location;
+ }
+
+ outFile.println("<div class=\"celldiv\">" + newLocation + "</div>");
+ }
+ outFile.println("</div>");
+ }
+ }
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+
+
+
+ }
+
+ public static void makeStringLiteralsClassesTableHtmls(TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{
+
+
+ for (String literalType : nameToLitColl.get("string").stringTypeToSize.keySet()){
+
+
+ String outFileName = literalType + "Strings.html";
+ final PrintWriter outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<title>Literals of type \"" + literalType + "\"</title>");
+ outFile.println("</head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println("</style>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h2>Literals of type \"" + literalType + "\"</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<center>");
+ outFile.println("<table border=\"1\" width=\"80%\" style=\"font-size: 11pt;\" bgcolor=\"white\">");
+
+
+
+ for (String literal : nameToLitColl.get("string").stringLiteralToType.keySet()){
+
+ if (nameToLitColl.get("string").stringLiteralToType.get(literal).compareTo(literalType) == 0){
+
+ if (literal.trim().compareTo("") == 0){
+ literal = "[whitespace only string]";
+ }
+
+ String newLiteral = "";
+ if(literal.length() > 80){
+ int i;
+ for (i = 80; i < literal.length(); i=i+80){
+ String part1 = literal.substring(i-80, i);
+ newLiteral = newLiteral + part1 + " ";
+ }
+ if (i-80 > 0){
+ newLiteral = newLiteral + literal.substring(i-80);
+ }
+ }
+ else{
+ newLiteral = literal;
+ }
+
+ String escliteral = escapeXml(newLiteral);
+
+ outFile.println("<tr>");
+ outFile.println("<td width=\"40%\">" + escliteral + "</td>");
+
+
+ int ct = 0;
+
+ for (String location : nameToLitColl.get("string").literalToLocations.get(literal)){
+
+ if (ct > 0){
+ outFile.println("<tr>");
+ outFile.println("<td width=\"40%\"> </td>");
+ }
+
+ String newLocation = "";
+ if(location.length() > 80){
+ int i;
+ for (i = 80; i < location.length(); i=i+80){
+ String part1 = location.substring(i-80, i);
+ newLocation = newLocation + part1 + " ";
+ }
+ if (i-80 > 0){
+ newLocation = newLocation + location.substring(i-80);
+ }
+ }
+ else{
+ newLocation = location;
+ }
+
+
+ outFile.println("<td width=\"40%\">" + newLocation + "</td>");
+
+ if (ct > 0){
+ outFile.println("</tr>");
+ }
+ ct++;
+ }
+ outFile.println("</tr>");
+ }
+ }
+
+ outFile.println("</table>");
+ outFile.println("<center>");
+
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+ }
+
+
+
+ public static void makeDependenciesHtml(Map<String, ArrayList<String>> dependencies) throws IOException{
+
+ String origOutFileName = "methodDependencies-";
+ PrintWriter outFile = null;
+ String curPackageName = "";
+
+ for (String method : dependencies.keySet()){
+ // this key set is already in alphabetical order
+ // get the package of this method, i.e., everything up to .[A-Z]
+
+ String packageName = method;
+ packageName = packageName.replaceAll("\\.\\p{Upper}.*", "");
+
+
+ if ((curPackageName.compareTo("") == 0) || (curPackageName.compareTo(packageName) != 0)){
+
+ curPackageName = packageName;
+ if (outFile != null){
+ //finish up the current file
+ outFile.println("</table>");
+ outFile.println("<center>");
+
+ outFile.println("</div>");
+ outFile.println("</body>");
+ outFile.println("</html>");
+ outFile.close();
+ }
+
+ String outFileName = origOutFileName + curPackageName + ".html";
+ outFile = new PrintWriter(outFileName);
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ outFile.println("<title>Method Dependencies</title>");
+ outFile.println("</head>");
+
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("p {background-color: fuchsia}");
+ outFile.println("</style>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h2>Method Dependencies</h2>");
+ outFile.println("</center>");
+ outFile.println("<hr>");
+
+ outFile.println("<center>");
+ outFile.println("<table border=\"1\" width=\"80%\" style=\"font-size: 11pt;\" bgcolor=\"white\">");
+
+ }
+ outFile.println("<tr>");
+ outFile.println("<td width=\"80%\"><a name=\"" + method + "\">" + method + "</a></td>");
+ outFile.println("</tr>");
+
+ for (int i = 0; i < dependencies.get(method).size(); i++){
+ String depMethod = dependencies.get(method).get(i);
+
+ outFile.println("<tr>");
+ outFile.println("<td width=\"20%\"></td>");
+ outFile.println("<td width=\"60%\">" + depMethod + "</td>");
+ outFile.println("</tr>");
+ }
+ }
+ }
+}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java b/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java
new file mode 100644
index 0000000..4afe351
--- /dev/null
+++ b/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java
@@ -0,0 +1,879 @@
+/*
+ * 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.soyc;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+import org.xml.sax.SAXException;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.TreeSet;
+import java.util.TreeMap;
+import java.util.zip.GZIPInputStream;
+import javax.xml.parsers.*;
+
+public class SoycDashboard {
+
+ /**
+ * @param args Input: XML file containing soyc compile output
+ * @throws IOException
+ * @throws SAXException
+ */
+ public static void main(String[] args) {
+
+ String inFileName = "";
+ String depInFileName = "";
+ if ((args.length != 1) && (args.length != 2)){
+
+ if (args.length == 1){
+ GlobalInformation.displayDependencies = false;
+ }
+ else{
+ GlobalInformation.displayDependencies = true;
+ depInFileName = args[1];
+ }
+
+ System.err.println("Usage: java com/google/gwt/soyc/SoycDashboard soyc-report0.xml[.gz] soyc-dependencies0.xml[.gz] OR java com/google/gwt/soyc/SoycDashboard soyc-report0.xml[.gz]");
+ System.exit(1);
+ }
+
+ inFileName = args[0];
+
+
+
+ if (GlobalInformation.displayDependencies == true){
+ /**
+ * handle dependencies
+ */
+
+ Map<String, ArrayList<String>> dependencies = new TreeMap<String, ArrayList<String>>();
+ DefaultHandler depHandler = parseXMLDocumentDependencies(dependencies);
+
+ // start parsing
+ SAXParserFactory depFactoryMain = SAXParserFactory.newInstance();
+ depFactoryMain.setNamespaceAware(true);
+ try {
+ SAXParser saxParser = depFactoryMain.newSAXParser();
+ InputStream in = new FileInputStream(depInFileName);
+ if (depInFileName.endsWith(".gz")) {
+ in = new GZIPInputStream(in);
+ }
+ in = new BufferedInputStream(in);
+ saxParser.parse(in,depHandler);
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException("Could not parse document. ", e);
+ } catch (SAXException e) {
+ throw new RuntimeException("Could not create SAX parser. ", e);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException("Could not open file. ", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Could not open file. ", e);
+ }
+
+ try{
+ MakeTopLevelHtmlForPerm.makeDependenciesHtml(dependencies);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot open file. ", e);
+ }
+ }
+
+ /**
+ * handle everything else
+ */
+
+ // to store literals data
+ GlobalInformation.nameToLitColl.put("long",new LiteralsCollection("long"));
+ GlobalInformation.nameToLitColl.put("null",new LiteralsCollection("null"));
+ GlobalInformation.nameToLitColl.put("class",new LiteralsCollection("class"));
+ GlobalInformation.nameToLitColl.put("int",new LiteralsCollection("int"));
+ GlobalInformation.nameToLitColl.put("string",new LiteralsCollection("string"));
+ GlobalInformation.nameToLitColl.put("number",new LiteralsCollection("number"));
+ GlobalInformation.nameToLitColl.put("boolean",new LiteralsCollection("boolean"));
+ GlobalInformation.nameToLitColl.put("double",new LiteralsCollection("double"));
+ GlobalInformation.nameToLitColl.put("char",new LiteralsCollection("char"));
+ GlobalInformation.nameToLitColl.put("undefined",new LiteralsCollection("undefined"));
+ GlobalInformation.nameToLitColl.put("float",new LiteralsCollection("float"));
+
+ // to store code data
+ GlobalInformation.nameToCodeColl.put("allOther", new CodeCollection("allOther"));
+ GlobalInformation.nameToCodeColl.put("widget", new CodeCollection("widget"));
+ GlobalInformation.nameToCodeColl.put("rpcUser", new CodeCollection("rpcUser"));
+ GlobalInformation.nameToCodeColl.put("rpcGen", new CodeCollection("rpcGen"));
+ GlobalInformation.nameToCodeColl.put("rpcGwt", new CodeCollection("rpcGwt"));
+ GlobalInformation.nameToCodeColl.put("gwtLang", new CodeCollection("long"));
+ GlobalInformation.nameToCodeColl.put("jre", new CodeCollection("jre"));
+
+
+ // make the parser handler
+ DefaultHandler handler = parseXMLDocument(GlobalInformation.nameToLitColl, GlobalInformation.nameToCodeColl);
+
+
+ // start parsing
+ SAXParserFactory factoryMain = SAXParserFactory.newInstance();
+ factoryMain.setNamespaceAware(true);
+ try {
+ SAXParser saxParser = factoryMain.newSAXParser();
+ InputStream in = new FileInputStream(inFileName);
+ if (inFileName.endsWith(".gz")) {
+ in = new GZIPInputStream(in);
+ }
+ in = new BufferedInputStream(in);
+ saxParser.parse(in,handler);
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException("Could not parse document. ", e);
+ } catch (SAXException e) {
+ throw new RuntimeException("Could not create SAX parser. ", e);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException("Could not open file. ", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Could not open file. ", e);
+ }
+
+ // add to "All Other Code" if none of the special categories apply
+ updateAllOtherCodeType(GlobalInformation.nameToCodeColl);
+
+ // now we need to aggregate numbers
+ GlobalInformation.computePackageSizes();
+ GlobalInformation.computePartialPackageSizes();
+
+ // clean up the RPC categories
+ foldInRPCHeuristic(GlobalInformation.nameToCodeColl);
+
+ // generate all the html files
+ makeHTMLFiles(GlobalInformation.nameToLitColl, GlobalInformation.nameToCodeColl);
+
+ System.out.println("Finished creating reports. To see the dashboard, open SoycDashboard-index.html in your browser.");
+ }
+
+
+ private static DefaultHandler parseXMLDocument(
+ final TreeMap<String, LiteralsCollection> nameToLitColl,
+ final HashMap<String, CodeCollection> nameToCodeColl) {
+
+ DefaultHandler handler = new DefaultHandler() {
+
+ String curStoryId;
+ String curStoryLiteralType;
+ String curLineNumber;
+ String curLocation;
+ String curStoryRef;
+ HashSet<String> curRelevantLitTypes = new HashSet<String>();
+ HashSet<String> curRelevantCodeTypes = new HashSet<String>();
+ String curClassId;
+ String curPackage;
+ Integer curFragment;
+ String curFunctionId = "";
+ boolean specialCodeType = false;
+ StringBuilder valueBuilder = new StringBuilder();
+ int ct = 0;
+ boolean fragmentInLoadOrder = false;
+
+ /**
+ * This method deals with the beginning of the XML element.
+ * It analyzes the XML node and adds its information to the relevant literal or code collection for later analysis.
+ * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
+ */
+ @Override
+ public void startElement(String nsUri, String strippedName, String tagName, Attributes attributes) {
+
+ if ((ct % 10000) == 0){
+ System.out.println(ct);
+ }
+ ct++;
+
+ valueBuilder.delete(0,valueBuilder.length());
+
+ if (strippedName.compareTo("splitpoint") == 0){
+ System.out.println("about to process splitpoint");
+ parseSplitPoint(attributes);
+ }
+ else if ((strippedName.compareTo("package") == 0)&&(attributes.getValue("id") != null)){
+ curPackage = attributes.getValue("id");
+
+ if (curPackage.compareTo("") == 0){
+ curPackage = "emptyPackageName";
+ }
+
+ if (! GlobalInformation.packageToClasses.containsKey(curPackage)){
+ TreeSet<String> insertSet = new TreeSet<String>();
+ GlobalInformation.packageToClasses.put(curPackage, insertSet);
+ }
+ }
+
+ else if (strippedName.compareTo("class") == 0){
+
+ parseClass(nameToCodeColl, attributes);
+ }
+
+ else if (strippedName.compareTo("function") == 0){
+ if (attributes.getValue("id") != null){
+ curFunctionId = attributes.getValue("id");
+ }
+ }
+
+ //TODO(kprobst): not currently used, but will be for dependencies
+ else if (strippedName.compareTo("on") == 0){
+ parseDependsOn(nameToCodeColl, attributes);
+ }
+
+ else if (strippedName.compareTo("of") == 0){
+ parseOverrides(nameToCodeColl, attributes);
+ }
+
+ else if (strippedName.compareTo("by") == 0){
+ parseCorrelations(nameToCodeColl, attributes);
+ }
+
+ else if (strippedName.compareTo("story") == 0){
+ parseStory(attributes);
+ }
+
+ else if (strippedName.compareTo("origin") == 0){
+ parseOrigins(nameToLitColl, attributes);
+ }
+
+ else if (strippedName.compareTo("js") == 0){
+ if (attributes.getValue("fragment") != null){
+ // ignore all code that is not in the first load order
+
+ curFragment = Integer.parseInt(attributes.getValue("fragment"));
+ if((curFragment == 0)||
+ (curFragment == (GlobalInformation.numSplitPoints+1))||
+ (curFragment == (GlobalInformation.numSplitPoints+2))||
+ ((curFragment >= 2) && (curFragment <= GlobalInformation.numSplitPoints))){
+ fragmentInLoadOrder = true;
+ }
+ else{
+ fragmentInLoadOrder = false;
+ }
+ }
+ else{
+
+ curFragment = -2;
+ }
+ }
+
+ else if (strippedName.compareTo("storyref") == 0){
+ parseJs(nameToLitColl, nameToCodeColl, attributes, curFragment);
+ }
+ }
+
+
+ /**
+ * This method collects a block of the value of the current XML node that the SAX parser parses.
+ * It simply adds to the the previous blocks, so that we can collect the entire value block.
+ */
+ @Override
+ public void characters (char ch[], int start, int length){
+ valueBuilder.append(ch, start, length);
+ }
+
+
+ /**
+ * This method marks the end of an XML element that the SAX parser parses.
+ * It has access to the full value of the node and uses it add information to the relevant literal or code collections.
+ * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void endElement (String nsUri, String strippedName, String qName){
+ String value = valueBuilder.toString();
+
+ int numBytes = value.getBytes().length;
+
+ if (curStoryRef != null){
+
+ //add this size to the current fragment
+ if (GlobalInformation.storiesToCorrClasses.containsKey(curStoryRef)){
+
+ if ((GlobalInformation.storiesToLitType.containsKey(curStoryRef))&&(GlobalInformation.storiesToCorrClasses.get(curStoryRef).size() > 0)){
+ GlobalInformation.numBytesDoubleCounted += numBytes;
+ }
+
+ float partialSize = (float)numBytes / (float)GlobalInformation.storiesToCorrClasses.get(curStoryRef).size();
+ if (!GlobalInformation.fragmentToPartialSize.containsKey(curFragment)){
+ GlobalInformation.fragmentToPartialSize.put(curFragment, partialSize);
+ }
+ else{
+ float newSize = GlobalInformation.fragmentToPartialSize.get(curFragment) + partialSize;
+ GlobalInformation.fragmentToPartialSize.put(curFragment, newSize);
+ }
+
+ // now do different things depending on whether this fragment is in the load order or not
+ if (fragmentInLoadOrder == false){
+ GlobalInformation.allOtherFragmentsPartialSize += numBytes;
+ }
+ else{
+ GlobalInformation.cumSizeAllCode += numBytes;
+
+ if ((!GlobalInformation.storiesToLitType.containsKey(curStoryRef))&&
+ (!GlobalInformation.storiesToCorrClasses.containsKey(curStoryRef))){
+ GlobalInformation.nonAttributedStories.add(curStoryRef);
+ GlobalInformation.nonAttributedBytes += numBytes;
+ }
+
+
+ // go through all the classes for this story
+ for (String className : GlobalInformation.storiesToCorrClasses.get(curStoryRef)){
+ // get the corresponding package
+ if (GlobalInformation.classToPackage.containsKey(className)){
+ String packageName = GlobalInformation.classToPackage.get(className);
+
+ if (!GlobalInformation.packageToClasses.containsKey(packageName)){
+ TreeSet<String> insertSet = new TreeSet<String>();
+ insertSet.add(className);
+ GlobalInformation.packageToClasses.put(packageName, insertSet);
+ }
+ else{
+ GlobalInformation.packageToClasses.get(packageName).add(className);
+ }
+
+ if (GlobalInformation.classToSize.containsKey(className)){
+ int newSize = GlobalInformation.classToSize.get(className) + numBytes;
+ GlobalInformation.classToSize.put(className, newSize);
+ }
+ else{
+ GlobalInformation.classToSize.put(className, numBytes);
+ }
+
+ if (GlobalInformation.classToPartialSize.containsKey(className)){
+ float newSize = GlobalInformation.classToPartialSize.get(className) + partialSize;
+ GlobalInformation.classToPartialSize.put(className, newSize);
+ }
+ else{
+ GlobalInformation.classToPartialSize.put(className, partialSize);
+ }
+ }
+ }
+ }
+ }
+ updateLitTypes(nameToLitColl, value, numBytes);
+ }
+ }
+
+
+ /*
+ * This method assigns strings to the appropriate category
+ */
+ private void updateLitTypes(
+ final TreeMap<String, LiteralsCollection> nameToLitColl,
+ String value, int numBytes) {
+
+ int iNumCounted = 0;
+
+ for (String relLitType : curRelevantLitTypes){
+ iNumCounted++;
+
+ //then give string literals special treatment
+ if (relLitType.compareTo("string") == 0){
+
+ // note that this will double-count (i.e., it will count a string twice if it's in the output twice), as it should.
+ nameToLitColl.get("string").cumStringSize += numBytes;
+ nameToLitColl.get(relLitType).cumSize += numBytes;
+
+ //get the origins
+ HashSet<String> originSet = nameToLitColl.get("string").storyToLocations.get(curStoryRef);
+
+ // find the most appropriate string literal category
+ String mostAppropriateCategory = "";
+ String mostAppropriateLocation = "";
+ String backupLocation = "";
+ for (String origin : originSet){
+
+ if ((origin.contains("ClassLiteralHolder")) && (mostAppropriateCategory.compareTo("") == 0)){
+ mostAppropriateCategory = "compiler";
+ mostAppropriateLocation = origin;
+ }
+ else if ((origin.startsWith("transient source for"))&&(origin.contains("_TypeSerializer")) && (mostAppropriateCategory.compareTo("") == 0)){
+ mostAppropriateCategory = "transient";
+ mostAppropriateLocation = origin;
+ }
+ else if ((origin.contains("InlineResourceBundleGenerator")) && (mostAppropriateCategory.compareTo("") == 0)){
+ mostAppropriateCategory = "inlinedTextRes";
+ mostAppropriateLocation = origin;
+ }
+ if (origin.compareTo("com.google.gwt.dev.js.ast.JsProgram: Line 0") != 0){
+ backupLocation = origin;
+ }
+ }
+
+ if (backupLocation.compareTo("") == 0){
+ backupLocation = "com.google.gwt.dev.js.ast.JsProgram: Line 0";
+ }
+ if ((((value.startsWith("'")) && (value.endsWith("'"))) ||
+ ((value.startsWith("\""))&&(value.endsWith("\"")))) &&
+ (mostAppropriateCategory.compareTo("") == 0)){
+ mostAppropriateCategory = "user";
+ mostAppropriateLocation = backupLocation;
+ }
+ else if (mostAppropriateCategory.compareTo("") == 0){
+ mostAppropriateCategory = "otherStrings";
+ mostAppropriateLocation = backupLocation;
+ }
+
+ if (!nameToLitColl.get("string").stringLiteralToType.containsKey(value)){
+ nameToLitColl.get("string").stringLiteralToType.put(value, mostAppropriateCategory);
+ if (!nameToLitColl.get("string").stringTypeToCount.containsKey(mostAppropriateCategory)){
+ nameToLitColl.get("string").stringTypeToCount.put(mostAppropriateCategory, 1);
+ }
+ else{
+ int iNewCount = nameToLitColl.get("string").stringTypeToCount.get(mostAppropriateCategory) + 1;
+ nameToLitColl.get("string").stringTypeToCount.put(mostAppropriateCategory, iNewCount);
+ }
+
+
+ int iNewSize = numBytes;
+ if (nameToLitColl.get("string").stringTypeToSize.containsKey(mostAppropriateCategory)){
+ iNewSize += nameToLitColl.get("string").stringTypeToSize.get(mostAppropriateCategory);
+ }
+ nameToLitColl.get("string").stringTypeToSize.put(mostAppropriateCategory, iNewSize);
+
+
+ if (nameToLitColl.get("string").storyToLocations.containsKey(curStoryRef)){
+ HashSet<String> insertSet = new HashSet<String>();
+ insertSet.add(mostAppropriateLocation);
+ nameToLitColl.get(relLitType).literalToLocations.put(value,insertSet);
+ }
+ }
+ }
+
+ else{
+ // note that this will double-count (i.e., it will count a literal twice if it's in the output twice), as it should.
+ nameToLitColl.get(relLitType).cumSize += numBytes;
+
+ if (nameToLitColl.get(relLitType).storyToLocations.containsKey(curStoryRef)){
+ if (nameToLitColl.get(relLitType).literalToLocations.containsKey(value)){
+ nameToLitColl.get(relLitType).literalToLocations.get(value).addAll(nameToLitColl.get(relLitType).
+ storyToLocations.get(curStoryRef));
+ }
+ else{
+ HashSet<String> insertSet = nameToLitColl.get(relLitType).storyToLocations.get(curStoryRef);
+ nameToLitColl.get(relLitType).literalToLocations.put(value,insertSet);
+ }
+
+ }
+ }
+ }
+ }
+
+ /*
+ * parses the "JS" portion of the XML file
+ */
+ private void parseJs(
+ final TreeMap<String, LiteralsCollection> nameToLitColl,
+ final HashMap<String, CodeCollection> nameToCodeColl,
+ Attributes attributes, Integer curFragment) {
+ curRelevantLitTypes.clear();
+ curRelevantCodeTypes.clear();
+
+ if (attributes.getValue("idref") != null){
+
+ curStoryRef = attributes.getValue("idref");
+
+ if (curFragment != -1){
+ //add this to the stories for this fragment
+ if (!GlobalInformation.fragmentToStories.containsKey(curFragment)){
+ HashSet<String> insertSet = new HashSet<String>();
+ insertSet.add(curStoryRef);
+ GlobalInformation.fragmentToStories.put(curFragment, insertSet);
+ }
+ else{
+ GlobalInformation.fragmentToStories.get(curFragment).add(curStoryRef);
+ }
+ }
+
+ for (String litType : nameToLitColl.keySet()){
+ if (nameToLitColl.get(litType).storyToLocations.containsKey(curStoryRef)){
+ curRelevantLitTypes.add(litType);
+ }
+ }
+
+ specialCodeType = false;
+ for (String codeType : nameToCodeColl.keySet()){
+ if (nameToCodeColl.get(codeType).stories.contains(curStoryRef)){
+ curRelevantCodeTypes.add(codeType);
+ specialCodeType = true;
+ }
+ }
+ if (specialCodeType == false){
+
+ nameToCodeColl.get("allOther").stories.add(curStoryRef);
+ curRelevantCodeTypes.add("allOther");
+ }
+ }
+ }
+
+ /*
+ * parses the "origins" portion of the XML file
+ */
+ private void parseOrigins(
+ final TreeMap<String, LiteralsCollection> nameToLitColl,
+ Attributes attributes) {
+ if ((curStoryLiteralType.compareTo("") != 0)&&
+ (attributes.getValue("lineNumber") != null)&&
+ (attributes.getValue("location") != null)){
+ curLineNumber = attributes.getValue("lineNumber");
+ curLocation = attributes.getValue("location");
+ String curOrigin = curLocation + ": Line " + curLineNumber;
+
+ if (!nameToLitColl.get(curStoryLiteralType).storyToLocations.containsKey(curStoryId)){
+ HashSet<String> insertSet = new HashSet<String>();
+ insertSet.add(curOrigin);
+ nameToLitColl.get(curStoryLiteralType).storyToLocations.put(curStoryId, insertSet);
+ }
+ else{
+ nameToLitColl.get(curStoryLiteralType).storyToLocations.get(curStoryId).add(curOrigin);
+ }
+ }
+ }
+
+ /*
+ * parses the split points
+ */
+ private void parseSplitPoint(Attributes attributes){
+ System.out.println("processing split point");
+ if (attributes.getValue("id") != null){
+ String curSplitPoint = attributes.getValue("id");
+ System.out.println("\tcurSplitPoint is: " + curSplitPoint);
+ if (attributes.getValue("location") != null){
+ String curSplitPointLocation = attributes.getValue("location");
+
+ curSplitPointLocation = curSplitPointLocation.replaceAll("\\(L.*","");
+
+ System.out.println("\tcurSplitPointLocation is: " + curSplitPointLocation);
+ GlobalInformation.splitPointToLocation.put(Integer.parseInt(curSplitPoint), curSplitPointLocation);
+ GlobalInformation.numSplitPoints++;
+
+ System.out.println("adding split point and location: " + curSplitPoint + "-->" + curSplitPointLocation);
+ System.out.println("\t(Number of split points is now: " + GlobalInformation.numSplitPoints + ")");
+
+ }
+ }
+ }
+
+ /*
+ * parses the "story" portion of the XML file
+ */
+ private void parseStory(Attributes attributes) {
+ if (attributes.getValue("id") != null){
+ curStoryId = attributes.getValue("id");
+ if (attributes.getValue("literal") != null){
+ curStoryLiteralType = attributes.getValue("literal");
+ GlobalInformation.storiesToLitType.put(curStoryId, curStoryLiteralType);
+
+
+ if (!nameToLitColl.get(curStoryLiteralType).storyToLocations.containsKey(curStoryId)){
+ HashSet<String> insertSet = new HashSet<String>();
+ nameToLitColl.get(curStoryLiteralType).storyToLocations.put(curStoryId, insertSet);
+ }
+
+ }
+ else{
+ curStoryLiteralType = "";
+ }
+ }
+ }
+
+ /*
+ * parses the "correlations" portion of the XML file
+ */
+ private void parseCorrelations(
+ final HashMap<String, CodeCollection> nameToCodeColl,
+ Attributes attributes) {
+
+ if (attributes.getValue("idref") != null){
+
+ String corrClassOrMethod = attributes.getValue("idref");
+
+ String corrClass = attributes.getValue("idref");
+
+ if (corrClass.contains(":")){
+ corrClass = corrClass.replaceAll(":.*", "");
+ }
+
+ if (GlobalInformation.classToPackage.containsKey(corrClass)){ //if we know about this class
+
+ if (! GlobalInformation.storiesToCorrClassesAndMethods.containsKey(curStoryId)){
+ HashSet<String> insertSet = new HashSet<String>();
+ insertSet.add(corrClassOrMethod);
+ GlobalInformation.storiesToCorrClassesAndMethods.put(curStoryId, insertSet);
+ }
+ else{
+ GlobalInformation.storiesToCorrClassesAndMethods.get(curStoryId).add(corrClassOrMethod);
+ }
+
+
+ if (! GlobalInformation.storiesToCorrClasses.containsKey(curStoryId)){
+ HashSet<String> insertSet = new HashSet<String>();
+ insertSet.add(corrClass);
+ GlobalInformation.storiesToCorrClasses.put(curStoryId, insertSet);
+ }
+ else{
+ GlobalInformation.storiesToCorrClasses.get(curStoryId).add(corrClass);
+ }
+
+ for (String codeType : nameToCodeColl.keySet()){
+ if (nameToCodeColl.get(codeType).classes.contains(corrClass)){
+ nameToCodeColl.get(codeType).stories.add(curStoryId);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * parses the "overrides" portion of the XML file
+ */
+ private void parseOverrides(
+ final HashMap<String, CodeCollection> nameToCodeColl,
+ Attributes attributes) {
+ if (attributes.getValue("idref") != null){
+ String overriddenClass = attributes.getValue("idref");
+
+
+ //TODO(kprobst): fix this -- we either generalize to classes, or the numbers are messed up...
+ if (overriddenClass.contains(":")){
+ overriddenClass = overriddenClass.replaceAll(":.*", "");
+ }
+
+ if (overriddenClass.compareTo("com.google.gwt.user.client.ui.UIObject") == 0){
+ nameToCodeColl.get("widget").classes.add(curClassId);
+ }
+ else if (overriddenClass.contains("java.io.Serializable") ||
+ overriddenClass.contains("IsSerializable")){
+ nameToCodeColl.get("rpcUser").classes.add(curClassId);
+ }
+ else if (overriddenClass.contains("com.google.gwt.user.client.rpc.core.java")){
+ nameToCodeColl.get("rpcGwt").classes.add(curClassId);
+ }
+ }
+ }
+
+ /*
+ * parses the "class" portion of the XML file
+ */
+ private void parseClass(
+ final HashMap<String, CodeCollection> nameToCodeColl,
+ Attributes attributes) {
+ if (attributes.getValue("id") != null){
+ curClassId = attributes.getValue("id");
+
+ GlobalInformation.classToPackage.put(curClassId, curPackage);
+
+ if (curPackage.startsWith("java")){
+ nameToCodeColl.get("jre").classes.add(curClassId);
+ }
+ else if (curPackage.startsWith("com.google.gwt.lang")){
+ nameToCodeColl.get("gwtLang").classes.add(curClassId);
+ }
+ if (curClassId.contains("_CustomFieldSerializer")){
+ nameToCodeColl.get("rpcUser").classes.add(curClassId);
+ }
+ else if (curClassId.endsWith("_FieldSerializer") ||
+ curClassId.endsWith("_Proxy") ||
+ curClassId.endsWith("_TypeSerializer")){
+ nameToCodeColl.get("rpcGen").classes.add(curClassId);
+ }
+ }
+ }
+
+ /*
+ * parses the "depends on" portion of the XML file
+ */
+ private void parseDependsOn(final HashMap<String, CodeCollection> nameToCodeColl, Attributes attributes) {
+ if (curFunctionId.compareTo("") == 0){
+ if (attributes.getValue("idref") != null){
+ String curDepClassId = attributes.getValue("idref");
+
+ if (curDepClassId.contains(":")){
+ // strip everything after the :: (to get to class, even if it's a method)
+ curDepClassId = curDepClassId.replaceAll(":.*", "");
+ }
+
+ if (curDepClassId.contains(".")){
+ if (! GlobalInformation.classToWhatItDependsOn.containsKey(curClassId)){
+ HashSet<String> insertSet = new HashSet<String>();
+ insertSet.add(curDepClassId);
+ GlobalInformation.classToWhatItDependsOn.put(curClassId, insertSet);
+ }
+ else{
+ GlobalInformation.classToWhatItDependsOn.get(curClassId).add(curDepClassId);
+ }
+ }
+ }
+ }
+ }
+ };
+ return handler;
+ }
+
+
+
+
+
+
+
+ private static DefaultHandler parseXMLDocumentDependencies(final Map<String, ArrayList<String>> dependencies) {
+
+ DefaultHandler handler = new DefaultHandler() {
+
+ StringBuilder valueBuilder = new StringBuilder();
+ // may want to create a class for this later
+ String curMethod;
+
+ /**
+ * This method deals with the beginning of the XML element.
+ * It analyzes the XML node and adds its information to the relevant literal or code collection for later analysis.
+ * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
+ */
+ @Override
+ public void startElement(String nsUri, String strippedName, String tagName, Attributes attributes) {
+
+ valueBuilder.delete(0,valueBuilder.length());
+
+
+ if ((strippedName.compareTo("method") == 0)&&(attributes.getValue("name") != null)){
+ curMethod = attributes.getValue("name");
+ }
+ else if ((strippedName.compareTo("called") == 0)&&(attributes.getValue("by") != null)){
+ String curDepMethod = attributes.getValue("by");
+ if (!dependencies.containsKey(curMethod)){
+ ArrayList<String> insertArray = new ArrayList<String>();
+ insertArray.add(curDepMethod);
+ dependencies.put(curMethod, insertArray);
+ }
+ else{
+ dependencies.get(curMethod).add(curDepMethod);
+ }
+ }
+ }
+
+ };
+ return handler;
+ }
+
+
+
+
+
+ /*
+ * cleans up the RPC code categories
+ */
+ private static void foldInRPCHeuristic(
+ final HashMap<String, CodeCollection> nameToCodeColl) {
+ /**
+ * Heuristic: this moves all classes that override serializable from RPC to "Other Code" *if* there is no RPC generated code, i.e., if the
+ * application really is not using RPC
+ */
+
+
+ if (nameToCodeColl.get("rpcGen").classes.size() == 0){
+
+ for (String className : nameToCodeColl.get("rpcUser").classes){
+
+ if ((! nameToCodeColl.get("widget").classes.contains(className))&&
+ (! nameToCodeColl.get("jre").classes.contains(className))&&
+ (! nameToCodeColl.get("gwtLang").classes.contains(className))){
+ nameToCodeColl.get("allOther").classes.add(className);
+ }
+ }
+ nameToCodeColl.get("rpcUser").classes.clear();
+
+ for (String className : nameToCodeColl.get("rpcGwt").classes){
+ if ((! nameToCodeColl.get("widget").classes.contains(className))&&
+ (! nameToCodeColl.get("jre").classes.contains(className))&&
+ (! nameToCodeColl.get("gwtLang").classes.contains(className))){
+ nameToCodeColl.get("allOther").classes.add(className);
+ }
+
+ }
+ nameToCodeColl.get("rpcGwt").classes.clear();
+ }
+
+
+ }
+
+
+ /*
+ * generates all the HTML files
+ */
+ private static void makeHTMLFiles(
+ final TreeMap<String, LiteralsCollection> nameToLitColl,
+ final HashMap<String, CodeCollection> nameToCodeColl) {
+
+ try {
+ MakeTopLevelHtmlForPerm.makePackageClassesHtmls();
+ MakeTopLevelHtmlForPerm.makeCodeTypeClassesHtmls(nameToCodeColl);
+ MakeTopLevelHtmlForPerm.makeLiteralsClassesTableHtmls(nameToLitColl);
+ MakeTopLevelHtmlForPerm.makeStringLiteralsClassesTableHtmls(nameToLitColl);
+ // MakeTopLevelHtmlForPerm.makeFragmentClassesHtmls();
+ MakeTopLevelHtmlForPerm.makeSplitPointClassesHtmls();
+ MakeTopLevelHtmlForPerm.makeDependenciesTableHtmls();
+
+ //make the shell last so we can display aggregate information here
+ MakeTopLevelHtmlForPerm.makeHTMLShell(nameToCodeColl, nameToLitColl);
+
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot open file. ", e);
+ }
+ }
+
+
+ /*
+ * assigns code to "all other code" if none of the special categories apply
+ */
+ private static void updateAllOtherCodeType(final HashMap<String, CodeCollection> nameToCodeColl){
+ //all classes not in any of the other categories
+ for (String className : GlobalInformation.classToPackage.keySet()){
+ if ( (!nameToCodeColl.get("widget").classes.contains(className))&&
+ (!nameToCodeColl.get("rpcUser").classes.contains(className))&&
+ (!nameToCodeColl.get("rpcGwt").classes.contains(className))&&
+ (!nameToCodeColl.get("rpcGen").classes.contains(className))&&
+ (!nameToCodeColl.get("jre").classes.contains(className))&&
+ (!nameToCodeColl.get("gwtLang").classes.contains(className))){
+ nameToCodeColl.get("allOther").classes.add(className);
+ }
+ }
+ }
+
+
+ /*
+ * unescape the JS snippets - in the XML file they are XML encoded for correct display, but this
+ * will mess up the byte counts
+ */
+ public static String unEscapeXml(String escaped) {
+ String unescaped = escaped.replaceAll("&","\\&");
+ unescaped = unescaped.replaceAll("<","\\<");
+ unescaped = unescaped.replaceAll(">","\\>");
+ unescaped = unescaped.replaceAll(""","\\\"");
+ //escaped = escaped.replaceAll("\\n", "");
+ unescaped = unescaped.replaceAll("'","\\'");
+ return unescaped;
+ }
+
+
+
+
+}
+
+
+
+
+
diff --git a/user/build.xml b/user/build.xml
index 326563d..196959a 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -133,6 +133,22 @@
</gwt.junit>
</target>
+ <target name="test.web.disableClassMetadata" depends="compile, compile.tests" description="Run only web-mode tests for this project.">
+ <gwt.junit test.args="${test.args} -XdisableClassMetadata -out www -web" test.out="${junit.out}/${build.host.platform}-web-mode-disableClassMetadata" test.cases="default.web.tests" >
+ <extraclasspaths>
+ <pathelement location="${gwt.build}/out/dev/core/bin-test" />
+ </extraclasspaths>
+ </gwt.junit>
+ </target>
+
+ <target name="test.web.draft" depends="compile, compile.tests" description="Run only web-mode tests for this project.">
+ <gwt.junit test.args="${test.args} -draftCompile -out www -web" test.out="${junit.out}/${build.host.platform}-web-mode-draft" test.cases="default.web.tests" >
+ <extraclasspaths>
+ <pathelement location="${gwt.build}/out/dev/core/bin-test" />
+ </extraclasspaths>
+ </gwt.junit>
+ </target>
+
<target name="test" depends="compile, compile.tests" description="Run hosted-mode, web-mode, remoteweb, and selenium tests for this project.">
<property.ensure name="distro.built" location="${gwt.dev.staging.jar}" message="GWT must be built before performing any tests. This can be fixed by running ant in the ${gwt.root} directory." />
@@ -141,13 +157,15 @@
is executing
-->
<limit failonerror="true" hours="2">
- <parallel threadsPerProcessor="1">
+ <parallel threadsPerProcessor="${gwt.threadsPerProcessor}">
<!-- selenium-test is a no-op unless gwt.selenium.hosts is defined -->
<antcall target="selenium-test"/>
<!-- remoteweb-test is a no-op unless gwt.remote.browsers is defined -->
<antcall target="remoteweb-test"/>
<antcall target="test.hosted"/>
<antcall target="test.web"/>
+ <antcall target="test.web.disableClassMetadata"/>
+ <antcall target="test.web.draft"/>
</parallel>
</limit>
</target>
diff --git a/user/src/com/google/gwt/core/Core.gwt.xml b/user/src/com/google/gwt/core/Core.gwt.xml
index fa52b58..b207319 100644
--- a/user/src/com/google/gwt/core/Core.gwt.xml
+++ b/user/src/com/google/gwt/core/Core.gwt.xml
@@ -20,9 +20,15 @@
<module>
<inherits name="com.google.gwt.dev.jjs.intrinsic.Intrinsic" />
<inherits name="com.google.gwt.emul.Emulation" />
- <define-linker name="std" class="com.google.gwt.core.linker.IFrameLinker" />
- <define-linker name="xs" class="com.google.gwt.core.linker.XSLinker" />
+
+ <define-linker name="soycReport" class="com.google.gwt.core.linker.soyc.SoycReportLinker" />
<define-linker name="sso" class="com.google.gwt.core.linker.SingleScriptLinker" />
-
+ <define-linker name="std" class="com.google.gwt.core.linker.IFrameLinker" />
+ <define-linker name="symbolMaps" class="com.google.gwt.core.linker.SymbolMapsLinker" />
+ <define-linker name="xs" class="com.google.gwt.core.linker.XSLinker" />
+
<add-linker name="std" />
+ <add-linker name="soycReport" />
+ <add-linker name="symbolMaps" />
+
</module>
diff --git a/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml b/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml
new file mode 100644
index 0000000..f6a87e2
--- /dev/null
+++ b/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml
@@ -0,0 +1,33 @@
+<!-- -->
+<!-- Copyright 2009 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<!-- Deferred binding rules for core classes based on user agent. -->
+<module>
+ <inherits name="com.google.gwt.core.Core"/>
+
+ <replace-with class="com.google.gwt.core.client.impl.StackTraceCreator.CollectorMoz">
+ <when-type-is class="com.google.gwt.core.client.impl.StackTraceCreator.Collector" />
+ <any>
+ <when-property-is name="user.agent" value="gecko" />
+ <when-property-is name="user.agent" value="gecko1_8" />
+ </any>
+ </replace-with>
+
+ <replace-with class="com.google.gwt.core.client.impl.StackTraceCreator.CollectorOpera">
+ <when-type-is class="com.google.gwt.core.client.impl.StackTraceCreator.Collector" />
+ <any>
+ <when-property-is name="user.agent" value="opera" />
+ </any>
+ </replace-with>
+</module>
\ No newline at end of file
diff --git a/user/src/com/google/gwt/core/client/AsyncFragmentLoader.java b/user/src/com/google/gwt/core/client/AsyncFragmentLoader.java
new file mode 100644
index 0000000..829cfc6
--- /dev/null
+++ b/user/src/com/google/gwt/core/client/AsyncFragmentLoader.java
@@ -0,0 +1,246 @@
+/*
+ * 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.core.client;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * <p>
+ * Low-level support to download an extra fragment of code. This should not be
+ * invoked directly by user code.
+ * </p>
+ *
+ * <p>
+ * The fragments are numbered as follows, assuming there are <em>m</em> split
+ * points:
+ *
+ * <ul>
+ * <li>0 -- the <em>base</em> fragment, which is initially downloaded
+ * <li>1-m -- the <em>exclusively live</em> fragments, holding the code needed
+ * exclusively for each split point
+ * <li>m -- the <em>secondary base</em> fragment for entry point 1. It holds
+ * precisely that code needed if entry point 1 is the first one reached after
+ * the application downloads.
+ * <li>m+1 -- the <em>leftovers fragment</em> for entry point 1. It holds all
+ * code not in fragments 0-(m-1) nor in fragment m.
+ * <li>(m+2)..(3m) -- secondary bases and leftovers for entry points 2..m
+ * </ul>
+ *
+ * <p>
+ * Different linkers have different requirements about how the code is
+ * downloaded and installed. Thus, when it is time to actually download the
+ * code, this class defers to a JavaScript function named
+ * <code>__gwtStartLoadingFragment</code>. Linkers must arrange that a suitable
+ * <code>__gwtStartLoadingFragment</code> function is in scope.
+ */
+public class AsyncFragmentLoader {
+ /**
+ * Labels used for runAsync lightweight metrics.
+ */
+ public static class LwmLabels {
+ public static final String BEGIN = "begin";
+
+ public static final String END = "end";
+
+ private static final String LEFTOVERS_DOWNLOAD = "leftoversDownload";
+
+ /**
+ * @param splitPoint
+ * @return
+ */
+ private static String downloadGroup(int splitPoint) {
+ return "download" + splitPoint;
+ }
+ }
+
+ /**
+ * The first entry point reached after the program started.
+ */
+ private static int base = -1;
+
+ /**
+ * Whether the secondary base fragment is currently loading.
+ */
+ private static boolean baseLoading = false;
+
+ /**
+ * Whether the leftovers fragment has loaded yet.
+ */
+ private static boolean leftoversLoaded = false;
+
+ /**
+ * Whether the leftovers fragment is currently loading.
+ */
+ private static boolean leftoversLoading = false;
+
+ /**
+ * The total number of split points in the program, counting the initial entry
+ * as a split point. This is changed to the correct value by
+ * {@link com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs}.
+ */
+ private static int numEntries = 1;
+
+ /**
+ * Split points that have been reached, but that cannot be downloaded until
+ * the leftovers fragment finishes downloading.
+ */
+ private static Queue<Integer> waitingForLeftovers = new LinkedList<Integer>();
+
+ /**
+ * Inform the loader that the code for an entry point has now finished
+ * loading.
+ *
+ * @param entry The entry whose code fragment is now loaded.
+ */
+ public static void fragmentHasLoaded(int entry) {
+ int fragment = base >= 0 ? entry : baseFragmentNumber(entry);
+ logEventProgress(LwmLabels.downloadGroup(entry), LwmLabels.END, fragment,
+ null);
+
+ if (base < 0) {
+ // The base fragment has loaded
+ base = entry;
+ baseLoading = false;
+
+ // Go ahead and download the appropriate leftovers fragment
+ leftoversLoading = true;
+ logEventProgress(LwmLabels.LEFTOVERS_DOWNLOAD, LwmLabels.BEGIN,
+ leftoversFragmentNumber(), null);
+ startLoadingFragment(leftoversFragmentNumber());
+ }
+ }
+
+ /**
+ * Loads the specified split point.
+ *
+ * @param splitPoint the fragment to load
+ */
+ public static void inject(int splitPoint) {
+ if (leftoversLoaded) {
+ /*
+ * A base and a leftovers fragment have loaded. Load an exclusively live
+ * fragment.
+ */
+ logEventProgress(LwmLabels.downloadGroup(splitPoint), LwmLabels.BEGIN,
+ splitPoint, null);
+ startLoadingFragment(splitPoint);
+ return;
+ }
+
+ if (baseLoading || leftoversLoading) {
+ /*
+ * Wait until the leftovers fragment has loaded before loading this one.
+ */
+ waitingForLeftovers.add(splitPoint);
+ return;
+ }
+
+ // Nothing has loaded or started to load. Treat this fragment as the base.
+ baseLoading = true;
+ logEventProgress(LwmLabels.downloadGroup(splitPoint), LwmLabels.BEGIN,
+ baseFragmentNumber(splitPoint), null);
+ startLoadingFragment(baseFragmentNumber(splitPoint));
+ }
+
+ /**
+ * Inform the loader that the "leftovers" fragment has loaded.
+ */
+ public static void leftoversFragmentHasLoaded() {
+ leftoversLoaded = true;
+ leftoversLoading = false;
+ logEventProgress(LwmLabels.LEFTOVERS_DOWNLOAD, LwmLabels.END,
+ leftoversFragmentNumber(), null);
+
+ while (!waitingForLeftovers.isEmpty()) {
+ inject(waitingForLeftovers.remove());
+ }
+ }
+
+ /**
+ * Log an event with the lightweight metrics framework.
+ */
+ public static void logEventProgress(String eventGroup, String type) {
+ logEventProgress(eventGroup, type, null, null);
+ }
+
+ /**
+ * Compute the fragment number for the base fragment of
+ * <code>splitPoint</code>.
+ */
+ private static int baseFragmentNumber(int splitPoint) {
+ return numEntries + 2 * (splitPoint - 1);
+ }
+
+ private static native JavaScriptObject createStatsEvent(String eventGroup,
+ String type, Integer fragment, Integer size) /*-{
+ var evt = {
+ moduleName: @com.google.gwt.core.client.GWT::getModuleName()(),
+ subSystem: 'runAsync',
+ evtGroup: eventGroup,
+ millis: (new Date()).getTime(),
+ type: type
+ };
+ if (fragment != null) {
+ evt.fragment = fragment.@java.lang.Integer::intValue()();
+ }
+ if (size != null) {
+ evt.size = size.@java.lang.Integer::intValue()();
+ }
+ return evt;
+ }-*/;
+
+ private static native void gwtStartLoadingFragment(int fragment) /*-{
+ __gwtStartLoadingFragment(fragment);
+ }-*/;
+
+ private static native boolean isStatsAvailable() /*-{
+ return !!$stats;
+ }-*/;
+
+ /**
+ * Compute the leftovers fragment number. This method can only be called once
+ * <code>base</code> has been set.
+ */
+ private static int leftoversFragmentNumber() {
+ assert (base >= 0);
+ return numEntries + 2 * (base - 1) + 1;
+ }
+
+ /**
+ * Log an event with the lightweight metrics framework. The
+ * <code>fragment</code> and <code>size</code> objects are allowed to be
+ * <code>null</code>.
+ */
+ private static void logEventProgress(String eventGroup, String type,
+ Integer fragment, Integer size) {
+ @SuppressWarnings("unused")
+ boolean toss = isStatsAvailable()
+ && stats(createStatsEvent(eventGroup, type, fragment, size));
+ }
+
+ private static void startLoadingFragment(int fragment) {
+ gwtStartLoadingFragment(fragment);
+ }
+
+ /**
+ * Always use this as {@link isStatsAvailable} &&
+ * {@link #stats(JavaScriptObject)}.
+ */
+ private static native boolean stats(JavaScriptObject data) /*-{
+ return $stats(data);
+ }-*/;
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/core/client/GWT.java b/user/src/com/google/gwt/core/client/GWT.java
index a1c5c0b..06c9860 100644
--- a/user/src/com/google/gwt/core/client/GWT.java
+++ b/user/src/com/google/gwt/core/client/GWT.java
@@ -50,6 +50,12 @@
}
/**
+ * This constant is used by {@link #getPermutationStrongName} when running in
+ * hosted mode.
+ */
+ public static final String HOSTED_MODE_PERMUTATION_STRONG_NAME = "HostedMode";
+
+ /**
* Always <code>null</code> in web mode; in hosted mode provides the
* implementation for certain methods.
*/
@@ -123,6 +129,19 @@
}
/**
+ * Returns the permutation's strong name. This can be used to distinguish
+ * between different permutations of the same module. In hosted mode, this
+ * method will return {@value #HOSTED_MODE_PERMUTATION_ID}.
+ */
+ public static String getPermutationStrongName() {
+ if (GWT.isScript()) {
+ return Impl.getPermutationStrongName();
+ } else {
+ return HOSTED_MODE_PERMUTATION_STRONG_NAME;
+ }
+ }
+
+ /**
* @deprecated Use {@link Object#getClass()}, {@link Class#getName()}
*/
@Deprecated
@@ -184,6 +203,27 @@
}
/**
+ * Run the specified callback once the necessary code for it has been loaded.
+ */
+ public static void runAsync(RunAsyncCallback callback) {
+ /*
+ * By default, just call the callback. This allows using
+ * <code>runAsync</code> in code that might or might not run in a web
+ * browser.
+ */
+ UncaughtExceptionHandler handler = sUncaughtExceptionHandler;
+ if (handler == null) {
+ callback.onSuccess();
+ } else {
+ try {
+ callback.onSuccess();
+ } catch (Throwable e) {
+ handler.onUncaughtException(e);
+ }
+ }
+ }
+
+ /**
* Sets a custom uncaught exception handler. See
* {@link #getUncaughtExceptionHandler()} for details.
*
diff --git a/user/src/com/google/gwt/core/client/HttpThrowableReporter.java b/user/src/com/google/gwt/core/client/HttpThrowableReporter.java
new file mode 100644
index 0000000..5088667
--- /dev/null
+++ b/user/src/com/google/gwt/core/client/HttpThrowableReporter.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2009 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.core.client;
+
+import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
+import com.google.gwt.xhr.client.XMLHttpRequest;
+
+/**
+ * This is a utility class which can report Throwables to the server via a
+ * JSON-formatted payload.
+ */
+public final class HttpThrowableReporter {
+
+ private static class MyHandler implements UncaughtExceptionHandler {
+ private final String url;
+
+ public MyHandler(String url) {
+ this.url = url;
+ }
+
+ public void onUncaughtException(Throwable e) {
+ report(url, e);
+ }
+ }
+
+ /**
+ * Installs an {@link UncaughtExceptionHandler} that will automatically invoke
+ * {@link #report(String, Throwable)}.
+ *
+ * @param url A URL that is suitable for use with {@link XMLHttpRequest}
+ */
+ public static void installUncaughtExceptionHandler(String url) {
+ GWT.setUncaughtExceptionHandler(new MyHandler(url));
+ }
+
+ /**
+ * Report a Throwable to the server. This method will sent an HTTP
+ * <code>POST</code> request with a JSON-formatted payload. The payload will
+ * consist of a single JSON object with the following keys:
+ * <dl>
+ * <dt>strongName</dt>
+ * <dd>The result of calling {@link GWT#getPermutationStrongName()}</dd>
+ * <dt>message</dt>
+ * <dd>The result of calling {@link Throwable#getMessage()}</dd>
+ * <dt>stackTrace</dt>
+ * <dd>A list of the methods names in the Throwable's stack trace, derived
+ * from {@link StackTraceElement#getMethodName()}.</dd>
+ * </dl>
+ *
+ * The response from the server is ignored.
+ *
+ * @param url A URL that is suitable for use with {@link XMLHttpRequest}
+ * @param t The Throwable to report
+ * @return <code>true</code> if the request was successfully initiated
+ * @see com.google.gwt.core.linker.SymbolMapsLinker
+ */
+ public static boolean report(String url, Throwable t) {
+ try {
+ XMLHttpRequest xhr = XMLHttpRequest.create();
+ xhr.open("POST", url);
+ xhr.send(buildPayload(t));
+ return true;
+ } catch (Throwable t2) {
+ return false;
+ }
+ }
+
+ /**
+ * Visible for testing.
+ */
+ static String buildPayload(Throwable t) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("{\"strongName\" : ");
+ sb.append(JsonUtils.escapeValue(GWT.getPermutationStrongName()));
+ sb.append(",\"message\" : ");
+ sb.append(JsonUtils.escapeValue(t.getMessage()));
+
+ sb.append(",\"stackTrace\" : [");
+ boolean needsComma = false;
+ for (StackTraceElement e : t.getStackTrace()) {
+ if (needsComma) {
+ sb.append(",");
+ } else {
+ needsComma = true;
+ }
+
+ sb.append(JsonUtils.escapeValue(e.getMethodName()));
+ }
+ sb.append("]}");
+
+ return sb.toString();
+ }
+
+ private HttpThrowableReporter() {
+ }
+}
diff --git a/user/src/com/google/gwt/core/client/JavaScriptException.java b/user/src/com/google/gwt/core/client/JavaScriptException.java
index ba1d750..2284d0e 100644
--- a/user/src/com/google/gwt/core/client/JavaScriptException.java
+++ b/user/src/com/google/gwt/core/client/JavaScriptException.java
@@ -15,12 +15,33 @@
*/
package com.google.gwt.core.client;
+import com.google.gwt.core.client.impl.StackTraceCreator;
+
/**
* Any JavaScript exceptions occurring within JSNI methods are wrapped as this
* class when caught in Java code. The wrapping does not occur until the
* exception passes out of JSNI into Java. Before that, the thrown object
* remains a native JavaScript exception object, and can be caught in JSNI as
* normal.
+ * <p>
+ * The return value of {@link #getStackTrace()} may vary between browsers due to
+ * variations in the underlying error-reporting capabilities. When possible, the
+ * stack trace will be the stack trace of the underlying error object. If it is
+ * not possible to accurately report a stack trace, a zero-length array will be
+ * returned. In those cases where the underlying stack trace cannot be
+ * determined, {@link #fillInStackTrace()} can be called in the associated catch
+ * block to create a stack trace corresponding to the location where the
+ * JavaScriptException object was created.
+ *
+ * <pre>
+ * try {
+ * nativeMethod();
+ * } catch (JavaScriptException e) {
+ * if (e.getStackTrace().length == 0) {
+ * e.fillInStackTrace();
+ * }
+ * }
+ * </pre>
*/
public final class JavaScriptException extends RuntimeException {
@@ -105,6 +126,17 @@
*/
public JavaScriptException(Object e) {
this.e = e;
+ /*
+ * In hosted mode, JavaScriptExceptions are created exactly when the native
+ * method returns and their stack traces are fixed-up by the hosted-mode
+ * plumbing.
+ *
+ * In web mode, we'll attempt to infer the stack trace from the thrown
+ * object, although this is not possible in all browsers.
+ */
+ if (GWT.isScript()) {
+ StackTraceCreator.createStackTrace(this);
+ }
}
public JavaScriptException(String name, String description) {
@@ -163,7 +195,7 @@
}
return name;
}
-
+
private void init() {
name = getName(e);
description = getDescription(e);
diff --git a/user/src/com/google/gwt/core/client/JsonUtils.java b/user/src/com/google/gwt/core/client/JsonUtils.java
new file mode 100644
index 0000000..c205ece
--- /dev/null
+++ b/user/src/com/google/gwt/core/client/JsonUtils.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009 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.core.client;
+
+/**
+ * Provides JSON-related utility methods.
+ */
+public class JsonUtils {
+ @SuppressWarnings("unused")
+ private static JavaScriptObject escapeTable = initEscapeTable();
+
+ /**
+ * Returns a quoted, escaped JSON String.
+ */
+ public static native String escapeValue(String toEscape) /*-{
+ var s = toEscape.replace(/[\x00-\x1F\u2028\u2029"\\]/g, function(x) {
+ return @com.google.gwt.core.client.JsonUtils::escapeChar(Ljava/lang/String;)(x);
+ });
+ return "\"" + s + "\"";
+ }-*/;
+
+ /*
+ * TODO: Implement safeEval using a proper parser.
+ */
+
+ /**
+ * Evaluates a JSON expression. This method does not validate the JSON text
+ * and should only be used on JSON from trusted sources.
+ *
+ * @param <T> The type of JavaScriptObject that should be returned
+ * @param json The source JSON text
+ * @return The evaluated object
+ */
+ public static native <T extends JavaScriptObject> T unsafeEval(String json) /*-{
+ return eval('(' + json + ')');
+ }-*/;
+
+ @SuppressWarnings("unused")
+ private static native String escapeChar(String c) /*-{
+ var lookedUp = @com.google.gwt.core.client.JsonUtils::escapeTable[c.charCodeAt(0)];
+ return (lookedUp == null) ? c : lookedUp;
+ }-*/;
+
+ private static native JavaScriptObject initEscapeTable() /*-{
+ var out = [
+ "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005",
+ "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000B",
+ "\\f", "\\r", "\\u000E", "\\u000F", "\\u0010", "\\u0011",
+ "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017",
+ "\\u0018", "\\u0019", "\\u001A", "\\u001B", "\\u001C", "\\u001D",
+ "\\u001E", "\\u001F"];
+ out[34] = '\\"';
+ out[92] = '\\\\';
+
+ // Unicode line separator chars
+ out[0x2028] = '\\u2028';
+ out[0x2029] = '\\u2029';
+ return out;
+ }-*/;
+
+ private JsonUtils() {
+ }
+}
diff --git a/user/src/com/google/gwt/core/client/RunAsyncCallback.java b/user/src/com/google/gwt/core/client/RunAsyncCallback.java
new file mode 100644
index 0000000..4c76817
--- /dev/null
+++ b/user/src/com/google/gwt/core/client/RunAsyncCallback.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.core.client;
+
+/**
+ * A callback meant to be used by
+ * {@link com.google.gwt.core.client.GWT#runAsync(RunAsyncCallback) }.
+ */
+public interface RunAsyncCallback {
+ /**
+ * Called when, for some reason, the necessary code cannot be loaded. For
+ * example, the user might no longer be on the network.
+ */
+ void onFailure(Throwable caught);
+
+ /**
+ * Called once the necessary code for it has been loaded.
+ */
+ void onSuccess();
+}
diff --git a/user/src/com/google/gwt/core/client/impl/Impl.java b/user/src/com/google/gwt/core/client/impl/Impl.java
index ab05a2f..2bbeb48 100644
--- a/user/src/com/google/gwt/core/client/impl/Impl.java
+++ b/user/src/com/google/gwt/core/client/impl/Impl.java
@@ -28,6 +28,9 @@
* expando. This method should not be used with <code>null</code> or any
* String. The former will crash and the later will produce unstable results
* when called repeatedly with a String primitive.
+ * <p>
+ * The sequence of hashcodes generated by this method are a
+ * monotonically-increasing sequence.
*/
public static native int getHashCode(Object o) /*-{
return o.$H || (o.$H = @com.google.gwt.core.client.impl.Impl::getNextHashId()());
@@ -50,7 +53,7 @@
i = s.lastIndexOf('/');
if (i != -1)
s = s.substring(0, i);
-
+
// Ensure a final slash if non-empty.
return s.length > 0 ? s + "/" : "";
}-*/;
@@ -63,8 +66,15 @@
return $moduleName;
}-*/;
+ public static native String getPermutationStrongName() /*-{
+ return $strongName;
+ }-*/;
+
/**
- * Called from JSNI.
+ * Called from JSNI. Do not change this implementation without updating:
+ * <ul>
+ * <li>{@link com.google.gwt.user.client.rpc.impl.SerializerBase}</li>
+ * </ul>
*/
@SuppressWarnings("unused")
private static int getNextHashId() {
diff --git a/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java b/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java
new file mode 100644
index 0000000..42af02a
--- /dev/null
+++ b/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2009 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.core.client.impl;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JavaScriptException;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
+
+/**
+ * Encapsulates logic to create a stack trace. This class should only be used in
+ * web mode.
+ */
+public class StackTraceCreator {
+ /**
+ * This class acts as a deferred-binding hook point to allow more optimal
+ * versions to be substituted. This base version simply crawls
+ * <code>arguments.callee.caller</code>.
+ */
+ static class Collector {
+ public native JsArrayString collect() /*-{
+ var seen = {};
+ var toReturn = [];
+
+ // Ignore the collect() and fillInStackTrace call
+ var callee = arguments.callee.caller.caller;
+ while (callee) {
+ var name = this.@com.google.gwt.core.client.impl.StackTraceCreator.Collector::extractName(Ljava/lang/String;)(callee.toString());
+ toReturn.push(name);
+
+ // Avoid infinite loop by associating names to function objects. We
+ // record each caller in the withThisName variable to handle functions
+ // with identical names but separate identity (such as 'anonymous')
+ var keyName = ':' + name;
+ var withThisName = seen[keyName];
+ if (withThisName) {
+ var i, j;
+ for (i = 0, j = withThisName.length; i < j; i++) {
+ if (withThisName[i] === callee) {
+ return toReturn;
+ }
+ }
+ }
+
+ (withThisName || (seen[keyName] = [])).push(callee);
+ callee = callee.caller;
+ }
+ return toReturn;
+ }-*/;
+
+ /**
+ * Attempt to infer the stack from an unknown JavaScriptObject that had been
+ * thrown. The default implementation just returns an empty array.
+ */
+ public JsArrayString inferFrom(JavaScriptObject e) {
+ return JavaScriptObject.createArray().cast();
+ }
+
+ /**
+ * Extract the name of a function from it's toString() representation.
+ * Package-access for testing.
+ */
+ protected String extractName(String fnToString) {
+ return extractNameFromToString(fnToString);
+ }
+
+ /**
+ * Raise an exception and return it.
+ */
+ protected native JavaScriptObject makeException() /*-{
+ try {
+ null.a();
+ } catch (e) {
+ return e;
+ }
+ }-*/;
+ }
+
+ /**
+ * Mozilla provides a <code>stack</code> property in thrown objects.
+ */
+ static class CollectorMoz extends Collector {
+ /**
+ * This implementation doesn't suffer from the limitations of crawling
+ * <code>caller</code> since Mozilla provides proper activation records.
+ */
+ @Override
+ public JsArrayString collect() {
+ return splice(inferFrom(makeException()), toSplice());
+ }
+
+ @Override
+ public JsArrayString inferFrom(JavaScriptObject e) {
+ JsArrayString stack = getStack(e);
+ for (int i = 0, j = stack.length(); i < j; i++) {
+ stack.set(i, extractName(stack.get(i)));
+ }
+ return stack;
+ }
+
+ protected native JsArrayString getStack(JavaScriptObject e) /*-{
+ return (e && e.stack) ? e.stack.split('\n') : [];
+ }-*/;
+
+ protected int toSplice() {
+ return 2;
+ }
+ }
+
+ /**
+ * Opera encodes stack trace information in the error's message.
+ */
+ static class CollectorOpera extends CollectorMoz {
+ /**
+ * We have much a much simpler format to work with.
+ */
+ @Override
+ protected String extractName(String fnToString) {
+ return fnToString.length() == 0 ? "anonymous" : fnToString;
+ }
+
+ /**
+ * Opera has the function name on every-other line.
+ */
+ @Override
+ protected JsArrayString getStack(JavaScriptObject e) {
+ JsArrayString toReturn = getMessage(e);
+ assert toReturn.length() % 2 == 0 : "Expecting an even number of lines";
+
+ int i, i2, j;
+ for (i = 0, i2 = 0, j = toReturn.length(); i2 < j; i++, i2 += 2) {
+ int idx = toReturn.get(i2).lastIndexOf("function ");
+ if (idx == -1) {
+ toReturn.set(i, "");
+ } else {
+ toReturn.set(i, toReturn.get(i2).substring(idx + 9).trim());
+ }
+ }
+ setLength(toReturn, i);
+
+ return toReturn;
+ }
+
+ @Override
+ protected int toSplice() {
+ return 3;
+ }
+
+ private native JsArrayString getMessage(JavaScriptObject e) /*-{
+ return (e && e.message) ? e.message.split('\n') : [];
+ }-*/;
+
+ private native void setLength(JsArrayString obj, int length) /*-{
+ obj.length = length;
+ }-*/;
+ }
+
+ /**
+ * Create a stack trace based on the current execution stack. This method
+ * should only be called in web mode.
+ */
+ public static JsArrayString createStackTrace() {
+ if (!GWT.isScript()) {
+ throw new RuntimeException(
+ "StackTraceCreator should only be called in web mode");
+ }
+
+ return GWT.<Collector> create(Collector.class).collect();
+ }
+
+ /**
+ * Create a stack trace based on a JavaScriptException. This method should
+ * only be called in web mode.
+ */
+ public static void createStackTrace(JavaScriptException e) {
+ if (!GWT.isScript()) {
+ throw new RuntimeException(
+ "StackTraceCreator should only be called in web mode");
+ }
+
+ JsArrayString stack = GWT.<Collector> create(Collector.class).inferFrom(
+ e.getException());
+
+ StackTraceElement[] stackTrace = new StackTraceElement[stack.length()];
+ for (int i = 0, j = stackTrace.length; i < j; i++) {
+ stackTrace[i] = new StackTraceElement("Unknown", stack.get(i),
+ "Unknown source", 0);
+ }
+ e.setStackTrace(stackTrace);
+ }
+
+ static String extractNameFromToString(String fnToString) {
+ String toReturn = "";
+ fnToString = fnToString.trim();
+ int index = fnToString.indexOf("(");
+ if (index != -1) {
+ int start = fnToString.startsWith("function") ? 8 : 0;
+ toReturn = fnToString.substring(start, index).trim();
+ }
+
+ return toReturn.length() > 0 ? toReturn : "anonymous";
+ }
+
+ private static native JsArrayString splice(JsArrayString arr, int length) /*-{
+ (arr.length >= length) && arr.splice(0, length);
+ return arr;
+ }-*/;
+}
diff --git a/user/src/com/google/gwt/http/HTTP.gwt.xml b/user/src/com/google/gwt/http/HTTP.gwt.xml
index 76d3238..c212dd4 100644
--- a/user/src/com/google/gwt/http/HTTP.gwt.xml
+++ b/user/src/com/google/gwt/http/HTTP.gwt.xml
@@ -18,5 +18,10 @@
<!-- package must inherit this module. -->
<!-- -->
<module>
- <inherits name="com.google.gwt.core.Core"/>
+ <inherits name="com.google.gwt.core.Core"/>
+ <inherits name="com.google.gwt.xhr.XMLHttpRequest"/>
+
+ <!-- Inheriting User module for Window and Timer. These should be factored
+ out of User soon. -->
+ <inherits name="com.google.gwt.user.User"/>
</module>
diff --git a/user/src/com/google/gwt/http/client/Request.java b/user/src/com/google/gwt/http/client/Request.java
index ddc8ecd..fd0ea9d 100644
--- a/user/src/com/google/gwt/http/client/Request.java
+++ b/user/src/com/google/gwt/http/client/Request.java
@@ -16,22 +16,23 @@
package com.google.gwt.http.client;
import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.user.client.Timer;
+import com.google.gwt.xhr.client.XMLHttpRequest;
/**
* An HTTP request that is waiting for a response. Requests can be queried for
* their pending status or they can be canceled.
*
- * <h3>Required Module</h3>
- * Modules that use this class should inherit
+ * <h3>Required Module</h3> Modules that use this class should inherit
* <code>com.google.gwt.http.HTTP</code>.
*
- * {@gwt.include com/google/gwt/examples/http/InheritsExample.gwt.xml}
+ * {@gwt.include
+ * com/google/gwt/examples/http/InheritsExample.gwt.xml}
*
*/
public class Request {
+
/**
* Creates a {@link Response} instance for the given JavaScript XmlHttpRequest
* object.
@@ -39,45 +40,98 @@
* @param xmlHttpRequest xmlHttpRequest object for which we need a response
* @return a {@link Response} object instance
*/
- private static Response createResponse(final JavaScriptObject xmlHttpRequest) {
- assert (XMLHTTPRequest.isResponseReady(xmlHttpRequest));
+ private static Response createResponse(final XMLHttpRequest xmlHttpRequest) {
+ assert (isResponseReady(xmlHttpRequest));
Response response = new Response() {
@Override
public String getHeader(String header) {
StringValidator.throwIfEmptyOrNull("header", header);
- return XMLHTTPRequest.getResponseHeader(xmlHttpRequest, header);
+ return xmlHttpRequest.getResponseHeader(header);
}
@Override
public Header[] getHeaders() {
- return XMLHTTPRequest.getHeaders(xmlHttpRequest);
+ return Request.getHeaders(xmlHttpRequest);
}
@Override
public String getHeadersAsString() {
- return XMLHTTPRequest.getAllResponseHeaders(xmlHttpRequest);
+ return xmlHttpRequest.getAllResponseHeaders();
}
@Override
public int getStatusCode() {
- return XMLHTTPRequest.getStatusCode(xmlHttpRequest);
+ return xmlHttpRequest.getStatus();
}
@Override
public String getStatusText() {
- return XMLHTTPRequest.getStatusText(xmlHttpRequest);
+ return xmlHttpRequest.getStatusText();
}
@Override
public String getText() {
- return XMLHTTPRequest.getResponseText(xmlHttpRequest);
+ return xmlHttpRequest.getResponseText();
}
};
return response;
}
/**
+ * Returns an array of headers built by parsing the string of headers returned
+ * by the JavaScript <code>XmlHttpRequest</code> object.
+ *
+ * @param xmlHttpRequest
+ * @return array of Header items
+ */
+ private static Header[] getHeaders(XMLHttpRequest xmlHttp) {
+ String allHeaders = xmlHttp.getAllResponseHeaders();
+ String[] unparsedHeaders = allHeaders.split("\n");
+ Header[] parsedHeaders = new Header[unparsedHeaders.length];
+
+ for (int i = 0, n = unparsedHeaders.length; i < n; ++i) {
+ String unparsedHeader = unparsedHeaders[i];
+
+ if (unparsedHeader.length() == 0) {
+ continue;
+ }
+
+ int endOfNameIdx = unparsedHeader.indexOf(':');
+ if (endOfNameIdx < 0) {
+ continue;
+ }
+
+ final String name = unparsedHeader.substring(0, endOfNameIdx).trim();
+ final String value = unparsedHeader.substring(endOfNameIdx + 1).trim();
+ Header header = new Header() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return name + " : " + value;
+ }
+ };
+
+ parsedHeaders[i] = header;
+ }
+
+ return parsedHeaders;
+ }
+
+ private static boolean isResponseReady(XMLHttpRequest xhr) {
+ return xhr.getReadyState() == XMLHttpRequest.DONE;
+ }
+
+ /**
* The number of milliseconds to wait for this HTTP request to complete.
*/
private final int timeoutMillis;
@@ -93,7 +147,7 @@
* not final because we transfer ownership of it to the HTTPResponse object
* and set this field to null.
*/
- private JavaScriptObject xmlHttpRequest;
+ private XMLHttpRequest xmlHttpRequest;
/**
* Constructs an instance of the Request object.
@@ -105,7 +159,7 @@
* @throws IllegalArgumentException if timeoutMillis < 0
* @throws NullPointerException if xmlHttpRequest, or callback are null
*/
- Request(JavaScriptObject xmlHttpRequest, int timeoutMillis,
+ Request(XMLHttpRequest xmlHttpRequest, int timeoutMillis,
final RequestCallback callback) {
if (xmlHttpRequest == null) {
throw new NullPointerException();
@@ -157,10 +211,11 @@
* this in Java by nulling out our reference to the XmlHttpRequest object.
*/
if (xmlHttpRequest != null) {
- JavaScriptObject xmlHttp = xmlHttpRequest;
+ XMLHttpRequest xmlHttp = xmlHttpRequest;
xmlHttpRequest = null;
- XMLHTTPRequest.abort(xmlHttp);
+ xmlHttp.clearOnReadyStateChange();
+ xmlHttp.abort();
cancelTimer();
}
@@ -176,19 +231,19 @@
return false;
}
- int readyState = XMLHTTPRequest.getReadyState(xmlHttpRequest);
+ int readyState = xmlHttpRequest.getReadyState();
/*
* Because we are doing asynchronous requests it is possible that we can
* call XmlHttpRequest.send and still have the XmlHttpRequest.getReadyState
* method return the state as XmlHttpRequest.OPEN. That is why we include
- * open although it is not *technically* true since open implies that the
+ * open although it is nottechnically true since open implies that the
* request has not been sent.
*/
switch (readyState) {
- case XMLHTTPRequest.OPEN:
- case XMLHTTPRequest.SENT:
- case XMLHTTPRequest.RECEIVING:
+ case XMLHttpRequest.OPENED:
+ case XMLHttpRequest.HEADERS_RECEIVED:
+ case XMLHttpRequest.LOADING:
return true;
}
@@ -196,6 +251,19 @@
}
/*
+ * Method called when the JavaScript XmlHttpRequest object's readyState
+ * reaches 4 (LOADED).
+ */
+ void fireOnResponseReceived(RequestCallback callback) {
+ UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();
+ if (handler != null) {
+ fireOnResponseReceivedAndCatch(handler, callback);
+ } else {
+ fireOnResponseReceivedImpl(callback);
+ }
+ }
+
+ /*
* Stops the current HTTPRequest timer if there is one.
*/
private void cancelTimer() {
@@ -204,22 +272,6 @@
}
}
- /*
- * Method called when the JavaScript XmlHttpRequest object's readyState
- * reaches 4 (LOADED).
- *
- * NOTE: this method is called from JSNI
- */
- @SuppressWarnings("unused")
- private void fireOnResponseReceived(RequestCallback callback) {
- UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();
- if (handler != null) {
- fireOnResponseReceivedAndCatch(handler, callback);
- } else {
- fireOnResponseReceivedImpl(callback);
- }
- }
-
private void fireOnResponseReceivedAndCatch(UncaughtExceptionHandler handler,
RequestCallback callback) {
try {
@@ -242,15 +294,15 @@
* JavaScript XmlHttpRequest object so we manually null out our reference to
* the JavaScriptObject
*/
- final JavaScriptObject xmlHttp = xmlHttpRequest;
+ final XMLHttpRequest xhr = xmlHttpRequest;
xmlHttpRequest = null;
- String errorMsg = XMLHTTPRequest.getBrowserSpecificFailure(xmlHttp);
+ String errorMsg = getBrowserSpecificFailure(xhr);
if (errorMsg != null) {
Throwable exception = new RuntimeException(errorMsg);
callback.onError(this, exception);
} else {
- Response response = createResponse(xmlHttp);
+ Response response = createResponse(xhr);
callback.onResponseReceived(this, response);
}
}
@@ -270,4 +322,41 @@
callback.onError(this, new RequestTimeoutException(this, timeoutMillis));
}
+
+ /**
+ * Tests if the JavaScript <code>XmlHttpRequest.status</code> property is
+ * readable. This can return failure in two different known scenarios:
+ *
+ * <ol>
+ * <li>On Mozilla, after a network error, attempting to read the status code
+ * results in an exception being thrown. See <a
+ * href="https://bugzilla.mozilla.org/show_bug.cgi?id=238559">https://bugzilla.mozilla.org/show_bug.cgi?id=238559</a>.
+ * </li>
+ * <li>On Safari, if the HTTP response does not include any response text.
+ * See <a
+ * href="http://bugs.webkit.org/show_bug.cgi?id=3810">http://bugs.webkit.org/show_bug.cgi?id=3810</a>.
+ * </li>
+ * </ol>
+ *
+ * @param xhr the JavaScript <code>XmlHttpRequest</code> object
+ * to test
+ * @return a String message containing an error message if the
+ * <code>XmlHttpRequest.status</code> code is unreadable or null if
+ * the status code could be successfully read.
+ */
+ private native String getBrowserSpecificFailure(
+ XMLHttpRequest xhr) /*-{
+ try {
+ if (xhr.status === undefined) {
+ return "XmlHttpRequest.status == undefined, please see Safari bug " +
+ "http://bugs.webkit.org/show_bug.cgi?id=3810 for more details";
+ }
+ return null;
+ } catch (e) {
+ return "Unable to read XmlHttpRequest.status; likely causes are a " +
+ "networking error or bad cross-domain request. Please see " +
+ "https://bugzilla.mozilla.org/show_bug.cgi?id=238559 for more " +
+ "details";
+ }
+ }-*/;
}
diff --git a/user/src/com/google/gwt/http/client/RequestBuilder.java b/user/src/com/google/gwt/http/client/RequestBuilder.java
index 91ab448..38a9fb6 100644
--- a/user/src/com/google/gwt/http/client/RequestBuilder.java
+++ b/user/src/com/google/gwt/http/client/RequestBuilder.java
@@ -15,9 +15,9 @@
*/
package com.google.gwt.http.client;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.user.client.impl.HTTPRequestImpl;
+import com.google.gwt.core.client.JavaScriptException;
+import com.google.gwt.xhr.client.ReadyStateChangeHandler;
+import com.google.gwt.xhr.client.XMLHttpRequest;
import java.util.HashMap;
import java.util.Map;
@@ -36,11 +36,11 @@
* http://bugs.webkit.org/show_bug.cgi?id=3812</a> for more details.
* </p>
*
- * <h3>Required Module</h3>
- * Modules that use this class should inherit
+ * <h3>Required Module</h3> Modules that use this class should inherit
* <code>com.google.gwt.http.HTTP</code>.
*
- * {@gwt.include com/google/gwt/examples/http/InheritsExample.gwt.xml}
+ * {@gwt.include
+ * com/google/gwt/examples/http/InheritsExample.gwt.xml}
*
*/
public class RequestBuilder {
@@ -70,8 +70,6 @@
*/
public static final Method POST = new Method("POST");
- private static final HTTPRequestImpl httpRequest = (HTTPRequestImpl) GWT.create(HTTPRequestImpl.class);
-
/**
* The callback to call when the request completes.
*/
@@ -139,11 +137,12 @@
* @throws IllegalArgumentException if the httpMethod or URL are empty
* @throws NullPointerException if the httpMethod or the URL are null
*
- * <p>
- * <b>WARNING:</b>This method is provided in order to allow the creation of
- * HTTP request other than GET and POST to be made. If this is done, the
- * developer must accept that the behavior on Safari is undefined.
- * </p>
+ * <p>
+ * <b>WARNING:</b>This method is provided in order to allow the
+ * creation of HTTP request other than GET and POST to be made. If
+ * this is done, the developer must accept that the behavior on
+ * Safari is undefined.
+ * </p>
*/
protected RequestBuilder(String httpMethod, String url) {
@@ -156,8 +155,8 @@
/**
* Returns the callback previously set by
- * {@link #setCallback(RequestCallback)}, or <code>null</code> if no
- * callback was set.
+ * {@link #setCallback(RequestCallback)}, or <code>null</code> if no callback
+ * was set.
*/
public RequestCallback getCallback() {
return callback;
@@ -165,8 +164,8 @@
/**
* Returns the value of a header previous set by
- * {@link #setHeader(String, String)}, or <code>null</code> if no such
- * header was set.
+ * {@link #setHeader(String, String)}, or <code>null</code> if no such header
+ * was set.
*
* @param header the name of the header
*/
@@ -265,8 +264,7 @@
* @param callback the response handler to be notified when the request fails
* or completes
*
- * @throws NullPointerException if <code>callback</code> is
- * <code>null</code>
+ * @throws NullPointerException if <code>callback</code> is <code>null</code>
*/
public void setCallback(RequestCallback callback) {
StringValidator.throwIfNull("callback", callback);
@@ -367,34 +365,43 @@
* @throws NullPointerException if request data has not been set
* @throws NullPointerException if a request callback has not been set
*/
- private Request doSend(String requestData, RequestCallback callback)
+ private Request doSend(String requestData, final RequestCallback callback)
throws RequestException {
- JavaScriptObject xmlHttpRequest = httpRequest.createXmlHTTPRequest();
- String openError;
- if (user != null && password != null) {
- openError = XMLHTTPRequest.open(xmlHttpRequest, httpMethod, url, true,
- user, password);
- } else if (user != null) {
- openError = XMLHTTPRequest.open(xmlHttpRequest, httpMethod, url, true,
- user);
- } else {
- openError = XMLHTTPRequest.open(xmlHttpRequest, httpMethod, url, true);
- }
- if (openError != null) {
+ XMLHttpRequest xmlHttpRequest = XMLHttpRequest.create();
+
+ try {
+ if (user != null && password != null) {
+ xmlHttpRequest.open(httpMethod, url, user, password);
+ } else if (user != null) {
+ xmlHttpRequest.open(httpMethod, url, user);
+ } else {
+ xmlHttpRequest.open(httpMethod, url);
+ }
+ } catch (JavaScriptException e) {
RequestPermissionException requestPermissionException = new RequestPermissionException(
url);
- requestPermissionException.initCause(new RequestException(openError));
+ requestPermissionException.initCause(new RequestException(e.getMessage()));
throw requestPermissionException;
}
setHeaders(xmlHttpRequest);
- Request request = new Request(xmlHttpRequest, timeoutMillis, callback);
+ final Request request = new Request(xmlHttpRequest, timeoutMillis, callback);
- String sendError = XMLHTTPRequest.send(xmlHttpRequest, request,
- requestData, callback);
- if (sendError != null) {
- throw new RequestException(sendError);
+ // Must set the onreadystatechange handler before calling send().
+ xmlHttpRequest.setOnReadyStateChange(new ReadyStateChangeHandler() {
+ public void onReadyStateChange(XMLHttpRequest xhr) {
+ if (xhr.getReadyState() == XMLHttpRequest.DONE) {
+ xhr.clearOnReadyStateChange();
+ request.fireOnResponseReceived(callback);
+ }
+ }
+ });
+
+ try {
+ xmlHttpRequest.send(requestData);
+ } catch (JavaScriptException e) {
+ throw new RequestException(e.getMessage());
}
return request;
@@ -406,18 +413,18 @@
* the "Content-Type" to "text/plain; charset=utf-8". This is really lining us
* up for integration with RPC.
*/
- private void setHeaders(JavaScriptObject xmlHttpRequest)
+ private void setHeaders(XMLHttpRequest xmlHttpRequest)
throws RequestException {
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> header : headers.entrySet()) {
- String errorMessage = XMLHTTPRequest.setRequestHeader(xmlHttpRequest,
- header.getKey(), header.getValue());
- if (errorMessage != null) {
- throw new RequestException(errorMessage);
+ try {
+ xmlHttpRequest.setRequestHeader(header.getKey(), header.getValue());
+ } catch (JavaScriptException e) {
+ throw new RequestException(e.getMessage());
}
}
} else {
- XMLHTTPRequest.setRequestHeader(xmlHttpRequest, "Content-Type",
+ xmlHttpRequest.setRequestHeader("Content-Type",
"text/plain; charset=utf-8");
}
}
diff --git a/user/src/com/google/gwt/http/client/RequestCallback.java b/user/src/com/google/gwt/http/client/RequestCallback.java
index 14e79e2..7a01893 100644
--- a/user/src/com/google/gwt/http/client/RequestCallback.java
+++ b/user/src/com/google/gwt/http/client/RequestCallback.java
@@ -26,6 +26,7 @@
* {@gwt.include com/google/gwt/examples/http/InheritsExample.gwt.xml}
*/
public interface RequestCallback {
+
/**
* Called when a pending {@link com.google.gwt.http.client.Request} completes
* normally. Note this method is called even when the status code of the
diff --git a/user/src/com/google/gwt/http/client/XMLHTTPRequest.java b/user/src/com/google/gwt/http/client/XMLHTTPRequest.java
deleted file mode 100644
index 32da515..0000000
--- a/user/src/com/google/gwt/http/client/XMLHTTPRequest.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may 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.http.client;
-
-import com.google.gwt.core.client.JavaScriptObject;
-
-/**
- * Utility class that serves as the one place where we interact with the
- * JavaScript <code>XmlHttpRequest</code> object.
- */
-final class XMLHTTPRequest {
-
- /*
- * NOTE: Testing discovered that for some bizarre reason, on Mozilla, the
- * JavaScript <code>XmlHttpRequest.onreadystatechange</code> handler
- * function maybe still be called after it is deleted. The theory is that the
- * callback is cached somewhere. Setting it to null or an empty function does
- * seem to work properly, though.
- *
- * On IE, there are two problems: Setting onreadystatechange to null (as
- * opposed to an empty function) sometimes throws an exception. With
- * particular (rare) versions of jscript.dll, setting onreadystatechange from
- * within onreadystatechange causes a crash. Setting it from within a timeout
- * fixes this bug (see issue 1610).
- *
- * End result: *always* set onreadystatechange to an empty function (never to
- * null). Never set onreadystatechange from within onreadystatechange (always
- * in a setTimeout()).
- */
-
- public static final int UNITIALIZED = 0;
- public static final int OPEN = 1;
- public static final int SENT = 2;
- public static final int RECEIVING = 3;
- public static final int LOADED = 4;
-
- static native void abort(JavaScriptObject xmlHttpRequest) /*-{
- xmlHttpRequest.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
- xmlHttpRequest.abort();
- }-*/;
-
- static native String getAllResponseHeaders(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.getAllResponseHeaders();
- }-*/;
-
- /**
- * Tests if the JavaScript <code>XmlHttpRequest.status</code> property is
- * readable. This can return failure in two different known scenarios:
- *
- * <ol>
- * <li>On Mozilla, after a network error, attempting to read the status code
- * results in an exception being thrown. See <a
- * href="https://bugzilla.mozilla.org/show_bug.cgi?id=238559">https://bugzilla.mozilla.org/show_bug.cgi?id=238559</a>.
- * </li>
- * <li>On Safari, if the HTTP response does not include any response text.
- * See <a
- * href="http://bugs.webkit.org/show_bug.cgi?id=3810">http://bugs.webkit.org/show_bug.cgi?id=3810</a>.
- * </li>
- * </ol>
- *
- * @param xmlHttpRequest the JavaScript <code>XmlHttpRequest</code> object
- * to test
- * @return a String message containing an error message if the
- * <code>XmlHttpRequest.status</code> code is unreadable or null if
- * the status code could be successfully read.
- */
- static native String getBrowserSpecificFailure(
- JavaScriptObject xmlHttpRequest) /*-{
- try {
- if (xmlHttpRequest.status === undefined) {
- return "XmlHttpRequest.status == undefined, please see Safari bug " +
- "http://bugs.webkit.org/show_bug.cgi?id=3810 for more details";
- }
- return null;
- } catch (e) {
- return "Unable to read XmlHttpRequest.status; likely causes are a " +
- "networking error or bad cross-domain request. Please see " +
- "https://bugzilla.mozilla.org/show_bug.cgi?id=238559 for more " +
- "details";
- }
- }-*/;
-
- /**
- * Returns an array of headers built by parsing the string of headers returned
- * by the JavaScript <code>XmlHttpRequest</code> object.
- *
- * @param xmlHttpRequest
- * @return array of Header items
- */
- static Header[] getHeaders(JavaScriptObject xmlHttpRequest) {
- String allHeaders = getAllResponseHeaders(xmlHttpRequest);
- String[] unparsedHeaders = allHeaders.split("\n");
- Header[] parsedHeaders = new Header[unparsedHeaders.length];
-
- for (int i = 0, n = unparsedHeaders.length; i < n; ++i) {
- String unparsedHeader = unparsedHeaders[i];
-
- if (unparsedHeader.length() == 0) {
- continue;
- }
-
- int endOfNameIdx = unparsedHeader.indexOf(':');
- if (endOfNameIdx < 0) {
- continue;
- }
-
- final String name = unparsedHeader.substring(0, endOfNameIdx).trim();
- final String value = unparsedHeader.substring(endOfNameIdx + 1).trim();
- Header header = new Header() {
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public String getValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return name + " : " + value;
- }
- };
-
- parsedHeaders[i] = header;
- }
-
- return parsedHeaders;
- }
-
- static native int getReadyState(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.readyState;
- }-*/;
-
- static native String getResponseHeader(JavaScriptObject xmlHttpRequest,
- String header) /*-{
- try {
- return xmlHttpRequest.getResponseHeader(header);
- } catch (e) {
- // purposely ignored
- }
- return null;
- }-*/;
-
- static native String getResponseText(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.responseText;
- }-*/;
-
- static native int getStatusCode(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.status;
- }-*/;
-
- static native String getStatusText(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.statusText;
- }-*/;
-
- static boolean isResponseReady(JavaScriptObject xmlHttpRequest) {
- return getReadyState(xmlHttpRequest) == LOADED;
- }
-
- /**
- * Opens the request and catches any exceptions thrown. If an exception is
- * caught, its string representation will be returned. This is the only signal
- * that an error has occurred.
- *
- * @param xmlHttpRequest JavaScript <code>XmlHttpRequest</code> object
- * @param httpMethod the method to use for open call
- * @param url the URL to use for the open call
- * @param async true if we should do an asynchronous open
- * @return error message if an exception is thrown or null if there is none
- */
- static native String open(JavaScriptObject xmlHttpRequest, String httpMethod,
- String url, boolean async) /*-{
- try {
- xmlHttpRequest.open(httpMethod, url, async);
- return null;
- } catch (e) {
- return e.message || e.toString();
- }
- }-*/;
-
- /**
- * Opens the request and catches any exceptions thrown. If an exception is
- * caught, its string representation will be returned. This is the only signal
- * that an error has occurred.
- *
- * @param xmlHttpRequest JavaScript <code>XmlHttpRequest</code> object
- * @param httpMethod the method to use for open call
- * @param url the URL to use for the open call
- * @param async true if we should do an asynchronous open
- * @param user user to use in the URL
- * @return error message if an exception is thrown or null if there is none
- */
- static native String open(JavaScriptObject xmlHttpRequest, String httpMethod,
- String url, boolean async, String user) /*-{
- try {
- xmlHttpRequest.open(httpMethod, url, async, user);
- return null;
- } catch (e) {
- return e.message || e.toString();
- }
- }-*/;
-
- /**
- * Opens the request and catches any exceptions thrown. If an exception is
- * caught, its string representation will be returned. This is the only signal
- * that an error has occurred.
- *
- * @param xmlHttpRequest JavaScript <code>XmlHttpRequest</code> object
- * @param httpMethod the method to use for open call
- * @param url the URL to use for the open call
- * @param async true if we should do an asynchronous open
- * @param user user to use in the URL
- * @param password password to use in the URL
- * @return error message if an exception is thrown or null if there is none
- */
- static native String open(JavaScriptObject xmlHttpRequest, String httpMethod,
- String url, boolean async, String user, String password) /*-{
- try {
- xmlHttpRequest.open(httpMethod, url, async, user, password);
- return null;
- } catch (e) {
- return e.message || e.toString();
- }
- }-*/;
-
- /*
- * Creates a closure that calls the HTTPRequest::fireOnResponseRecieved method
- * when the server's response is received and sends the data.
- */
- static native String send(JavaScriptObject xmlHttpRequest, Request httpRequest,
- String requestData, RequestCallback callback) /*-{
- xmlHttpRequest.onreadystatechange = function() {
- if (xmlHttpRequest.readyState == @com.google.gwt.http.client.XMLHTTPRequest::LOADED) {
- $wnd.setTimeout(function() {
- xmlHttpRequest.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
- }, 0);
- httpRequest.@com.google.gwt.http.client.Request::fireOnResponseReceived(Lcom/google/gwt/http/client/RequestCallback;)(callback);
- }
- };
- try {
- xmlHttpRequest.send(requestData);
- return null;
- } catch (e) {
- xmlHttpRequest.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
- return e.message || e.toString();
- }
- }-*/;
-
- static native String setRequestHeader(JavaScriptObject xmlHttpRequest,
- String header, String value) /*-{
- try {
- xmlHttpRequest.setRequestHeader(header, value);
- return null;
- } catch (e) {
- return e.message || e.toString();
- }
- }-*/;
-
- private XMLHTTPRequest() {
- }
-}
diff --git a/user/src/com/google/gwt/i18n/CldrLocales.gwt.xml b/user/src/com/google/gwt/i18n/CldrLocales.gwt.xml
new file mode 100644
index 0000000..cec511e
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/CldrLocales.gwt.xml
@@ -0,0 +1,472 @@
+<!-- -->
+<!-- Copyright 2008 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<!-- List of all locales imported into GWT from CLDR, as runtime locales -->
+<module>
+ <append-configuration-property name="runtime.locales" value="aa"/>
+ <append-configuration-property name="runtime.locales" value="aa_DJ"/>
+ <append-configuration-property name="runtime.locales" value="aa_ER"/>
+ <append-configuration-property name="runtime.locales" value="aa_ER_SAAHO"/>
+ <append-configuration-property name="runtime.locales" value="aa_ET"/>
+ <append-configuration-property name="runtime.locales" value="af"/>
+ <append-configuration-property name="runtime.locales" value="af_NA"/>
+ <append-configuration-property name="runtime.locales" value="af_ZA"/>
+ <append-configuration-property name="runtime.locales" value="ak"/>
+ <append-configuration-property name="runtime.locales" value="ak_GH"/>
+ <append-configuration-property name="runtime.locales" value="am"/>
+ <append-configuration-property name="runtime.locales" value="am_ET"/>
+ <append-configuration-property name="runtime.locales" value="ar"/>
+ <append-configuration-property name="runtime.locales" value="ar_AE"/>
+ <append-configuration-property name="runtime.locales" value="ar_BH"/>
+ <append-configuration-property name="runtime.locales" value="ar_DZ"/>
+ <append-configuration-property name="runtime.locales" value="ar_EG"/>
+ <append-configuration-property name="runtime.locales" value="ar_IQ"/>
+ <append-configuration-property name="runtime.locales" value="ar_JO"/>
+ <append-configuration-property name="runtime.locales" value="ar_KW"/>
+ <append-configuration-property name="runtime.locales" value="ar_LB"/>
+ <append-configuration-property name="runtime.locales" value="ar_LY"/>
+ <append-configuration-property name="runtime.locales" value="ar_MA"/>
+ <append-configuration-property name="runtime.locales" value="ar_OM"/>
+ <append-configuration-property name="runtime.locales" value="ar_QA"/>
+ <append-configuration-property name="runtime.locales" value="ar_SA"/>
+ <append-configuration-property name="runtime.locales" value="ar_SD"/>
+ <append-configuration-property name="runtime.locales" value="ar_SY"/>
+ <append-configuration-property name="runtime.locales" value="ar_TN"/>
+ <append-configuration-property name="runtime.locales" value="ar_YE"/>
+ <append-configuration-property name="runtime.locales" value="as"/>
+ <append-configuration-property name="runtime.locales" value="as_IN"/>
+ <append-configuration-property name="runtime.locales" value="az"/>
+ <append-configuration-property name="runtime.locales" value="az_AZ"/>
+ <append-configuration-property name="runtime.locales" value="az_Cyrl"/>
+ <append-configuration-property name="runtime.locales" value="az_Cyrl_AZ"/>
+ <append-configuration-property name="runtime.locales" value="az_Latn"/>
+ <append-configuration-property name="runtime.locales" value="az_Latn_AZ"/>
+ <append-configuration-property name="runtime.locales" value="be"/>
+ <append-configuration-property name="runtime.locales" value="be_BY"/>
+ <append-configuration-property name="runtime.locales" value="bg"/>
+ <append-configuration-property name="runtime.locales" value="bg_BG"/>
+ <append-configuration-property name="runtime.locales" value="bn"/>
+ <append-configuration-property name="runtime.locales" value="bn_BD"/>
+ <append-configuration-property name="runtime.locales" value="bn_IN"/>
+ <append-configuration-property name="runtime.locales" value="bs"/>
+ <append-configuration-property name="runtime.locales" value="bs_BA"/>
+ <append-configuration-property name="runtime.locales" value="byn"/>
+ <append-configuration-property name="runtime.locales" value="byn_ER"/>
+ <append-configuration-property name="runtime.locales" value="ca"/>
+ <append-configuration-property name="runtime.locales" value="ca_ES"/>
+ <append-configuration-property name="runtime.locales" value="cch"/>
+ <append-configuration-property name="runtime.locales" value="cch_NG"/>
+ <append-configuration-property name="runtime.locales" value="cop"/>
+ <append-configuration-property name="runtime.locales" value="cs"/>
+ <append-configuration-property name="runtime.locales" value="cs_CZ"/>
+ <append-configuration-property name="runtime.locales" value="cy"/>
+ <append-configuration-property name="runtime.locales" value="cy_GB"/>
+ <append-configuration-property name="runtime.locales" value="da"/>
+ <append-configuration-property name="runtime.locales" value="da_DK"/>
+ <append-configuration-property name="runtime.locales" value="de"/>
+ <append-configuration-property name="runtime.locales" value="de_AT"/>
+ <append-configuration-property name="runtime.locales" value="de_BE"/>
+ <append-configuration-property name="runtime.locales" value="de_CH"/>
+ <append-configuration-property name="runtime.locales" value="de_DE"/>
+ <append-configuration-property name="runtime.locales" value="de_LI"/>
+ <append-configuration-property name="runtime.locales" value="de_LU"/>
+ <append-configuration-property name="runtime.locales" value="dv"/>
+ <append-configuration-property name="runtime.locales" value="dv_MV"/>
+ <append-configuration-property name="runtime.locales" value="dz"/>
+ <append-configuration-property name="runtime.locales" value="dz_BT"/>
+ <append-configuration-property name="runtime.locales" value="ee"/>
+ <append-configuration-property name="runtime.locales" value="ee_GH"/>
+ <append-configuration-property name="runtime.locales" value="ee_TG"/>
+ <append-configuration-property name="runtime.locales" value="el"/>
+ <append-configuration-property name="runtime.locales" value="el_CY"/>
+ <append-configuration-property name="runtime.locales" value="el_GR"/>
+ <append-configuration-property name="runtime.locales" value="el_POLYTON"/>
+ <append-configuration-property name="runtime.locales" value="en"/>
+ <append-configuration-property name="runtime.locales" value="en_AS"/>
+ <append-configuration-property name="runtime.locales" value="en_AU"/>
+ <append-configuration-property name="runtime.locales" value="en_BE"/>
+ <append-configuration-property name="runtime.locales" value="en_BW"/>
+ <append-configuration-property name="runtime.locales" value="en_BZ"/>
+ <append-configuration-property name="runtime.locales" value="en_CA"/>
+ <append-configuration-property name="runtime.locales" value="en_Dsrt"/>
+ <append-configuration-property name="runtime.locales" value="en_Dsrt_US"/>
+ <append-configuration-property name="runtime.locales" value="en_GB"/>
+ <append-configuration-property name="runtime.locales" value="en_GU"/>
+ <append-configuration-property name="runtime.locales" value="en_HK"/>
+ <append-configuration-property name="runtime.locales" value="en_IE"/>
+ <append-configuration-property name="runtime.locales" value="en_IN"/>
+ <append-configuration-property name="runtime.locales" value="en_JM"/>
+ <append-configuration-property name="runtime.locales" value="en_MH"/>
+ <append-configuration-property name="runtime.locales" value="en_MP"/>
+ <append-configuration-property name="runtime.locales" value="en_MT"/>
+ <append-configuration-property name="runtime.locales" value="en_NA"/>
+ <append-configuration-property name="runtime.locales" value="en_NZ"/>
+ <append-configuration-property name="runtime.locales" value="en_PH"/>
+ <append-configuration-property name="runtime.locales" value="en_PK"/>
+ <append-configuration-property name="runtime.locales" value="en_SG"/>
+ <append-configuration-property name="runtime.locales" value="en_Shaw"/>
+ <append-configuration-property name="runtime.locales" value="en_TT"/>
+ <append-configuration-property name="runtime.locales" value="en_UM"/>
+ <append-configuration-property name="runtime.locales" value="en_US"/>
+ <!-- This doesn't seem appropriate to include here, if you want it just
+ include the following line right after the import for this module.
+ <append-configuration-property name="runtime.locales" value="en_US_POSIX"/>
+ -->
+ <append-configuration-property name="runtime.locales" value="en_VI"/>
+ <append-configuration-property name="runtime.locales" value="en_ZA"/>
+ <append-configuration-property name="runtime.locales" value="en_ZW"/>
+ <append-configuration-property name="runtime.locales" value="eo"/>
+ <append-configuration-property name="runtime.locales" value="es"/>
+ <append-configuration-property name="runtime.locales" value="es_AR"/>
+ <append-configuration-property name="runtime.locales" value="es_BO"/>
+ <append-configuration-property name="runtime.locales" value="es_CL"/>
+ <append-configuration-property name="runtime.locales" value="es_CO"/>
+ <append-configuration-property name="runtime.locales" value="es_CR"/>
+ <append-configuration-property name="runtime.locales" value="es_DO"/>
+ <append-configuration-property name="runtime.locales" value="es_EC"/>
+ <append-configuration-property name="runtime.locales" value="es_ES"/>
+ <append-configuration-property name="runtime.locales" value="es_GT"/>
+ <append-configuration-property name="runtime.locales" value="es_HN"/>
+ <append-configuration-property name="runtime.locales" value="es_MX"/>
+ <append-configuration-property name="runtime.locales" value="es_NI"/>
+ <append-configuration-property name="runtime.locales" value="es_PA"/>
+ <append-configuration-property name="runtime.locales" value="es_PE"/>
+ <append-configuration-property name="runtime.locales" value="es_PR"/>
+ <append-configuration-property name="runtime.locales" value="es_PY"/>
+ <append-configuration-property name="runtime.locales" value="es_SV"/>
+ <append-configuration-property name="runtime.locales" value="es_US"/>
+ <append-configuration-property name="runtime.locales" value="es_UY"/>
+ <append-configuration-property name="runtime.locales" value="es_VE"/>
+ <append-configuration-property name="runtime.locales" value="et"/>
+ <append-configuration-property name="runtime.locales" value="et_EE"/>
+ <append-configuration-property name="runtime.locales" value="eu"/>
+ <append-configuration-property name="runtime.locales" value="eu_ES"/>
+ <append-configuration-property name="runtime.locales" value="fa"/>
+ <append-configuration-property name="runtime.locales" value="fa_AF"/>
+ <append-configuration-property name="runtime.locales" value="fa_IR"/>
+ <append-configuration-property name="runtime.locales" value="fi"/>
+ <append-configuration-property name="runtime.locales" value="fi_FI"/>
+ <append-configuration-property name="runtime.locales" value="fil"/>
+ <append-configuration-property name="runtime.locales" value="fil_PH"/>
+ <append-configuration-property name="runtime.locales" value="fo"/>
+ <append-configuration-property name="runtime.locales" value="fo_FO"/>
+ <append-configuration-property name="runtime.locales" value="fr"/>
+ <append-configuration-property name="runtime.locales" value="fr_BE"/>
+ <append-configuration-property name="runtime.locales" value="fr_CA"/>
+ <append-configuration-property name="runtime.locales" value="fr_CH"/>
+ <append-configuration-property name="runtime.locales" value="fr_FR"/>
+ <append-configuration-property name="runtime.locales" value="fr_LU"/>
+ <append-configuration-property name="runtime.locales" value="fr_MC"/>
+ <append-configuration-property name="runtime.locales" value="fr_SN"/>
+ <append-configuration-property name="runtime.locales" value="fur"/>
+ <append-configuration-property name="runtime.locales" value="fur_IT"/>
+ <append-configuration-property name="runtime.locales" value="ga"/>
+ <append-configuration-property name="runtime.locales" value="gaa"/>
+ <append-configuration-property name="runtime.locales" value="gaa_GH"/>
+ <append-configuration-property name="runtime.locales" value="ga_IE"/>
+ <append-configuration-property name="runtime.locales" value="gez"/>
+ <append-configuration-property name="runtime.locales" value="gez_ER"/>
+ <append-configuration-property name="runtime.locales" value="gez_ET"/>
+ <append-configuration-property name="runtime.locales" value="gl"/>
+ <append-configuration-property name="runtime.locales" value="gl_ES"/>
+ <append-configuration-property name="runtime.locales" value="gu"/>
+ <append-configuration-property name="runtime.locales" value="gu_IN"/>
+ <append-configuration-property name="runtime.locales" value="gv"/>
+ <append-configuration-property name="runtime.locales" value="gv_GB"/>
+ <append-configuration-property name="runtime.locales" value="ha"/>
+ <append-configuration-property name="runtime.locales" value="ha_Arab"/>
+ <append-configuration-property name="runtime.locales" value="ha_Arab_NG"/>
+ <append-configuration-property name="runtime.locales" value="ha_Arab_SD"/>
+ <append-configuration-property name="runtime.locales" value="ha_GH"/>
+ <append-configuration-property name="runtime.locales" value="ha_Latn"/>
+ <append-configuration-property name="runtime.locales" value="ha_Latn_GH"/>
+ <append-configuration-property name="runtime.locales" value="ha_Latn_NE"/>
+ <append-configuration-property name="runtime.locales" value="ha_Latn_NG"/>
+ <append-configuration-property name="runtime.locales" value="ha_NE"/>
+ <append-configuration-property name="runtime.locales" value="ha_NG"/>
+ <append-configuration-property name="runtime.locales" value="ha_SD"/>
+ <append-configuration-property name="runtime.locales" value="haw"/>
+ <append-configuration-property name="runtime.locales" value="haw_US"/>
+ <append-configuration-property name="runtime.locales" value="he"/>
+ <append-configuration-property name="runtime.locales" value="he_IL"/>
+ <append-configuration-property name="runtime.locales" value="hi"/>
+ <append-configuration-property name="runtime.locales" value="hi_IN"/>
+ <append-configuration-property name="runtime.locales" value="hr"/>
+ <append-configuration-property name="runtime.locales" value="hr_HR"/>
+ <append-configuration-property name="runtime.locales" value="hu"/>
+ <append-configuration-property name="runtime.locales" value="hu_HU"/>
+ <append-configuration-property name="runtime.locales" value="hy"/>
+ <append-configuration-property name="runtime.locales" value="hy_AM"/>
+ <append-configuration-property name="runtime.locales" value="hy_AM_REVISED"/>
+ <append-configuration-property name="runtime.locales" value="ia"/>
+ <append-configuration-property name="runtime.locales" value="id"/>
+ <append-configuration-property name="runtime.locales" value="id_ID"/>
+ <append-configuration-property name="runtime.locales" value="ig"/>
+ <append-configuration-property name="runtime.locales" value="ig_NG"/>
+ <append-configuration-property name="runtime.locales" value="ii"/>
+ <append-configuration-property name="runtime.locales" value="ii_CN"/>
+ <append-configuration-property name="runtime.locales" value="in"/>
+ <append-configuration-property name="runtime.locales" value="is"/>
+ <append-configuration-property name="runtime.locales" value="is_IS"/>
+ <append-configuration-property name="runtime.locales" value="it"/>
+ <append-configuration-property name="runtime.locales" value="it_CH"/>
+ <append-configuration-property name="runtime.locales" value="it_IT"/>
+ <append-configuration-property name="runtime.locales" value="iu"/>
+ <append-configuration-property name="runtime.locales" value="iw"/>
+ <append-configuration-property name="runtime.locales" value="ja"/>
+ <append-configuration-property name="runtime.locales" value="ja_JP"/>
+ <append-configuration-property name="runtime.locales" value="ka"/>
+ <append-configuration-property name="runtime.locales" value="ka_GE"/>
+ <append-configuration-property name="runtime.locales" value="kaj"/>
+ <append-configuration-property name="runtime.locales" value="kaj_NG"/>
+ <append-configuration-property name="runtime.locales" value="kam"/>
+ <append-configuration-property name="runtime.locales" value="kam_KE"/>
+ <append-configuration-property name="runtime.locales" value="kcg"/>
+ <append-configuration-property name="runtime.locales" value="kcg_NG"/>
+ <append-configuration-property name="runtime.locales" value="kfo"/>
+ <append-configuration-property name="runtime.locales" value="kfo_CI"/>
+ <append-configuration-property name="runtime.locales" value="kk"/>
+ <append-configuration-property name="runtime.locales" value="kk_Cyrl"/>
+ <append-configuration-property name="runtime.locales" value="kk_Cyrl_KZ"/>
+ <append-configuration-property name="runtime.locales" value="kk_KZ"/>
+ <append-configuration-property name="runtime.locales" value="kl"/>
+ <append-configuration-property name="runtime.locales" value="kl_GL"/>
+ <append-configuration-property name="runtime.locales" value="km"/>
+ <append-configuration-property name="runtime.locales" value="km_KH"/>
+ <append-configuration-property name="runtime.locales" value="kn"/>
+ <append-configuration-property name="runtime.locales" value="kn_IN"/>
+ <append-configuration-property name="runtime.locales" value="ko"/>
+ <append-configuration-property name="runtime.locales" value="kok"/>
+ <append-configuration-property name="runtime.locales" value="kok_IN"/>
+ <append-configuration-property name="runtime.locales" value="ko_KR"/>
+ <append-configuration-property name="runtime.locales" value="kpe"/>
+ <append-configuration-property name="runtime.locales" value="kpe_GN"/>
+ <append-configuration-property name="runtime.locales" value="kpe_LR"/>
+ <append-configuration-property name="runtime.locales" value="ku"/>
+ <append-configuration-property name="runtime.locales" value="ku_Arab"/>
+ <append-configuration-property name="runtime.locales" value="ku_Latn"/>
+ <append-configuration-property name="runtime.locales" value="ku_Latn_TR"/>
+ <append-configuration-property name="runtime.locales" value="ku_TR"/>
+ <append-configuration-property name="runtime.locales" value="kw"/>
+ <append-configuration-property name="runtime.locales" value="kw_GB"/>
+ <append-configuration-property name="runtime.locales" value="ky"/>
+ <append-configuration-property name="runtime.locales" value="ky_KG"/>
+ <append-configuration-property name="runtime.locales" value="ln"/>
+ <append-configuration-property name="runtime.locales" value="ln_CD"/>
+ <append-configuration-property name="runtime.locales" value="ln_CG"/>
+ <append-configuration-property name="runtime.locales" value="lo"/>
+ <append-configuration-property name="runtime.locales" value="lo_LA"/>
+ <append-configuration-property name="runtime.locales" value="lt"/>
+ <append-configuration-property name="runtime.locales" value="lt_LT"/>
+ <append-configuration-property name="runtime.locales" value="lv"/>
+ <append-configuration-property name="runtime.locales" value="lv_LV"/>
+ <append-configuration-property name="runtime.locales" value="mk"/>
+ <append-configuration-property name="runtime.locales" value="mk_MK"/>
+ <append-configuration-property name="runtime.locales" value="ml"/>
+ <append-configuration-property name="runtime.locales" value="ml_IN"/>
+ <append-configuration-property name="runtime.locales" value="mn"/>
+ <append-configuration-property name="runtime.locales" value="mn_CN"/>
+ <append-configuration-property name="runtime.locales" value="mn_Cyrl"/>
+ <append-configuration-property name="runtime.locales" value="mn_Cyrl_MN"/>
+ <append-configuration-property name="runtime.locales" value="mn_MN"/>
+ <append-configuration-property name="runtime.locales" value="mn_Mong"/>
+ <append-configuration-property name="runtime.locales" value="mn_Mong_CN"/>
+ <append-configuration-property name="runtime.locales" value="mo"/>
+ <append-configuration-property name="runtime.locales" value="mr"/>
+ <append-configuration-property name="runtime.locales" value="mr_IN"/>
+ <append-configuration-property name="runtime.locales" value="ms"/>
+ <append-configuration-property name="runtime.locales" value="ms_BN"/>
+ <append-configuration-property name="runtime.locales" value="ms_MY"/>
+ <append-configuration-property name="runtime.locales" value="mt"/>
+ <append-configuration-property name="runtime.locales" value="mt_MT"/>
+ <append-configuration-property name="runtime.locales" value="my"/>
+ <append-configuration-property name="runtime.locales" value="my_MM"/>
+ <append-configuration-property name="runtime.locales" value="nb"/>
+ <append-configuration-property name="runtime.locales" value="nb_NO"/>
+ <append-configuration-property name="runtime.locales" value="ne"/>
+ <append-configuration-property name="runtime.locales" value="ne_IN"/>
+ <append-configuration-property name="runtime.locales" value="ne_NP"/>
+ <append-configuration-property name="runtime.locales" value="nl"/>
+ <append-configuration-property name="runtime.locales" value="nl_BE"/>
+ <append-configuration-property name="runtime.locales" value="nl_NL"/>
+ <append-configuration-property name="runtime.locales" value="nn"/>
+ <append-configuration-property name="runtime.locales" value="nn_NO"/>
+ <append-configuration-property name="runtime.locales" value="no"/>
+ <append-configuration-property name="runtime.locales" value="nr"/>
+ <append-configuration-property name="runtime.locales" value="nr_ZA"/>
+ <append-configuration-property name="runtime.locales" value="nso"/>
+ <append-configuration-property name="runtime.locales" value="nso_ZA"/>
+ <append-configuration-property name="runtime.locales" value="ny"/>
+ <append-configuration-property name="runtime.locales" value="ny_MW"/>
+ <append-configuration-property name="runtime.locales" value="om"/>
+ <append-configuration-property name="runtime.locales" value="om_ET"/>
+ <append-configuration-property name="runtime.locales" value="om_KE"/>
+ <append-configuration-property name="runtime.locales" value="or"/>
+ <append-configuration-property name="runtime.locales" value="or_IN"/>
+ <append-configuration-property name="runtime.locales" value="pa"/>
+ <append-configuration-property name="runtime.locales" value="pa_Arab"/>
+ <append-configuration-property name="runtime.locales" value="pa_Arab_PK"/>
+ <append-configuration-property name="runtime.locales" value="pa_Guru"/>
+ <append-configuration-property name="runtime.locales" value="pa_Guru_IN"/>
+ <append-configuration-property name="runtime.locales" value="pa_IN"/>
+ <append-configuration-property name="runtime.locales" value="pa_PK"/>
+ <append-configuration-property name="runtime.locales" value="pl"/>
+ <append-configuration-property name="runtime.locales" value="pl_PL"/>
+ <append-configuration-property name="runtime.locales" value="ps"/>
+ <append-configuration-property name="runtime.locales" value="ps_AF"/>
+ <append-configuration-property name="runtime.locales" value="pt"/>
+ <append-configuration-property name="runtime.locales" value="pt_BR"/>
+ <append-configuration-property name="runtime.locales" value="pt_PT"/>
+ <append-configuration-property name="runtime.locales" value="ro"/>
+ <append-configuration-property name="runtime.locales" value="ro_MD"/>
+ <append-configuration-property name="runtime.locales" value="root"/>
+ <append-configuration-property name="runtime.locales" value="ro_RO"/>
+ <append-configuration-property name="runtime.locales" value="ru"/>
+ <append-configuration-property name="runtime.locales" value="ru_RU"/>
+ <append-configuration-property name="runtime.locales" value="ru_UA"/>
+ <append-configuration-property name="runtime.locales" value="rw"/>
+ <append-configuration-property name="runtime.locales" value="rw_RW"/>
+ <append-configuration-property name="runtime.locales" value="sa"/>
+ <append-configuration-property name="runtime.locales" value="sa_IN"/>
+ <append-configuration-property name="runtime.locales" value="se"/>
+ <append-configuration-property name="runtime.locales" value="se_FI"/>
+ <append-configuration-property name="runtime.locales" value="se_NO"/>
+ <append-configuration-property name="runtime.locales" value="sh"/>
+ <append-configuration-property name="runtime.locales" value="sh_BA"/>
+ <append-configuration-property name="runtime.locales" value="sh_CS"/>
+ <append-configuration-property name="runtime.locales" value="sh_YU"/>
+ <append-configuration-property name="runtime.locales" value="si"/>
+ <append-configuration-property name="runtime.locales" value="sid"/>
+ <append-configuration-property name="runtime.locales" value="sid_ET"/>
+ <append-configuration-property name="runtime.locales" value="si_LK"/>
+ <append-configuration-property name="runtime.locales" value="sk"/>
+ <append-configuration-property name="runtime.locales" value="sk_SK"/>
+ <append-configuration-property name="runtime.locales" value="sl"/>
+ <append-configuration-property name="runtime.locales" value="sl_SI"/>
+ <append-configuration-property name="runtime.locales" value="so"/>
+ <append-configuration-property name="runtime.locales" value="so_DJ"/>
+ <append-configuration-property name="runtime.locales" value="so_ET"/>
+ <append-configuration-property name="runtime.locales" value="so_KE"/>
+ <append-configuration-property name="runtime.locales" value="so_SO"/>
+ <append-configuration-property name="runtime.locales" value="sq"/>
+ <append-configuration-property name="runtime.locales" value="sq_AL"/>
+ <append-configuration-property name="runtime.locales" value="sr"/>
+ <append-configuration-property name="runtime.locales" value="sr_BA"/>
+ <append-configuration-property name="runtime.locales" value="sr_CS"/>
+ <append-configuration-property name="runtime.locales" value="sr_Cyrl"/>
+ <append-configuration-property name="runtime.locales" value="sr_Cyrl_BA"/>
+ <append-configuration-property name="runtime.locales" value="sr_Cyrl_CS"/>
+ <append-configuration-property name="runtime.locales" value="sr_Cyrl_ME"/>
+ <append-configuration-property name="runtime.locales" value="sr_Cyrl_RS"/>
+ <append-configuration-property name="runtime.locales" value="sr_Cyrl_YU"/>
+ <append-configuration-property name="runtime.locales" value="sr_Latn"/>
+ <append-configuration-property name="runtime.locales" value="sr_Latn_BA"/>
+ <append-configuration-property name="runtime.locales" value="sr_Latn_CS"/>
+ <append-configuration-property name="runtime.locales" value="sr_Latn_ME"/>
+ <append-configuration-property name="runtime.locales" value="sr_Latn_RS"/>
+ <append-configuration-property name="runtime.locales" value="sr_Latn_YU"/>
+ <append-configuration-property name="runtime.locales" value="sr_ME"/>
+ <append-configuration-property name="runtime.locales" value="sr_RS"/>
+ <append-configuration-property name="runtime.locales" value="sr_YU"/>
+ <append-configuration-property name="runtime.locales" value="ss"/>
+ <append-configuration-property name="runtime.locales" value="ss_SZ"/>
+ <append-configuration-property name="runtime.locales" value="ss_ZA"/>
+ <append-configuration-property name="runtime.locales" value="st"/>
+ <append-configuration-property name="runtime.locales" value="st_LS"/>
+ <append-configuration-property name="runtime.locales" value="st_ZA"/>
+ <append-configuration-property name="runtime.locales" value="sv"/>
+ <append-configuration-property name="runtime.locales" value="sv_FI"/>
+ <append-configuration-property name="runtime.locales" value="sv_SE"/>
+ <append-configuration-property name="runtime.locales" value="sw"/>
+ <append-configuration-property name="runtime.locales" value="sw_KE"/>
+ <append-configuration-property name="runtime.locales" value="sw_TZ"/>
+ <append-configuration-property name="runtime.locales" value="syr"/>
+ <append-configuration-property name="runtime.locales" value="syr_SY"/>
+ <append-configuration-property name="runtime.locales" value="ta"/>
+ <append-configuration-property name="runtime.locales" value="ta_IN"/>
+ <append-configuration-property name="runtime.locales" value="te"/>
+ <append-configuration-property name="runtime.locales" value="te_IN"/>
+ <append-configuration-property name="runtime.locales" value="tg"/>
+ <append-configuration-property name="runtime.locales" value="tg_Cyrl"/>
+ <append-configuration-property name="runtime.locales" value="tg_Cyrl_TJ"/>
+ <append-configuration-property name="runtime.locales" value="tg_TJ"/>
+ <append-configuration-property name="runtime.locales" value="th"/>
+ <append-configuration-property name="runtime.locales" value="th_TH"/>
+ <append-configuration-property name="runtime.locales" value="ti"/>
+ <append-configuration-property name="runtime.locales" value="ti_ER"/>
+ <append-configuration-property name="runtime.locales" value="ti_ET"/>
+ <append-configuration-property name="runtime.locales" value="tig"/>
+ <append-configuration-property name="runtime.locales" value="tig_ER"/>
+ <append-configuration-property name="runtime.locales" value="tl"/>
+ <append-configuration-property name="runtime.locales" value="tn"/>
+ <append-configuration-property name="runtime.locales" value="tn_ZA"/>
+ <append-configuration-property name="runtime.locales" value="to"/>
+ <append-configuration-property name="runtime.locales" value="to_TO"/>
+ <append-configuration-property name="runtime.locales" value="tr"/>
+ <append-configuration-property name="runtime.locales" value="tr_TR"/>
+ <append-configuration-property name="runtime.locales" value="trv"/>
+ <append-configuration-property name="runtime.locales" value="ts"/>
+ <append-configuration-property name="runtime.locales" value="ts_ZA"/>
+ <append-configuration-property name="runtime.locales" value="tt"/>
+ <append-configuration-property name="runtime.locales" value="tt_RU"/>
+ <append-configuration-property name="runtime.locales" value="ug"/>
+ <append-configuration-property name="runtime.locales" value="ug_Arab"/>
+ <append-configuration-property name="runtime.locales" value="ug_Arab_CN"/>
+ <append-configuration-property name="runtime.locales" value="ug_CN"/>
+ <append-configuration-property name="runtime.locales" value="uk"/>
+ <append-configuration-property name="runtime.locales" value="uk_UA"/>
+ <append-configuration-property name="runtime.locales" value="ur"/>
+ <append-configuration-property name="runtime.locales" value="ur_IN"/>
+ <append-configuration-property name="runtime.locales" value="ur_PK"/>
+ <append-configuration-property name="runtime.locales" value="uz"/>
+ <append-configuration-property name="runtime.locales" value="uz_AF"/>
+ <append-configuration-property name="runtime.locales" value="uz_Arab"/>
+ <append-configuration-property name="runtime.locales" value="uz_Arab_AF"/>
+ <append-configuration-property name="runtime.locales" value="uz_Cyrl"/>
+ <append-configuration-property name="runtime.locales" value="uz_Cyrl_UZ"/>
+ <append-configuration-property name="runtime.locales" value="uz_Latn"/>
+ <append-configuration-property name="runtime.locales" value="uz_Latn_UZ"/>
+ <append-configuration-property name="runtime.locales" value="uz_UZ"/>
+ <append-configuration-property name="runtime.locales" value="ve"/>
+ <append-configuration-property name="runtime.locales" value="ve_ZA"/>
+ <append-configuration-property name="runtime.locales" value="vi"/>
+ <append-configuration-property name="runtime.locales" value="vi_VN"/>
+ <append-configuration-property name="runtime.locales" value="wal"/>
+ <append-configuration-property name="runtime.locales" value="wal_ET"/>
+ <append-configuration-property name="runtime.locales" value="wo"/>
+ <append-configuration-property name="runtime.locales" value="wo_Latn"/>
+ <append-configuration-property name="runtime.locales" value="wo_Latn_SN"/>
+ <append-configuration-property name="runtime.locales" value="wo_SN"/>
+ <append-configuration-property name="runtime.locales" value="xh"/>
+ <append-configuration-property name="runtime.locales" value="xh_ZA"/>
+ <append-configuration-property name="runtime.locales" value="yo"/>
+ <append-configuration-property name="runtime.locales" value="yo_NG"/>
+ <append-configuration-property name="runtime.locales" value="zh"/>
+ <append-configuration-property name="runtime.locales" value="zh_CN"/>
+ <append-configuration-property name="runtime.locales" value="zh_Hans"/>
+ <append-configuration-property name="runtime.locales" value="zh_Hans_CN"/>
+ <append-configuration-property name="runtime.locales" value="zh_Hans_HK"/>
+ <append-configuration-property name="runtime.locales" value="zh_Hans_MO"/>
+ <append-configuration-property name="runtime.locales" value="zh_Hans_SG"/>
+ <append-configuration-property name="runtime.locales" value="zh_Hant"/>
+ <append-configuration-property name="runtime.locales" value="zh_Hant_HK"/>
+ <append-configuration-property name="runtime.locales" value="zh_Hant_MO"/>
+ <append-configuration-property name="runtime.locales" value="zh_Hant_TW"/>
+ <append-configuration-property name="runtime.locales" value="zh_HK"/>
+ <append-configuration-property name="runtime.locales" value="zh_MO"/>
+ <append-configuration-property name="runtime.locales" value="zh_SG"/>
+ <append-configuration-property name="runtime.locales" value="zh_TW"/>
+ <append-configuration-property name="runtime.locales" value="zu"/>
+ <append-configuration-property name="runtime.locales" value="zu_ZA"/>
+</module>
diff --git a/user/src/com/google/gwt/i18n/I18N.gwt.xml b/user/src/com/google/gwt/i18n/I18N.gwt.xml
index e84868c..24202d8 100644
--- a/user/src/com/google/gwt/i18n/I18N.gwt.xml
+++ b/user/src/com/google/gwt/i18n/I18N.gwt.xml
@@ -47,6 +47,8 @@
if (locale == null) {
// Look for an override computed by other means in the selection script
locale = $wnd['__gwt_Locale'];
+ } else {
+ $wnd['__gwt_Locale'] = locale || 'default';
}
if (locale == null) {
@@ -79,4 +81,13 @@
<generate-with class="com.google.gwt.i18n.rebind.CurrencyListGenerator">
<when-type-is class="com.google.gwt.i18n.client.impl.CurrencyList" />
</generate-with>
+
+ <!--
+ Set of locales to be selectable at runtime. Only those which extend
+ the locale of the current permutation will actually be included. Note
+ that currently only number/date format constants, locale names, and
+ currency data will support runtime locales - everything else will just
+ reference the compile-time locale set in the "locale" property.
+ -->
+ <set-configuration-property name="runtime.locales" value=""/>
</module>
diff --git a/user/src/com/google/gwt/i18n/client/DateTimeFormat.java b/user/src/com/google/gwt/i18n/client/DateTimeFormat.java
index 56d6436..f5c9edf 100644
--- a/user/src/com/google/gwt/i18n/client/DateTimeFormat.java
+++ b/user/src/com/google/gwt/i18n/client/DateTimeFormat.java
@@ -16,7 +16,6 @@
package com.google.gwt.i18n.client;
-import com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.client.constants.DateTimeConstants;
import com.google.gwt.i18n.client.impl.DateRecord;
@@ -407,7 +406,7 @@
private static DateTimeFormat cachedShortDateTimeFormat;
private static final int NUM_MILLISECONDS_IN_DAY = 24 * 60 * 60000;
- private static final DateTimeConstants defaultDateTimeConstants = (DateTimeConstants) GWT.create(DateTimeConstants.class);
+ private static final DateTimeConstants defaultDateTimeConstants = LocaleInfo.getCurrentLocale().getDateTimeConstants();
private static final String PATTERN_CHARS = "GyMdkHmsSEDahKzZv";
diff --git a/user/src/com/google/gwt/i18n/client/LocaleInfo.java b/user/src/com/google/gwt/i18n/client/LocaleInfo.java
index 4d450d4..b00d586 100644
--- a/user/src/com/google/gwt/i18n/client/LocaleInfo.java
+++ b/user/src/com/google/gwt/i18n/client/LocaleInfo.java
@@ -16,6 +16,8 @@
package com.google.gwt.i18n.client;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.constants.DateTimeConstants;
+import com.google.gwt.i18n.client.constants.NumberConstants;
import com.google.gwt.i18n.client.impl.CldrImpl;
import com.google.gwt.i18n.client.impl.LocaleInfoImpl;
@@ -37,7 +39,7 @@
/**
* @return an array of available locale names
*/
- public static String[] getAvailableLocaleNames() {
+ public static final String[] getAvailableLocaleNames() {
/*
* The set of all locales is constant across all permutations, so this
* is static. Ideally, the set of available locales would be generated
@@ -55,7 +57,7 @@
/**
* @return a LocaleInfo instance for the current locale
*/
- public static LocaleInfo getCurrentLocale() {
+ public static final LocaleInfo getCurrentLocale() {
/*
* In the future, we could make additional static methods which returned a
* LocaleInfo instance for a specific locale (from the set of those the app
@@ -85,9 +87,13 @@
}
private final LocaleInfoImpl infoImpl;
-
+
private final CldrImpl cldrImpl;
+
+ private DateTimeConstants dateTimeConstants;
+ private NumberConstants numberConstants;
+
/**
* Constructor to be used by subclasses, such as mock classes for testing.
* Any such subclass should override all methods.
@@ -96,7 +102,7 @@
infoImpl = null;
cldrImpl = null;
}
-
+
/**
* Create a LocaleInfo instance, passing in the implementation classes.
*
@@ -107,18 +113,46 @@
this.infoImpl = impl;
this.cldrImpl = cldr;
}
-
+
/**
- * @return the name of this locale, such as "default, "en_US", etc
+ * @return a NumberConstants interface for this locale.
*/
- public String getLocaleName() {
- return infoImpl.getLocaleName();
+ public final DateTimeConstants getDateTimeConstants() {
+ ensureDateTimeConstants();
+ return dateTimeConstants;
}
/**
+ * @return the name of this locale, such as "default, "en_US", etc
+ */
+ public final String getLocaleName() {
+ return infoImpl.getLocaleName();
+ }
+
+ /**
+ * @return a NumberConstants interface for this locale.
+ */
+ public final NumberConstants getNumberConstants() {
+ ensureNumberConstants();
+ return numberConstants;
+ }
+
+ /**
* @return true if this locale is right-to-left instead of left-to-right
*/
- public boolean isRTL() {
+ public final boolean isRTL() {
return cldrImpl.isRTL();
}
+
+ private void ensureDateTimeConstants() {
+ if (dateTimeConstants == null) {
+ dateTimeConstants = infoImpl.getDateTimeConstants();
+ }
+ }
+
+ private void ensureNumberConstants() {
+ if (numberConstants == null) {
+ numberConstants = infoImpl.getNumberConstants();
+ }
+ }
}
diff --git a/user/src/com/google/gwt/i18n/client/LocalizableResource.java b/user/src/com/google/gwt/i18n/client/LocalizableResource.java
index b1791a4..04de765 100644
--- a/user/src/com/google/gwt/i18n/client/LocalizableResource.java
+++ b/user/src/com/google/gwt/i18n/client/LocalizableResource.java
@@ -36,15 +36,18 @@
* one.
*/
public interface LocalizableResource extends Localizable {
-
+
/**
* Specifies the default locale for messages in this file. If not
- * specified, the default is en_US.
+ * specified, the default is <code>DEFAULT_LOCALE</code>.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DefaultLocale {
- String value() default "en_US";
+
+ String DEFAULT_LOCALE = "en";
+
+ String value() default DEFAULT_LOCALE;
}
/**
diff --git a/user/src/com/google/gwt/i18n/client/NumberFormat.java b/user/src/com/google/gwt/i18n/client/NumberFormat.java
index a589e86..711820b 100644
--- a/user/src/com/google/gwt/i18n/client/NumberFormat.java
+++ b/user/src/com/google/gwt/i18n/client/NumberFormat.java
@@ -307,7 +307,7 @@
public class NumberFormat {
// Sets of constants as defined for the default locale.
- private static final NumberConstants defaultNumberConstants = (NumberConstants) GWT.create(NumberConstants.class);
+ private static final NumberConstants defaultNumberConstants = LocaleInfo.getCurrentLocale().getNumberConstants();
// Constants for characters used in programmatic (unlocalized) patterns.
private static final char PATTERN_ZERO_DIGIT = '0';
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants.java b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants.java
index 240ce81d..998803b 100644
--- a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants.java
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants.java
@@ -15,16 +15,17 @@
*/
package com.google.gwt.i18n.client.constants;
-import com.google.gwt.i18n.client.Constants;
-
/**
* DateTimeConstants class encapsulate a collection of DateTime formatting
* symbols for use with DateTime format and parse services. This class extends
* GWT's Constants class. The actual symbol collections are defined in a set of
* property files named like "DateTimeConstants_xx.properties". GWT will will
* perform late binding to the property file that specific to user's locale.
+ *
+ * If you previously were using GWT.create on this interface, you should
+ * use LocaleInfo.getDateTimeConstants() instead.
*/
-public interface DateTimeConstants extends Constants {
+public interface DateTimeConstants {
String[] ampms();
String[] dateFormats();
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl.java b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl.java
new file mode 100644
index 0000000..f95e4ea
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl.java
@@ -0,0 +1,69 @@
+/*
+ * 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.constants;
+
+import com.google.gwt.i18n.client.Constants;
+
+/**
+ * DateTimeConstantsImpl class encapsulate a collection of DateTime formatting
+ * symbols for use with DateTime format and parse services. This class extends
+ * GWT's Constants class. The actual symbol collections are defined in a set of
+ * property files named like "DateTimeConstants_xx.properties". GWT will will
+ * perform late binding to the property file that specific to user's locale.
+ */
+public interface DateTimeConstantsImpl extends Constants, DateTimeConstants {
+ String[] ampms();
+
+ String[] dateFormats();
+
+ String[] eraNames();
+
+ String[] eras();
+
+ String firstDayOfTheWeek();
+
+ String[] months();
+
+ String[] narrowMonths();
+
+ String[] narrowWeekdays();
+
+ String[] quarters();
+
+ String[] shortMonths();
+
+ String[] shortQuarters();
+
+ String[] shortWeekdays();
+
+ String[] standaloneMonths();
+
+ String[] standaloneNarrowMonths();
+
+ String[] standaloneNarrowWeekdays();
+
+ String[] standaloneShortMonths();
+
+ String[] standaloneShortWeekdays();
+
+ String[] standaloneWeekdays();
+
+ String[] timeFormats();
+
+ String[] weekdays();
+
+ String[] weekendRange();
+}
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa_DJ.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa_DJ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa_DJ.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa_DJ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa_ER.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa_ER.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa_ER.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa_ER.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa_ER_SAAHO.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa_ER_SAAHO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa_ER_SAAHO.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa_ER_SAAHO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa_ET.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa_ET.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_aa_ET.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_aa_ET.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_af.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_af.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_af.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_af.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_af_NA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_af_NA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_af_NA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_af_NA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ak.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ak.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ak.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ak.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_am.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_am.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_am.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_am.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_AE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_AE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_AE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_AE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_DZ.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_DZ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_DZ.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_DZ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_EG.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_EG.properties
new file mode 100644
index 0000000..b3aba40
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_EG.properties
@@ -0,0 +1,21 @@
+eras = ق.م, م
+eraNames = قبل الميلاد, ميلادي
+narrowMonths = ي, ف, م, أ, و, ن, ل, غ, س, ك, ب, د
+months = يناير, فبراير, مارس, أبريل, مايو, يونيو, يوليو, أغسطس, سبتمبر, أكتوبر, نوفمبر, ديسمبر
+shortMonths = يناير, فبراير, مارس, أبريل, مايو, يونيو, يوليو, أغسطس, سبتمبر, أكتوبر, نوفمبر, ديسمبر
+standaloneNarrowMonths = ي, ف, م, أ, و, ن, ل, غ, س, ك, ب, د
+standaloneMonths = يناير, فبراير, مارس, أبريل, مايو, يونيو, يوليو, أغسطس, سبتمبر, أكتوبر, نوفمبر, ديسمبر
+standaloneShortMonths = يناير, فبراير, مارس, أبريل, مايو, يونيو, يوليو, أغسطس, سبتمبر, أكتوبر, نوفمبر, ديسمبر
+weekdays = الأحد, الاثنين, الثلاثاء, الأربعاء, الخميس, الجمعة, السبت
+shortWeekdays = ح, ن, ث, ر, خ, ج, س
+narrowWeekdays = ح, ن, ث, ر, خ, ج, س
+standaloneWeekdays = الأحد, الاثنين, الثلاثاء, الأربعاء, الخميس, الجمعة, السبت
+standaloneShortWeekdays = ح, ن, ث, ر, خ, ج, س
+standaloneNarrowWeekdays = ح, ن, ث, ر, خ, ج, س
+shortQuarters = الربع الأول, الربع الثاني, الربع الثالث, الربع الرابع
+quarters = الربع الأول, الربع الثاني, الربع الثالث, الربع الرابع
+ampms = ص, م
+dateFormats = EEEE\\, d MMMM\\, yyyy, d MMMM\\, yyyy, dd/MM/yyyy, d/M/yyyy
+timeFormats = v h:mm:ss a, z h:mm:ss a, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 7
+weekendRange = 6, 7
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_JO.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_JO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_JO.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_JO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_KW.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_KW.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_KW.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_KW.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_LB.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_LB.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_LB.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_LB.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_OM.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_OM.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_OM.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_OM.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_QA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_QA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_QA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_QA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_SA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_SA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_SA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_SA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_SD.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_SD.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_SD.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_SD.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_SY.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_SY.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_SY.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_SY.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_TN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_TN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_TN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_TN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_YE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_YE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ar_YE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ar_YE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_as.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_as.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_as.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_as.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_as_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_as_IN.properties
new file mode 100644
index 0000000..e4844ac
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_as_IN.properties
@@ -0,0 +1,21 @@
+eras = BCE, CE
+eraNames = Before Christ, Anno Domini
+narrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+months = জানুয়াৰী, ফেব্ৰুয়াৰী, মাৰ্চ, এপ্ৰিল, মে, জুন, জুলাই, আগষ্ট, সেপ্টেম্বৰ, অক্টোবৰ, নভেম্বৰ, ডিসেম্বৰ
+shortMonths = জানু, ফেব্ৰু, মাৰ্চ, এপ্ৰিল, মে, জুন, জুলাই, আগ, সেপ্ট, অক্টো, নভে, ডিসে
+standaloneNarrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneMonths = জানুয়াৰী, ফেব্ৰুয়াৰী, মাৰ্চ, এপ্ৰিল, মে, জুন, জুলাই, আগষ্ট, সেপ্টেম্বৰ, অক্টোবৰ, নভেম্বৰ, ডিসেম্বৰ
+standaloneShortMonths = জানু, ফেব্ৰু, মাৰ্চ, এপ্ৰিল, মে, জুন, জুলাই, আগ, সেপ্ট, অক্টো, নভে, ডিসে
+weekdays = দেওবাৰ, সোমবাৰ, মঙ্গলবাৰ, বুধবাৰ, বৃহষ্পতিবাৰ, শুক্ৰবাৰ, শনিবাৰ
+shortWeekdays = ৰবি, সোম, মঙ্গল, বুধ, বৃহষ্পতি, শুক্ৰ, শনি
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = দেওবাৰ, সোমবাৰ, মঙ্গলবাৰ, বুধবাৰ, বৃহষ্পতিবাৰ, শুক্ৰবাৰ, শনিবাৰ
+standaloneShortWeekdays = ৰবি, সোম, মঙ্গল, বুধ, বৃহষ্পতি, শুক্ৰ, শনি
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = Q1, Q2, Q3, Q4
+ampms = পূৰ্বা, অপ
+dateFormats = EEEE\\, d MMMM\\, yyyy, d MMMM\\, yyyy, dd-MM-yyyy, d-M-yyyy
+timeFormats = h.mm.ss a v, h.mm.ss a z, h.mm.ss a, h.mm. a
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_az.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_az.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_az.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_az.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_az_Cyrl.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_az_Cyrl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_az_Cyrl.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_az_Cyrl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_be.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_be.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_be.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_be.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_bg.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bg.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_bg.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bg.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_bn.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_bn.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_bn_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bn_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_bn_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bn_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bo.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bo.properties
new file mode 100644
index 0000000..f303881
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bo.properties
@@ -0,0 +1,21 @@
+eras = སྤྱི་ལོ་སྔོན།, སྤྱི་ལོ།
+eraNames = སྤྱི་ལོ་སྔོན།, སྤྱི་ལོ།
+narrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+months = ཟླ་བ་དང་པོ་, ཟླ་བ་གཉིས་པ་, ཟླ་བ་སུམ་པ་, ཟླ་བ་བཞི་པ་, ཟླ་བ་ལྔ་པ་, ཟླ་བ་དྲུག་པ་, ཟླ་བ་བདུན་པ་, ཟླ་བ་བརྒྱད་པ་, ཟླ་བ་དགུ་པ་, ཟླ་བ་བཅུ་པ་, ཟླ་བ་བཅུ་གཅིག་པ་, ཟླ་བ་བཅུ་གཉིས་པ་
+shortMonths = ཟླ་༡, ཟླ་༢, ཟླ་༣, ཟླ་༤, ཟླ་༥, ཟླ་༦, ཟླ་༧, ཟླ་༨, ཟླ་༩, ཟླ་༡༠, ཟླ་༡༡, ཟླ་༡༢
+standaloneNarrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+standaloneMonths = ཟླ་བ་དང་པོ་, ཟླ་བ་གཉིས་པ་, ཟླ་བ་སུམ་པ་, ཟླ་བ་བཞི་པ་, ཟླ་བ་ལྔ་པ་, ཟླ་བ་དྲུག་པ་, ཟླ་བ་བདུན་པ་, ཟླ་བ་བརྒྱད་པ་, ཟླ་བ་དགུ་པ་, ཟླ་བ་བཅུ་པ་, ཟླ་བ་བཅུ་གཅིག་པ་, ཟླ་བ་བཅུ་གཉིས་པ་
+standaloneShortMonths = ཟླ་༡, ཟླ་༢, ཟླ་༣, ཟླ་༤, ཟླ་༥, ཟླ་༦, ཟླ་༧, ཟླ་༨, ཟླ་༩, ཟླ་༡༠, ཟླ་༡༡, ཟླ་༡༢
+weekdays = གཟའ་ཉི་མ་, གཟའ་ཟླ་བ་, གཟའ་མིག་དམར་, གཟའ་ཧླག་པ་, གཟའ་ཕུར་བུ་, གཟའ་སངས་, གཟའ་སྤེན་པ་
+shortWeekdays = ཉི་མ་, ཟླ་བ་, མིག་དམར་, ཧླག་པ་, ཕུར་བུ་, སངས་, སྤེན་པ་
+narrowWeekdays = ཉི, ཟླ, མི, ཧླ, ཕུ, ས, སྤེ
+standaloneWeekdays = གཟའ་ཉི་མ་, གཟའ་ཟླ་བ་, གཟའ་མིག་དམར་, གཟའ་ཧླག་པ་, གཟའ་ཕུར་བུ་, གཟའ་སངས་, གཟའ་སྤེན་པ་
+standaloneShortWeekdays = ཉི་མ་, ཟླ་བ་, མིག་དམར་, ཧླག་པ་, ཕུར་བུ་, སངས་, སྤེན་པ་
+standaloneNarrowWeekdays = ཉི, ཟླ, མི, ཧླ, ཕུ, ས, སྤེ
+shortQuarters = དུས་ཚིགས་དང་པོ།, དུས་ཚིགས་གཉིས་པ།, ་དུས་ཚིགས་གསུམ་པ།, དུས་ཚིགས་བཞི་པ།
+quarters = དུས་ཚིགས་དང་པོ།, དུས་ཚིགས་གཉིས་པ།, ་དུས་ཚིགས་གསུམ་པ།, དུས་ཚིགས་བཞི་པ།
+ampms = སྔ་དྲོ་, ཕྱི་དྲོ་
+dateFormats = EEEE\\, MMMM d\\, yyyy, སྦྱི་ལོ་yyyy MMMMའི་ཙེས་dད, yyyy ལོ་འི་MMMཙེས་d, M/d/yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 1
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bo_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bo_IN.properties
new file mode 100644
index 0000000..2b22dea
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bo_IN.properties
@@ -0,0 +1,21 @@
+eras = སྤྱི་ལོ་སྔོན།, སྤྱི་ལོ།
+eraNames = སྤྱི་ལོ་སྔོན།, སྤྱི་ལོ།
+narrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+months = ཟླ་བ་དང་པོ་, ཟླ་བ་གཉིས་པ་, ཟླ་བ་སུམ་པ་, ཟླ་བ་བཞི་པ་, ཟླ་བ་ལྔ་པ་, ཟླ་བ་དྲུག་པ་, ཟླ་བ་བདུན་པ་, ཟླ་བ་བརྒྱད་པ་, ཟླ་བ་དགུ་པ་, ཟླ་བ་བཅུ་པ་, ཟླ་བ་བཅུ་གཅིག་པ་, ཟླ་བ་བཅུ་གཉིས་པ་
+shortMonths = ཟླ་༡, ཟླ་༢, ཟླ་༣, ཟླ་༤, ཟླ་༥, ཟླ་༦, ཟླ་༧, ཟླ་༨, ཟླ་༩, ཟླ་༡༠, ཟླ་༡༡, ཟླ་༡༢
+standaloneNarrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+standaloneMonths = ཟླ་བ་དང་པོ་, ཟླ་བ་གཉིས་པ་, ཟླ་བ་སུམ་པ་, ཟླ་བ་བཞི་པ་, ཟླ་བ་ལྔ་པ་, ཟླ་བ་དྲུག་པ་, ཟླ་བ་བདུན་པ་, ཟླ་བ་བརྒྱད་པ་, ཟླ་བ་དགུ་པ་, ཟླ་བ་བཅུ་པ་, ཟླ་བ་བཅུ་གཅིག་པ་, ཟླ་བ་བཅུ་གཉིས་པ་
+standaloneShortMonths = ཟླ་༡, ཟླ་༢, ཟླ་༣, ཟླ་༤, ཟླ་༥, ཟླ་༦, ཟླ་༧, ཟླ་༨, ཟླ་༩, ཟླ་༡༠, ཟླ་༡༡, ཟླ་༡༢
+weekdays = གཟའ་ཉི་མ་, གཟའ་ཟླ་བ་, གཟའ་མིག་དམར་, གཟའ་ཧླག་པ་, གཟའ་ཕུར་བུ་, གཟའ་སངས་, གཟའ་སྤེན་པ་
+shortWeekdays = ཉི་མ་, ཟླ་བ་, མིག་དམར་, ཧླག་པ་, ཕུར་བུ་, སངས་, སྤེན་པ་
+narrowWeekdays = ཉི, ཟླ, མི, ཧླ, ཕུ, ས, སྤེ
+standaloneWeekdays = གཟའ་ཉི་མ་, གཟའ་ཟླ་བ་, གཟའ་མིག་དམར་, གཟའ་ཧླག་པ་, གཟའ་ཕུར་བུ་, གཟའ་སངས་, གཟའ་སྤེན་པ་
+standaloneShortWeekdays = ཉི་མ་, ཟླ་བ་, མིག་དམར་, ཧླག་པ་, ཕུར་བུ་, སངས་, སྤེན་པ་
+standaloneNarrowWeekdays = ཉི, ཟླ, མི, ཧླ, ཕུ, ས, སྤེ
+shortQuarters = དུས་ཚིགས་དང་པོ།, དུས་ཚིགས་གཉིས་པ།, ་དུས་ཚིགས་གསུམ་པ།, དུས་ཚིགས་བཞི་པ།
+quarters = དུས་ཚིགས་དང་པོ།, དུས་ཚིགས་གཉིས་པ།, ་དུས་ཚིགས་གསུམ་པ།, དུས་ཚིགས་བཞི་པ།
+ampms = སྔ་དྲོ་, ཕྱི་དྲོ་
+dateFormats = EEEE\\, MMMM d\\, yyyy, སྦྱི་ལོ་yyyy MMMMའི་ཙེས་dད, yyyy ལོ་འི་MMMཙེས་d, M/d/yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_bs.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bs.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_bs.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_bs.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_byn.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_byn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_byn.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_byn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_byn_ER.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_byn_ER.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_byn_ER.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_byn_ER.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ca.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ca.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ca.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ca.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_cch.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_cch.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_cch.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_cch.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_cop.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_cop.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_cop.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_cop.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_cs.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_cs.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_cs.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_cs.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_cy.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_cy.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_cy.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_cy.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_da.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_da.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_da.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_da.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_de.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_de.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_de.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_de.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_de_AT.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_de_AT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_de_AT.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_de_AT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_de_BE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_de_BE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_de_BE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_de_BE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_dv.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_dv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_dv.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_dv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_dz.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_dz.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_dz.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_dz.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ee.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ee.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ee.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ee.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_el.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_el.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_el.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_el.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_el_POLYTON.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_el_POLYTON.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_el_POLYTON.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_el_POLYTON.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en.properties
new file mode 100644
index 0000000..21a1223
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en.properties
@@ -0,0 +1,21 @@
+eras = BC, AD
+eraNames = Before Christ, Anno Domini
+narrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+months = January, February, March, April, May, June, July, August, September, October, November, December
+shortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+standaloneNarrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+standaloneMonths = January, February, March, April, May, June, July, August, September, October, November, December
+standaloneShortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+weekdays = Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
+shortWeekdays = Sun, Mon, Tue, Wed, Thu, Fri, Sat
+narrowWeekdays = S, M, T, W, T, F, S
+standaloneWeekdays = Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
+standaloneShortWeekdays = Sun, Mon, Tue, Wed, Thu, Fri, Sat
+standaloneNarrowWeekdays = S, M, T, W, T, F, S
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = 1st quarter, 2nd quarter, 3rd quarter, 4th quarter
+ampms = AM, PM
+dateFormats = EEEE\\, MMMM d\\, yyyy, MMMM d\\, yyyy, MMM d\\, yyyy, M/d/yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 1
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_AU.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_AU.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_AU.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_AU.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_BE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_BE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_BE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_BE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_BW.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_BW.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_BW.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_BW.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_BZ.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_BZ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_BZ.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_BZ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_CA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_CA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_CA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_CA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_Dsrt.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_Dsrt.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_Dsrt.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_Dsrt.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_Dsrt_US.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_Dsrt_US.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_Dsrt_US.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_Dsrt_US.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_GB.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_GB.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_GB.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_GB.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_HK.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_HK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_HK.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_HK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_IE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_IE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_IE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_IE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_MT.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_MT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_MT.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_MT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_NA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_NA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_NA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_NA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_NZ.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_NZ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_NZ.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_NZ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_PK.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_PK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_PK.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_PK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_SG.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_SG.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_SG.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_SG.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_Shaw.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_Shaw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_Shaw.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_Shaw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_ZA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_ZA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_ZA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_ZA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_ZW.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_ZW.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_en_ZW.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_en_ZW.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_eo.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_eo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_eo.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_eo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_AR.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_AR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_AR.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_AR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_CL.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_CL.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_CL.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_CL.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_CO.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_CO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_CO.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_CO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_EC.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_EC.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_EC.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_EC.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_ES.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_ES.properties
new file mode 100644
index 0000000..e5cb004
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_ES.properties
@@ -0,0 +1,21 @@
+eras = a.C., d.C.
+eraNames = antes de Cristo, anno Dómini
+narrowMonths = E, F, M, A, M, J, J, A, S, O, N, D
+months = enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre
+shortMonths = ene, feb, mar, abr, may, jun, jul, ago, sep, oct, nov, dic
+standaloneNarrowMonths = E, F, M, A, M, J, J, A, S, O, N, D
+standaloneMonths = enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre
+standaloneShortMonths = ene, feb, mar, abr, may, jun, jul, ago, sep, oct, nov, dic
+weekdays = domingo, lunes, martes, miércoles, jueves, viernes, sábado
+shortWeekdays = dom, lun, mar, mié, jue, vie, sáb
+narrowWeekdays = D, L, M, M, J, V, S
+standaloneWeekdays = domingo, lunes, martes, miércoles, jueves, viernes, sábado
+standaloneShortWeekdays = dom, lun, mar, mié, jue, vie, sáb
+standaloneNarrowWeekdays = D, L, M, M, J, V, S
+shortQuarters = T1, T2, T3, T4
+quarters = 1er trimestre, 2º trimestre, 3er trimestre, 4º trimestre
+ampms = a.m., p.m.
+dateFormats = EEEE d 'de' MMMM 'de' yyyy, d 'de' MMMM 'de' yyyy, dd/MM/yyyy, dd/MM/yy
+timeFormats = HH'H'mm''ss" v, HH:mm:ss z, H:mm:ss, H:mm
+firstDayOfTheWeek = 2
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_GT.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_GT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_GT.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_GT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_HN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_HN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_HN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_HN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_PA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_PA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_PA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_PA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_PE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_PE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_PE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_PE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_PR.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_PR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_PR.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_PR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_US.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_US.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_es_US.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_es_US.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_et.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_et.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_et.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_et.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_eu.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_eu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_eu.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_eu.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fa.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fa.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fa_AF.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fa_AF.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fa_AF.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fa_AF.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fi.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fi.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fi.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fi.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fil.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fil.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fil.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fil.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fo.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fo.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fr.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fr.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fr_BE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fr_BE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fr_BE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fr_BE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fr_CA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fr_CA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fr_CA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fr_CA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fr_CH.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fr_CH.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fr_CH.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fr_CH.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fur.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fur.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_fur.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_fur.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ga.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ga.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ga.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ga.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gaa.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gaa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gaa.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gaa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gez.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gez.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gez.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gez.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gez_ER.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gez_ER.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gez_ER.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gez_ER.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gez_ET.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gez_ET.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gez_ET.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gez_ET.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gl.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gl.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gu.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gu.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gu.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gu_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gu_IN.properties
new file mode 100644
index 0000000..f9ae518
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gu_IN.properties
@@ -0,0 +1,21 @@
+eras = BCE, CE
+eraNames = ઈસાપૂઋ્વ., સન.
+narrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+months = જાન્યુઆરી, ફેબ્રુઆરી, માર્ચ, એપ્રિલ, મે, જૂન, જુલાઈ, ઑગસ્ટ, સપ્ટેમ્બર, ઑક્ટ્બર, નવેમ્બર, ડિસેમ્બર
+shortMonths = જાન્યુ, ફેબ્રુ, માર્ચ, એપ્રિલ, મે, જૂન, જુલાઈ, ઑગસ્ટ, સપ્ટે, ઑક્ટો, નવે, ડિસે
+standaloneNarrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneMonths = જાન્યુઆરી, ફેબ્રુઆરી, માર્ચ, એપ્રિલ, મે, જૂન, જુલાઈ, ઑગસ્ટ, સપ્ટેમ્બર, ઑક્ટ્બર, નવેમ્બર, ડિસેમ્બર
+standaloneShortMonths = જાન્યુ, ફેબ્રુ, માર્ચ, એપ્રિલ, મે, જૂન, જુલાઈ, ઑગસ્ટ, સપ્ટે, ઑક્ટો, નવે, ડિસે
+weekdays = રવિવાર, સોમવાર, મંગળવાર, બુધવાર, ગુરુવાર, શુક્રવાર, શનિવાર
+shortWeekdays = રવિ, સોમ, મંગળ, બુધ, ગુરુ, શુક્ર, શનિ
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = રવિવાર, સોમવાર, મંગળવાર, બુધવાર, ગુરુવાર, શુક્રવાર, શનિવાર
+standaloneShortWeekdays = રવિ, સોમ, મંગળ, બુધ, ગુરુ, શુક્ર, શનિ
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = પેહલા હંત 1, ડૂસઋા હંત 2, તીસઋા હંત 3, ચૌતા હંત 4
+ampms = પૂર્વ મધ્યાહ્ન, ઉત્તર મધ્યાહ્ન
+dateFormats = EEEE d MMMM yyyy, d MMMM yyyy, dd-MM-yyyy, d-MM-yy
+timeFormats = hh:mm:ss a v, hh:mm:ss a z, hh:mm:ss a, hh:mm a
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gv.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_gv.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_gv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ha.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ha.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ha_Arab.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Arab.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ha_Arab.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Arab.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ha_Arab_SD.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Arab_SD.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ha_Arab_SD.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Arab_SD.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Latn_GH.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Latn_GH.properties
new file mode 100644
index 0000000..82db34d
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Latn_GH.properties
@@ -0,0 +1,21 @@
+eras = GM, M
+eraNames = Gabanin Miladi, Miladi
+narrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+months = Janairu, Fabrairu, Maris, Afrilu, Mayu, Yuni, Yuli, Agusta, Satumba, Oktoba, Nuwamba, Disamba
+shortMonths = Jan, Fab, Mar, Afr, May, Yun, Yul, Agu, Sat, Okt, Nuw, Dis
+standaloneNarrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneMonths = Janairu, Fabrairu, Maris, Afrilu, Mayu, Yuni, Yuli, Agusta, Satumba, Oktoba, Nuwamba, Disamba
+standaloneShortMonths = Jan, Fab, Mar, Afr, May, Yun, Yul, Agu, Sat, Okt, Nuw, Dis
+weekdays = Lahadi, Littinin, Talata, Laraba, Alhamis, Jumma'a, Asabar
+shortWeekdays = Lah, Lit, Tal, Lar, Alh, Jum, Asa
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = Lahadi, Littinin, Talata, Laraba, Alhamis, Jumma'a, Asabar
+standaloneShortWeekdays = Lah, Lit, Tal, Lar, Alh, Jum, Asa
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = Q1, Q2, Q3, Q4
+ampms = AM, PM
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 2
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Latn_NE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Latn_NE.properties
new file mode 100644
index 0000000..82db34d
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_Latn_NE.properties
@@ -0,0 +1,21 @@
+eras = GM, M
+eraNames = Gabanin Miladi, Miladi
+narrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+months = Janairu, Fabrairu, Maris, Afrilu, Mayu, Yuni, Yuli, Agusta, Satumba, Oktoba, Nuwamba, Disamba
+shortMonths = Jan, Fab, Mar, Afr, May, Yun, Yul, Agu, Sat, Okt, Nuw, Dis
+standaloneNarrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneMonths = Janairu, Fabrairu, Maris, Afrilu, Mayu, Yuni, Yuli, Agusta, Satumba, Oktoba, Nuwamba, Disamba
+standaloneShortMonths = Jan, Fab, Mar, Afr, May, Yun, Yul, Agu, Sat, Okt, Nuw, Dis
+weekdays = Lahadi, Littinin, Talata, Laraba, Alhamis, Jumma'a, Asabar
+shortWeekdays = Lah, Lit, Tal, Lar, Alh, Jum, Asa
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = Lahadi, Littinin, Talata, Laraba, Alhamis, Jumma'a, Asabar
+standaloneShortWeekdays = Lah, Lit, Tal, Lar, Alh, Jum, Asa
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = Q1, Q2, Q3, Q4
+ampms = AM, PM
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 2
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_NE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_NE.properties
new file mode 100644
index 0000000..82db34d
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_NE.properties
@@ -0,0 +1,21 @@
+eras = GM, M
+eraNames = Gabanin Miladi, Miladi
+narrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+months = Janairu, Fabrairu, Maris, Afrilu, Mayu, Yuni, Yuli, Agusta, Satumba, Oktoba, Nuwamba, Disamba
+shortMonths = Jan, Fab, Mar, Afr, May, Yun, Yul, Agu, Sat, Okt, Nuw, Dis
+standaloneNarrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneMonths = Janairu, Fabrairu, Maris, Afrilu, Mayu, Yuni, Yuli, Agusta, Satumba, Oktoba, Nuwamba, Disamba
+standaloneShortMonths = Jan, Fab, Mar, Afr, May, Yun, Yul, Agu, Sat, Okt, Nuw, Dis
+weekdays = Lahadi, Littinin, Talata, Laraba, Alhamis, Jumma'a, Asabar
+shortWeekdays = Lah, Lit, Tal, Lar, Alh, Jum, Asa
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = Lahadi, Littinin, Talata, Laraba, Alhamis, Jumma'a, Asabar
+standaloneShortWeekdays = Lah, Lit, Tal, Lar, Alh, Jum, Asa
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = Q1, Q2, Q3, Q4
+ampms = AM, PM
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 2
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ha_SD.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_SD.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ha_SD.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ha_SD.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_haw.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_haw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_haw.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_haw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_haw_US.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_haw_US.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_haw_US.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_haw_US.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_he.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_he.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_he.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_he.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_hi.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_hi.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_hi.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_hi.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_hr.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_hr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_hr.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_hr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_hu.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_hu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_hu.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_hu.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_hy.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_hy.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_hy.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_hy.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ia.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ia.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ia.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ia.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_id.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_id.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_id.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_id.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ig.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ig.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ig.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ig.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ii.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ii.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ii.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ii.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ii_CN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ii_CN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ii_CN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ii_CN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_in.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_in.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_in.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_in.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_is.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_is.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_is.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_is.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_it.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_it.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_it.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_it.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_it_CH.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_it_CH.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_it_CH.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_it_CH.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_iu.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_iu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_iu.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_iu.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_iw.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_iw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_iw.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_iw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ja.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ja.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ja.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ja.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ka.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ka.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ka.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ka.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kaj.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kaj.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kaj.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kaj.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kam.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kam.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kam.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kam.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kam_KE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kam_KE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kam_KE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kam_KE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kcg.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kcg.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kcg.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kcg.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kfo.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kfo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kfo.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kfo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kk.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kk.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kk.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kk.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kl.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kl.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_km.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_km.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_km.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_km.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kn.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kn.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ko.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ko.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ko.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ko.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kok.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kok.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kok.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kok.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kok_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kok_IN.properties
new file mode 100644
index 0000000..3715450
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kok_IN.properties
@@ -0,0 +1,21 @@
+eras = क्रिस्तपूर्व, क्रिस्तशखा
+eraNames = Before Christ, Anno Domini
+narrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+months = जानेवारी, फेब्रुवारी, मार्च, एप्रिल, मे, जून, जुलै, ओगस्ट, सेप्टेंबर, ओक्टोबर, नोव्हेंबर, डिसेंबर
+shortMonths = जानेवारी, फेबृवारी, मार्च, एप्रिल, मे, जून, जुलै, ओगस्ट, सेप्टेंबर, ओक्टोबर, नोव्हेंबर, डिसेंबर
+standaloneNarrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneMonths = जानेवारी, फेब्रुवारी, मार्च, एप्रिल, मे, जून, जुलै, ओगस्ट, सेप्टेंबर, ओक्टोबर, नोव्हेंबर, डिसेंबर
+standaloneShortMonths = जानेवारी, फेबृवारी, मार्च, एप्रिल, मे, जून, जुलै, ओगस्ट, सेप्टेंबर, ओक्टोबर, नोव्हेंबर, डिसेंबर
+weekdays = आदित्यवार, सोमवार, मंगळार, बुधवार, गुरुवार, शुक्रवार, शनिवार
+shortWeekdays = रवि, सोम, मंगळ, बुध, गुरु, शुक्र, शनि
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = आदित्यवार, सोमवार, मंगळार, बुधवार, गुरुवार, शुक्रवार, शनिवार
+standaloneShortWeekdays = रवि, सोम, मंगळ, बुध, गुरु, शुक्र, शनि
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = Q1, Q2, Q3, Q4
+ampms = म.पू., म.नं.
+dateFormats = EEEE d MMMM yyyy, d MMMM yyyy, dd-MM-yyyy, d-M-yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kpe.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kpe.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kpe.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kpe.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ku.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ku.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_IQ.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_IQ.properties
new file mode 100644
index 0000000..8444422
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_IQ.properties
@@ -0,0 +1,21 @@
+eras = BZ, PZ
+eraNames = Before Christ, Anno Domini
+narrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+months = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+shortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+standaloneNarrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+standaloneMonths = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+standaloneShortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+weekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+shortWeekdays = yş, dş, sş, çş, pş, în, ş
+narrowWeekdays = y, d, s, ç, p, î, ş
+standaloneWeekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+standaloneShortWeekdays = yş, dş, sş, çş, pş, în, ş
+standaloneNarrowWeekdays = y, d, s, ç, p, î, ş
+shortQuarters = Ç1, Ç2, Ç3, Ç4
+quarters = Ç1, Ç2, Ç3, Ç4
+ampms = BN, PN
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 7
+weekendRange = 5, 6
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_IR.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_IR.properties
new file mode 100644
index 0000000..8444422
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_IR.properties
@@ -0,0 +1,21 @@
+eras = BZ, PZ
+eraNames = Before Christ, Anno Domini
+narrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+months = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+shortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+standaloneNarrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+standaloneMonths = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+standaloneShortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+weekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+shortWeekdays = yş, dş, sş, çş, pş, în, ş
+narrowWeekdays = y, d, s, ç, p, î, ş
+standaloneWeekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+standaloneShortWeekdays = yş, dş, sş, çş, pş, în, ş
+standaloneNarrowWeekdays = y, d, s, ç, p, î, ş
+shortQuarters = Ç1, Ç2, Ç3, Ç4
+quarters = Ç1, Ç2, Ç3, Ç4
+ampms = BN, PN
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 7
+weekendRange = 5, 6
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ku_Latn.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ku_Latn.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_IQ.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_IQ.properties
new file mode 100644
index 0000000..8444422
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_IQ.properties
@@ -0,0 +1,21 @@
+eras = BZ, PZ
+eraNames = Before Christ, Anno Domini
+narrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+months = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+shortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+standaloneNarrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+standaloneMonths = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+standaloneShortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+weekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+shortWeekdays = yş, dş, sş, çş, pş, în, ş
+narrowWeekdays = y, d, s, ç, p, î, ş
+standaloneWeekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+standaloneShortWeekdays = yş, dş, sş, çş, pş, în, ş
+standaloneNarrowWeekdays = y, d, s, ç, p, î, ş
+shortQuarters = Ç1, Ç2, Ç3, Ç4
+quarters = Ç1, Ç2, Ç3, Ç4
+ampms = BN, PN
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 7
+weekendRange = 5, 6
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_IR.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_IR.properties
new file mode 100644
index 0000000..8444422
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_IR.properties
@@ -0,0 +1,21 @@
+eras = BZ, PZ
+eraNames = Before Christ, Anno Domini
+narrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+months = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+shortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+standaloneNarrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+standaloneMonths = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+standaloneShortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+weekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+shortWeekdays = yş, dş, sş, çş, pş, în, ş
+narrowWeekdays = y, d, s, ç, p, î, ş
+standaloneWeekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+standaloneShortWeekdays = yş, dş, sş, çş, pş, în, ş
+standaloneNarrowWeekdays = y, d, s, ç, p, î, ş
+shortQuarters = Ç1, Ç2, Ç3, Ç4
+quarters = Ç1, Ç2, Ç3, Ç4
+ampms = BN, PN
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 7
+weekendRange = 5, 6
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_SY.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_SY.properties
new file mode 100644
index 0000000..8071494
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_SY.properties
@@ -0,0 +1,21 @@
+eras = BZ, PZ
+eraNames = Before Christ, Anno Domini
+narrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+months = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+shortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+standaloneNarrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+standaloneMonths = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+standaloneShortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+weekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+shortWeekdays = yş, dş, sş, çş, pş, în, ş
+narrowWeekdays = y, d, s, ç, p, î, ş
+standaloneWeekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+standaloneShortWeekdays = yş, dş, sş, çş, pş, în, ş
+standaloneNarrowWeekdays = y, d, s, ç, p, î, ş
+shortQuarters = Ç1, Ç2, Ç3, Ç4
+quarters = Ç1, Ç2, Ç3, Ç4
+ampms = BN, PN
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 5
+weekendRange = 6, 7
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_TR.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_TR.properties
new file mode 100644
index 0000000..e51686b
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_Latn_TR.properties
@@ -0,0 +1,21 @@
+eras = BZ, PZ
+eraNames = Before Christ, Anno Domini
+narrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+months = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+shortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+standaloneNarrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+standaloneMonths = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+standaloneShortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+weekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+shortWeekdays = yş, dş, sş, çş, pş, în, ş
+narrowWeekdays = y, d, s, ç, p, î, ş
+standaloneWeekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+standaloneShortWeekdays = yş, dş, sş, çş, pş, în, ş
+standaloneNarrowWeekdays = y, d, s, ç, p, î, ş
+shortQuarters = Ç1, Ç2, Ç3, Ç4
+quarters = Ç1, Ç2, Ç3, Ç4
+ampms = BN, PN
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 2
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_SY.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_SY.properties
new file mode 100644
index 0000000..8071494
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_SY.properties
@@ -0,0 +1,21 @@
+eras = BZ, PZ
+eraNames = Before Christ, Anno Domini
+narrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+months = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+shortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+standaloneNarrowMonths = ç, s, a, n, g, h, 7, 8, 9, 10, 11, 12
+standaloneMonths = çile, sibat, adar, nîsan, gulan, hezîran, 7, 8, 9, 10, 11, 12
+standaloneShortMonths = çil, sib, adr, nîs, gul, hez, tîr, 8, 9, 10, 11, 12
+weekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+shortWeekdays = yş, dş, sş, çş, pş, în, ş
+narrowWeekdays = y, d, s, ç, p, î, ş
+standaloneWeekdays = yekşem, duşem, şê, çarşem, pêncşem, în, şemî
+standaloneShortWeekdays = yş, dş, sş, çş, pş, în, ş
+standaloneNarrowWeekdays = y, d, s, ç, p, î, ş
+shortQuarters = Ç1, Ç2, Ç3, Ç4
+quarters = Ç1, Ç2, Ç3, Ç4
+ampms = BN, PN
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yy/MM/dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 5
+weekendRange = 6, 7
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ku_TR.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_TR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ku_TR.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ku_TR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kw.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_kw.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_kw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ky.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ky.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ky.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ky.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ln.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ln.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ln.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ln.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_lo.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_lo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_lo.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_lo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_lt.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_lt.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_lt.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_lt.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_lv.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_lv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_lv.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_lv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mk.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mk.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mk.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mk.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ml.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ml.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ml.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ml.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ml_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ml_IN.properties
new file mode 100644
index 0000000..1bfc2fd
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ml_IN.properties
@@ -0,0 +1,21 @@
+eras = ക്രി.മു., ക്രി.പി.
+eraNames = ക്രിസ്തുവിനു് മുമ്പ്, ക്രിസ്തുവിനു് പിമ്പ്
+narrowMonths = ജ, ഫ, മ, ഏ, മ, ജ, ജ, ആ, സ, ഒ, ന, ഡ
+months = ജനുവരി, ഫെബ്രുവരി, മാര്ച്ച്, ഏപ്രില്, മെയ്, ജൂണ്, ജൂലൈ, ആഗസ്ത്, സെപ്തംബര്, ഒക്ടോബര്, നവംബര്, ഡിസംബര്
+shortMonths = ജനു, ഫെബ്രു, മാര്, ഏപ്രി, മെയ്, ജൂണ്, ജൂലൈ, ആഗ, സെപ്തം, ഒക്ടോ, നവം, ഡിസം
+standaloneNarrowMonths = ജ, ഫ, മ, ഏ, മ, ജ, ജ, ആ, സ, ഒ, ന, ഡ
+standaloneMonths = ജനുവരി, ഫെബ്രുവരി, മാര്ച്ച്, ഏപ്രില്, മെയ്, ജൂണ്, ജൂലൈ, ആഗസ്ത്, സെപ്തംബര്, ഒക്ടോബര്, നവംബര്, ഡിസംബര്
+standaloneShortMonths = ജനു, ഫെബ്രു, മാര്, ഏപ്രി, മെയ്, ജൂണ്, ജൂലൈ, ആഗ, സെപ്തം, ഒക്ടോ, നവം, ഡിസം
+weekdays = ഞായര്, തിങ്കള്, ചൊവ്വ, ബുധന്, വ്യാഴം, വെള്ളി, ശനി
+shortWeekdays = ഞാ, തി, ചൊ, ബു, വ്യാ, വെ, ശ
+narrowWeekdays = ഞ, ത, ച, ബ, വ, വ, ശ
+standaloneWeekdays = ഞായര്, തിങ്കള്, ചൊവ്വ, ബുധന്, വ്യാഴം, വെള്ളി, ശനി
+standaloneShortWeekdays = ഞാ, തി, ചൊ, ബു, വ്യാ, വെ, ശ
+standaloneNarrowWeekdays = ഞ, ത, ച, ബ, വ, വ, ശ
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = ഒന്നാം പാദം, രണ്ടാം പാദം, മൂന്നാം പാദം, നാലാം പാദം
+ampms = രാവിലെ, വൈകുന്നേരം
+dateFormats = yyyy\\, MMMM d\\, EEEE, yyyy\\, MMMM d, yyyy\\, MMM d, dd-MM-yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mn.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mn.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mo.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mo.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mr.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mr.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mr_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mr_IN.properties
new file mode 100644
index 0000000..f39b9cd
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mr_IN.properties
@@ -0,0 +1,21 @@
+eras = ईसापूर्व, सन
+eraNames = Before Christ, Anno Domini
+narrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+months = जानेवारी, फेबृवारी, मार्च, एप्रिल, मे, जून, जुलै, ओगस्ट, सेप्टेंबर, ओक्टोबर, नोव्हेंबर, डिसेंबर
+shortMonths = जानेवारी, फेबृवारी, मार्च, एप्रिल, मे, जून, जुलै, ओगस्ट, सेप्टेंबर, ओक्टोबर, नोव्हेंबर, डिसेंबर
+standaloneNarrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneMonths = जानेवारी, फेबृवारी, मार्च, एप्रिल, मे, जून, जुलै, ओगस्ट, सेप्टेंबर, ओक्टोबर, नोव्हेंबर, डिसेंबर
+standaloneShortMonths = जानेवारी, फेबृवारी, मार्च, एप्रिल, मे, जून, जुलै, ओगस्ट, सेप्टेंबर, ओक्टोबर, नोव्हेंबर, डिसेंबर
+weekdays = रविवार, सोमवार, मंगळवार, बुधवार, गुरुवार, शुक्रवार, शनिवार
+shortWeekdays = रवि, सोम, मंगळ, बुध, गुरु, शुक्र, शनि
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = रविवार, सोमवार, मंगळवार, बुधवार, गुरुवार, शुक्रवार, शनिवार
+standaloneShortWeekdays = रवि, सोम, मंगळ, बुध, गुरु, शुक्र, शनि
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = Q1, Q2, Q3, Q4
+ampms = म.पू., म.नं.
+dateFormats = EEEE d MMMM yyyy, d MMMM yyyy, dd-MM-yyyy, d-M-yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ms.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ms.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ms.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ms.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ms_BN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ms_BN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ms_BN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ms_BN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mt.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mt.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_mt.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_mt.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_my.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_my.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_my.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_my.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nb.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nb.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nb.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nb.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ne.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ne.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ne.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ne.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ne_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ne_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ne_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ne_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nl.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nl.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nl_BE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nl_BE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nl_BE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nl_BE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nn.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nn.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_no.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_no.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_no.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_no.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nr.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nr.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nso.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nso.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_nso.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_nso.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ny.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ny.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ny.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ny.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_om.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_om.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_om.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_om.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_om_ET.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_om_ET.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_om_ET.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_om_ET.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_om_KE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_om_KE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_om_KE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_om_KE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_or.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_or.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_or.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_or.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pa.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pa.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pa_Arab.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_Arab.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pa_Arab.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_Arab.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pa_Arab_PK.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_Arab_PK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pa_Arab_PK.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_Arab_PK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_Guru.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_Guru.properties
new file mode 100644
index 0000000..de81a9e
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_Guru.properties
@@ -0,0 +1,21 @@
+eras = BCE, CE
+eraNames = ਈਸਾਪੂਰਵ, ਸੰਨ
+narrowMonths = ਜ, ਫ, ਮਾ, ਅ, ਮ, ਜੂ, ਜੁ, ਅ, ਸ, ਅ, ਨ, ਦ
+months = ਜਨਵਰੀ, ਫ਼ਰਵਰੀ, ਮਾਰਚ, ਅਪ੍ਰੈਲ, ਮਈ, ਜੂਨ, ਜੁਲਾਈ, ਅਗਸਤ, ਸਤੰਬਰ, ਅਕਤੂਬਰ, ਨਵੰਬਰ, ਦਸੰਬਰ
+shortMonths = ਜਨਵਰੀ, ਫ਼ਰਵਰੀ, ਮਾਰਚ, ਅਪ੍ਰੈਲ, ਮਈ, ਜੂਨ, ਜੁਲਾਈ, ਅਗਸਤ, ਸਤੰਬਰ, ਅਕਤੂਬਰ, ਨਵੰਬਰ, ਦਸੰਬਰ
+standaloneNarrowMonths = ਜ, ਫ, ਮਾ, ਅ, ਮ, ਜੂ, ਜੁ, ਅ, ਸ, ਅ, ਨ, ਦ
+standaloneMonths = ਜਨਵਰੀ, ਫ਼ਰਵਰੀ, ਮਾਰਚ, ਅਪ੍ਰੈਲ, ਮਈ, ਜੂਨ, ਜੁਲਾਈ, ਅਗਸਤ, ਸਤੰਬਰ, ਅਕਤੂਬਰ, ਨਵੰਬਰ, ਦਸੰਬਰ
+standaloneShortMonths = ਜਨਵਰੀ, ਫ਼ਰਵਰੀ, ਮਾਰਚ, ਅਪ੍ਰੈਲ, ਮਈ, ਜੂਨ, ਜੁਲਾਈ, ਅਗਸਤ, ਸਤੰਬਰ, ਅਕਤੂਬਰ, ਨਵੰਬਰ, ਦਸੰਬਰ
+weekdays = ਐਤਵਾਰ, ਸੋਮਵਾਰ, ਮੰਗਲਵਾਰ, ਬੁਧਵਾਰ, ਵੀਰਵਾਰ, ਸ਼ੁੱਕਰਵਾਰ, ਸ਼ਨੀਚਰਵਾਰ
+shortWeekdays = ਐਤ., ਸੋਮ., ਮੰਗਲ., ਬੁਧ., ਵੀਰ., ਸ਼ੁਕਰ., ਸ਼ਨੀ.
+narrowWeekdays = ਐ, ਸੋ, ਮੰ, ਬੁੱ, ਵੀ, ਸ਼ੁੱ, ਸ਼
+standaloneWeekdays = ਐਤਵਾਰ, ਸੋਮਵਾਰ, ਮੰਗਲਵਾਰ, ਬੁਧਵਾਰ, ਵੀਰਵਾਰ, ਸ਼ੁੱਕਰਵਾਰ, ਸ਼ਨੀਚਰਵਾਰ
+standaloneShortWeekdays = ਐਤ., ਸੋਮ., ਮੰਗਲ., ਬੁਧ., ਵੀਰ., ਸ਼ੁਕਰ., ਸ਼ਨੀ.
+standaloneNarrowWeekdays = ਐ, ਸੋ, ਮੰ, ਬੁੱ, ਵੀ, ਸ਼ੁੱ, ਸ਼
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = ਪਹਿਲਾਂ ਚੌਥਾਈ, ਦੂਜਾ ਚੌਥਾਈ, ਤੀਜਾ ਚੌਥਾਈ, ਚੌਥਾ ਚੌਥਾਈ
+ampms = ਸਵੇਰੇ, ਸ਼ਾਮ
+dateFormats = EEEE\\, dd MMMM yyyy, yyyy MMMM d, yyyy MMM d, dd/MM/yyy
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_IN.properties
new file mode 100644
index 0000000..de81a9e
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_IN.properties
@@ -0,0 +1,21 @@
+eras = BCE, CE
+eraNames = ਈਸਾਪੂਰਵ, ਸੰਨ
+narrowMonths = ਜ, ਫ, ਮਾ, ਅ, ਮ, ਜੂ, ਜੁ, ਅ, ਸ, ਅ, ਨ, ਦ
+months = ਜਨਵਰੀ, ਫ਼ਰਵਰੀ, ਮਾਰਚ, ਅਪ੍ਰੈਲ, ਮਈ, ਜੂਨ, ਜੁਲਾਈ, ਅਗਸਤ, ਸਤੰਬਰ, ਅਕਤੂਬਰ, ਨਵੰਬਰ, ਦਸੰਬਰ
+shortMonths = ਜਨਵਰੀ, ਫ਼ਰਵਰੀ, ਮਾਰਚ, ਅਪ੍ਰੈਲ, ਮਈ, ਜੂਨ, ਜੁਲਾਈ, ਅਗਸਤ, ਸਤੰਬਰ, ਅਕਤੂਬਰ, ਨਵੰਬਰ, ਦਸੰਬਰ
+standaloneNarrowMonths = ਜ, ਫ, ਮਾ, ਅ, ਮ, ਜੂ, ਜੁ, ਅ, ਸ, ਅ, ਨ, ਦ
+standaloneMonths = ਜਨਵਰੀ, ਫ਼ਰਵਰੀ, ਮਾਰਚ, ਅਪ੍ਰੈਲ, ਮਈ, ਜੂਨ, ਜੁਲਾਈ, ਅਗਸਤ, ਸਤੰਬਰ, ਅਕਤੂਬਰ, ਨਵੰਬਰ, ਦਸੰਬਰ
+standaloneShortMonths = ਜਨਵਰੀ, ਫ਼ਰਵਰੀ, ਮਾਰਚ, ਅਪ੍ਰੈਲ, ਮਈ, ਜੂਨ, ਜੁਲਾਈ, ਅਗਸਤ, ਸਤੰਬਰ, ਅਕਤੂਬਰ, ਨਵੰਬਰ, ਦਸੰਬਰ
+weekdays = ਐਤਵਾਰ, ਸੋਮਵਾਰ, ਮੰਗਲਵਾਰ, ਬੁਧਵਾਰ, ਵੀਰਵਾਰ, ਸ਼ੁੱਕਰਵਾਰ, ਸ਼ਨੀਚਰਵਾਰ
+shortWeekdays = ਐਤ., ਸੋਮ., ਮੰਗਲ., ਬੁਧ., ਵੀਰ., ਸ਼ੁਕਰ., ਸ਼ਨੀ.
+narrowWeekdays = ਐ, ਸੋ, ਮੰ, ਬੁੱ, ਵੀ, ਸ਼ੁੱ, ਸ਼
+standaloneWeekdays = ਐਤਵਾਰ, ਸੋਮਵਾਰ, ਮੰਗਲਵਾਰ, ਬੁਧਵਾਰ, ਵੀਰਵਾਰ, ਸ਼ੁੱਕਰਵਾਰ, ਸ਼ਨੀਚਰਵਾਰ
+standaloneShortWeekdays = ਐਤ., ਸੋਮ., ਮੰਗਲ., ਬੁਧ., ਵੀਰ., ਸ਼ੁਕਰ., ਸ਼ਨੀ.
+standaloneNarrowWeekdays = ਐ, ਸੋ, ਮੰ, ਬੁੱ, ਵੀ, ਸ਼ੁੱ, ਸ਼
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = ਪਹਿਲਾਂ ਚੌਥਾਈ, ਦੂਜਾ ਚੌਥਾਈ, ਤੀਜਾ ਚੌਥਾਈ, ਚੌਥਾ ਚੌਥਾਈ
+ampms = ਸਵੇਰੇ, ਸ਼ਾਮ
+dateFormats = EEEE\\, dd MMMM yyyy, yyyy MMMM d, yyyy MMM d, dd/MM/yyy
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pa_PK.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_PK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pa_PK.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pa_PK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pl.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pl.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ps.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ps.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ps.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ps.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pt.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pt.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pt.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pt.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pt_PT.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pt_PT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_pt_PT.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_pt_PT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ro.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ro.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ro.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ro.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_root.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_root.properties
new file mode 100644
index 0000000..07c0b58
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_root.properties
@@ -0,0 +1,21 @@
+eras = BCE, CE
+eraNames = Before Christ, Anno Domini
+narrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+months = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+shortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+standaloneNarrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneShortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+weekdays = 1, 2, 3, 4, 5, 6, 7
+shortWeekdays = Sun, Mon, Tue, Wed, Thu, Fri, Sat
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneShortWeekdays = Sun, Mon, Tue, Wed, Thu, Fri, Sat
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = Q1, Q2, Q3, Q4
+ampms = AM, PM
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yyyy-MM-dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 1
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ru.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ru.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ru.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ru.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ru_UA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ru_UA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ru_UA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ru_UA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_rw.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_rw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_rw.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_rw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sa.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sa.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sa_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sa_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sa_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sa_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_se.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_se.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_se.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_se.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_se_FI.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_se_FI.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_se_FI.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_se_FI.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sh.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sh.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sh.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sh.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_si.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_si.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_si.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_si.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sid.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sid.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sid.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sid.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sid_ET.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sid_ET.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sid_ET.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sid_ET.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sk.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sk.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sk.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sk.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sl.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sl.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_so.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_so.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_so.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_so.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sq.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sq.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sq.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sq.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr_BA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_BA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr_BA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_BA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr_Cyrl_BA.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_Cyrl_BA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr_Cyrl_BA.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_Cyrl_BA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr_Latn.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_Latn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr_Latn.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_Latn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr_Latn_ME.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_Latn_ME.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sr_Latn_ME.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_Latn_ME.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_Latn_RS.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_Latn_RS.properties
new file mode 100644
index 0000000..5578b97
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sr_Latn_RS.properties
@@ -0,0 +1,21 @@
+eras = p. n. e., n. e
+eraNames = Pre nove ere, Nove ere
+narrowMonths = j, f, m, a, m, j, j, a, s, o, n, d
+months = januar, februar, mart, april, maj, jun, jul, avgust, septembar, oktobar, novembar, decembar
+shortMonths = jan, feb, mar, apr, maj, jun, jul, avg, sep, okt, nov, dec
+standaloneNarrowMonths = j, f, m, a, m, j, j, a, s, o, n, d
+standaloneMonths = januar, februar, mart, april, maj, jun, jul, avgust, septembar, oktobar, novembar, decembar
+standaloneShortMonths = jan, feb, mar, apr, maj, jun, jul, avg, sep, okt, nov, dec
+weekdays = nedelja, ponedeljak, utorak, sreda, četvrtak, petak, subota
+shortWeekdays = ned, pon, uto, sre, čet, pet, sub
+narrowWeekdays = n, p, u, s, č, p, s
+standaloneWeekdays = nedelja, ponedeljak, utorak, sreda, četvrtak, petak, subota
+standaloneShortWeekdays = ned, pon, uto, sre, čet, pet, sub
+standaloneNarrowWeekdays = n, p, u, s, č, p, s
+shortQuarters = K1, K2, K3, K4
+quarters = Prvo tromesečje, Drugo tromesečje, Treće tromesečje, Četvrto tromesečje
+ampms = AM, PM
+dateFormats = EEEE\\, dd. MMMM yyyy., d. MMM yyyy., dd.MM.yyyy., d.M.yy.
+timeFormats = HH.mm.ss v, HH.mm.ss z, HH.mm.ss, HH.mm
+firstDayOfTheWeek = 2
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ss.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ss.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ss.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ss.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ssy.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ssy.properties
new file mode 100644
index 0000000..cfca3d5
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ssy.properties
@@ -0,0 +1,21 @@
+eras = BC, AD
+eraNames = Before Christ, Anno Domini
+narrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+months = January, February, March, April, May, June, July, August, September, October, November, December
+shortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+standaloneNarrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+standaloneMonths = January, February, March, April, May, June, July, August, September, October, November, December
+standaloneShortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+weekdays = Naba Sambat, Sani, Salus, Rabuq, Camus, Jumqata, Qunxa Sambat
+shortWeekdays = Nab, San, Sal, Rab, Cam, Jum, Qun
+narrowWeekdays = S, M, T, W, T, F, S
+standaloneWeekdays = Naba Sambat, Sani, Salus, Rabuq, Camus, Jumqata, Qunxa Sambat
+standaloneShortWeekdays = Nab, San, Sal, Rab, Cam, Jum, Qun
+standaloneNarrowWeekdays = S, M, T, W, T, F, S
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = 1st quarter, 2nd quarter, 3rd quarter, 4th quarter
+ampms = AM, PM
+dateFormats = EEEE\\, MMMM d\\, yyyy, MMMM d\\, yyyy, MMM d\\, yyyy, M/d/yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 2
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_st.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_st.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_st.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_st.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sv.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sv.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sw.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sw.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sw_KE.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sw_KE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_sw_KE.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_sw_KE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_syr.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_syr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_syr.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_syr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_syr_SY.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_syr_SY.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_syr_SY.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_syr_SY.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ta.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ta.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ta.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ta.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ta_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ta_IN.properties
new file mode 100644
index 0000000..79ec797
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ta_IN.properties
@@ -0,0 +1,21 @@
+eras = கிமு, கிபி
+eraNames = வர்ஷು., ஸந்.
+narrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+months = ஜனவரி, பிப்ரவரி, மார்ச், ஏப்ரல், மே, ஜூன், ஜூலை, ஆகஸ்ட், செப்டம்பர், அக்டோபர், நவம்பர், டிசம்பர்
+shortMonths = ஜன., பிப்., மார்., ஏப்., மே, ஜூன், ஜூலை, ஆக., செப்., அக்., நவ., டிச.
+standaloneNarrowMonths = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+standaloneMonths = ஜனவரி, பிப்ரவரி, மார்ச், ஏப்ரல், மே, ஜூன், ஜூலை, ஆகஸ்ட், செப்டம்பர், அக்டோபர், நவம்பர், டிசம்பர்
+standaloneShortMonths = ஜன., பிப்., மார்., ஏப்., மே, ஜூன், ஜூலை, ஆக., செப்., அக்., நவ., டிச.
+weekdays = ஞாயிறு, திங்கள், செவ்வாய், புதன், வியாழன், வெள்ளி, சனி
+shortWeekdays = ஞா, தி, செ, பு, வி, வெ, ச
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = ஞாயிறு, திங்கள், செவ்வாய், புதன், வியாழன், வெள்ளி, சனி
+standaloneShortWeekdays = ஞா, தி, செ, பு, வி, வெ, ச
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = வந்ந௧ 1, ரெஂட௨ 2, மூடு௩ 3, நால்௪ 4
+ampms = காலை, மாலை
+dateFormats = EEEE d MMMM yyyy, d MMMM yyyy, dd-MM-yyyy, d-M-yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_te.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_te.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_te.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_te.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_te_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_te_IN.properties
new file mode 100644
index 0000000..8789367
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_te_IN.properties
@@ -0,0 +1,21 @@
+eras = BCE, CE
+eraNames = ఈసాపూర్వ., సన్.
+narrowMonths = జ, ఫి, మ, ఎ, మె, జు, జు, ఆ, సె, అ, న, డి
+months = జనవరి, ఫిబ్రవరి, మార్చి, ఏప్రిల్, మే, జూన్, జూలై, ఆగస్టు, సెప్టెంబర్, అక్టోబర్, నవంబర్, డిసెంబర్
+shortMonths = జనవరి, ఫిబ్రవరి, మార్చి, ఏప్రిల్, మే, జూన్, జూలై, ఆగస్టు, సెప్టెంబర్, అక్టోబర్, నవంబర్, డిసెంబర్
+standaloneNarrowMonths = జ, ఫి, మ, ఎ, మె, జు, జు, ఆ, సె, అ, న, డి
+standaloneMonths = జనవరి, ఫిబ్రవరి, మార్చి, ఏప్రిల్, మే, జూన్, జూలై, ఆగస్టు, సెప్టెంబర్, అక్టోబర్, నవంబర్, డిసెంబర్
+standaloneShortMonths = జనవరి, ఫిబ్రవరి, మార్చి, ఏప్రిల్, మే, జూన్, జూలై, ఆగస్టు, సెప్టెంబర్, అక్టోబర్, నవంబర్, డిసెంబర్
+weekdays = ఆదివారం, సోమవారం, మంగళవారం, బుధవారం, గురువారం, శుక్రవారం, శనివారం
+shortWeekdays = ఆది, సోమ, మంగళ, బుధ, గురు, శుక్ర, శని
+narrowWeekdays = ఆ, 2, సొ, భు, గు, శు, శ
+standaloneWeekdays = ఆదివారం, సోమవారం, మంగళవారం, బుధవారం, గురువారం, శుక్రవారం, శనివారం
+standaloneShortWeekdays = ఆది, సోమ, మంగళ, బుధ, గురు, శుక్ర, శని
+standaloneNarrowWeekdays = ఆ, 2, సొ, భు, గు, శు, శ
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = ఒకటి 1, రెండు 2, మూడు 3, నాలుగు 4
+ampms = పూర్వాహ్నం, అపరాహ్నం
+dateFormats = EEEE d MMMM yyyy, d MMMM yyyy, dd-MM-yyyy, dd-MM-yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 2
+weekendRange = 1, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tg.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tg.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tg.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tg.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_th.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_th.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_th.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_th.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ti.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ti.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ti.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ti.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ti_ER.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ti_ER.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ti_ER.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ti_ER.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tig.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tig.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tig.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tig.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tig_ER.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tig_ER.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tig_ER.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tig_ER.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tl.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tl.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tn.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tn.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_to.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_to.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_to.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_to.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tr.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tr.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_trv.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_trv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_trv.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_trv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ts.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ts.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ts.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ts.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tt.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tt.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_tt.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_tt.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ug.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ug.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ug.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ug.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ug_Arab.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ug_Arab.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ug_Arab.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ug_Arab.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ug_Arab_CN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ug_Arab_CN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ug_Arab_CN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ug_Arab_CN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uk.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uk.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uk.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uk.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_und.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_und.properties
new file mode 100644
index 0000000..f1680af
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_und.properties
@@ -0,0 +1,21 @@
+eras = BC, AD
+eraNames = Before Christ, Anno Domini
+narrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+months = January, February, March, April, May, June, July, August, September, October, November, December
+shortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+standaloneNarrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+standaloneMonths = January, February, March, April, May, June, July, August, September, October, November, December
+standaloneShortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+weekdays = Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
+shortWeekdays = Sun, Mon, Tue, Wed, Thu, Fri, Sat
+narrowWeekdays = S, M, T, W, T, F, S
+standaloneWeekdays = Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
+standaloneShortWeekdays = Sun, Mon, Tue, Wed, Thu, Fri, Sat
+standaloneNarrowWeekdays = S, M, T, W, T, F, S
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = 1st quarter, 2nd quarter, 3rd quarter, 4th quarter
+ampms = AM, PM
+dateFormats = EEEE\\, MMMM d\\, yyyy, MMMM d\\, yyyy, MMM d\\, yyyy, M/d/yy
+timeFormats = h:mm:ss a v, h:mm:ss a z, h:mm:ss a, h:mm a
+firstDayOfTheWeek = 2
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ur.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ur.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ur.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ur.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ur_IN.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ur_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ur_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ur_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ur_PK.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ur_PK.properties
new file mode 100644
index 0000000..bb59539
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ur_PK.properties
@@ -0,0 +1,21 @@
+eras = ق م, عيسوی سن
+eraNames = قبل مسيح, عيسوی سن
+narrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+months = جنوری, فروری, مار چ, اپريل, مئی, جون, جولائی, اگست, ستمبر, اکتوبر, نومبر, دسمبر
+shortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+standaloneNarrowMonths = J, F, M, A, M, J, J, A, S, O, N, D
+standaloneMonths = جنوری, فروری, مار چ, اپريل, مئی, جون, جولائی, اگست, ستمبر, اکتوبر, نومبر, دسمبر
+standaloneShortMonths = Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
+weekdays = اتوار, پير, منگل, بدھ, جمعرات, جمعہ, ہفتہ
+shortWeekdays = Sun, Mon, Tue, Wed, Thu, Fri, Sat
+narrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+standaloneWeekdays = اتوار, پير, منگل, بدھ, جمعرات, جمعہ, ہفتہ
+standaloneShortWeekdays = Sun, Mon, Tue, Wed, Thu, Fri, Sat
+standaloneNarrowWeekdays = 1, 2, 3, 4, 5, 6, 7
+shortQuarters = Q1, Q2, Q3, Q4
+quarters = پہلی سہ ماہی, دوسری سہ ماہی, تيسری سہ ماہی, چوتهی سہ ماہی
+ampms = AM, PM
+dateFormats = EEEE\\, yyyy MMMM dd, yyyy MMMM d, yyyy MMM d, yyyy-MM-dd
+timeFormats = HH:mm:ss v, HH:mm:ss z, HH:mm:ss, HH:mm
+firstDayOfTheWeek = 1
+weekendRange = 7, 1
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz_AF.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz_AF.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz_AF.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz_AF.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz_Arab.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz_Arab.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz_Arab.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz_Arab.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz_Arab_AF.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz_Arab_AF.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz_Arab_AF.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz_Arab_AF.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz_Latn.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz_Latn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_uz_Latn.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_uz_Latn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ve.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ve.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_ve.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_ve.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_vi.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_vi.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_vi.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_vi.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_wal.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_wal.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_wal.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_wal.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_wal_ET.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_wal_ET.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_wal_ET.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_wal_ET.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_wo.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_wo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_wo.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_wo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_xh.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_xh.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_xh.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_xh.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_yo.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_yo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_yo.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_yo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_HK.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_HK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_HK.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_HK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_Hans_SG.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_Hans_SG.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_Hans_SG.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_Hans_SG.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_Hant.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_Hant.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_Hant.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_Hant.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_Hant_HK.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_Hant_HK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_Hant_HK.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_Hant_HK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_Hant_MO.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_Hant_MO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_Hant_MO.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_Hant_MO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_MO.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_MO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_MO.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_MO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_SG.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_SG.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_SG.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_SG.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_TW.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_TW.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zh_TW.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zh_TW.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zu.properties b/user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/DateTimeConstants_zu.properties
rename to user/src/com/google/gwt/i18n/client/constants/DateTimeConstantsImpl_zu.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/LocaleConstants.java b/user/src/com/google/gwt/i18n/client/constants/LocaleConstants.java
new file mode 100644
index 0000000..ecbff5e
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/LocaleConstants.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.constants;
+
+/**
+ * Interface that combines locale-specific interfaces.
+ */
+public interface LocaleConstants {
+
+ DateTimeConstants getDateTimeConstants();
+
+ NumberConstants getNumberConstants();
+}
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants.java b/user/src/com/google/gwt/i18n/client/constants/NumberConstants.java
index 1995cb1..d7c2b8b 100644
--- a/user/src/com/google/gwt/i18n/client/constants/NumberConstants.java
+++ b/user/src/com/google/gwt/i18n/client/constants/NumberConstants.java
@@ -16,17 +16,18 @@
package com.google.gwt.i18n.client.constants;
-import com.google.gwt.i18n.client.Constants;
-
/**
* NumberConstants class encapsulate a collection of Number formatting
* symbols for use with Number format and parse services. This class extends
* GWT's Constants class. The actual symbol collections are defined in a set
* of property files named like "NumberConstants_xx.properties". GWT will
* will perform late binding to the property file that specific to user's
- * locale.
+ * locale.
+ *
+ * If you previously were using GWT.create on this interface, you should
+ * use LocaleInfo.getCurrentLocale().getNumberConstants() instead.
*/
-public interface NumberConstants extends Constants {
+public interface NumberConstants {
String notANumber();
String currencyPattern();
String decimalPattern();
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl.java b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl.java
new file mode 100644
index 0000000..2fd1b77
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may 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.constants;
+
+import com.google.gwt.i18n.client.Constants;
+
+/**
+ * NumberConstantsImpl class encapsulate a collection of Number formatting
+ * symbols for use with Number format and parse services. This class extends
+ * GWT's Constants class. The actual symbol collections are defined in a set
+ * of property files named like "NumberConstants_xx.properties". GWT will
+ * will perform late binding to the property file that specific to user's
+ * locale.
+ */
+public interface NumberConstantsImpl extends Constants, NumberConstants {
+ String notANumber();
+ String currencyPattern();
+ String decimalPattern();
+ String decimalSeparator();
+ String defCurrencyCode();
+ String exponentialSymbol();
+ String groupingSeparator();
+ String infinity();
+ String minusSign();
+ String monetaryGroupingSeparator();
+ String monetarySeparator();
+ String percent();
+ String percentPattern();
+ String perMill();
+ String plusSign();
+ String scientificPattern();
+ String zeroDigit();
+}
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_aa.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_aa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_aa.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_aa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_aa_ER.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_aa_ER.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_aa_ER.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_aa_ER.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_aa_ET.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_aa_ET.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_aa_ET.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_aa_ET.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_af.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_af.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_af.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_af.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_af_NA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_af_NA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_af_NA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_af_NA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ak.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ak.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ak.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ak.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_am.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_am.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_am.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_am.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_BH.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_BH.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_BH.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_BH.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_DZ.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_DZ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_DZ.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_DZ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_EG.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_EG.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_EG.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_EG.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_IQ.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_IQ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_IQ.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_IQ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_JO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_JO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_JO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_JO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_KW.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_KW.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_KW.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_KW.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_LB.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_LB.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_LB.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_LB.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_LY.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_LY.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_LY.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_LY.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_MA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_MA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_MA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_MA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_OM.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_OM.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_OM.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_OM.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_QA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_QA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_QA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_QA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_SA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_SA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_SA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_SA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_SD.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_SD.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_SD.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_SD.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_SY.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_SY.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_SY.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_SY.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_TN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_TN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_TN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_TN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_YE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_YE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ar_YE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ar_YE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_as.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_as.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_as.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_as.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_az.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_az.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_az.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_az.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_be.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_be.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_be.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_be.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_bg.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_bg.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_bg.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_bg.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_bn.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_bn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_bn.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_bn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_bn_IN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_bn_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_bn_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_bn_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_bs.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_bs.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_bs.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_bs.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_byn.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_byn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_byn.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_byn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ca.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ca.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ca.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ca.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_cch.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_cch.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_cch.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_cch.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_cop.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_cop.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_cop.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_cop.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_cs.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_cs.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_cs.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_cs.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_cy.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_cy.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_cy.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_cy.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_da.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_da.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_da.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_da.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_de.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_de.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_de.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_de.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_de_AT.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_de_AT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_de_AT.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_de_AT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_de_CH.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_de_CH.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_de_CH.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_de_CH.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_de_LI.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_de_LI.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_de_LI.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_de_LI.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_dv.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_dv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_dv.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_dv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_dz.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_dz.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_dz.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_dz.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ee.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ee.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ee.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ee.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ee_TG.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ee_TG.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ee_TG.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ee_TG.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_el.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_el.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_el.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_el.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_el_CY.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_el_CY.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_el_CY.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_el_CY.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_el_GR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_el_GR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_el_GR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_el_GR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_AU.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_AU.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_AU.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_AU.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_BE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_BE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_BE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_BE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_BW.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_BW.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_BW.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_BW.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_BZ.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_BZ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_BZ.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_BZ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_CA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_CA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_CA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_CA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_GB.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_GB.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_GB.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_GB.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_HK.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_HK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_HK.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_HK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_IE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_IE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_IE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_IE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_IN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_JM.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_JM.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_JM.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_JM.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_MT.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_MT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_MT.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_MT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_NA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_NA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_NA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_NA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_NZ.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_NZ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_NZ.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_NZ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_PH.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_PH.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_PH.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_PH.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_PK.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_PK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_PK.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_PK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_SG.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_SG.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_SG.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_SG.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_TT.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_TT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_TT.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_TT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_ZA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_ZA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_ZA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_ZA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_ZW.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_ZW.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_en_ZW.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_en_ZW.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_eo.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_eo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_eo.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_eo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_BO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_BO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_BO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_BO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_CL.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_CL.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_CL.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_CL.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_CO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_CO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_CO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_CO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_CR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_CR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_CR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_CR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_DO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_DO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_DO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_DO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_EC.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_EC.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_EC.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_EC.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_ES.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_ES.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_ES.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_ES.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_GT.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_GT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_GT.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_GT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_HN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_HN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_HN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_HN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_MX.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_MX.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_MX.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_MX.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_NI.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_NI.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_NI.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_NI.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_PA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_PA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_PA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_PA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_PE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_PE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_PE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_PE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_PR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_PR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_PR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_PR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_PY.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_PY.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_PY.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_PY.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_SV.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_SV.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_SV.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_SV.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_US.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_US.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_US.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_US.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_UY.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_UY.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_UY.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_UY.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_VE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_VE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_es_VE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_es_VE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_et.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_et.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_et.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_et.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_eu.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_eu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_eu.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_eu.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fa.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fa.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fa_AF.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fa_AF.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fa_AF.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fa_AF.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fa_IR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fa_IR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fa_IR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fa_IR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fi.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fi.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fi.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fi.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fil.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fil.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fil.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fil.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fo.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fo.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_BE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_BE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_BE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_BE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_CA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_CA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_CA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_CA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_CH.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_CH.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_CH.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_CH.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_LU.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_LU.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_LU.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_LU.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_SN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_SN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fr_SN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fr_SN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_fur.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fur.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_fur.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_fur.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ga.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ga.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ga.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ga.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_gaa.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gaa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_gaa.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gaa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_gez.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gez.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_gez.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gez.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_gez_ET.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gez_ET.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_gez_ET.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gez_ET.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_gl.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_gl.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_gu.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_gu.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gu.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_gv.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_gv.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_gv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_Arab_SD.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_Arab_SD.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_Arab_SD.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_Arab_SD.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_GH.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_GH.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_GH.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_GH.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_Latn_GH.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_Latn_GH.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_Latn_GH.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_Latn_GH.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_Latn_NE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_Latn_NE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_Latn_NE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_Latn_NE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_NE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_NE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_NE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_NE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_SD.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_SD.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ha_SD.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ha_SD.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_haw.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_haw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_haw.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_haw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_he.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_he.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_he.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_he.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_hi.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_hi.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_hi.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_hi.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_hr.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_hr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_hr.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_hr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_hu.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_hu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_hu.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_hu.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_hy.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_hy.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_hy.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_hy.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ia.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ia.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ia.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ia.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_id.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_id.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_id.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_id.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ig.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ig.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ig.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ig.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ii.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ii.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ii.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ii.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_in.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_in.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_in.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_in.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_is.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_is.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_is.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_is.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_it.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_it.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_it.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_it.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_it_CH.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_it_CH.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_it_CH.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_it_CH.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_it_IT.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_it_IT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_it_IT.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_it_IT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_iu.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_iu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_iu.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_iu.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_iw.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_iw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_iw.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_iw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ja.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ja.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ja.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ja.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ka.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ka.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ka.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ka.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kaj.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kaj.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kaj.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kaj.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kam.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kam.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kam.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kam.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kcg.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kcg.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kcg.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kcg.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kfo.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kfo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kfo.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kfo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kfo_CI.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kfo_CI.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kfo_CI.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kfo_CI.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kk.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kk.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kk.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kk.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kl.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kl.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_km.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_km.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_km.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_km.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kn.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kn.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ko.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ko.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ko.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ko.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ko_KR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ko_KR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ko_KR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ko_KR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kok.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kok.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kok.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kok.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kpe.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kpe.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kpe.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kpe.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kpe_LR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kpe_LR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kpe_LR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kpe_LR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ku.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ku.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ku.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ku.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ku_Latn_TR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ku_Latn_TR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ku_Latn_TR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ku_Latn_TR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ku_TR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ku_TR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ku_TR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ku_TR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_kw.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_kw.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_kw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ky.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ky.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ky.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ky.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ln.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ln.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ln.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ln.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ln_CG.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ln_CG.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ln_CG.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ln_CG.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_lo.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_lo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_lo.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_lo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_lt.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_lt.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_lt.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_lt.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_lv.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_lv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_lv.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_lv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_mk.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mk.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_mk.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mk.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ml.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ml.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ml.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ml.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_mn.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_mn.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_mn_CN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mn_CN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_mn_CN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mn_CN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_mn_Mong_CN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mn_Mong_CN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_mn_Mong_CN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mn_Mong_CN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_mo.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_mo.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_mr.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_mr.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ms.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ms.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ms.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ms.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ms_BN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ms_BN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ms_BN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ms_BN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ms_MY.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ms_MY.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ms_MY.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ms_MY.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_mt.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mt.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_mt.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_mt.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_my.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_my.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_my.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_my.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_nb.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nb.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_nb.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nb.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ne.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ne.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ne.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ne.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ne_IN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ne_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ne_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ne_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_nl.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_nl.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_nl_BE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nl_BE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_nl_BE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nl_BE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_nn.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_nn.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_no.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_no.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_no.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_no.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_nr.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_nr.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_nso.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nso.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_nso.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_nso.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ny.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ny.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ny.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ny.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_om.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_om.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_om.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_om.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_om_KE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_om_KE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_om_KE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_om_KE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_or.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_or.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_or.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_or.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_pa.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_pa.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_pa_Guru.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pa_Guru.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_pa_Guru.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pa_Guru.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_pa_IN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pa_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_pa_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pa_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_pl.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_pl.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ps.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ps.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ps.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ps.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_pt.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pt.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_pt.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pt.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_pt_BR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pt_BR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_pt_BR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pt_BR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_pt_PT.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pt_PT.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_pt_PT.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_pt_PT.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ro.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ro.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ro.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ro.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ro_RO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ro_RO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ro_RO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ro_RO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ru.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ru.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ru.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ru.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ru_RU.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ru_RU.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ru_RU.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ru_RU.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ru_UA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ru_UA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ru_UA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ru_UA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_rw.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_rw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_rw.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_rw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sa.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sa.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sa.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sa.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_se.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_se.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_se.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_se.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_se_NO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_se_NO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_se_NO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_se_NO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sh.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sh.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sh.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sh.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sh_BA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sh_BA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sh_BA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sh_BA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sh_CS.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sh_CS.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sh_CS.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sh_CS.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sh_YU.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sh_YU.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sh_YU.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sh_YU.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_si.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_si.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_si.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_si.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sid.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sid.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sid.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sid.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sk.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sk.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sk.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sk.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sl.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sl.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_so.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_so.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_so.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_so.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_so_ET.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_so_ET.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_so_ET.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_so_ET.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_so_KE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_so_KE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_so_KE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_so_KE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_so_SO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_so_SO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_so_SO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_so_SO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sq.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sq.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sq.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sq.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sq_AL.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sq_AL.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sq_AL.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sq_AL.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_CS.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_CS.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_CS.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_CS.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Cyrl.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Cyrl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Cyrl.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Cyrl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Cyrl_BA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Cyrl_BA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Cyrl_BA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Cyrl_BA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Cyrl_RS.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Cyrl_RS.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Cyrl_RS.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Cyrl_RS.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Cyrl_YU.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Cyrl_YU.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Cyrl_YU.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Cyrl_YU.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn_BA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn_BA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn_BA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn_BA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn_CS.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn_CS.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn_CS.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn_CS.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn_ME.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn_ME.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn_ME.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn_ME.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn_YU.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn_YU.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_Latn_YU.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_Latn_YU.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_ME.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_ME.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_ME.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_ME.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_RS.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_RS.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_RS.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_RS.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_YU.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_YU.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sr_YU.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sr_YU.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ss.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ss.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ss.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ss.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ss_SZ.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ss_SZ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ss_SZ.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ss_SZ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_st.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_st.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_st.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_st.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_st_LS.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_st_LS.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_st_LS.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_st_LS.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sv.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sv.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sv_SE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sv_SE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sv_SE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sv_SE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sw.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sw.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sw.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sw.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sw_KE.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sw_KE.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sw_KE.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sw_KE.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_sw_TZ.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sw_TZ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_sw_TZ.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_sw_TZ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_syr.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_syr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_syr.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_syr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ta.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ta.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ta.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ta.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_te.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_te.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_te.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_te.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_tg.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tg.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_tg.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tg.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_th.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_th.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_th.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_th.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ti.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ti.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ti.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ti.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ti_ET.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ti_ET.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ti_ET.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ti_ET.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_tig.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tig.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_tig.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tig.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_tl.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_tl.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_tn.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_tn.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_tn_ZA.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tn_ZA.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_tn_ZA.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tn_ZA.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_to.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_to.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_to.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_to.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_tr.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tr.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_tr.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tr.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_tr_TR.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tr_TR.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_tr_TR.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tr_TR.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_trv.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_trv.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_trv.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_trv.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ts.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ts.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ts.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ts.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_tt.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tt.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_tt.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_tt.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ug.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ug.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ug.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ug.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_uk.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uk.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_uk.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uk.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ur.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ur.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ur.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ur.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ur_IN.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ur_IN.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ur_IN.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ur_IN.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ur_PK.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ur_PK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ur_PK.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ur_PK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_AF.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_AF.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_AF.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_AF.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_Arab.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_Arab.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_Arab.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_Arab.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_Cyrl.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_Cyrl.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_Cyrl.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_Cyrl.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_Latn.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_Latn.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_Latn.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_Latn.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_UZ.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_UZ.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_uz_UZ.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_uz_UZ.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_ve.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ve.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_ve.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_ve.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_vi.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_vi.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_vi.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_vi.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_wal.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_wal.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_wal.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_wal.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_wo.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_wo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_wo.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_wo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_xh.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_xh.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_xh.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_xh.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_yo.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_yo.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_yo.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_yo.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_HK.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_HK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_HK.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_HK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hans_HK.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hans_HK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hans_HK.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hans_HK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hans_MO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hans_MO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hans_MO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hans_MO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hans_SG.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hans_SG.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hans_SG.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hans_SG.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hant.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hant.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hant.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hant.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hant_HK.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hant_HK.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hant_HK.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hant_HK.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hant_MO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hant_MO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_Hant_MO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_Hant_MO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_MO.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_MO.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_MO.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_MO.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_SG.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_SG.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_SG.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_SG.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_TW.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_TW.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zh_TW.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zh_TW.properties
diff --git a/user/src/com/google/gwt/i18n/client/constants/NumberConstants_zu.properties b/user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zu.properties
similarity index 100%
rename from user/src/com/google/gwt/i18n/client/constants/NumberConstants_zu.properties
rename to user/src/com/google/gwt/i18n/client/constants/NumberConstantsImpl_zu.properties
diff --git a/user/src/com/google/gwt/i18n/client/impl/LocaleInfoImpl.java b/user/src/com/google/gwt/i18n/client/impl/LocaleInfoImpl.java
index ee23169..d98858b 100644
--- a/user/src/com/google/gwt/i18n/client/impl/LocaleInfoImpl.java
+++ b/user/src/com/google/gwt/i18n/client/impl/LocaleInfoImpl.java
@@ -15,6 +15,12 @@
*/
package com.google.gwt.i18n.client.impl;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.constants.DateTimeConstants;
+import com.google.gwt.i18n.client.constants.DateTimeConstantsImpl;
+import com.google.gwt.i18n.client.constants.NumberConstants;
+import com.google.gwt.i18n.client.constants.NumberConstantsImpl;
+
/**
* Implementation detail of LocaleInfo -- not a public API and subject to
* change.
@@ -27,11 +33,31 @@
public class LocaleInfoImpl {
/**
+ * @return the runtime locale (note that this requires the i18n locale
+ * property provider's assistance)
+ */
+ static native String getRuntimeLocale() /*-{
+ return $wnd['__gwt_Locale'];
+ }-*/;
+
+ /**
* @return an array of available locale names
*/
public String[] getAvailableLocaleNames() {
return null;
}
+
+ /**
+ * Create a DateTimeConstants instance appropriate for this locale.
+ *
+ * Note that the caller takes care of any caching so subclasses need not
+ * bother.
+ *
+ * @return a DateTimeConstants instance
+ */
+ public DateTimeConstants getDateTimeConstants() {
+ return GWT.create(DateTimeConstantsImpl.class);
+ }
/**
* @return the current locale name, such as "default, "en_US", etc.
@@ -39,12 +65,12 @@
public String getLocaleName() {
return null;
}
-
+
/**
* Return the display name of the requested locale in its native locale, if
* possible. If no native localization is available, the English name will
* be returned, or as a last resort just the locale name will be returned. If
- * the locale name is unknown (including an user overrides), null is returned.
+ * the locale name is unknown (including user overrides), null is returned.
*
* @param localeName the name of the locale to lookup.
* @return the name of the locale in its native locale
@@ -52,4 +78,11 @@
public String getLocaleNativeDisplayName(String localeName) {
return null;
}
+
+ /**
+ * @return a NumberConstants instance appropriate for this locale.
+ */
+ public NumberConstants getNumberConstants() {
+ return GWT.create(NumberConstantsImpl.class);
+ }
}
diff --git a/user/src/com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-generated.properties b/user/src/com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-generated.properties
index 67ab165..fa2a989 100644
--- a/user/src/com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-generated.properties
+++ b/user/src/com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-generated.properties
@@ -5,878 +5,906 @@
# to the values generated from CLDR.
#
# Source files used:
-# aa.xml, revision 1.39 (2007/07/19 22:31:38)
-# aa_DJ.xml, revision 1.36 (2007/07/19 22:31:38)
-# aa_ER.xml, revision 1.35 (2007/07/19 22:31:38)
-# aa_ER_SAAHO.xml, revision 1.32 (2007/07/19 22:31:38)
-# aa_ET.xml, revision 1.36 (2007/07/19 22:31:38)
-# af.xml, revision 1.60 (2007/07/19 23:30:28)
-# af_NA.xml, revision 1.16 (2007/07/19 22:31:38)
-# af_ZA.xml, revision 1.46 (2007/07/19 22:31:38)
-# ak.xml, revision 1.26 (2007/07/19 22:31:38)
-# ak_GH.xml, revision 1.14 (2007/07/19 22:31:38)
-# am.xml, revision 1.67 (2007/07/19 22:31:38)
-# am_ET.xml, revision 1.47 (2007/07/19 22:31:38)
-# ar.xml, revision 1.84 (2007/07/24 23:39:15)
-# ar_AE.xml, revision 1.43 (2007/07/19 22:31:38)
-# ar_BH.xml, revision 1.43 (2007/07/19 22:31:38)
-# ar_DZ.xml, revision 1.46 (2007/07/27 18:47:31)
-# ar_EG.xml, revision 1.46 (2007/07/19 22:31:38)
-# ar_IQ.xml, revision 1.43 (2007/07/19 22:31:38)
-# ar_JO.xml, revision 1.44 (2007/07/19 22:31:38)
-# ar_KW.xml, revision 1.45 (2007/07/19 22:31:38)
-# ar_LB.xml, revision 1.43 (2007/07/19 22:31:38)
-# ar_LY.xml, revision 1.43 (2007/07/19 22:31:38)
-# ar_MA.xml, revision 1.44 (2007/07/27 18:47:31)
-# ar_OM.xml, revision 1.43 (2007/07/19 22:31:38)
-# ar_QA.xml, revision 1.44 (2007/07/19 22:31:38)
-# ar_SA.xml, revision 1.47 (2007/07/19 22:31:38)
-# ar_SD.xml, revision 1.41 (2007/07/19 22:31:38)
-# ar_SY.xml, revision 1.46 (2007/07/19 22:31:38)
-# ar_TN.xml, revision 1.46 (2007/07/27 18:47:31)
-# ar_YE.xml, revision 1.44 (2007/07/19 22:31:38)
-# as.xml, revision 1.45 (2007/07/19 22:31:38)
-# as_IN.xml, revision 1.35 (2007/07/19 22:31:38)
-# az.xml, revision 1.48 (2007/07/19 22:31:38)
-# az_AZ.xml, revision 1.36 (2007/07/19 22:31:38)
-# az_Cyrl.xml, revision 1.23 (2007/07/19 22:31:38)
-# az_Cyrl_AZ.xml, revision 1.19 (2007/07/19 22:31:38)
-# az_Latn.xml, revision 1.24 (2007/07/19 22:31:38)
-# az_Latn_AZ.xml, revision 1.22 (2007/07/19 22:31:38)
-# be.xml, revision 1.64 (2007/07/23 15:32:12)
-# be_BY.xml, revision 1.43 (2007/07/19 22:31:38)
-# bg.xml, revision 1.90 (2007/11/14 16:26:57)
-# bg_BG.xml, revision 1.50 (2007/07/19 22:31:38)
-# bn.xml, revision 1.61 (2007/07/19 23:30:28)
-# bn_BD.xml, revision 1.21 (2007/07/19 22:31:38)
-# bn_IN.xml, revision 1.52 (2007/07/19 22:31:38)
-# bo.xml, revision 1.6 (2007/07/19 22:31:38)
-# bo_CN.xml, revision 1.4 (2007/07/19 22:31:38)
-# bo_IN.xml, revision 1.3 (2007/07/19 22:31:38)
-# bs.xml, revision 1.30 (2007/07/19 22:31:38)
-# bs_BA.xml, revision 1.20 (2007/07/19 22:31:38)
-# byn.xml, revision 1.49 (2007/07/19 22:31:38)
-# byn_ER.xml, revision 1.34 (2007/07/19 22:31:38)
-# ca.xml, revision 1.78 (2007/07/19 22:31:38)
-# ca_ES.xml, revision 1.46 (2007/07/19 22:31:38)
-# cch.xml, revision 1.20 (2007/07/19 22:31:38)
-# cch_NG.xml, revision 1.13 (2007/07/19 22:31:38)
-# cop.xml, revision 1.18 (2007/07/19 22:31:38)
-# cop_Arab.xml, revision 1.15 (2007/07/19 22:31:38)
-# cop_Arab_EG.xml, revision 1.15 (2007/07/19 22:31:38)
-# cop_Arab_US.xml, revision 1.15 (2007/07/19 22:31:38)
-# cop_EG.xml, revision 1.17 (2007/07/19 22:31:38)
-# cop_US.xml, revision 1.15 (2007/07/19 22:31:38)
-# cs.xml, revision 1.104 (2007/11/14 16:26:57)
-# cs_CZ.xml, revision 1.46 (2007/07/19 22:31:38)
-# cy.xml, revision 1.52 (2007/07/19 22:31:38)
-# cy_GB.xml, revision 1.40 (2007/07/19 22:31:38)
-# da.xml, revision 1.90 (2007/11/14 16:26:57)
-# da_DK.xml, revision 1.46 (2007/07/19 22:31:38)
-# de.xml, revision 1.99 (2007/07/24 23:39:15)
-# de_AT.xml, revision 1.49 (2007/07/19 22:31:38)
-# de_BE.xml, revision 1.49 (2007/07/19 22:31:38)
-# de_CH.xml, revision 1.50 (2007/07/19 22:31:38)
-# de_DE.xml, revision 1.45 (2007/07/19 22:31:38)
-# de_LI.xml, revision 1.39 (2007/07/19 22:31:38)
-# de_LU.xml, revision 1.49 (2007/07/19 22:31:38)
-# dv.xml, revision 1.39 (2007/07/19 22:31:38)
-# dv_MV.xml, revision 1.36 (2007/07/19 22:31:38)
-# dz.xml, revision 1.52 (2007/11/14 16:26:57)
-# dz_BT.xml, revision 1.39 (2007/07/19 22:31:38)
-# ee.xml, revision 1.26 (2007/07/19 22:31:38)
-# ee_GH.xml, revision 1.13 (2007/07/19 22:31:38)
-# ee_TG.xml, revision 1.16 (2007/07/19 22:31:38)
-# el.xml, revision 1.84 (2007/07/19 22:31:38)
-# el_CY.xml, revision 1.22 (2007/07/19 22:31:39)
-# el_GR.xml, revision 1.48 (2007/07/19 22:31:39)
-# el_POLYTON.xml, revision 1.4 (2007/07/19 22:31:39)
-# en.xml, revision 1.161 (2007/11/07 23:36:50)
-# en_AS.xml, revision 1.34 (2007/07/19 22:31:39)
-# en_AU.xml, revision 1.46 (2007/08/21 16:11:36)
-# en_BE.xml, revision 1.52 (2007/07/19 22:31:39)
-# en_BW.xml, revision 1.42 (2007/07/19 22:31:39)
-# en_BZ.xml, revision 1.40 (2007/07/19 22:31:39)
-# en_CA.xml, revision 1.54 (2007/08/21 16:11:36)
-# en_GB.xml, revision 1.55 (2007/08/21 16:11:36)
-# en_GU.xml, revision 1.34 (2007/07/19 22:31:39)
-# en_HK.xml, revision 1.44 (2007/07/19 22:31:39)
-# en_IE.xml, revision 1.52 (2007/07/19 22:31:39)
-# en_IN.xml, revision 1.49 (2007/07/19 22:31:39)
-# en_JM.xml, revision 1.39 (2007/07/19 22:31:39)
-# en_MH.xml, revision 1.34 (2007/07/19 22:31:39)
-# en_MP.xml, revision 1.34 (2007/07/19 22:31:39)
-# en_MT.xml, revision 1.50 (2007/07/19 22:31:39)
-# en_NA.xml, revision 1.14 (2007/07/19 22:31:39)
-# en_NZ.xml, revision 1.49 (2007/08/21 16:11:36)
-# en_PH.xml, revision 1.44 (2007/07/19 22:31:39)
-# en_PK.xml, revision 1.26 (2007/07/19 22:31:39)
-# en_SG.xml, revision 1.50 (2007/07/19 22:31:39)
-# en_TT.xml, revision 1.37 (2007/07/19 22:31:39)
-# en_UM.xml, revision 1.34 (2007/07/19 22:31:39)
-# en_US.xml, revision 1.49 (2007/07/19 22:31:39)
-# en_US_POSIX.xml, revision 1.52 (2007/07/19 22:31:39)
-# en_VI.xml, revision 1.42 (2007/07/19 22:31:39)
-# en_ZA.xml, revision 1.50 (2007/08/21 16:11:36)
-# en_ZW.xml, revision 1.43 (2007/08/21 16:11:36)
-# eo.xml, revision 1.62 (2007/07/19 22:31:39)
-# es.xml, revision 1.99 (2007/11/14 16:26:57)
-# es_AR.xml, revision 1.52 (2007/07/21 21:12:28)
-# es_BO.xml, revision 1.49 (2007/07/21 21:12:28)
-# es_CL.xml, revision 1.53 (2007/07/21 21:12:28)
-# es_CO.xml, revision 1.52 (2007/07/21 21:12:28)
-# es_CR.xml, revision 1.50 (2007/07/21 21:12:28)
-# es_DO.xml, revision 1.50 (2007/11/19 23:42:54)
-# es_EC.xml, revision 1.53 (2007/07/21 21:12:28)
-# es_ES.xml, revision 1.50 (2007/07/21 21:12:28)
-# es_GT.xml, revision 1.50 (2007/11/19 23:42:54)
-# es_HN.xml, revision 1.51 (2007/11/19 23:42:54)
-# es_MX.xml, revision 1.49 (2007/11/19 23:42:54)
-# es_NI.xml, revision 1.50 (2007/11/19 23:42:54)
-# es_PA.xml, revision 1.51 (2007/11/19 23:42:54)
-# es_PE.xml, revision 1.52 (2007/11/19 23:42:54)
-# es_PR.xml, revision 1.52 (2007/11/19 23:42:54)
-# es_PY.xml, revision 1.50 (2007/07/21 21:12:28)
-# es_SV.xml, revision 1.50 (2007/11/19 23:42:54)
-# es_US.xml, revision 1.59 (2007/11/19 23:42:54)
-# es_UY.xml, revision 1.50 (2007/07/21 21:12:28)
-# es_VE.xml, revision 1.49 (2007/07/21 21:12:28)
-# et.xml, revision 1.71 (2007/07/19 23:40:49)
-# et_EE.xml, revision 1.46 (2007/07/19 22:31:39)
-# eu.xml, revision 1.62 (2007/07/19 22:31:39)
-# eu_ES.xml, revision 1.45 (2007/07/19 22:31:39)
-# fa.xml, revision 1.79 (2007/11/14 16:26:57)
-# fa_AF.xml, revision 1.55 (2007/07/19 22:31:39)
-# fa_IR.xml, revision 1.50 (2007/07/19 22:31:39)
-# fi.xml, revision 1.96 (2007/11/14 16:26:57)
-# fi_FI.xml, revision 1.45 (2007/07/19 22:31:39)
-# fil.xml, revision 1.8 (2007/11/20 02:39:11)
-# fo.xml, revision 1.54 (2007/07/19 22:31:39)
-# fo_FO.xml, revision 1.44 (2007/07/19 22:31:39)
-# fr.xml, revision 1.107 (2007/11/14 16:26:57)
-# fr_BE.xml, revision 1.47 (2007/07/19 22:31:39)
-# fr_CA.xml, revision 1.50 (2007/08/21 16:11:36)
-# fr_CH.xml, revision 1.47 (2007/07/19 22:31:39)
-# fr_FR.xml, revision 1.41 (2007/07/19 22:31:39)
-# fr_LU.xml, revision 1.44 (2007/07/19 22:31:39)
-# fr_MC.xml, revision 1.36 (2007/07/19 22:31:39)
-# fur.xml, revision 1.22 (2007/07/19 22:31:39)
-# fur_IT.xml, revision 1.13 (2007/07/19 22:31:39)
-# ga.xml, revision 1.61 (2007/07/19 22:31:39)
-# ga_IE.xml, revision 1.45 (2007/07/19 22:31:39)
-# gaa.xml, revision 1.20 (2007/07/19 22:31:39)
-# gaa_GH.xml, revision 1.13 (2007/07/19 22:31:39)
-# gez.xml, revision 1.50 (2007/07/19 22:31:39)
-# gez_ER.xml, revision 1.37 (2007/07/19 22:31:39)
-# gez_ET.xml, revision 1.37 (2007/07/19 22:31:39)
-# gl.xml, revision 1.52 (2007/07/19 23:30:28)
-# gl_ES.xml, revision 1.47 (2007/07/19 22:31:39)
-# gu.xml, revision 1.56 (2007/07/19 22:31:39)
-# gu_IN.xml, revision 1.53 (2007/07/19 22:31:39)
-# gv.xml, revision 1.47 (2007/07/19 22:31:39)
-# gv_GB.xml, revision 1.44 (2007/07/19 22:31:39)
-# ha.xml, revision 1.23 (2007/07/19 22:31:39)
-# ha_Arab.xml, revision 1.18 (2007/07/19 22:31:39)
-# ha_Arab_NG.xml, revision 1.13 (2007/07/19 22:31:39)
-# ha_GH.xml, revision 1.14 (2007/07/19 22:31:39)
-# ha_Latn.xml, revision 1.9 (2007/07/19 22:31:39)
-# ha_Latn_GH.xml, revision 1.9 (2007/07/19 22:31:39)
-# ha_Latn_NE.xml, revision 1.9 (2007/07/19 22:31:39)
-# ha_Latn_NG.xml, revision 1.9 (2007/07/19 22:31:39)
-# ha_NE.xml, revision 1.14 (2007/07/19 22:31:39)
-# ha_NG.xml, revision 1.14 (2007/07/19 22:31:39)
-# haw.xml, revision 1.35 (2007/07/19 22:31:39)
-# haw_US.xml, revision 1.33 (2007/07/19 22:31:39)
-# he.xml, revision 1.88 (2007/07/24 01:06:03)
-# he_IL.xml, revision 1.47 (2007/07/19 22:31:39)
-# hi.xml, revision 1.70 (2007/07/19 22:31:39)
-# hi_IN.xml, revision 1.52 (2007/07/19 22:31:39)
-# hr.xml, revision 1.79 (2007/07/19 23:30:28)
-# hr_HR.xml, revision 1.46 (2007/07/19 22:31:39)
-# hu.xml, revision 1.89 (2007/11/14 16:26:57)
-# hu_HU.xml, revision 1.44 (2007/07/19 22:31:39)
-# hy.xml, revision 1.59 (2007/07/19 23:30:28)
-# hy_AM.xml, revision 1.43 (2007/07/19 22:31:39)
-# hy_AM_REVISED.xml, revision 1.43 (2007/07/19 22:31:39)
-# ia.xml, revision 1.19 (2007/07/19 23:30:28)
-# id.xml, revision 1.64 (2007/07/19 22:31:39)
-# id_ID.xml, revision 1.43 (2007/07/19 22:31:39)
-# ig.xml, revision 1.20 (2007/07/19 22:31:39)
-# ig_NG.xml, revision 1.12 (2007/07/19 22:31:39)
-# ii.xml, revision 1.5 (2007/11/28 00:17:37)
-# ii_CN.xml, revision 1.3 (2007/07/19 22:31:39)
-# is.xml, revision 1.77 (2007/11/14 16:26:58)
-# is_IS.xml, revision 1.46 (2007/07/19 22:31:39)
-# it.xml, revision 1.93 (2007/11/14 16:26:58)
-# it_CH.xml, revision 1.48 (2007/07/19 22:31:39)
-# it_IT.xml, revision 1.43 (2007/07/19 22:31:39)
-# iu.xml, revision 1.32 (2007/07/19 22:31:39)
-# ja.xml, revision 1.115 (2007/11/14 16:26:58)
-# ja_JP.xml, revision 1.43 (2007/07/19 22:31:39)
-# ka.xml, revision 1.47 (2007/11/28 21:17:49)
-# ka_GE.xml, revision 1.33 (2007/07/19 22:31:39)
-# kaj.xml, revision 1.17 (2007/07/19 22:31:39)
-# kaj_NG.xml, revision 1.11 (2007/07/19 22:31:39)
-# kam.xml, revision 1.20 (2007/07/19 22:31:39)
-# kam_KE.xml, revision 1.12 (2007/07/19 22:31:39)
-# kcg.xml, revision 1.18 (2007/07/19 22:31:39)
-# kcg_NG.xml, revision 1.12 (2007/07/19 22:31:39)
-# kfo.xml, revision 1.19 (2007/07/19 22:31:39)
-# kfo_NG.xml, revision 1.12 (2007/07/19 22:31:39)
-# kk.xml, revision 1.50 (2007/07/19 22:31:39)
-# kk_KZ.xml, revision 1.37 (2007/07/19 22:31:39)
-# kl.xml, revision 1.42 (2007/07/19 22:31:39)
-# kl_GL.xml, revision 1.40 (2007/07/19 22:31:39)
-# km.xml, revision 1.58 (2007/07/19 22:31:39)
-# km_KH.xml, revision 1.33 (2007/07/19 22:31:39)
-# kn.xml, revision 1.57 (2007/07/19 22:31:39)
-# kn_IN.xml, revision 1.54 (2007/07/19 22:31:39)
-# ko.xml, revision 1.96 (2007/11/14 16:26:58)
-# ko_KR.xml, revision 1.53 (2007/07/19 22:31:39)
-# kok.xml, revision 1.52 (2007/07/19 22:31:39)
-# kok_IN.xml, revision 1.49 (2007/07/19 22:31:39)
-# kpe.xml, revision 1.17 (2007/07/19 22:31:39)
-# kpe_GN.xml, revision 1.14 (2007/07/19 22:31:39)
-# kpe_LR.xml, revision 1.14 (2007/07/19 22:31:39)
-# ku.xml, revision 1.18 (2007/07/19 22:31:39)
-# ku_Arab.xml, revision 1.13 (2007/07/19 22:31:39)
-# ku_IQ.xml, revision 1.13 (2007/07/19 22:31:39)
-# ku_IR.xml, revision 1.13 (2007/07/19 22:31:39)
-# ku_Latn.xml, revision 1.12 (2007/07/19 22:31:39)
-# ku_Latn_IQ.xml, revision 1.8 (2007/07/19 22:31:39)
-# ku_Latn_IR.xml, revision 1.8 (2007/07/19 22:31:39)
-# ku_Latn_SY.xml, revision 1.8 (2007/07/19 22:31:39)
-# ku_Latn_TR.xml, revision 1.8 (2007/07/19 22:31:39)
-# ku_SY.xml, revision 1.13 (2007/07/19 22:31:39)
-# ku_TR.xml, revision 1.13 (2007/07/19 22:31:39)
-# kw.xml, revision 1.46 (2007/07/19 22:31:39)
-# kw_GB.xml, revision 1.44 (2007/07/19 22:31:39)
-# ky.xml, revision 1.35 (2007/07/19 22:31:39)
-# ky_KG.xml, revision 1.33 (2007/07/19 22:31:39)
-# ln.xml, revision 1.31 (2007/07/19 23:30:28)
-# ln_CD.xml, revision 1.12 (2007/07/19 22:31:39)
-# ln_CG.xml, revision 1.12 (2007/07/19 22:31:39)
-# lo.xml, revision 1.57 (2007/07/19 22:31:39)
-# lo_LA.xml, revision 1.36 (2007/07/19 22:31:39)
-# lt.xml, revision 1.86 (2007/07/19 22:31:39)
-# lt_LT.xml, revision 1.46 (2007/07/19 22:31:39)
-# lv.xml, revision 1.70 (2007/07/19 23:40:49)
-# lv_LV.xml, revision 1.44 (2007/07/19 22:31:39)
-# mk.xml, revision 1.69 (2007/07/19 22:31:39)
-# mk_MK.xml, revision 1.40 (2007/07/19 22:31:39)
-# ml.xml, revision 1.42 (2007/07/26 04:28:12)
-# ml_IN.xml, revision 1.33 (2007/07/19 22:31:39)
-# mn.xml, revision 1.40 (2007/07/19 22:31:39)
-# mn_MN.xml, revision 1.36 (2007/07/19 22:31:39)
-# mr.xml, revision 1.63 (2007/07/19 22:31:39)
-# mr_IN.xml, revision 1.54 (2007/07/19 22:31:39)
-# ms.xml, revision 1.57 (2007/07/19 23:30:28)
-# ms_BN.xml, revision 1.41 (2007/07/19 22:31:39)
-# ms_MY.xml, revision 1.42 (2007/07/19 22:31:39)
-# mt.xml, revision 1.71 (2007/07/19 23:40:49)
-# mt_MT.xml, revision 1.43 (2007/07/14 23:02:15)
-# my.xml, revision 1.16 (2007/07/19 22:31:39)
-# my_MM.xml, revision 1.13 (2007/07/14 23:02:15)
-# nb.xml, revision 1.85 (2007/07/26 04:29:36)
-# nb_NO.xml, revision 1.43 (2007/07/14 23:02:15)
-# ne.xml, revision 1.19 (2007/07/19 02:12:22)
-# ne_NP.xml, revision 1.11 (2007/07/14 23:02:15)
-# nl.xml, revision 1.94 (2007/11/14 16:26:58)
-# nl_BE.xml, revision 1.57 (2007/07/19 22:31:39)
-# nl_NL.xml, revision 1.42 (2007/07/14 23:02:15)
-# nn.xml, revision 1.77 (2007/07/19 23:40:49)
-# nn_NO.xml, revision 1.43 (2007/07/14 23:02:15)
-# nr.xml, revision 1.18 (2007/07/14 23:02:15)
-# nr_ZA.xml, revision 1.11 (2007/07/14 23:02:15)
-# nso.xml, revision 1.19 (2007/07/14 23:02:15)
-# nso_ZA.xml, revision 1.11 (2007/07/14 23:02:16)
-# ny.xml, revision 1.20 (2007/07/14 23:02:16)
-# ny_MW.xml, revision 1.12 (2007/07/14 23:02:16)
-# om.xml, revision 1.50 (2007/07/19 22:31:39)
-# om_ET.xml, revision 1.44 (2007/07/14 23:02:16)
-# om_KE.xml, revision 1.44 (2007/07/14 23:02:16)
-# or.xml, revision 1.35 (2007/07/19 22:31:39)
-# or_IN.xml, revision 1.34 (2007/07/14 23:02:16)
-# pa.xml, revision 1.56 (2007/07/19 23:40:49)
-# pa_Arab.xml, revision 1.15 (2007/07/14 23:02:16)
-# pa_Arab_PK.xml, revision 1.10 (2007/07/14 23:02:16)
-# pa_Guru.xml, revision 1.10 (2007/07/14 23:02:16)
-# pa_Guru_IN.xml, revision 1.10 (2007/07/14 23:02:16)
-# pa_IN.xml, revision 1.46 (2007/07/14 23:02:16)
-# pa_PK.xml, revision 1.11 (2007/07/14 23:02:16)
-# pl.xml, revision 1.89 (2007/07/20 17:14:05)
-# pl_PL.xml, revision 1.46 (2007/07/14 23:02:16)
-# ps.xml, revision 1.50 (2007/07/21 15:33:36)
-# ps_AF.xml, revision 1.43 (2007/07/14 23:02:16)
-# pt.xml, revision 1.91 (2007/11/29 18:23:44)
-# pt_BR.xml, revision 1.48 (2007/07/14 23:02:16)
-# pt_PT.xml, revision 1.64 (2007/11/14 16:26:58)
-# ro.xml, revision 1.86 (2007/11/28 00:21:09)
-# ro_RO.xml, revision 1.43 (2007/07/14 23:02:16)
-# root.xml, revision 1.124 (2007/11/16 18:12:39)
-# ru.xml, revision 1.110 (2007/07/20 04:40:45)
-# ru_RU.xml, revision 1.48 (2007/07/14 23:02:16)
-# ru_UA.xml, revision 1.48 (2007/07/19 22:31:40)
-# rw.xml, revision 1.18 (2007/07/19 22:31:40)
-# rw_RW.xml, revision 1.11 (2007/07/14 23:02:16)
-# sa.xml, revision 1.39 (2007/07/19 22:31:40)
-# sa_IN.xml, revision 1.36 (2007/07/14 23:02:16)
-# se.xml, revision 1.20 (2007/07/19 22:31:40)
-# se_FI.xml, revision 1.19 (2007/07/19 22:31:40)
-# se_NO.xml, revision 1.17 (2007/07/14 23:02:16)
-# sh.xml, revision 1.43 (2007/07/14 23:02:16)
-# sh_BA.xml, revision 1.19 (2007/07/19 01:02:18)
-# sh_CS.xml, revision 1.44 (2007/07/19 01:02:18)
-# sh_YU.xml, revision 1.43 (2007/07/19 01:02:18)
-# sid.xml, revision 1.39 (2007/07/19 22:31:40)
-# sid_ET.xml, revision 1.32 (2007/07/14 23:02:16)
-# sk.xml, revision 1.76 (2007/07/19 22:31:40)
-# sk_SK.xml, revision 1.43 (2007/07/14 23:02:16)
-# sl.xml, revision 1.85 (2007/11/28 21:17:49)
-# sl_SI.xml, revision 1.47 (2007/07/14 23:02:16)
-# so.xml, revision 1.52 (2007/07/19 23:30:29)
-# so_DJ.xml, revision 1.45 (2007/07/14 23:02:16)
-# so_ET.xml, revision 1.45 (2007/07/14 23:02:16)
-# so_KE.xml, revision 1.44 (2007/07/14 23:02:16)
-# so_SO.xml, revision 1.44 (2007/07/14 23:02:16)
-# sq.xml, revision 1.64 (2007/07/19 22:31:40)
-# sq_AL.xml, revision 1.40 (2007/07/14 23:02:16)
-# sr.xml, revision 1.88 (2007/07/21 21:40:42)
-# sr_BA.xml, revision 1.18 (2007/07/19 01:02:18)
-# sr_CS.xml, revision 1.43 (2007/07/19 01:02:18)
-# sr_Cyrl.xml, revision 1.34 (2007/07/19 22:31:40)
-# sr_Cyrl_BA.xml, revision 1.29 (2007/07/24 23:39:15)
-# sr_Cyrl_CS.xml, revision 1.29 (2007/07/19 01:02:18)
-# sr_Cyrl_ME.xml, revision 1.5 (2007/07/14 23:02:16)
-# sr_Cyrl_RS.xml, revision 1.5 (2007/07/14 23:02:16)
-# sr_Cyrl_YU.xml, revision 1.27 (2007/07/14 23:02:16)
-# sr_Latn.xml, revision 1.65 (2007/07/21 21:12:28)
-# sr_Latn_BA.xml, revision 1.25 (2007/07/14 23:02:16)
-# sr_Latn_CS.xml, revision 1.32 (2007/07/19 01:02:18)
-# sr_Latn_ME.xml, revision 1.12 (2007/07/21 21:12:28)
-# sr_Latn_RS.xml, revision 1.12 (2007/07/21 21:12:28)
-# sr_Latn_YU.xml, revision 1.27 (2007/07/14 23:02:16)
-# sr_ME.xml, revision 1.6 (2007/07/19 01:02:18)
-# sr_RS.xml, revision 1.6 (2007/07/19 01:02:18)
-# sr_YU.xml, revision 1.42 (2007/07/14 23:02:16)
-# ss.xml, revision 1.17 (2007/07/14 23:02:17)
-# ss_ZA.xml, revision 1.11 (2007/07/14 23:02:17)
-# ssy.xml, revision 1.1 (2007/07/19 20:48:11)
-# st.xml, revision 1.18 (2007/07/15 23:39:11)
-# st_ZA.xml, revision 1.11 (2007/07/14 23:02:17)
-# sv.xml, revision 1.109 (2007/11/14 16:26:58)
-# sv_FI.xml, revision 1.50 (2007/07/19 22:31:40)
-# sv_SE.xml, revision 1.49 (2007/07/14 23:02:17)
-# sw.xml, revision 1.60 (2007/07/21 17:23:34)
-# sw_KE.xml, revision 1.42 (2007/07/14 23:02:17)
-# sw_TZ.xml, revision 1.48 (2007/07/14 23:02:17)
-# syr.xml, revision 1.36 (2007/07/19 22:31:40)
-# syr_SY.xml, revision 1.36 (2007/07/14 23:02:17)
-# ta.xml, revision 1.64 (2007/07/14 23:02:17)
-# ta_IN.xml, revision 1.53 (2007/07/14 23:02:17)
-# te.xml, revision 1.62 (2007/07/21 17:25:02)
-# te_IN.xml, revision 1.52 (2007/07/14 23:02:17)
-# tg.xml, revision 1.20 (2007/07/15 23:39:11)
-# tg_TJ.xml, revision 1.11 (2007/07/14 23:02:17)
-# th.xml, revision 1.95 (2007/11/14 16:26:58)
-# th_TH.xml, revision 1.45 (2007/07/14 23:02:17)
-# ti.xml, revision 1.55 (2007/07/19 22:31:40)
-# ti_ER.xml, revision 1.45 (2007/07/14 23:02:17)
-# ti_ET.xml, revision 1.46 (2007/07/14 23:02:17)
-# tig.xml, revision 1.50 (2007/07/19 22:31:40)
-# tig_ER.xml, revision 1.32 (2007/07/14 23:02:17)
-# tn.xml, revision 1.20 (2007/07/14 23:02:17)
-# tn_ZA.xml, revision 1.11 (2007/07/14 23:02:17)
-# to.xml, revision 1.5 (2007/07/19 22:31:40)
-# to_TO.xml, revision 1.3 (2007/07/14 23:02:17)
-# tr.xml, revision 1.92 (2007/11/14 16:26:58)
-# tr_TR.xml, revision 1.44 (2007/07/14 23:02:17)
-# ts.xml, revision 1.18 (2007/07/14 23:02:17)
-# ts_ZA.xml, revision 1.11 (2007/07/14 23:02:17)
-# tt.xml, revision 1.35 (2007/07/19 22:31:40)
-# tt_RU.xml, revision 1.35 (2007/07/14 23:02:17)
-# ug.xml, revision 1.19 (2007/07/19 22:31:40)
-# uk.xml, revision 1.95 (2007/07/19 23:30:29)
-# uk_UA.xml, revision 1.42 (2007/07/14 23:02:17)
-# und.xml, revision 1.3 (2007/07/19 01:02:18)
-# und_ZZ.xml, revision 1.4 (2007/07/19 01:46:01)
-# ur.xml, revision 1.46 (2007/07/21 17:40:15)
-# ur_IN.xml, revision 1.11 (2007/07/14 23:02:17)
-# ur_PK.xml, revision 1.31 (2007/07/14 23:02:17)
-# uz.xml, revision 1.42 (2007/07/19 22:31:40)
-# uz_AF.xml, revision 1.37 (2007/07/19 01:57:28)
-# uz_Arab.xml, revision 1.24 (2007/07/19 22:31:40)
-# uz_Arab_AF.xml, revision 1.18 (2007/07/14 23:02:17)
-# uz_Cyrl.xml, revision 1.18 (2007/07/14 23:02:17)
-# uz_Cyrl_UZ.xml, revision 1.17 (2007/07/14 23:02:17)
-# uz_Latn.xml, revision 1.17 (2007/07/14 23:02:17)
-# uz_Latn_UZ.xml, revision 1.17 (2007/07/14 23:02:17)
-# uz_UZ.xml, revision 1.34 (2007/07/19 01:57:28)
-# ve.xml, revision 1.18 (2007/07/14 23:02:17)
-# ve_ZA.xml, revision 1.11 (2007/07/14 23:02:17)
-# vi.xml, revision 1.60 (2007/07/19 23:30:29)
-# vi_VN.xml, revision 1.37 (2007/07/14 23:02:17)
-# wal.xml, revision 1.47 (2007/07/19 22:31:40)
-# wal_ET.xml, revision 1.33 (2007/07/14 23:02:17)
-# wo.xml, revision 1.21 (2007/07/19 22:31:40)
-# wo_Arab.xml, revision 1.10 (2007/07/14 23:02:17)
-# wo_Arab_SN.xml, revision 1.10 (2007/07/14 23:02:17)
-# wo_Latn.xml, revision 1.10 (2007/07/14 23:02:17)
-# wo_Latn_SN.xml, revision 1.10 (2007/07/14 23:02:17)
-# wo_SN.xml, revision 1.13 (2007/07/14 23:02:17)
-# xh.xml, revision 1.18 (2007/07/14 23:02:17)
-# xh_ZA.xml, revision 1.11 (2007/07/14 23:02:17)
-# yo.xml, revision 1.22 (2007/07/15 23:39:12)
-# yo_NG.xml, revision 1.11 (2007/07/14 23:02:17)
-# zh.xml, revision 1.105 (2007/11/14 16:26:58)
-# zh_CN.xml, revision 1.42 (2007/07/14 23:02:17)
-# zh_HK.xml, revision 1.40 (2007/07/14 23:02:17)
-# zh_Hans.xml, revision 1.46 (2007/07/19 22:31:40)
-# zh_Hans_CN.xml, revision 1.34 (2007/07/14 23:02:17)
-# zh_Hans_SG.xml, revision 1.47 (2007/11/28 21:17:49)
-# zh_Hant.xml, revision 1.91 (2007/11/29 18:23:45)
-# zh_Hant_HK.xml, revision 1.58 (2007/07/19 22:31:40)
-# zh_Hant_MO.xml, revision 1.53 (2007/07/21 21:12:28)
-# zh_Hant_TW.xml, revision 1.35 (2007/07/14 23:02:17)
-# zh_MO.xml, revision 1.41 (2007/07/14 23:02:17)
-# zh_SG.xml, revision 1.41 (2007/07/14 23:02:17)
-# zh_TW.xml, revision 1.46 (2007/07/14 23:02:17)
-# zu.xml, revision 1.19 (2007/07/14 23:02:17)
-# zu_ZA.xml, revision 1.11 (2007/07/14 23:02:17)
+# aa.xml, revision 1.44 (2008/05/28 15:49:27)
+# aa_DJ.xml, revision 1.38 (2008/05/28 15:49:27)
+# aa_ER.xml, revision 1.37 (2008/05/28 15:49:27)
+# aa_ER_SAAHO.xml, revision 1.34 (2008/05/28 15:49:27)
+# aa_ET.xml, revision 1.38 (2008/05/28 15:49:27)
+# af.xml, revision 1.65 (2008/06/17 14:12:13)
+# af_NA.xml, revision 1.19 (2008/06/15 08:09:45)
+# af_ZA.xml, revision 1.48 (2008/05/28 15:49:27)
+# ak.xml, revision 1.28 (2008/05/28 15:49:27)
+# ak_GH.xml, revision 1.16 (2008/05/28 15:49:27)
+# am.xml, revision 1.77 (2008/06/26 03:47:57)
+# am_ET.xml, revision 1.49 (2008/05/28 15:49:28)
+# ar.xml, revision 1.102 (2008/06/15 08:09:46)
+# ar_AE.xml, revision 1.45 (2008/05/28 15:49:28)
+# ar_BH.xml, revision 1.45 (2008/05/28 15:49:28)
+# ar_DZ.xml, revision 1.48 (2008/05/28 15:49:28)
+# ar_EG.xml, revision 1.48 (2008/05/28 15:49:28)
+# ar_IQ.xml, revision 1.45 (2008/05/28 15:49:28)
+# ar_JO.xml, revision 1.46 (2008/05/28 15:49:28)
+# ar_KW.xml, revision 1.47 (2008/05/28 15:49:28)
+# ar_LB.xml, revision 1.46 (2008/06/17 14:12:15)
+# ar_LY.xml, revision 1.45 (2008/05/28 15:49:28)
+# ar_MA.xml, revision 1.46 (2008/05/28 15:49:28)
+# ar_OM.xml, revision 1.45 (2008/05/28 15:49:28)
+# ar_QA.xml, revision 1.46 (2008/05/28 15:49:28)
+# ar_SA.xml, revision 1.49 (2008/05/28 15:49:28)
+# ar_SD.xml, revision 1.43 (2008/05/28 15:49:28)
+# ar_SY.xml, revision 1.48 (2008/05/28 15:49:28)
+# ar_TN.xml, revision 1.48 (2008/05/28 15:49:28)
+# ar_YE.xml, revision 1.46 (2008/05/28 15:49:28)
+# as.xml, revision 1.49 (2008/06/15 09:11:18)
+# as_IN.xml, revision 1.37 (2008/05/28 15:49:28)
+# az.xml, revision 1.63 (2008/06/26 03:47:57)
+# az_AZ.xml, revision 1.40 (2008/06/24 16:36:03)
+# az_Cyrl.xml, revision 1.28 (2008/06/24 16:36:03)
+# az_Cyrl_AZ.xml, revision 1.21 (2008/05/28 15:49:28)
+# az_Latn.xml, revision 1.28 (2008/06/24 16:36:03)
+# az_Latn_AZ.xml, revision 1.24 (2008/05/28 15:49:28)
+# be.xml, revision 1.76 (2008/06/26 03:47:57)
+# be_BY.xml, revision 1.45 (2008/05/28 15:49:28)
+# bg.xml, revision 1.102 (2008/06/15 18:49:20)
+# bg_BG.xml, revision 1.52 (2008/05/28 15:49:28)
+# bn.xml, revision 1.70 (2008/06/26 03:47:57)
+# bn_BD.xml, revision 1.23 (2008/05/28 15:49:28)
+# bn_IN.xml, revision 1.56 (2008/06/17 14:12:14)
+# bs.xml, revision 1.32 (2008/05/28 15:49:28)
+# bs_BA.xml, revision 1.22 (2008/05/28 15:49:28)
+# byn.xml, revision 1.51 (2008/05/28 15:49:28)
+# byn_ER.xml, revision 1.36 (2008/05/28 15:49:28)
+# ca.xml, revision 1.90 (2008/06/26 03:47:57)
+# ca_ES.xml, revision 1.48 (2008/05/28 15:49:28)
+# cch.xml, revision 1.22 (2008/05/28 15:49:28)
+# cch_NG.xml, revision 1.15 (2008/05/28 15:49:28)
+# cop.xml, revision 1.20 (2008/05/28 15:49:28)
+# cs.xml, revision 1.117 (2008/06/26 03:47:57)
+# cs_CZ.xml, revision 1.48 (2008/05/28 15:49:28)
+# cy.xml, revision 1.56 (2008/06/15 18:49:20)
+# cy_GB.xml, revision 1.42 (2008/05/28 15:49:29)
+# da.xml, revision 1.103 (2008/06/26 03:47:57)
+# da_DK.xml, revision 1.48 (2008/05/28 15:49:29)
+# de.xml, revision 1.116 (2008/06/26 03:47:57)
+# de_AT.xml, revision 1.57 (2008/06/17 14:12:12)
+# de_BE.xml, revision 1.56 (2008/06/17 14:12:12)
+# de_CH.xml, revision 1.53 (2008/06/15 08:09:45)
+# de_DE.xml, revision 1.47 (2008/05/28 15:49:29)
+# de_LI.xml, revision 1.42 (2008/06/15 08:09:45)
+# de_LU.xml, revision 1.51 (2008/05/28 15:49:29)
+# dv.xml, revision 1.43 (2008/06/15 08:09:47)
+# dv_MV.xml, revision 1.38 (2008/05/28 15:49:29)
+# dz.xml, revision 1.56 (2008/06/15 08:09:47)
+# dz_BT.xml, revision 1.41 (2008/05/28 15:49:29)
+# ee.xml, revision 1.28 (2008/05/28 15:49:29)
+# ee_GH.xml, revision 1.15 (2008/05/28 15:49:29)
+# ee_TG.xml, revision 1.18 (2008/05/28 15:49:29)
+# el.xml, revision 1.95 (2008/06/26 03:47:57)
+# el_CY.xml, revision 1.24 (2008/05/28 15:49:29)
+# el_GR.xml, revision 1.50 (2008/05/28 15:49:29)
+# el_POLYTON.xml, revision 1.6 (2008/05/28 15:49:29)
+# en.xml, revision 1.197 (2008/07/09 17:41:17)
+# en_AS.xml, revision 1.36 (2008/05/28 15:49:29)
+# en_AU.xml, revision 1.53 (2008/06/17 14:12:15)
+# en_BE.xml, revision 1.57 (2008/06/15 08:09:47)
+# en_BW.xml, revision 1.48 (2008/06/05 01:32:20)
+# en_BZ.xml, revision 1.44 (2008/06/05 01:32:20)
+# en_CA.xml, revision 1.60 (2008/06/17 14:12:12)
+# en_Dsrt.xml, revision 1.6 (2008/06/26 03:47:57)
+# en_Dsrt_US.xml, revision 1.2 (2008/05/28 15:49:29)
+# en_GB.xml, revision 1.60 (2008/06/17 14:12:12)
+# en_GU.xml, revision 1.36 (2008/05/28 15:49:29)
+# en_HK.xml, revision 1.48 (2008/06/05 01:32:20)
+# en_IE.xml, revision 1.57 (2008/06/17 14:12:12)
+# en_IN.xml, revision 1.54 (2008/06/15 08:09:47)
+# en_JM.xml, revision 1.41 (2008/05/28 15:49:29)
+# en_MH.xml, revision 1.36 (2008/05/28 15:49:29)
+# en_MP.xml, revision 1.36 (2008/05/28 15:49:29)
+# en_MT.xml, revision 1.54 (2008/06/05 01:32:20)
+# en_NA.xml, revision 1.16 (2008/05/28 15:49:29)
+# en_NZ.xml, revision 1.56 (2008/06/17 14:12:12)
+# en_PH.xml, revision 1.48 (2008/05/28 15:49:29)
+# en_PK.xml, revision 1.31 (2008/06/15 08:09:47)
+# en_SG.xml, revision 1.54 (2008/06/05 01:32:20)
+# en_Shaw.xml, revision 1.5 (2008/06/26 03:47:57)
+# en_TT.xml, revision 1.39 (2008/05/28 15:49:30)
+# en_UM.xml, revision 1.36 (2008/05/28 15:49:30)
+# en_US.xml, revision 1.51 (2008/05/28 15:49:30)
+# en_US_POSIX.xml, revision 1.55 (2008/06/15 08:09:47)
+# en_VI.xml, revision 1.44 (2008/05/28 15:49:30)
+# en_ZA.xml, revision 1.58 (2008/06/17 14:12:11)
+# en_ZW.xml, revision 1.49 (2008/06/05 01:32:20)
+# eo.xml, revision 1.66 (2008/06/05 01:32:20)
+# es.xml, revision 1.112 (2008/06/17 14:12:12)
+# es_AR.xml, revision 1.57 (2008/06/17 14:12:14)
+# es_BO.xml, revision 1.51 (2008/05/28 15:49:30)
+# es_CL.xml, revision 1.58 (2008/06/17 14:12:11)
+# es_CO.xml, revision 1.56 (2008/06/05 01:32:20)
+# es_CR.xml, revision 1.52 (2008/05/28 15:49:30)
+# es_DO.xml, revision 1.52 (2008/05/28 15:49:30)
+# es_EC.xml, revision 1.57 (2008/06/05 01:32:20)
+# es_ES.xml, revision 1.59 (2008/06/19 01:24:40)
+# es_GT.xml, revision 1.54 (2008/06/05 01:32:20)
+# es_HN.xml, revision 1.55 (2008/06/05 01:32:20)
+# es_MX.xml, revision 1.51 (2008/05/28 15:49:30)
+# es_NI.xml, revision 1.52 (2008/05/28 15:49:30)
+# es_PA.xml, revision 1.55 (2008/06/05 01:32:20)
+# es_PE.xml, revision 1.56 (2008/06/05 01:32:20)
+# es_PR.xml, revision 1.56 (2008/06/05 01:32:20)
+# es_PY.xml, revision 1.53 (2008/06/15 08:09:46)
+# es_SV.xml, revision 1.52 (2008/05/28 15:49:30)
+# es_US.xml, revision 1.64 (2008/06/17 14:12:11)
+# es_UY.xml, revision 1.54 (2008/06/17 18:53:46)
+# es_VE.xml, revision 1.53 (2008/06/17 18:53:46)
+# et.xml, revision 1.78 (2008/06/15 08:09:47)
+# et_EE.xml, revision 1.48 (2008/05/28 15:49:30)
+# eu.xml, revision 1.65 (2008/06/15 08:09:47)
+# eu_ES.xml, revision 1.47 (2008/05/28 15:49:30)
+# fa.xml, revision 1.92 (2008/06/17 14:12:13)
+# fa_AF.xml, revision 1.59 (2008/06/17 14:12:16)
+# fa_IR.xml, revision 1.52 (2008/05/28 15:49:30)
+# fi.xml, revision 1.109 (2008/06/26 03:47:57)
+# fi_FI.xml, revision 1.47 (2008/05/28 15:49:30)
+# fil.xml, revision 1.18 (2008/06/26 03:47:57)
+# fil_PH.xml, revision 1.1 (2008/06/19 01:39:15)
+# fo.xml, revision 1.61 (2008/06/17 18:53:46)
+# fo_FO.xml, revision 1.46 (2008/05/28 15:49:30)
+# fr.xml, revision 1.124 (2008/06/17 14:12:14)
+# fr_BE.xml, revision 1.54 (2008/06/17 14:12:11)
+# fr_CA.xml, revision 1.57 (2008/06/17 18:53:46)
+# fr_CH.xml, revision 1.53 (2008/06/17 14:12:15)
+# fr_FR.xml, revision 1.43 (2008/05/28 15:49:31)
+# fr_LU.xml, revision 1.46 (2008/05/28 15:49:31)
+# fr_MC.xml, revision 1.38 (2008/05/28 15:49:31)
+# fr_SN.xml, revision 1.2 (2008/05/28 15:49:31)
+# fur.xml, revision 1.29 (2008/06/17 14:12:15)
+# fur_IT.xml, revision 1.15 (2008/05/28 15:49:31)
+# ga.xml, revision 1.65 (2008/06/26 03:47:57)
+# ga_IE.xml, revision 1.47 (2008/05/28 15:49:31)
+# gaa.xml, revision 1.22 (2008/05/28 15:49:31)
+# gaa_GH.xml, revision 1.15 (2008/05/28 15:49:31)
+# gez.xml, revision 1.54 (2008/05/28 15:49:31)
+# gez_ER.xml, revision 1.39 (2008/05/28 15:49:31)
+# gez_ET.xml, revision 1.39 (2008/05/28 15:49:31)
+# gl.xml, revision 1.60 (2008/06/17 14:12:15)
+# gl_ES.xml, revision 1.49 (2008/05/28 15:49:31)
+# gu.xml, revision 1.59 (2008/06/15 08:09:47)
+# gu_IN.xml, revision 1.55 (2008/05/28 15:49:31)
+# gv.xml, revision 1.51 (2008/05/28 15:49:31)
+# gv_GB.xml, revision 1.46 (2008/05/28 15:49:31)
+# ha.xml, revision 1.27 (2008/06/15 08:09:45)
+# ha_Arab.xml, revision 1.21 (2008/05/28 15:49:31)
+# ha_Arab_NG.xml, revision 1.15 (2008/05/28 15:49:31)
+# ha_Arab_SD.xml, revision 1.1 (2008/06/18 21:08:12)
+# ha_GH.xml, revision 1.16 (2008/05/28 15:49:31)
+# ha_Latn.xml, revision 1.11 (2008/05/28 15:49:31)
+# ha_Latn_GH.xml, revision 1.11 (2008/05/28 15:49:31)
+# ha_Latn_NE.xml, revision 1.11 (2008/05/28 15:49:31)
+# ha_Latn_NG.xml, revision 1.11 (2008/05/28 15:49:31)
+# ha_NE.xml, revision 1.16 (2008/05/28 15:49:31)
+# ha_NG.xml, revision 1.16 (2008/05/28 15:49:31)
+# ha_SD.xml, revision 1.1 (2008/06/18 21:08:12)
+# haw.xml, revision 1.37 (2008/05/28 15:49:31)
+# haw_US.xml, revision 1.35 (2008/05/28 15:49:31)
+# he.xml, revision 1.105 (2008/06/26 03:47:57)
+# he_IL.xml, revision 1.49 (2008/05/28 15:49:31)
+# hi.xml, revision 1.85 (2008/06/20 22:46:58)
+# hi_IN.xml, revision 1.54 (2008/05/28 15:49:31)
+# hr.xml, revision 1.90 (2008/06/26 03:47:57)
+# hr_HR.xml, revision 1.48 (2008/05/28 15:49:31)
+# hu.xml, revision 1.104 (2008/06/17 14:12:12)
+# hu_HU.xml, revision 1.46 (2008/05/28 15:49:32)
+# hy.xml, revision 1.64 (2008/06/15 08:09:45)
+# hy_AM.xml, revision 1.45 (2008/05/28 15:49:32)
+# hy_AM_REVISED.xml, revision 1.45 (2008/05/28 15:49:32)
+# ia.xml, revision 1.21 (2008/05/28 15:49:32)
+# id.xml, revision 1.66 (2008/05/28 15:49:32)
+# id_ID.xml, revision 1.45 (2008/05/28 15:49:32)
+# ig.xml, revision 1.22 (2008/05/28 15:49:32)
+# ig_NG.xml, revision 1.14 (2008/05/28 15:49:32)
+# ii.xml, revision 1.7 (2008/05/28 15:49:32)
+# ii_CN.xml, revision 1.5 (2008/05/28 15:49:32)
+# in.xml, revision 1.2 (2008/06/10 21:00:28)
+# is.xml, revision 1.88 (2008/06/26 03:47:57)
+# is_IS.xml, revision 1.48 (2008/05/28 15:49:32)
+# it.xml, revision 1.105 (2008/06/17 14:12:15)
+# it_CH.xml, revision 1.56 (2008/06/17 14:12:15)
+# it_IT.xml, revision 1.45 (2008/05/28 15:49:32)
+# iu.xml, revision 1.34 (2008/05/28 15:49:32)
+# iw.xml, revision 1.14 (2008/06/02 20:30:10)
+# ja.xml, revision 1.147 (2008/06/17 17:13:48)
+# ja_JP.xml, revision 1.45 (2008/05/28 15:49:32)
+# ka.xml, revision 1.56 (2008/06/26 03:47:57)
+# ka_GE.xml, revision 1.35 (2008/05/28 15:49:32)
+# kaj.xml, revision 1.19 (2008/05/28 15:49:32)
+# kaj_NG.xml, revision 1.13 (2008/05/28 15:49:32)
+# kam.xml, revision 1.22 (2008/05/28 15:49:33)
+# kam_KE.xml, revision 1.14 (2008/05/28 15:49:33)
+# kcg.xml, revision 1.20 (2008/05/28 15:49:33)
+# kcg_NG.xml, revision 1.14 (2008/05/28 15:49:33)
+# kfo.xml, revision 1.21 (2008/05/28 15:49:33)
+# kfo_CI.xml, revision 1.2 (2008/05/28 15:49:33)
+# kk.xml, revision 1.57 (2008/06/26 03:47:57)
+# kk_Cyrl.xml, revision 1.1 (2008/06/18 21:18:43)
+# kk_Cyrl_KZ.xml, revision 1.1 (2008/06/18 21:18:43)
+# kk_KZ.xml, revision 1.40 (2008/06/18 21:18:43)
+# kl.xml, revision 1.46 (2008/06/17 18:53:46)
+# kl_GL.xml, revision 1.42 (2008/05/28 15:49:33)
+# km.xml, revision 1.63 (2008/06/15 08:09:45)
+# km_KH.xml, revision 1.35 (2008/05/28 15:49:33)
+# kn.xml, revision 1.60 (2008/06/15 08:09:47)
+# kn_IN.xml, revision 1.56 (2008/05/28 15:49:33)
+# ko.xml, revision 1.117 (2008/06/26 03:47:57)
+# ko_KR.xml, revision 1.55 (2008/05/28 15:49:33)
+# kok.xml, revision 1.56 (2008/06/15 08:09:47)
+# kok_IN.xml, revision 1.51 (2008/05/28 15:49:33)
+# kpe.xml, revision 1.19 (2008/05/28 15:49:33)
+# kpe_GN.xml, revision 1.16 (2008/05/28 15:49:33)
+# kpe_LR.xml, revision 1.16 (2008/05/28 15:49:33)
+# ku.xml, revision 1.22 (2008/06/16 03:11:01)
+# ku_Arab.xml, revision 1.17 (2008/06/12 23:34:43)
+# ku_Latn.xml, revision 1.16 (2008/06/17 14:12:13)
+# ku_Latn_TR.xml, revision 1.10 (2008/05/28 15:49:33)
+# ku_TR.xml, revision 1.15 (2008/05/28 15:49:33)
+# kw.xml, revision 1.50 (2008/05/28 15:49:33)
+# kw_GB.xml, revision 1.46 (2008/05/28 15:49:33)
+# ky.xml, revision 1.37 (2008/05/28 15:49:33)
+# ky_KG.xml, revision 1.35 (2008/05/28 15:49:33)
+# ln.xml, revision 1.38 (2008/06/17 14:12:11)
+# ln_CD.xml, revision 1.14 (2008/05/28 15:49:33)
+# ln_CG.xml, revision 1.14 (2008/05/28 15:49:33)
+# lo.xml, revision 1.59 (2008/05/28 15:49:33)
+# lo_LA.xml, revision 1.38 (2008/05/28 15:49:33)
+# lt.xml, revision 1.92 (2008/06/15 08:09:46)
+# lt_LT.xml, revision 1.48 (2008/05/28 15:49:33)
+# lv.xml, revision 1.82 (2008/06/26 03:47:58)
+# lv_LV.xml, revision 1.46 (2008/05/28 15:49:33)
+# mk.xml, revision 1.74 (2008/06/05 01:32:22)
+# mk_MK.xml, revision 1.42 (2008/05/28 15:49:33)
+# ml.xml, revision 1.57 (2008/06/26 03:47:58)
+# ml_IN.xml, revision 1.35 (2008/05/28 15:49:33)
+# mn.xml, revision 1.42 (2008/05/28 15:49:33)
+# mn_CN.xml, revision 1.4 (2008/05/28 15:49:34)
+# mn_Cyrl.xml, revision 1.2 (2008/05/28 15:49:34)
+# mn_Cyrl_MN.xml, revision 1.2 (2008/05/28 15:49:34)
+# mn_MN.xml, revision 1.41 (2008/05/28 15:49:34)
+# mn_Mong.xml, revision 1.2 (2008/05/28 15:49:34)
+# mn_Mong_CN.xml, revision 1.2 (2008/05/28 15:49:34)
+# mo.xml, revision 1.1 (2008/06/02 20:30:10)
+# mr.xml, revision 1.69 (2008/06/15 08:09:46)
+# mr_IN.xml, revision 1.56 (2008/05/28 15:49:34)
+# ms.xml, revision 1.59 (2008/05/28 15:49:34)
+# ms_BN.xml, revision 1.47 (2008/06/17 14:12:12)
+# ms_MY.xml, revision 1.44 (2008/05/28 15:49:34)
+# mt.xml, revision 1.77 (2008/06/09 02:17:47)
+# mt_MT.xml, revision 1.45 (2008/05/28 15:49:34)
+# my.xml, revision 1.26 (2008/06/17 14:12:12)
+# my_MM.xml, revision 1.15 (2008/05/28 15:49:34)
+# nb.xml, revision 1.96 (2008/06/26 03:47:58)
+# nb_NO.xml, revision 1.45 (2008/05/28 15:49:34)
+# ne.xml, revision 1.24 (2008/06/26 03:47:58)
+# ne_IN.xml, revision 1.2 (2008/05/28 15:49:34)
+# ne_NP.xml, revision 1.13 (2008/05/28 15:49:34)
+# nl.xml, revision 1.108 (2008/06/17 14:12:14)
+# nl_BE.xml, revision 1.65 (2008/06/17 14:12:12)
+# nl_NL.xml, revision 1.44 (2008/05/28 15:49:34)
+# nn.xml, revision 1.87 (2008/06/17 14:12:13)
+# nn_NO.xml, revision 1.45 (2008/05/28 15:49:34)
+# no.xml, revision 1.19 (2008/06/02 20:30:10)
+# nr.xml, revision 1.20 (2008/05/28 15:49:34)
+# nr_ZA.xml, revision 1.13 (2008/05/28 15:49:34)
+# nso.xml, revision 1.21 (2008/05/28 15:49:34)
+# nso_ZA.xml, revision 1.13 (2008/05/28 15:49:34)
+# ny.xml, revision 1.22 (2008/05/28 15:49:34)
+# ny_MW.xml, revision 1.14 (2008/05/28 15:49:34)
+# om.xml, revision 1.52 (2008/05/28 15:49:34)
+# om_ET.xml, revision 1.46 (2008/05/28 15:49:34)
+# om_KE.xml, revision 1.46 (2008/05/28 15:49:34)
+# or.xml, revision 1.41 (2008/06/15 09:11:18)
+# or_IN.xml, revision 1.36 (2008/05/28 15:49:34)
+# pa.xml, revision 1.61 (2008/06/26 03:47:58)
+# pa_Arab.xml, revision 1.20 (2008/06/15 08:09:47)
+# pa_Arab_PK.xml, revision 1.12 (2008/05/28 15:49:34)
+# pa_Guru.xml, revision 1.12 (2008/05/28 15:49:34)
+# pa_Guru_IN.xml, revision 1.12 (2008/05/28 15:49:34)
+# pa_IN.xml, revision 1.48 (2008/05/28 15:49:34)
+# pa_PK.xml, revision 1.13 (2008/05/28 15:49:34)
+# pl.xml, revision 1.107 (2008/06/26 03:47:58)
+# pl_PL.xml, revision 1.48 (2008/05/28 15:49:35)
+# ps.xml, revision 1.53 (2008/06/15 08:09:47)
+# ps_AF.xml, revision 1.45 (2008/05/28 15:49:35)
+# pt.xml, revision 1.105 (2008/06/17 14:12:14)
+# pt_BR.xml, revision 1.50 (2008/05/28 15:49:35)
+# pt_PT.xml, revision 1.76 (2008/06/26 03:47:58)
+# ro.xml, revision 1.96 (2008/06/26 03:47:58)
+# ro_MD.xml, revision 1.1 (2008/06/02 20:30:10)
+# ro_RO.xml, revision 1.45 (2008/05/28 15:49:35)
+# root.xml, revision 1.162 (2008/07/09 17:41:17)
+# ru.xml, revision 1.126 (2008/06/26 03:47:58)
+# ru_RU.xml, revision 1.50 (2008/05/28 15:49:35)
+# ru_UA.xml, revision 1.53 (2008/06/17 14:12:15)
+# rw.xml, revision 1.20 (2008/05/28 15:49:36)
+# rw_RW.xml, revision 1.13 (2008/05/28 15:49:36)
+# sa.xml, revision 1.41 (2008/05/28 15:49:36)
+# sa_IN.xml, revision 1.38 (2008/05/28 15:49:36)
+# se.xml, revision 1.25 (2008/06/15 08:09:47)
+# se_FI.xml, revision 1.22 (2008/06/17 14:12:15)
+# se_NO.xml, revision 1.19 (2008/05/28 15:49:36)
+# sh.xml, revision 1.45 (2008/05/28 15:49:36)
+# sh_BA.xml, revision 1.21 (2008/05/28 15:49:36)
+# sh_CS.xml, revision 1.46 (2008/05/28 15:49:36)
+# sh_YU.xml, revision 1.45 (2008/05/28 15:49:36)
+# si.xml, revision 1.2 (2008/05/28 15:49:36)
+# si_LK.xml, revision 1.2 (2008/05/28 15:49:36)
+# sid.xml, revision 1.41 (2008/05/28 15:49:36)
+# sid_ET.xml, revision 1.34 (2008/05/28 15:49:36)
+# sk.xml, revision 1.84 (2008/06/17 14:12:15)
+# sk_SK.xml, revision 1.45 (2008/05/28 15:49:36)
+# sl.xml, revision 1.94 (2008/06/26 03:47:58)
+# sl_SI.xml, revision 1.49 (2008/05/28 15:49:36)
+# so.xml, revision 1.56 (2008/06/05 01:32:23)
+# so_DJ.xml, revision 1.47 (2008/05/28 15:49:36)
+# so_ET.xml, revision 1.47 (2008/05/28 15:49:36)
+# so_KE.xml, revision 1.46 (2008/05/28 15:49:36)
+# so_SO.xml, revision 1.46 (2008/05/28 15:49:36)
+# sq.xml, revision 1.69 (2008/06/05 01:32:23)
+# sq_AL.xml, revision 1.42 (2008/05/28 15:49:36)
+# sr.xml, revision 1.99 (2008/06/26 03:47:58)
+# sr_BA.xml, revision 1.20 (2008/05/28 15:49:36)
+# sr_CS.xml, revision 1.45 (2008/05/28 15:49:36)
+# sr_Cyrl.xml, revision 1.36 (2008/05/28 15:49:36)
+# sr_Cyrl_BA.xml, revision 1.35 (2008/06/17 14:12:15)
+# sr_Cyrl_CS.xml, revision 1.31 (2008/05/28 15:49:36)
+# sr_Cyrl_ME.xml, revision 1.7 (2008/05/28 15:49:36)
+# sr_Cyrl_RS.xml, revision 1.7 (2008/05/28 15:49:36)
+# sr_Cyrl_YU.xml, revision 1.29 (2008/05/28 15:49:36)
+# sr_Latn.xml, revision 1.75 (2008/06/26 03:47:58)
+# sr_Latn_BA.xml, revision 1.27 (2008/05/28 15:49:36)
+# sr_Latn_CS.xml, revision 1.34 (2008/05/28 15:49:36)
+# sr_Latn_ME.xml, revision 1.18 (2008/06/17 14:12:16)
+# sr_Latn_RS.xml, revision 1.19 (2008/06/19 01:24:40)
+# sr_Latn_YU.xml, revision 1.29 (2008/05/28 15:49:36)
+# sr_ME.xml, revision 1.8 (2008/05/28 15:49:36)
+# sr_RS.xml, revision 1.8 (2008/05/28 15:49:36)
+# sr_YU.xml, revision 1.44 (2008/05/28 15:49:36)
+# ss.xml, revision 1.19 (2008/05/28 15:49:36)
+# ss_SZ.xml, revision 1.1 (2008/06/18 21:11:39)
+# ss_ZA.xml, revision 1.13 (2008/05/28 15:49:36)
+# st.xml, revision 1.20 (2008/05/28 15:49:36)
+# st_LS.xml, revision 1.2 (2008/05/28 15:49:36)
+# st_ZA.xml, revision 1.13 (2008/05/28 15:49:36)
+# sv.xml, revision 1.124 (2008/06/17 14:12:11)
+# sv_FI.xml, revision 1.56 (2008/06/17 14:12:12)
+# sv_SE.xml, revision 1.51 (2008/05/28 15:49:36)
+# sw.xml, revision 1.64 (2008/06/15 08:09:46)
+# sw_KE.xml, revision 1.44 (2008/05/28 15:49:36)
+# sw_TZ.xml, revision 1.50 (2008/05/28 15:49:36)
+# syr.xml, revision 1.40 (2008/06/15 08:09:47)
+# syr_SY.xml, revision 1.38 (2008/05/28 15:49:36)
+# ta.xml, revision 1.70 (2008/06/15 08:09:47)
+# ta_IN.xml, revision 1.55 (2008/05/28 15:49:36)
+# te.xml, revision 1.65 (2008/06/15 08:09:47)
+# te_IN.xml, revision 1.54 (2008/05/28 15:49:36)
+# tg.xml, revision 1.22 (2008/05/28 15:49:36)
+# tg_Cyrl.xml, revision 1.1 (2008/06/18 21:41:57)
+# tg_Cyrl_TJ.xml, revision 1.1 (2008/06/18 21:41:57)
+# tg_TJ.xml, revision 1.14 (2008/06/18 21:41:57)
+# th.xml, revision 1.111 (2008/06/26 03:47:58)
+# th_TH.xml, revision 1.47 (2008/05/28 15:49:37)
+# ti.xml, revision 1.59 (2008/05/28 15:49:37)
+# ti_ER.xml, revision 1.50 (2008/06/17 14:12:15)
+# ti_ET.xml, revision 1.48 (2008/05/28 15:49:37)
+# tig.xml, revision 1.52 (2008/05/28 15:49:37)
+# tig_ER.xml, revision 1.34 (2008/05/28 15:49:37)
+# tl.xml, revision 1.6 (2008/06/02 20:30:10)
+# tn.xml, revision 1.22 (2008/05/28 15:49:37)
+# tn_ZA.xml, revision 1.13 (2008/05/28 15:49:37)
+# to.xml, revision 1.11 (2008/06/26 03:47:58)
+# to_TO.xml, revision 1.5 (2008/05/28 15:49:37)
+# tr.xml, revision 1.107 (2008/06/17 14:19:19)
+# tr_TR.xml, revision 1.46 (2008/05/28 15:49:37)
+# trv.xml, revision 1.6 (2008/06/26 03:47:58)
+# ts.xml, revision 1.20 (2008/05/28 15:49:37)
+# ts_ZA.xml, revision 1.13 (2008/05/28 15:49:37)
+# tt.xml, revision 1.37 (2008/05/28 15:49:37)
+# tt_RU.xml, revision 1.37 (2008/05/28 15:49:37)
+# ug.xml, revision 1.22 (2008/05/28 15:49:37)
+# ug_Arab.xml, revision 1.3 (2008/06/17 14:12:16)
+# ug_Arab_CN.xml, revision 1.2 (2008/05/28 15:49:37)
+# ug_CN.xml, revision 1.2 (2008/05/28 15:49:37)
+# uk.xml, revision 1.113 (2008/06/26 03:47:58)
+# uk_UA.xml, revision 1.44 (2008/05/28 15:49:37)
+# ur.xml, revision 1.54 (2008/06/17 14:12:14)
+# ur_IN.xml, revision 1.14 (2008/06/15 08:09:46)
+# ur_PK.xml, revision 1.33 (2008/05/28 15:49:37)
+# uz.xml, revision 1.45 (2008/06/09 02:17:48)
+# uz_AF.xml, revision 1.39 (2008/05/28 15:49:37)
+# uz_Arab.xml, revision 1.28 (2008/06/15 08:09:47)
+# uz_Arab_AF.xml, revision 1.20 (2008/05/28 15:49:37)
+# uz_Cyrl.xml, revision 1.20 (2008/05/28 15:49:37)
+# uz_Cyrl_UZ.xml, revision 1.19 (2008/05/28 15:49:37)
+# uz_Latn.xml, revision 1.19 (2008/05/28 15:49:37)
+# uz_Latn_UZ.xml, revision 1.19 (2008/05/28 15:49:37)
+# uz_UZ.xml, revision 1.36 (2008/05/28 15:49:37)
+# ve.xml, revision 1.20 (2008/05/28 15:49:37)
+# ve_ZA.xml, revision 1.13 (2008/05/28 15:49:38)
+# vi.xml, revision 1.70 (2008/06/17 14:12:14)
+# vi_VN.xml, revision 1.39 (2008/05/28 15:49:38)
+# wal.xml, revision 1.49 (2008/05/28 15:49:38)
+# wal_ET.xml, revision 1.35 (2008/05/28 15:49:38)
+# wo.xml, revision 1.23 (2008/05/28 15:49:38)
+# wo_Latn.xml, revision 1.12 (2008/05/28 15:49:38)
+# wo_Latn_SN.xml, revision 1.12 (2008/05/28 15:49:38)
+# wo_SN.xml, revision 1.15 (2008/05/28 15:49:38)
+# xh.xml, revision 1.20 (2008/05/28 15:49:38)
+# xh_ZA.xml, revision 1.13 (2008/05/28 15:49:38)
+# yo.xml, revision 1.26 (2008/06/15 18:49:21)
+# yo_NG.xml, revision 1.13 (2008/05/28 15:49:38)
+# zh.xml, revision 1.134 (2008/06/26 03:47:58)
+# zh_CN.xml, revision 1.44 (2008/05/28 15:49:38)
+# zh_HK.xml, revision 1.42 (2008/05/28 15:49:38)
+# zh_Hans.xml, revision 1.48 (2008/05/28 15:49:38)
+# zh_Hans_CN.xml, revision 1.36 (2008/05/28 15:49:39)
+# zh_Hans_HK.xml, revision 1.2 (2008/05/28 15:49:39)
+# zh_Hans_MO.xml, revision 1.2 (2008/05/28 15:49:39)
+# zh_Hans_SG.xml, revision 1.58 (2008/06/17 14:12:12)
+# zh_Hant.xml, revision 1.116 (2008/06/26 03:47:58)
+# zh_Hant_HK.xml, revision 1.67 (2008/06/17 14:12:11)
+# zh_Hant_MO.xml, revision 1.59 (2008/06/17 14:12:14)
+# zh_Hant_TW.xml, revision 1.37 (2008/05/28 15:49:39)
+# zh_MO.xml, revision 1.43 (2008/05/28 15:49:39)
+# zh_SG.xml, revision 1.43 (2008/05/28 15:49:39)
+# zh_TW.xml, revision 1.48 (2008/05/28 15:49:39)
+# zu.xml, revision 1.21 (2008/05/28 15:49:39)
+# zu_ZA.xml, revision 1.13 (2008/05/28 15:49:39)
-aa_DJ=Qafar [Yabuuti]
-aa_ER_SAAHO=Qafar [Eretria - Saho]
-aa_ER=Qafar [Eretria]
-aa_ET=Qafar [Otobbia]
+aa_DJ=Qafar - Yabuuti
+aa_ER_SAAHO=Qafar - Eretria - Saho
+aa_ER=Qafar - Eretria
+aa_ET=Qafar - Otobbia
aa=Qafar
-af_NA=Afrikaans [Namibië]
+af_NA=Afrikaans - Namibië
af=Afrikaans
-af_ZA=Afrikaans [Suid-Afrika]
-ak_GH=Akan [Ghana]
+af_ZA=Afrikaans - Suid-Afrika
+ak_GH=Akan - Ghana
ak=Akan
-am_ET=አማርኛ [ኢትዮጵያ]
+am_ET=አማርኛ - ኢትዮጵያ
am=አማርኛ
-ar_AE=العربية [الامارات العربية المتحدة]
-ar_BH=العربية [البحرين]
-ar_DZ=العربية [الجزائر]
-ar_EG=العربية [مصر]
-ar_IQ=العربية [العراق]
-ar_JO=العربية [الأردن]
-ar_KW=العربية [الكويت]
-ar_LB=العربية [لبنان]
-ar_LY=العربية [ليبيا]
-ar_MA=العربية [المغرب]
-ar_OM=العربية [عمان]
-ar_QA=العربية [قطر]
-ar_SA=العربية [المملكة العربية السعودية]
-ar_SD=العربية [السودان]
-ar_SY=العربية [سوريا]
-ar_TN=العربية [تونس]
+ar_AE=العربية - الامارات العربية المتحدة
+ar_BH=العربية - البحرين
+ar_DZ=العربية - الجزائر
+ar_EG=العربية - مصر
+ar_IQ=العربية - العراق
+ar_JO=العربية - الأردن
+ar_KW=العربية - الكويت
+ar_LB=العربية - لبنان
+ar_LY=العربية - ليبيا
+ar_MA=العربية - المغرب
+ar_OM=العربية - عمان
+ar_QA=العربية - قطر
+ar_SA=العربية - المملكة العربية السعودية
+ar_SD=العربية - السودان
+ar_SY=العربية - سوريا
+ar_TN=العربية - تونس
ar=العربية
-ar_YE=العربية [اليمن]
-as_IN=অসমীয়া [ভাৰত]
+ar_YE=العربية - اليمن
+as_IN=অসমীয়া - ভাৰত
as=অসমীয়া
-az_AZ=azərbaycanca [Latin - Azərbaycan]
-az_Cyrl_AZ=Азәрбајҹан [Cyrillic - Азәрбајҹан]
-az_Cyrl=Азәрбајҹан [Cyrillic]
-az_Latn_AZ=azərbaycanca [Latin - Azərbaycan]
-az_Latn=azərbaycanca [Latin]
+az_AZ=azərbaycanca - latın - Azərbaycan
+az_Cyrl_AZ=Азәрбајҹан - kiril - Азәрбајҹан
+az_Cyrl=Азәрбајҹан - kiril
+az_Latn_AZ=azərbaycanca - latın - Azərbaycan
+az_Latn=azərbaycanca - latın
az=azərbaycanca
-be_BY=беларуская [Беларусь]
+be_BY=беларуская - Беларусь
be=беларуская
-bg_BG=български [България]
+bg_BG=български - България
bg=български
-bn_BD=বাংলা [বাংলাদেশ]
-bn_IN=বাংলা [ভারত]
+bn_BD=বাংলা - বাংলাদেশ
+bn_IN=বাংলা - ভারত
bn=বাংলা
-bo_CN=པོད་སྐད་ [རྒྱ་ནག]
-bo_IN=པོད་སྐད་ [རྒྱ་གར་]
-bo=པོད་སྐད་
-bs_BA=bosanski [Bosna i Hercegovina]
+bs_BA=bosanski - Bosna i Hercegovina
bs=bosanski
-byn_ER=ብሊን [ኤርትራ]
+byn_ER=ብሊን - ኤርትራ
byn=ብሊን
-ca_ES=català [Espanya]
+ca_ES=català - Espanya
ca=català
-cch_NG=Atsam [Nigeria]
+cch_NG=Atsam - Nigeria
cch=Atsam
-cop_Arab_EG=Coptic [Arabic - Egypt]
-cop_Arab_US=Coptic [Arabic - United States]
-cop_Arab=Coptic [Arabic]
-cop_EG=Coptic [Egypt]
-cop_US=Coptic [United States]
cop=Coptic
-cs_CZ=čeština [Česká republika]
+cs_CZ=čeština - Česká republika
cs=čeština
-cy_GB=Cymraeg [Prydain Fawr]
+cy_GB=Cymraeg - Prydain Fawr
cy=Cymraeg
-da_DK=dansk [Danmark]
+da_DK=dansk - Danmark
da=dansk
-de_AT=Deutsch [Österreich]
-de_BE=Deutsch [Belgien]
-de_CH=Deutsch [Schweiz]
-de_DE=Deutsch [Deutschland]
-de_LI=Deutsch [Liechtenstein]
-de_LU=Deutsch [Luxemburg]
+de_AT=Österreichisches Deutsch
+de_BE=Deutsch - Belgien
+de_CH=Schweizer Hochdeutsch
+de_DE=Deutsch - Deutschland
+de_LI=Deutsch - Liechtenstein
+de_LU=Deutsch - Luxemburg
de=Deutsch
-dv_MV=ދިވެހިބަސް [ދިވެހި ރާއްޖެ]
+dv_MV=ދިވެހިބަސް - ދިވެހި ރާއްޖެ
dv=ދިވެހިބަސް
-dz_BT=རྫོང་ཁ [འབྲུག]
+dz_BT=རྫོང་ཁ - འབྲུག
dz=རྫོང་ཁ
-ee_GH=Ewe [Ghana]
-ee_TG=Ewe [Togo]
+ee_GH=Ewe - Ghana
+ee_TG=Ewe - Togo
ee=Ewe
-el_CY=Ελληνικά [Κύπρος]
-el_GR=Ελληνικά [Ελλάδα]
-el_POLYTON=Ἑλληνικά [Πολυτονικό]
+el_CY=Ελληνικά - Κύπρος
+el_GR=Ελληνικά - Ελλάδα
+el_POLYTON=Ἑλληνικά - Πολυτονικό
el=Ελληνικά
-en_AS=English [American Samoa]
+en_AS=English - American Samoa
en_AU=Australian English
-en_BE=English [Belgium]
-en_BW=English [Botswana]
-en_BZ=English [Belize]
+en_BE=English - Belgium
+en_BW=English - Botswana
+en_BZ=English - Belize
en_CA=Canadian English
+en_Dsrt_US=𐐀𐑍𐑊𐐮𐑇 - 𐐔𐐯𐑆𐐲𐑉𐐯𐐻 - 𐐏𐐭𐑌𐐴𐐻𐐲𐐼 𐐝𐐻𐐩𐐻𐑅
+en_Dsrt=𐐀𐑍𐑊𐐮𐑇 - 𐐔𐐯𐑆𐐲𐑉𐐯𐐻
en_GB=British English
-en_GU=English [Guam]
-en_HK=English [Hong Kong SAR China]
-en_IE=English [Ireland]
-en_IN=English [India]
-en_JM=English [Jamaica]
-en_MH=English [Marshall Islands]
-en_MP=English [Northern Mariana Islands]
-en_MT=English [Malta]
-en_NA=English [Namibia]
-en_NZ=English [New Zealand]
-en_PH=English [Philippines]
-en_PK=English [Pakistan]
-en_SG=English [Singapore]
-en_TT=English [Trinidad and Tobago]
-en_UM=English [United States Minor Outlying Islands]
-en_US_POSIX=U.S. English [Computer]
+en_GU=English - Guam
+en_HK=English - Hong Kong SAR China
+en_IE=English - Ireland
+en_IN=English - India
+en_JM=English - Jamaica
+en_MH=English - Marshall Islands
+en_MP=English - Northern Mariana Islands
+en_MT=English - Malta
+en_NA=English - Namibia
+en_NZ=English - New Zealand
+en_PH=English - Philippines
+en_PK=English - Pakistan
+en_SG=English - Singapore
+en_Shaw=English - Shavian
+en_TT=English - Trinidad and Tobago
+en_UM=English - United States Minor Outlying Islands
+en_US_POSIX=U.S. English - Computer
en_US=U.S. English
-en_VI=English [U.S. Virgin Islands]
+en_VI=English - U.S. Virgin Islands
en=English
-en_ZA=English [South Africa]
-en_ZW=English [Zimbabwe]
+en_ZA=English - South Africa
+en_ZW=English - Zimbabwe
eo=esperanto
-es_AR=español [Argentina]
-es_BO=español [Bolivia]
-es_CL=español [Chile]
-es_CO=español [Colombia]
-es_CR=español [Costa Rica]
-es_DO=español [República Dominicana]
-es_EC=español [Ecuador]
+es_AR=español - Argentina
+es_BO=español - Bolivia
+es_CL=español - Chile
+es_CO=español - Colombia
+es_CR=español - Costa Rica
+es_DO=español - República Dominicana
+es_EC=español - Ecuador
es_ES=español de España
-es_GT=español [Guatemala]
-es_HN=español [Honduras]
-es_MX=español [México]
-es_NI=español [Nicaragua]
-es_PA=español [Panamá]
-es_PE=español [Perú]
-es_PR=español [Puerto Rico]
-es_PY=español [Paraguay]
-es_SV=español [El Salvador]
-es_US=español [Estados Unidos]
-es_UY=español [Uruguay]
-es_VE=español [Venezuela]
+es_GT=español - Guatemala
+es_HN=español - Honduras
+es_MX=español - México
+es_NI=español - Nicaragua
+es_PA=español - Panamá
+es_PE=español - Perú
+es_PR=español - Puerto Rico
+es_PY=español - Paraguay
+es_SV=español - El Salvador
+es_US=español - Estados Unidos
+es_UY=español - Uruguay
+es_VE=español - Venezuela
es=español
-et_EE=eesti [Eesti]
+et_EE=eesti - Eesti
et=eesti
-eu_ES=euskara [Espainia]
+eu_ES=euskara - Espainia
eu=euskara
-fa_AF=دری [افغانستان]
-fa_IR=فارسی [ایران]
+fa_AF=دری - افغانستان
+fa_IR=فارسی - ایران
fa=فارسی
-fi_FI=suomi [Suomi]
+fi_FI=suomi - Suomi
+fil_PH=Filipino - Pilipinas
fil=Filipino
fi=suomi
-fo_FO=føroyskt [Føroyar]
+fo_FO=føroyskt - Føroyar
fo=føroyskt
-fr_BE=français [Belgique]
+fr_BE=français - Belgique
fr_CA=français canadien
fr_CH=français suisse
-fr_FR=français [France]
-fr_LU=français [Luxembourg]
-fr_MC=français [Monaco]
+fr_FR=français - France
+fr_LU=français - Luxembourg
+fr_MC=français - Monaco
+fr_SN=français - Sénégal
fr=français
-fur_IT=furlan [Italie]
+fur_IT=furlan - Italie
fur=furlan
-gaa_GH=Ga [Ghana]
+gaa_GH=Ga - Ghana
gaa=Ga
-ga_IE=Gaeilge [Éire]
+ga_IE=Gaeilge - Éire
ga=Gaeilge
-gez_ER=ግዕዝኛ [ኤርትራ]
-gez_ET=ግዕዝኛ [ኢትዮጵያ]
+gez_ER=ግዕዝኛ - ኤርትራ
+gez_ET=ግዕዝኛ - ኢትዮጵያ
gez=ግዕዝኛ
-gl_ES=galego [España]
+gl_ES=galego - España
gl=galego
-gu_IN=ગુજરાતી [ભારત]
+gu_IN=ગુજરાતી - ભારત
gu=ગુજરાતી
-gv_GB=Gaelg [Rywvaneth Unys]
+gv_GB=Gaelg - Rywvaneth Unys
gv=Gaelg
-ha_Arab_NG=Hausa [Arabic - Nigeria]
-ha_Arab=Hausa [Arabic]
-ha_GH=Hausa [Ghana]
-ha_Latn_GH=Hausa [Latin - Ghana]
-ha_Latn_NE=Hausa [Latin - Niger]
-ha_Latn_NG=Hausa [Latin - Nigeria]
-ha_Latn=Hausa [Latin]
-ha_NE=Hausa [Niger]
-ha_NG=Hausa [Nigeria]
-haw_US=ʻōlelo Hawaiʻi [ʻAmelika Hui Pū ʻIa]
+ha_Arab_NG=Haoussa - Arabic - Nijeriya
+ha_Arab_SD=Haoussa - Arabic - Sudan
+ha_Arab=Haoussa - Arabic
+ha_GH=Haoussa - Latin - Ghana
+ha_Latn_GH=Haoussa - Latin - Ghana
+ha_Latn_NE=Haoussa - Latin - Niger
+ha_Latn_NG=Haoussa - Latin - Nijeriya
+ha_Latn=Haoussa - Latin
+ha_NE=Haoussa - Latin - Niger
+ha_NG=Haoussa - Latin - Nijeriya
+ha_SD=Haoussa - Arabic - Sudan
+haw_US=ʻōlelo Hawaiʻi - ʻAmelika Hui Pū ʻIa
haw=ʻōlelo Hawaiʻi
-ha=Hausa
-he_IL=עברית [ישראל]
+ha=Haoussa
+he_IL=עברית - ישראל
he=עברית
-hi_IN=हिंदी [भारत]
-hi=हिंदी
-hr_HR=hrvatski [Hrvatska]
+hi_IN=हिन्दी - भारत
+hi=हिन्दी
+hr_HR=hrvatski - Hrvatska
hr=hrvatski
-hu_HU=magyar [Magyarország]
+hu_HU=magyar - Magyarország
hu=magyar
-hy_AM_REVISED=Հայերէն [Հայաստանի Հանրապետութիւն - Revised Orthography]
-hy_AM=Հայերէն [Հայաստանի Հանրապետութիւն]
+hy_AM_REVISED=Հայերէն - Հայաստանի Հանրապետութիւն - Revised Orthography
+hy_AM=Հայերէն - Հայաստանի Հանրապետութիւն
hy=Հայերէն
ia=interlingua
-id_ID=Bahasa Indonesia [Indonesia]
+id_ID=Bahasa Indonesia - Indonesia
id=Bahasa Indonesia
-ig_NG=Igbo [Nigeria]
+ig_NG=Igbo - Nigeria
ig=Igbo
-ii_CN=ꆈꌠꉙ [ꍏꇩ]
+ii_CN=ꆈꌠꉙ - ꍏꇩ
ii=ꆈꌠꉙ
-is_IS=íslenska [Ísland]
+in=Bahasa Indonesia
+is_IS=íslenska - Ísland
is=íslenska
-it_CH=italiano [Svizzera]
-it_IT=italiano [Italia]
+it_CH=italiano - Svizzera
+it_IT=italiano - Italia
it=italiano
iu=ᐃᓄᒃᑎᑐᑦ ᑎᑎᕋᐅᓯᖅ
-ja_JP=日本語 [日本]
+iw=עברית
+ja_JP=日本語 - 日本
ja=日本語
-ka_GE=ქართული [საქართველო]
-kaj_NG=Jju [Nigeria]
+ka_GE=ქართული - საქართველო
+kaj_NG=Jju - Nigeria
kaj=Jju
-kam_KE=Kamba [Kenya]
+kam_KE=Kamba - Kenya
kam=Kamba
ka=ქართული
-kcg_NG=Tyap [Nigeria]
+kcg_NG=Tyap - Nigeria
kcg=Tyap
-kfo_NG=Koro [Nigeria]
+kfo_CI=Koro - Ivory Coast
kfo=Koro
-kk_KZ=Қазақ [Қазақстан]
+kk_Cyrl_KZ=Қазақ - Cyrillic - Қазақстан
+kk_Cyrl=Қазақ - Cyrillic
+kk_KZ=Қазақ - Cyrillic - Қазақстан
kk=Қазақ
-kl_GL=kalaallisut [Kalaallit Nunaat]
+kl_GL=kalaallisut - Kalaallit Nunaat
kl=kalaallisut
-km_KH=ភាសាខ្មែរ [កម្ពុជា]
+km_KH=ភាសាខ្មែរ - កម្ពុជា
km=ភាសាខ្មែរ
-kn_IN=ಕನ್ನಡ [ಭಾರತ]
+kn_IN=ಕನ್ನಡ - ಭಾರತ
kn=ಕನ್ನಡ
-kok_IN=कोंकणी [भारत]
-ko_KR=한국어 [대한민국]
+kok_IN=कोंकणी - भारत
+ko_KR=한국어 - 대한민국
kok=कोंकणी
ko=한국어
-kpe_GN=Kpelle [Guinea]
-kpe_LR=Kpelle [Liberia]
+kpe_GN=Kpelle - Guinea
+kpe_LR=Kpelle - Liberia
kpe=Kpelle
-ku_Arab=كوردی [erebî]
-ku_IQ=kurdî [Latin - Iraq]
-ku_IR=kurdî [Latin - Iran]
-ku_Latn_IQ=kurdî [Latin - Iraq]
-ku_Latn_IR=kurdî [Latin - Iran]
-ku_Latn_SY=kurdî [Latin - Syria]
-ku_Latn_TR=kurdî [Latin - Tirkiye]
-ku_Latn=kurdî [Latin]
-ku_SY=kurdî [Latin - Syria]
-ku_TR=kurdî [Latin - Tirkiye]
-ku=kurdî
-kw_GB=kernewek [Rywvaneth Unys]
+ku_Arab=كوردی - Arabic
+ku_Latn_TR=kurdî - Latin - Tirkiye
+ku_Latn=kurdî - Latin
+ku_TR=كوردی - Latin - Turkey
+ku=كوردی
+kw_GB=kernewek - Rywvaneth Unys
kw=kernewek
-ky_KG=Кыргыз [Кыргызстан]
+ky_KG=Кыргыз - Кыргызстан
ky=Кыргыз
-ln_CD=lingála [Kongó-Kinsásá]
-ln_CG=lingála [Kongó-Brazzaville]
+ln_CD=lingála - Kongó-Kinsásá
+ln_CG=lingála - Kongó-Brazzaville
ln=lingála
-lo_LA=ລາວ [ລາວ]
+lo_LA=ລາວ - ລາວ
lo=ລາວ
-lt_LT=lietuvių [Lietuva]
+lt_LT=lietuvių - Lietuva
lt=lietuvių
-lv_LV=latviešu [Latvija]
+lv_LV=latviešu - Latvija
lv=latviešu
-mk_MK=македонски [Македонија]
+mk_MK=македонски - Македонија
mk=македонски
-ml_IN=മലയാളം [ഇന്ത്യ]
+ml_IN=മലയാളം - ഇന്ത്യ
ml=മലയാളം
-mn_MN=монгол [Монгол улс]
+mn_CN=монгол - Mongolian - China
+mn_Cyrl_MN=монгол - Cyrillic - Монгол улс
+mn_Cyrl=монгол - Cyrillic
+mn_MN=монгол - Cyrillic - Монгол улс
+mn_Mong_CN=монгол - Mongolian - China
+mn_Mong=монгол - Mongolian
mn=монгол
-mr_IN=मराठी [भारत]
+mo=Moldavian
+mr_IN=मराठी - भारत
mr=मराठी
-ms_BN=Bahasa Melayu [Brunei]
-ms_MY=Bahasa Melayu [Malaysia]
+ms_BN=Bahasa Melayu - Brunei
+ms_MY=Bahasa Melayu - Malaysia
ms=Bahasa Melayu
-mt_MT=Malti [Malta]
+mt_MT=Malti - Malta
mt=Malti
-my_MM=Burmese [Myanmar]
-my=Burmese
-nb_NO=norsk bokmål [Norge]
+my_MM=ဗမာ - မြန်မာ
+my=ဗမာ
+nb_NO=norsk bokmål - Norge
nb=norsk bokmål
-ne_NP=नेपाली [Nepal]
+ne_IN=नेपाली - भारत
+ne_NP=नेपाली - नेपाल
ne=नेपाली
nl_BE=Vlaams
-nl_NL=Nederlands [Nederland]
+nl_NL=Nederlands - Nederland
nl=Nederlands
-nn_NO=nynorsk [Noreg]
+nn_NO=nynorsk - Noreg
nn=nynorsk
+no=norsk bokmål
nr=isiNdebele
-nr_ZA=isiNdebele [South Africa]
+nr_ZA=isiNdebele - South Africa
nso=Sesotho sa Leboa
-nso_ZA=Sesotho sa Leboa [South Africa]
-ny_MW=Nyanja [Malawi]
+nso_ZA=Sesotho sa Leboa - South Africa
+ny_MW=Nyanja - Malawi
ny=Nyanja
-om_ET=Oromoo [Itoophiyaa]
-om_KE=Oromoo [Keeniyaa]
+om_ET=Oromoo - Itoophiyaa
+om_KE=Oromoo - Keeniyaa
om=Oromoo
-or_IN=ଓଡ଼ିଆ [ଭାରତ]
+or_IN=ଓଡ଼ିଆ - ଭାରତ
or=ଓଡ଼ିଆ
-pa_Arab_PK=پنجاب [Arabic - Pakistan]
-pa_Arab=پنجاب [Arabic]
-pa_Guru_IN=ਪੰਜਾਬੀ [ਗੁਰਮੁਖੀ - ਭਾਰਤ]
-pa_Guru=ਪੰਜਾਬੀ [ਗੁਰਮੁਖੀ]
-pa_IN=ਪੰਜਾਬੀ [ਗੁਰਮੁਖੀ - ਭਾਰਤ]
-pa_PK=ਪੰਜਾਬੀ [Arabic - Pakistan]
+pa_Arab_PK=پنجاب - العربية - پکستان
+pa_Arab=پنجاب - العربية
+pa_Guru_IN=ਪੰਜਾਬੀ - ਗੁਰਮੁਖੀ - ਭਾਰਤ
+pa_Guru=ਪੰਜਾਬੀ - ਗੁਰਮੁਖੀ
+pa_IN=ਪੰਜਾਬੀ - ਗੁਰਮੁਖੀ - ਭਾਰਤ
+pa_PK=ਪੰਜਾਬੀ - Arabic - Pakistan
pa=ਪੰਜਾਬੀ
-pl_PL=polski [Polska]
+pl_PL=polski - Polska
pl=polski
-ps_AF=پښتو [افغانستان]
+ps_AF=پښتو - افغانستان
ps=پښتو
-pt_BR=português [Brasil]
-pt_PT=português [Portugal]
+pt_BR=português do Brasil
+pt_PT=português europeu
pt=português
-ro_RO=română [România]
+ro_MD=română - Moldova, Republica
+ro_RO=română - România
ro=română
-ru_RU=русский [Россия]
-ru_UA=русский [Украина]
+ru_RU=русский - Россия
+ru_UA=русский - Украина
ru=русский
-rw_RW=Kinyarwanda [Rwanda]
+rw_RW=Kinyarwanda - Rwanda
rw=Kinyarwanda
-sa_IN=संस्कृत भाषा [भारतम्]
+sa_IN=संस्कृत भाषा - भारतम्
sa=संस्कृत भाषा
-se_FI=se [FI]
-se_NO=dávvisámegiella [Norgga]
-se=dávvisámegiella
-sh_BA=Srpski [Latinica - Bosna i Hercegovina]
-sh_CS=Srpski [Latinica - Srbija]
-sh=Srpski [Latinica]
-sh_YU=Srpski [Latinica - Srbija]
-sid_ET=Sidaamu Afo [Itiyoophiya]
+se_FI=se - FI
+se_NO=davvisámegiella - Norga
+se=davvisámegiella
+sh_BA=Srpski - Latinica - Bosna i Hercegovina
+sh_CS=Srpski - Latinica - Srbija
+sh=Srpski - Latinica
+sh_YU=Srpski - Latinica - Srbija
+sid_ET=Sidaamu Afo - Itiyoophiya
sid=Sidaamu Afo
-sk_SK=slovenský [Slovenská republika]
+si_LK=සිංහල - ශ්රී ලංකාව
+si=සිංහල
+sk_SK=slovenský - Slovenská republika
sk=slovenský
-sl_SI=slovenščina [Slovenija]
+sl_SI=slovenščina - Slovenija
sl=slovenščina
-so_DJ=Soomaali [Jabuuti]
-so_ET=Soomaali [Itoobiya]
-so_KE=Soomaali [Kiiniya]
-so_SO=Soomaali [Soomaaliya]
+so_DJ=Soomaali - Jabuuti
+so_ET=Soomaali - Itoobiya
+so_KE=Soomaali - Kiiniya
+so_SO=Soomaali - Soomaaliya
so=Soomaali
-sq_AL=shqipe [Shqipëria]
+sq_AL=shqipe - Shqipëria
sq=shqipe
-sr_BA=српски [Ћирилица - Босна и Херцеговина]
-sr_CS=Српски [Ћирилица - Србија]
-sr_Cyrl_BA=српски [Ћирилица - Босна и Херцеговина]
-sr_Cyrl_CS=Српски [Ћирилица - Србија]
-sr_Cyrl_ME=Српски [Ћирилица - Црна Гора]
-sr_Cyrl_RS=Српски [Ћирилица - Србија]
-sr_Cyrl=Српски [Ћирилица]
-sr_Cyrl_YU=Српски [Ћирилица - Србија]
-sr_Latn_BA=Srpski [Latinica - Bosna i Hercegovina]
-sr_Latn_CS=Srpski [Latinica - Srbija]
-sr_Latn_ME=Srpski [Latinica - Crna Gora]
-sr_Latn_RS=Srpski [Latinica - Srbija]
-sr_Latn=Srpski [Latinica]
-sr_Latn_YU=Srpski [Latinica - Srbija]
-sr_ME=Српски [Ћирилица - Црна Гора]
-sr_RS=Српски [Ћирилица - Србија]
+sr_BA=српски - Ћирилица - Босна и Херцеговина
+sr_CS=Српски - Ћирилица - Србија
+sr_Cyrl_BA=српски - Ћирилица - Босна и Херцеговина
+sr_Cyrl_CS=Српски - Ћирилица - Србија
+sr_Cyrl_ME=Српски - Ћирилица - Црна Гора
+sr_Cyrl_RS=Српски - Ћирилица - Србија
+sr_Cyrl=Српски - Ћирилица
+sr_Cyrl_YU=Српски - Ћирилица - Србија
+sr_Latn_BA=Srpski - Latinica - Bosna i Hercegovina
+sr_Latn_CS=Srpski - Latinica - Srbija
+sr_Latn_ME=Srpski - Latinica - Crna Gora
+sr_Latn_RS=Srpski - Latinica - Srbija
+sr_Latn=Srpski - Latinica
+sr_Latn_YU=Srpski - Latinica - Srbija
+sr_ME=Српски - Ћирилица - Црна Гора
+sr_RS=Српски - Ћирилица - Србија
sr=Српски
-sr_YU=Српски [Ћирилица - Србија]
+sr_YU=Српски - Ћирилица - Србија
+ss_SZ=Siswati - Swaziland
ss=Siswati
-ss_ZA=Siswati [South Africa]
+ss_ZA=Siswati - South Africa
+st_LS=Sesotho - Lesotho
st=Sesotho
-st_ZA=Sesotho [South Africa]
-sv_FI=svenska [Finland]
-sv_SE=svenska [Sverige]
+st_ZA=Sesotho - South Africa
+sv_FI=svenska - Finland
+sv_SE=svenska - Sverige
sv=svenska
-sw_KE=Kiswahili [Kenya]
-sw_TZ=Kiswahili [Tanzania]
+sw_KE=Kiswahili - Kenya
+sw_TZ=Kiswahili - Tanzania
sw=Kiswahili
-syr_SY=ܣܘܪܝܝܐ [ܣܘܪܝܝܐ]
+syr_SY=ܣܘܪܝܝܐ - ܣܘܪܝܝܐ
syr=ܣܘܪܝܝܐ
-ta_IN=தமிழ் [இந்தியா]
+ta_IN=தமிழ் - இந்தியா
ta=தமிழ்
-te_IN=తెలుగు [భారత దేళం]
+te_IN=తెలుగు - భారత దేళం
te=తెలుగు
-tg_TJ=Tajik [Tajikistan]
+tg_Cyrl_TJ=Tajik - Cyrillic - Tajikistan
+tg_Cyrl=Tajik - Cyrillic
+tg_TJ=Tajik - Tajikistan
tg=Tajik
-th_TH=ไทย [ประเทศไทย]
+th_TH=ไทย - ไทย
th=ไทย
-ti_ER=ትግርኛ [Eritrea]
-ti_ET=ትግርኛ [Ethiopia]
-tig_ER=ትግረ [ኤርትራ]
+ti_ER=ትግርኛ - Eritrea
+ti_ET=ትግርኛ - Ethiopia
+tig_ER=ትግረ - ኤርትራ
tig=ትግረ
ti=ትግርኛ
+tl=Filipino
tn=Setswana
-tn_ZA=Setswana [South Africa]
-to_TO=lea fakatonga [Tonga]
+tn_ZA=Setswana - South Africa
+to_TO=lea fakatonga - Tonga
to=lea fakatonga
-tr_TR=Türkçe [Türkiye]
+tr_TR=Türkçe - Türkiye
tr=Türkçe
ts=Xitsonga
-ts_ZA=Xitsonga [South Africa]
-tt_RU=Татар [Россия]
+ts_ZA=Xitsonga - South Africa
+tt_RU=Татар - Россия
tt=Татар
+ug_Arab_CN=Uighur - Arabic - China
+ug_Arab=Uighur - Arabic
+ug_CN=Uighur - China
ug=Uighur
-uk_UA=українська [Україна]
+uk_UA=українська - Україна
uk=українська
-und=Unknown or Invalid Language
-und_ZZ=Unknown or Invalid Language [Unknown or Invalid Region]
-ur_IN=اردو [بھارت]
-ur_PK=اردو [پاکستان]
+ur_IN=اردو - بھارت
+ur_PK=اردو - پاکستان
ur=اردو
-uz_AF=Ўзбек [Араб - Афғонистон]
-uz_Arab_AF=اۉزبېک [Араб - افغانستان]
-uz_Arab=اۉزبېک [Араб]
-uz_Cyrl_UZ=Ўзбек [Кирил - Ўзбекистон]
-uz_Cyrl=Ўзбек [Кирил]
-uz_Latn_UZ=o'zbekcha [Lotin - Oʿzbekiston]
-uz_Latn=o'zbekcha [Lotin]
-uz_UZ=Ўзбек [Кирил - Ўзбекистон]
+uz_AF=Ўзбек - Араб - Афғонистон
+uz_Arab_AF=اۉزبېک - Араб - افغانستان
+uz_Arab=اۉزبېک - Араб
+uz_Cyrl_UZ=Ўзбек - Кирил - Ўзбекистон
+uz_Cyrl=Ўзбек - Кирил
+uz_Latn_UZ=o'zbekcha - Lotin - Oʿzbekiston
+uz_Latn=o'zbekcha - Lotin
+uz_UZ=Ўзбек - Кирил - Ўзбекистон
uz=Ўзбек
ve=Tshivenḓa
-ve_ZA=Tshivenḓa [South Africa]
-vi_VN=Tiếng Việt [Việt Nam]
+ve_ZA=Tshivenḓa - South Africa
+vi_VN=Tiếng Việt - Việt Nam
vi=Tiếng Việt
-wal_ET=ወላይታቱ [ኢትዮጵያ]
+wal_ET=ወላይታቱ - ኢትዮጵያ
wal=ወላይታቱ
-wo_Arab_SN=Wolof [Arabic - Senegal]
-wo_Arab=Wolof [Arabic]
-wo_Latn_SN=Wolof [Latin - Senegal]
-wo_Latn=Wolof [Latin]
-wo_SN=Wolof [Senegal]
+wo_Latn_SN=Wolof - Latin - Senegal
+wo_Latn=Wolof - Latin
+wo_SN=Wolof - Senegal
wo=Wolof
xh=isiXhosa
-xh_ZA=isiXhosa [South Africa]
-yo_NG=Yoruba [Nigeria]
-yo=Yoruba
-zh_CN=中文(简体) [中国]
-zh_Hans_CN=中文(简体) [中国]
-zh_Hans_SG=中文(简体) [新加坡]
+xh_ZA=isiXhosa - South Africa
+yo_NG=Yorùbá - NG
+yo=Yorùbá
+zh_CN=中文(简体) - 中国
+zh_Hans_CN=中文(简体) - 中国
+zh_Hans_HK=中文(简体) - 中国香港特别行政区
+zh_Hans_MO=中文(简体) - 中国澳门特别行政区
+zh_Hans_SG=中文(简体) - 新加坡
zh_Hans=中文(简体)
-zh_Hant_HK=繁體中文 [中華人民共和國香港特別行政區]
-zh_Hant_MO=繁體中文 [中華人民共和國澳門特別行政區]
-zh_Hant_TW=繁體中文 [臺灣]
+zh_Hant_HK=繁體中文 - 中華人民共和國香港特別行政區
+zh_Hant_MO=繁體中文 - 中華人民共和國澳門特別行政區
+zh_Hant_TW=繁體中文 - 臺灣
zh_Hant=繁體中文
-zh_HK=中文(繁体) [中国香港特别行政区]
-zh_MO=中文(繁体) [中国澳门特别行政区]
-zh_SG=中文(简体) [新加坡]
-zh_TW=中文(繁体) [台湾]
+zh_HK=中文(繁体) - 中国香港特别行政区
+zh_MO=中文(繁体) - 中国澳门特别行政区
+zh_SG=中文(简体) - 新加坡
+zh_TW=中文(繁体) - 台湾
zh=中文
zu=isiZulu
-zu_ZA=isiZulu [South Africa]
+zu_ZA=isiZulu - South Africa
diff --git a/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java b/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java
index 8852eb9..5f89f40 100644
--- a/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java
@@ -30,6 +30,7 @@
import com.google.gwt.i18n.rebind.AnnotationsResource.AnnotationsError;
import com.google.gwt.i18n.rebind.format.MessageCatalogFormat;
import com.google.gwt.i18n.rebind.keygen.KeyGenerator;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.AbstractGeneratorClassCreator;
import com.google.gwt.user.rebind.AbstractMethodCreator;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
@@ -51,7 +52,7 @@
AbstractGeneratorClassCreator {
static String generateConstantOrMessageClass(TreeLogger logger,
- TreeLogger deprecatedLogger, GeneratorContext context, String locale,
+ TreeLogger deprecatedLogger, GeneratorContext context, GwtLocale locale,
JClassType targetClass) throws UnableToCompleteException {
TypeOracle oracle = context.getTypeOracle();
JClassType constantsClass;
@@ -108,10 +109,9 @@
// generated implementations for interface X will be named X_, X_en,
// X_en_CA, etc.
+ GwtLocale generatedLocale = resourceList.findLeastDerivedLocale(locale);
String localeSuffix = String.valueOf(ResourceFactory.LOCALE_SEPARATOR);
- if (!ResourceFactory.DEFAULT_TOKEN.equals(locale)) {
- localeSuffix += locale;
- }
+ localeSuffix += generatedLocale.getAsString();
// Use _ rather than "." in class name, cannot use $
String resourceName = targetClass.getName().replace('.', '_');
String className = resourceName + localeSuffix;
@@ -126,17 +126,17 @@
ConstantsWithLookupImplCreator c = new ConstantsWithLookupImplCreator(
logger, deprecatedLogger, writer, targetClass, resourceList,
context.getTypeOracle());
- c.emitClass(logger, locale);
+ c.emitClass(logger, generatedLocale);
} else if (constantsClass.isAssignableFrom(targetClass)) {
ConstantsImplCreator c = new ConstantsImplCreator(logger,
deprecatedLogger, writer, targetClass, resourceList,
context.getTypeOracle());
- c.emitClass(logger, locale);
+ c.emitClass(logger, generatedLocale);
} else {
MessagesImplCreator messages = new MessagesImplCreator(logger,
deprecatedLogger, writer, targetClass, resourceList,
context.getTypeOracle());
- messages.emitClass(logger, locale);
+ messages.emitClass(logger, generatedLocale);
}
context.commit(logger, pw);
}
@@ -155,7 +155,7 @@
if (genLocales.length != 0) {
// verify the current locale is in the list
for (String genLocale : genLocales) {
- if (genLocale.equals(locale)) {
+ if (genLocale.equals(locale.toString())) {
found = true;
break;
}
@@ -194,7 +194,7 @@
if (genLocales.length != 1) {
// If the user explicitly specified only one locale, do not add the
// locale.
- genPath += '_' + locale;
+ genPath += '_' + locale.toString();
}
genPath += msgWriter.getExtension();
OutputStream outStr = context.tryCreateResource(logger, genPath);
@@ -210,7 +210,9 @@
throw error(logger, e.getMessage());
}
try {
- msgWriter.write(branch, locale, resourceList, out, targetClass);
+ // TODO(jat): change writer interface to use GwtLocale
+ msgWriter.write(branch, locale.toString(), resourceList, out,
+ targetClass);
out.flush();
context.commitResource(logger, outStr).setPrivate(true);
} catch (UnableToCompleteException e) {
@@ -296,7 +298,7 @@
* @throws UnableToCompleteException
*/
protected void delegateToCreator(TreeLogger logger, JMethod method,
- String locale) throws UnableToCompleteException {
+ GwtLocale locale) throws UnableToCompleteException {
AbstractMethodCreator methodCreator = getMethodCreator(logger, method);
String key = getKey(logger, method);
if (key == null) {
diff --git a/user/src/com/google/gwt/i18n/rebind/AbstractResource.java b/user/src/com/google/gwt/i18n/rebind/AbstractResource.java
index dea4cb7..8c28605 100644
--- a/user/src/com/google/gwt/i18n/rebind/AbstractResource.java
+++ b/user/src/com/google/gwt/i18n/rebind/AbstractResource.java
@@ -17,6 +17,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.i18n.client.PluralRule.PluralForm;
+import com.google.gwt.i18n.shared.GwtLocale;
import java.util.AbstractList;
import java.util.ArrayList;
@@ -128,6 +129,38 @@
}
}
+ /**
+ * From the list of locales matched for any resources in this resource list,
+ * choose the one that is least derived from the original search locale.
+ *
+ * @param locale originally requested locale
+ * @return least derived matched locale
+ */
+ public GwtLocale findLeastDerivedLocale(GwtLocale locale) {
+ List<GwtLocale> searchList = locale.getCompleteSearchList();
+ Map<GwtLocale, Integer> derivedIndex = new HashMap<GwtLocale, Integer>();
+ for (int i = 0; i < searchList.size(); ++i) {
+ derivedIndex.put(searchList.get(i), i);
+ }
+ GwtLocale best = LocaleUtils.getLocaleFactory().getDefault();
+ int bestIdx = Integer.MAX_VALUE;
+ for (int i = 0; i < list.size(); ++i) {
+ GwtLocale matchLocale = list.get(i).getMatchLocale();
+ Integer wrappedIdx = derivedIndex.get(matchLocale);
+ if (wrappedIdx == null) {
+ assert false : "Locale " + matchLocale + " not in searchlist "
+ + searchList;
+ continue;
+ }
+ int idx = wrappedIdx;
+ if (idx < bestIdx) {
+ bestIdx = idx;
+ best = matchLocale;
+ }
+ }
+ return best;
+ }
+
@Override
public AbstractResource get(int index) {
return list.get(index);
@@ -305,10 +338,16 @@
return key;
}
+ private final GwtLocale matchLocale;
+
private Set<String> keySet;
private String path;
+ public AbstractResource(GwtLocale matchLocale) {
+ this.matchLocale = matchLocale;
+ }
+
public Collection<String> getExtensions(String key) {
return new ArrayList<String>();
}
@@ -394,6 +433,10 @@
abstract void addToKeySet(Set<String> s);
+ GwtLocale getMatchLocale() {
+ return matchLocale;
+ }
+
String getPath() {
return path;
}
diff --git a/user/src/com/google/gwt/i18n/rebind/AnnotationsResource.java b/user/src/com/google/gwt/i18n/rebind/AnnotationsResource.java
index 9e5cc4e..7dd4cf4 100644
--- a/user/src/com/google/gwt/i18n/rebind/AnnotationsResource.java
+++ b/user/src/com/google/gwt/i18n/rebind/AnnotationsResource.java
@@ -46,6 +46,7 @@
import com.google.gwt.i18n.client.Messages.PluralText;
import com.google.gwt.i18n.rebind.keygen.KeyGenerator;
import com.google.gwt.i18n.rebind.keygen.MethodNameKeyGenerator;
+import com.google.gwt.i18n.shared.GwtLocale;
import java.util.ArrayList;
import java.util.Collection;
@@ -110,8 +111,8 @@
return argInfo;
}
- public void addPluralText(String form, String text) {
- pluralText.put(form, text);
+ public void addPluralText(String form, String pluralFormText) {
+ pluralText.put(form, pluralFormText);
}
}
@@ -374,15 +375,31 @@
* annotations
*/
public AnnotationsResource(TreeLogger logger, JClassType clazz,
- String locale, boolean isConstants) throws AnnotationsError {
+ GwtLocale locale, boolean isConstants) throws AnnotationsError {
+ super(locale);
KeyGenerator keyGenerator = getKeyGenerator(clazz);
map = new HashMap<String, MethodEntry>();
setPath(clazz.getQualifiedSourceName());
- DefaultLocale defLocale = getClassAnnotation(clazz, DefaultLocale.class);
- if (defLocale != null && !ResourceFactory.DEFAULT_TOKEN.equals(locale)
- && !locale.equalsIgnoreCase(defLocale.value())) {
- logger.log(TreeLogger.WARN, "@DefaultLocale on "
- + clazz.getQualifiedSourceName() + " doesn't match " + locale);
+ String defLocaleValue = null;
+
+ // If the class has an embedded locale in it, use that for the default
+ String className = clazz.getSimpleSourceName();
+ int underscore = className.indexOf('_');
+ if (underscore >= 0) {
+ defLocaleValue = className.substring(underscore + 1);
+ }
+
+ // If there is an annotation declaring the default locale, use that
+ DefaultLocale defLocaleAnnot = getClassAnnotation(clazz,
+ DefaultLocale.class);
+ if (defLocaleAnnot != null) {
+ defLocaleValue = defLocaleAnnot.value();
+ }
+ GwtLocale defLocale = LocaleUtils.getLocaleFactory().fromString(
+ defLocaleValue);
+ if (!locale.isDefault() && !locale.equals(defLocale)) {
+ logger.log(TreeLogger.WARN, "Default locale " + defLocale + " on "
+ + clazz.getQualifiedSourceName() + " doesn't match " + locale);
return;
}
for (JMethod method : clazz.getMethods()) {
@@ -492,6 +509,6 @@
@Override
public String toString() {
- return "Annotations from class " + getPath();
+ return "Annotations from class " + getPath() + " @" + getMatchLocale();
}
}
diff --git a/user/src/com/google/gwt/i18n/rebind/CachedGeneratorContext.java b/user/src/com/google/gwt/i18n/rebind/CachedGeneratorContext.java
new file mode 100644
index 0000000..5fa75e0
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/rebind/CachedGeneratorContext.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2009 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.GeneratorContext;
+import com.google.gwt.core.ext.PropertyOracle;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.linker.Artifact;
+import com.google.gwt.core.ext.linker.GeneratedResource;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Keeps track of types/resources previously created to avoid warnings about
+ * trying to generate the same file multiple times during a single generator
+ * run. This is needed when one generator calls other generators multiple
+ * times (such as for runtime locale support).
+ */
+class CachedGeneratorContext implements GeneratorContext {
+ private final GeneratorContext context;
+ private Set<String> generatedTypes = new HashSet<String>();
+ private Set<String> generatedResources = new HashSet<String>();
+
+ CachedGeneratorContext(GeneratorContext context) {
+ this.context = context;
+ }
+
+ public void commit(TreeLogger logger, PrintWriter pw) {
+ context.commit(logger, pw);
+ }
+
+ public void commitArtifact(TreeLogger logger, Artifact<?> artifact)
+ throws UnableToCompleteException {
+ context.commitArtifact(logger, artifact);
+ }
+
+ public GeneratedResource commitResource(TreeLogger logger,
+ OutputStream os) throws UnableToCompleteException {
+ return context.commitResource(logger, os);
+ }
+
+ public PropertyOracle getPropertyOracle() {
+ return context.getPropertyOracle();
+ }
+
+ public TypeOracle getTypeOracle() {
+ return context.getTypeOracle();
+ }
+
+ public PrintWriter tryCreate(TreeLogger logger, String packageName,
+ String simpleName) {
+ String typeName = packageName + '.' + simpleName;
+ if (generatedTypes.contains(typeName)) {
+ return null;
+ }
+ generatedTypes.add(typeName);
+ return context.tryCreate(logger, packageName, simpleName);
+ }
+
+ public OutputStream tryCreateResource(TreeLogger logger,
+ String partialPath) throws UnableToCompleteException {
+ if (generatedResources.contains(partialPath)) {
+ return null;
+ }
+ generatedResources.add(partialPath);
+ return context.tryCreateResource(logger, partialPath);
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/i18n/rebind/ConstantsImplCreator.java b/user/src/com/google/gwt/i18n/rebind/ConstantsImplCreator.java
index f189751..d971ecd 100644
--- a/user/src/com/google/gwt/i18n/rebind/ConstantsImplCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/ConstantsImplCreator.java
@@ -27,6 +27,7 @@
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.SourceWriter;
import java.util.Map;
@@ -154,8 +155,8 @@
* arg0...argN.
*/
@Override
- protected void emitMethodBody(TreeLogger logger, JMethod method, String locale)
- throws UnableToCompleteException {
+ protected void emitMethodBody(TreeLogger logger, JMethod method,
+ GwtLocale locale) throws UnableToCompleteException {
checkConstantMethod(logger, method);
delegateToCreator(logger, method, locale);
}
diff --git a/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
index ee6fa28..1da3076 100644
--- a/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
@@ -20,6 +20,7 @@
import com.google.gwt.i18n.client.impl.ConstantMap;
import com.google.gwt.i18n.rebind.AbstractResource.MissingResourceException;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.AbstractGeneratorClassCreator;
import java.util.LinkedHashMap;
@@ -52,7 +53,7 @@
*/
@Override
public void createMethodFor(TreeLogger logger, JMethod method,
- String mapName, ResourceList resourceList, String locale) {
+ String mapName, ResourceList resourceList, GwtLocale locale) {
String methodName = method.getName();
if (method.getParameters().length > 0) {
error(
diff --git a/user/src/com/google/gwt/i18n/rebind/ConstantsStringArrayMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/ConstantsStringArrayMethodCreator.java
index 358010e..2d15fd3 100644
--- a/user/src/com/google/gwt/i18n/rebind/ConstantsStringArrayMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/ConstantsStringArrayMethodCreator.java
@@ -18,6 +18,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.AbstractGeneratorClassCreator;
/**
@@ -61,7 +62,7 @@
@Override
public void createMethodFor(TreeLogger logger, JMethod method, String key,
- ResourceList resource, String locale) {
+ ResourceList resource, GwtLocale locale) {
String methodName = method.getName();
// Make sure cache exists.
enableCache();
diff --git a/user/src/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreator.java b/user/src/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreator.java
index 8a7272b..0e4aa9c 100644
--- a/user/src/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreator.java
@@ -24,6 +24,7 @@
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.AbstractMethodCreator;
import com.google.gwt.user.rebind.SourceWriter;
@@ -156,8 +157,8 @@
* arg0...argN.
*/
@Override
- protected void emitMethodBody(TreeLogger logger, JMethod method, String locale)
- throws UnableToCompleteException {
+ protected void emitMethodBody(TreeLogger logger, JMethod method,
+ GwtLocale locale) throws UnableToCompleteException {
checkMethod(logger, method);
if (method.getParameters().length == 1) {
String name = method.getName();
diff --git a/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java b/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java
index 4293680..b9354c6 100644
--- a/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java
+++ b/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.i18n.rebind;
-import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.PropertyOracle;
@@ -26,6 +25,7 @@
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.i18n.client.impl.CurrencyData;
import com.google.gwt.i18n.client.impl.CurrencyList;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
@@ -37,13 +37,16 @@
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Map.Entry;
/**
* Generator used to generate a localized version of CurrencyList, which
* contains the list of currencies (with names, symbols, and other information)
- * localized to the current locale.
+ * localized to the current locale.
*/
public class CurrencyListGenerator extends Generator {
@@ -52,31 +55,23 @@
private static final String CURRENCY_LIST = CurrencyList.class.getCanonicalName();
/**
- * Prefix for properties files containing CLDR-derived currency data for
- * each locale.
+ * Prefix for properties files containing CLDR-derived currency data for each
+ * locale.
*/
- private static final String CURRENCY_DATA_PREFIX =
- "com/google/gwt/i18n/client/impl/cldr/CurrencyData";
-
+ private static final String CURRENCY_DATA_PREFIX = "com/google/gwt/i18n/client/impl/cldr/CurrencyData";
+
/**
* Prefix for properties files containing additional flags about currencies
* each locale, which are not present in CLDR.
*/
- private static final String CURRENCY_EXTRA_PREFIX =
- "com/google/gwt/i18n/client/constants/CurrencyExtra";
-
+ private static final String CURRENCY_EXTRA_PREFIX = "com/google/gwt/i18n/client/constants/CurrencyExtra";
+
/**
- * Prefix for properties files containing number formatting constants for
- * each locale. We use this only to get the default currency for our
- * current locale.
+ * Prefix for properties files containing number formatting constants for each
+ * locale. We use this only to get the default currency for our current
+ * locale.
*/
- private static final String NUMBER_CONSTANTS_PREFIX =
- "com/google/gwt/i18n/client/constants/NumberConstants";
-
- /**
- * The token representing the locale property controlling Localization.
- */
- private static final String PROP_LOCALE = "locale";
+ private static final String NUMBER_CONSTANTS_PREFIX = "com/google/gwt/i18n/client/constants/NumberConstantsImpl";
/**
* Generate an implementation for the given type.
@@ -93,14 +88,10 @@
assert CURRENCY_LIST.equals(typeName);
TypeOracle typeOracle = context.getTypeOracle();
- // Get the current locale.
PropertyOracle propertyOracle = context.getPropertyOracle();
- String locale = "default";
- try {
- locale = propertyOracle.getPropertyValue(logger, PROP_LOCALE);
- } catch (BadPropertyValueException e) {
- logger.log(TreeLogger.WARN, "locale property not defined, using defaults", e);
- }
+ LocaleUtils.init(logger, propertyOracle);
+ GwtLocale locale = LocaleUtils.getCompileLocale();
+ Set<GwtLocale> runtimeLocales = LocaleUtils.getRuntimeLocales();
JClassType targetClass;
try {
@@ -109,12 +100,20 @@
logger.log(TreeLogger.ERROR, "No such type", e);
throw new UnableToCompleteException();
}
-
- String packageName = targetClass.getPackage().getName();
- String className = targetClass.getName().replace('.', '_') + "_";
- if (!locale.equals("default")) {
- className += locale;
+ if (runtimeLocales.isEmpty()) {
+ return generateOne(logger, context, targetClass, locale);
}
+ CachedGeneratorContext cachedContext = new CachedGeneratorContext(context);
+ return generateRuntimeSelection(logger, cachedContext, targetClass, locale,
+ runtimeLocales);
+ }
+
+ private String generateOne(TreeLogger logger, GeneratorContext context,
+ JClassType targetClass, GwtLocale locale)
+ throws UnableToCompleteException {
+ String packageName = targetClass.getPackage().getName();
+ String className = targetClass.getName().replace('.', '_') + "_"
+ + locale.getAsString();
PrintWriter pw = context.tryCreate(logger, packageName, className);
if (pw != null) {
ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(
@@ -123,20 +122,26 @@
factory.addImport(CURRENCY_LIST);
factory.addImport(CURRENCY_DATA);
SourceWriter writer = factory.createSourceWriter(context, pw);
-
+
// Load property files for this locale, handling inheritance properly.
- LocalizedProperties currencyData = readProperties(logger, CURRENCY_DATA_PREFIX, locale);
- LocalizedProperties currencyExtra = readProperties(logger, CURRENCY_EXTRA_PREFIX, locale);
- LocalizedProperties numberConstants = readProperties(logger, NUMBER_CONSTANTS_PREFIX, locale);
-
+ GwtLocale[] currencyLocale = new GwtLocale[1];
+ LocalizedProperties currencyData = readProperties(logger,
+ CURRENCY_DATA_PREFIX, locale, currencyLocale);
+ GwtLocale[] extraLocale = new GwtLocale[1];
+ LocalizedProperties currencyExtra = readProperties(logger,
+ CURRENCY_EXTRA_PREFIX, locale, extraLocale);
+ GwtLocale[] numberLocale = new GwtLocale[1];
+ LocalizedProperties numberConstants = readProperties(logger,
+ NUMBER_CONSTANTS_PREFIX, locale, numberLocale);
+
// Get default currency code, set defaults in case it isn't found.
String defCurrencyCode = numberConstants.getProperty("defCurrencyCode");
if (defCurrencyCode == null) {
defCurrencyCode = "USD";
}
-
+
// Sort for deterministic output.
- Set<Object> keySet = currencyData.getPropertyMap().keySet();
+ Set<?> keySet = currencyData.getPropertyMap().keySet();
String[] currencies = new String[keySet.size()];
keySet.toArray(currencies);
Arrays.sort(currencies);
@@ -163,7 +168,8 @@
currencyFractionDigits = Integer.valueOf(currencySplit[2]);
} catch (NumberFormatException e) {
// Ignore bad values
- logger.log(TreeLogger.WARN, "Parse of \"" + currencySplit[2] + "\" failed", e);
+ logger.log(TreeLogger.WARN, "Parse of \"" + currencySplit[2]
+ + "\" failed", e);
}
}
boolean currencyObsolete = false;
@@ -172,7 +178,8 @@
currencyObsolete = Integer.valueOf(currencySplit[3]) != 0;
} catch (NumberFormatException e) {
// Ignore bad values
- logger.log(TreeLogger.WARN, "Parse of \"" + currencySplit[3] + "\" failed", e);
+ logger.log(TreeLogger.WARN, "Parse of \"" + currencySplit[3]
+ + "\" failed", e);
}
}
int currencyFlags = currencyFractionDigits;
@@ -180,28 +187,33 @@
String portableSymbol = "";
if (extraData != null) {
// CurrencyExtra contains up to 3 fields separated by |
- // 0 - portable currency symbol
- // 1 - space-separated flags regarding currency symbol positioning/spacing
- // 2 - override of CLDR-derived currency symbol
+ // 0 - portable currency symbol
+ // 1 - space-separated flags regarding currency symbol
+ // positioning/spacing
+ // 2 - override of CLDR-derived currency symbol
String[] extraSplit = extraData.split("\\|");
portableSymbol = extraSplit[0];
if (extraSplit.length > 1) {
if (extraSplit[1].contains("SymPrefix")) {
- currencyFlags |= CurrencyData.POS_FIXED_FLAG;
+ currencyFlags |= CurrencyData.POS_FIXED_FLAG;
} else if (extraSplit[1].contains("SymSuffix")) {
- currencyFlags |= CurrencyData.POS_FIXED_FLAG | CurrencyData.POS_SUFFIX_FLAG;
- }
+ currencyFlags |= CurrencyData.POS_FIXED_FLAG
+ | CurrencyData.POS_SUFFIX_FLAG;
+ }
if (extraSplit[1].contains("ForceSpace")) {
- currencyFlags |= CurrencyData.SPACING_FIXED_FLAG | CurrencyData.SPACE_FORCED_FLAG;
+ currencyFlags |= CurrencyData.SPACING_FIXED_FLAG
+ | CurrencyData.SPACE_FORCED_FLAG;
} else if (extraSplit[1].contains("ForceNoSpace")) {
currencyFlags |= CurrencyData.SPACING_FIXED_FLAG;
}
}
- // If a non-empty override is supplied, use it for the currency symbol.
+ // If a non-empty override is supplied, use it for the currency
+ // symbol.
if (extraSplit.length > 2 && extraSplit[2].length() > 0) {
currencySymbol = extraSplit[2];
}
- // If we don't have a currency symbol yet, use the portable symbol if supplied.
+ // If we don't have a currency symbol yet, use the portable symbol if
+ // supplied.
if (currencySymbol == null && portableSymbol.length() > 0) {
currencySymbol = portableSymbol;
}
@@ -210,8 +222,8 @@
if (currencySymbol == null) {
currencySymbol = currencyCode;
}
- String currencyObject = "[ \"" + quote(currencyCode) + "\", \"" + quote(currencySymbol)
- + "\", " + currencyFlags;
+ String currencyObject = "[ \"" + quote(currencyCode) + "\", \""
+ + quote(currencySymbol) + "\", " + currencyFlags;
if (portableSymbol.length() > 0) {
currencyObject += ", \"" + quote(portableSymbol) + "\"";
}
@@ -219,10 +231,11 @@
if (!currencyObsolete) {
nameMap.put(currencyCode, currencyDisplay);
writer.println("// " + currencyDisplay);
- writer.println("\":" + quote(currencyCode) + "\": " + currencyObject + ",");
+ writer.println("\":" + quote(currencyCode) + "\": " + currencyObject
+ + ",");
}
if (currencyCode.equals(defCurrencyCode)) {
- defCurrencyObject = currencyObject;
+ defCurrencyObject = currencyObject;
}
}
writer.outdent();
@@ -231,14 +244,15 @@
writer.println("}-*/;");
writer.println();
writer.println("@Override");
- writer.println("public native void loadNamesMap() /*-{");
+ writer.println("protected native void loadNamesMap() /*-{");
writer.indent();
writer.println("this.@com.google.gwt.i18n.client.impl.CurrencyList::namesMap = {");
writer.indent();
for (String currencyCode : currencies) {
String displayName = nameMap.get(currencyCode);
if (displayName != null && !currencyCode.equals(displayName)) {
- writer.println("\"" + quote(currencyCode) + "\": \"" + quote(displayName) + "\",");
+ writer.println("\"" + quote(currencyCode) + "\": \""
+ + quote(displayName) + "\",");
}
}
writer.outdent();
@@ -254,7 +268,118 @@
}
return packageName + "." + className;
}
-
+
+
+ private String generateRuntimeSelection(TreeLogger logger,
+ GeneratorContext context, JClassType targetClass,
+ GwtLocale compileLocale, Set<GwtLocale> locales)
+ throws UnableToCompleteException {
+ String packageName = targetClass.getPackage().getName();
+ String className = targetClass.getName().replace('.', '_') + "_"
+ + compileLocale.getAsString() + "_runtimeSelection";
+ PrintWriter pw = context.tryCreate(logger, packageName, className);
+ if (pw != null) {
+ ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(
+ packageName, className);
+ factory.setSuperclass(targetClass.getQualifiedSourceName());
+ factory.addImport(CURRENCY_LIST);
+ factory.addImport(CURRENCY_DATA);
+ factory.addImport("com.google.gwt.i18n.client.LocaleInfo");
+ SourceWriter writer = factory.createSourceWriter(context, pw);
+ writer.println("private CurrencyList instance;");
+ writer.println();
+ writer.println("@Override");
+ writer.println("public CurrencyData getDefault() {");
+ writer.println(" ensureInstance();");
+ writer.println(" return instance.getDefault();");
+ writer.println("}");
+ writer.println();
+ writer.println("@Override");
+ writer.println("protected void loadCurrencyMap() {");
+ writer.println(" ensureInstance();");
+ writer.println(" instance.loadCurrencyMap();");
+ writer.println("}");
+ writer.println();
+ writer.println("@Override");
+ writer.println("protected void loadNamesMap() {");
+ writer.println(" ensureInstance();");
+ writer.println(" instance.loadNamesMap();");
+ writer.println("}");
+ writer.println();
+ writer.println("private void ensureInstance() {");
+ writer.indent();
+ writer.println("if (instance != null) {");
+ writer.println(" return;");
+ writer.println("}");
+ boolean fetchedLocale = false;
+ Map<String, Set<GwtLocale>> localeMap = new HashMap<String,
+ Set<GwtLocale>>();
+ String compileLocaleClass = processChildLocale(logger, context,
+ targetClass, localeMap, compileLocale);
+ if (compileLocaleClass == null) {
+ // already gave warning, just use default implementation
+ return null;
+ }
+ for (GwtLocale runtimeLocale : locales) {
+ processChildLocale(logger, context, targetClass, localeMap,
+ runtimeLocale);
+ }
+ for (Entry<String, Set<GwtLocale>> entry : localeMap.entrySet()) {
+ if (!fetchedLocale) {
+ writer.println("String runtimeLocale = LocaleInfo.getCurrentLocale().getLocaleName();");
+ fetchedLocale = true;
+ }
+ boolean firstLocale = true;
+ String generatedClass = entry.getKey();
+ if (compileLocaleClass.equals(generatedClass)) {
+ // The catch-all will handle this
+ continue;
+ }
+ writer.print("if (");
+ for (GwtLocale locale : entry.getValue()) {
+ if (firstLocale) {
+ firstLocale = false;
+ } else {
+ writer.println();
+ writer.print(" || ");
+ }
+ writer.print("\"" + locale.toString()
+ + "\".equals(runtimeLocale)");
+ }
+ writer.println(") {");
+ writer.println(" instance = new " + generatedClass + "();");
+ writer.println(" return;");
+ writer.println("}");
+ }
+ writer.println("instance = new " + compileLocaleClass + "();");
+ writer.outdent();
+ writer.println("}");
+ writer.commit(logger);
+ }
+ return packageName + "." + className;
+ }
+
+ private String processChildLocale(TreeLogger logger, GeneratorContext context,
+ JClassType targetClass, Map<String, Set<GwtLocale>> localeMap,
+ GwtLocale locale) throws UnableToCompleteException {
+ String generatedClass = generateOne(logger, context,
+ targetClass, locale);
+ if (generatedClass == null) {
+ logger.log(TreeLogger.ERROR, "Failed to generate "
+ + targetClass.getQualifiedSourceName() + " in locale "
+ + locale.toString());
+ // skip failed locale
+ return null;
+ }
+ Set<GwtLocale> locales = localeMap.get(generatedClass);
+ if (locales == null) {
+ locales = new HashSet<GwtLocale>();
+ localeMap.put(generatedClass, locales);
+ }
+ locales.add(locale);
+ return generatedClass;
+ }
+
/**
* Backslash-escape any double quotes in the supplied string.
*
@@ -266,49 +391,26 @@
}
/**
- * Load a chain of localized properties files, starting with the default and
- * adding locale components so inheritance is properly recognized.
- *
- * @param logger TreeLogger instance
- * @param propFilePrefix property file name prefix; locale is added to it
- * @return a LocalizedProperties object containing all properties
- * @throws UnableToCompleteException if an error occurs reading the file
- */
- private LocalizedProperties readProperties(TreeLogger logger, String propFilePrefix,
- String locale) throws UnableToCompleteException {
- LocalizedProperties props = new LocalizedProperties();
- ClassLoader classLoader = getClass().getClassLoader();
- readProperties(logger, classLoader, propFilePrefix, props);
- if (locale.equals("default")) {
- return props;
- }
- int idx = -1;
- while ((idx = locale.indexOf('_', idx + 1)) >= 0) {
- readProperties(logger, classLoader, propFilePrefix + "_" + locale.substring(0, idx), props);
- }
- if (locale.length() > 0) {
- readProperties(logger, classLoader, propFilePrefix + "_" + locale, props);
- }
- return props;
- }
-
- /**
- * Load a single localized properties file, adding to an existing LocalizedProperties object.
+ * Load a single localized properties file, adding to an existing
+ * LocalizedProperties object.
*
* @param logger TreeLogger instance
* @param classLoader class loader to use to find property file
* @param propFile property file name
* @param props existing LocalizedProperties object to add to
+ * @return true if the properties were successfully read
* @throws UnableToCompleteException if an error occurs reading the file
*/
- private void readProperties(TreeLogger logger, ClassLoader classLoader,
- String propFile, LocalizedProperties props) throws UnableToCompleteException {
+ private boolean readProperties(TreeLogger logger, ClassLoader classLoader,
+ String propFile, LocalizedProperties props)
+ throws UnableToCompleteException {
propFile += ".properties";
InputStream str = null;
try {
str = classLoader.getResourceAsStream(propFile);
if (str != null) {
props.load(str, "UTF-8");
+ return true;
}
} catch (UnsupportedEncodingException e) {
// UTF-8 should always be defined
@@ -327,5 +429,36 @@
}
}
}
+ return false;
+ }
+
+ /**
+ * Load a chain of localized properties files, starting with the default and
+ * adding locale components so inheritance is properly recognized.
+ *
+ * @param logger TreeLogger instance
+ * @param propFilePrefix property file name prefix; locale is added to it
+ * @return a LocalizedProperties object containing all properties
+ * @throws UnableToCompleteException if an error occurs reading the file
+ */
+ private LocalizedProperties readProperties(TreeLogger logger,
+ String propFilePrefix, GwtLocale locale, GwtLocale[] foundLocale)
+ throws UnableToCompleteException {
+ LocalizedProperties props = new LocalizedProperties();
+ ClassLoader classLoader = getClass().getClassLoader();
+ List<GwtLocale> searchList = locale.getCompleteSearchList();
+ GwtLocale lastFound = LocaleUtils.getLocaleFactory().fromString(null);
+ for (int i = searchList.size(); i-- > 0; ) {
+ GwtLocale search = searchList.get(i);
+ String propFile = propFilePrefix;
+ if (!search.isDefault()) {
+ propFile += "_" + search.getAsString();
+ }
+ if (readProperties(logger, classLoader, propFile, props)) {
+ lastFound = search;
+ }
+ }
+ foundLocale[0] = lastFound;
+ return props;
}
}
diff --git a/user/src/com/google/gwt/i18n/rebind/LocaleInfoGenerator.java b/user/src/com/google/gwt/i18n/rebind/LocaleInfoGenerator.java
index e49bbf4..95145dd 100644
--- a/user/src/com/google/gwt/i18n/rebind/LocaleInfoGenerator.java
+++ b/user/src/com/google/gwt/i18n/rebind/LocaleInfoGenerator.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.i18n.rebind;
-import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.PropertyOracle;
@@ -25,6 +24,8 @@
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.i18n.client.impl.LocaleInfoImpl;
+import com.google.gwt.i18n.server.GwtLocaleImpl;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
@@ -34,6 +35,12 @@
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
/**
* Generator used to generate an implementation of the LocaleInfoImpl class,
@@ -42,30 +49,22 @@
public class LocaleInfoGenerator extends Generator {
/**
- * Properties file containing machine-generated locale display names, in
- * their native locales (if possible).
+ * Properties file containing machine-generated locale display names, in their
+ * native locales (if possible).
*/
- private static final String GENERATED_LOCALE_NATIVE_DISPLAY_NAMES =
- "com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-generated.properties";
-
+ private static final String GENERATED_LOCALE_NATIVE_DISPLAY_NAMES = "com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-generated.properties";
+
/**
* Properties file containing hand-made corrections to the machine-generated
* locale display names above.
*/
- private static final String MANUAL_LOCALE_NATIVE_DISPLAY_NAMES =
- "com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-manual.properties";
+ private static final String MANUAL_LOCALE_NATIVE_DISPLAY_NAMES = "com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-manual.properties";
/**
- * Properties file containing hand-made overrides of locale display names,
- * in their native locales (if possible).
+ * Properties file containing hand-made overrides of locale display names, in
+ * their native locales (if possible).
*/
- private static final String OVERRIDE_LOCALE_NATIVE_DISPLAY_NAMES =
- "com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-override.properties";
-
- /**
- * The token representing the locale property controlling Localization.
- */
- private static final String PROP_LOCALE = "locale";
+ private static final String OVERRIDE_LOCALE_NATIVE_DISPLAY_NAMES = "com/google/gwt/i18n/client/impl/cldr/LocaleNativeDisplayNames-override.properties";
/**
* Generate an implementation for the given type.
@@ -77,65 +76,100 @@
* @throws UnableToCompleteException
*/
@Override
- public final String generate(TreeLogger logger, GeneratorContext context,
+ public final String generate(TreeLogger logger, final GeneratorContext context,
String typeName) throws UnableToCompleteException {
TypeOracle typeOracle = context.getTypeOracle();
// Get the current locale and interface type.
PropertyOracle propertyOracle = context.getPropertyOracle();
- String locale = null;
- String[] localeValues = null;
- try {
- locale = propertyOracle.getPropertyValue(logger, PROP_LOCALE);
- localeValues = propertyOracle.getPropertyValueSet(logger, PROP_LOCALE);
- } catch (BadPropertyValueException e) {
- logger.log(TreeLogger.TRACE, "LocaleInfo used without I18N module, using defaults", e);
- return LocaleInfoImpl.class.getName();
- }
+ LocaleUtils.init(logger, propertyOracle);
JClassType targetClass;
try {
targetClass = typeOracle.getType(typeName);
} catch (NotFoundException e) {
- logger.log(TreeLogger.ERROR, "No such type", e);
+ logger.log(TreeLogger.ERROR, "No such type " + typeName, e);
throw new UnableToCompleteException();
}
assert (LocaleInfoImpl.class.getName().equals(targetClass.getQualifiedSourceName()));
-
+
String packageName = targetClass.getPackage().getName();
- String className = targetClass.getName().replace('.', '_') + "_";
- if (!locale.equals("default")) {
- className += locale;
+ GwtLocale locale = LocaleUtils.getCompileLocale();
+ String className = targetClass.getName().replace('.', '_') + "_"
+ + locale.getAsString();
+ Set<GwtLocale> runtimeLocales = LocaleUtils.getRuntimeLocales();
+ if (!runtimeLocales.isEmpty()) {
+ className += "_runtimeSelection";
}
String qualName = packageName + "." + className;
-
+
PrintWriter pw = context.tryCreate(logger, packageName, className);
if (pw != null) {
ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(
packageName, className);
factory.setSuperclass(targetClass.getQualifiedSourceName());
+ factory.addImport("com.google.gwt.core.client.GWT");
factory.addImport("com.google.gwt.core.client.JavaScriptObject");
+ factory.addImport("com.google.gwt.i18n.client.LocaleInfo");
+ factory.addImport("com.google.gwt.i18n.client.constants.NumberConstants");
+ factory.addImport("com.google.gwt.i18n.client.constants.NumberConstantsImpl");
+ factory.addImport("com.google.gwt.i18n.client.constants.DateTimeConstants");
+ factory.addImport("com.google.gwt.i18n.client.constants.DateTimeConstantsImpl");
SourceWriter writer = factory.createSourceWriter(context, pw);
writer.println("private JavaScriptObject nativeDisplayNames;");
writer.println();
+ writer.println("@Override");
writer.println("public String[] getAvailableLocaleNames() {");
writer.println(" return new String[] {");
- for (String propval : localeValues) {
- writer.println(" \"" + propval.replaceAll("\"", "\\\"") + "\",");
+ // sort for deterministic output
+ Set<GwtLocale> localeSet = LocaleUtils.getAllLocales();
+ GwtLocaleImpl[] allLocales = localeSet.toArray(new GwtLocaleImpl[localeSet.size()]);
+ Arrays.sort(allLocales);
+ for (GwtLocaleImpl possibleLocale : allLocales) {
+ writer.println(" \""
+ + possibleLocale.toString().replaceAll("\"", "\\\"") + "\",");
}
writer.println(" };");
writer.println("}");
writer.println();
+ writer.println("@Override");
writer.println("public String getLocaleName() {");
- writer.println(" return \"" + locale + "\";");
+ if (runtimeLocales.isEmpty()) {
+ writer.println(" return \"" + locale + "\";");
+ } else {
+ writer.println(" String rtLocale = getRuntimeLocale();");
+ writer.println(" return rtLocale != null ? rtLocale : \"" + locale
+ + "\";");
+ }
writer.println("}");
writer.println();
+ writer.println("@Override");
writer.println("public native String getLocaleNativeDisplayName(String localeName) /*-{");
writer.println(" this.@" + qualName + "::ensureNativeDisplayNames()();");
- writer.println(" return this.@" + qualName + "::nativeDisplayNames[localeName];");
+ writer.println(" return this.@" + qualName
+ + "::nativeDisplayNames[localeName];");
writer.println("}-*/;");
writer.println();
+ writer.println("@Override");
+ writer.println("public DateTimeConstants getDateTimeConstants() {");
+ LocalizableGenerator localizableGenerator = new LocalizableGenerator();
+ // Avoid warnings for trying to create the same type multiple times
+ @SuppressWarnings("hiding")
+ GeneratorContext subContext = new CachedGeneratorContext(context);
+ generateConstantsLookup(logger, subContext, writer, localizableGenerator,
+ runtimeLocales, locale,
+ "com.google.gwt.i18n.client.constants.DateTimeConstantsImpl");
+ writer.println("}");
+ writer.println();
+ writer.println("@Override");
+ writer.println("public NumberConstants getNumberConstants() {");
+ generateConstantsLookup(logger, subContext, writer, localizableGenerator,
+ runtimeLocales, locale,
+ "com.google.gwt.i18n.client.constants.NumberConstantsImpl");
+ writer.println("}");
+ writer.println();
writer.println("private native void ensureNativeDisplayNames() /*-{");
- writer.println(" if (this.@" + qualName + "::nativeDisplayNames != null) {");
+ writer.println(" if (this.@" + qualName
+ + "::nativeDisplayNames != null) {");
writer.println(" return;");
writer.println(" }");
writer.println(" this.@" + qualName + "::nativeDisplayNames = {");
@@ -161,25 +195,27 @@
logger.log(TreeLogger.ERROR, "UTF-8 encoding is not defined", e);
throw new UnableToCompleteException();
} catch (IOException e) {
- logger.log(TreeLogger.ERROR, "Exception reading locale display names", e);
+ logger.log(TreeLogger.ERROR, "Exception reading locale display names",
+ e);
throw new UnableToCompleteException();
}
boolean needComma = false;
- for (String propval : localeValues) {
- String displayName = displayNamesOverride.getProperty(propval);
+ for (GwtLocaleImpl possibleLocale : allLocales) {
+ String localeName = possibleLocale.toString();
+ String displayName = displayNamesOverride.getProperty(localeName);
if (displayName == null) {
- displayName = displayNamesManual.getProperty(propval);
+ displayName = displayNamesManual.getProperty(localeName);
}
if (displayName == null) {
- displayName = displayNames.getProperty(propval);
+ displayName = displayNames.getProperty(localeName);
}
if (displayName != null && displayName.length() != 0) {
- propval.replace("\"", "\\\"");
+ localeName.replace("\"", "\\\"");
displayName.replace("\"", "\\\"");
if (needComma) {
writer.println(",");
}
- writer.print(" \"" + propval + "\": \"" + displayName + "\"");
+ writer.print(" \"" + localeName + "\": \"" + displayName + "\"");
needComma = true;
}
}
@@ -192,4 +228,87 @@
}
return packageName + "." + className;
}
+
+ /**
+ * @param logger
+ * @param context
+ * @param writer
+ * @param localizableGenerator
+ * @param runtimeLocales
+ * @param locale
+ * @throws UnableToCompleteException
+ */
+ private void generateConstantsLookup(TreeLogger logger,
+ GeneratorContext context, SourceWriter writer,
+ LocalizableGenerator localizableGenerator, Set<GwtLocale> runtimeLocales,
+ GwtLocale locale, String typeName)
+ throws UnableToCompleteException {
+ writer.indent();
+ boolean fetchedRuntimeLocale = false;
+ Map<String, Set<GwtLocale>> localeMap = new HashMap<String, Set<GwtLocale>>();
+ generateOneLocale(logger, context, localizableGenerator, typeName,
+ localeMap, locale);
+ for (GwtLocale runtimeLocale : runtimeLocales) {
+ generateOneLocale(logger, context, localizableGenerator, typeName,
+ localeMap, runtimeLocale);
+ }
+ if (localeMap.size() > 1) {
+ for (Entry<String, Set<GwtLocale>> entry : localeMap.entrySet()) {
+ if (!fetchedRuntimeLocale) {
+ writer.println("String runtimeLocale = getLocaleName();");
+ fetchedRuntimeLocale = true;
+ }
+ writer.print("if (");
+ boolean firstLocale = true;
+ String generatedClass = entry.getKey();
+ for (GwtLocale runtimeLocale : entry.getValue()) {
+ if (firstLocale) {
+ firstLocale = false;
+ } else {
+ writer.println();
+ writer.print(" || ");
+ }
+ writer.print("\"" + runtimeLocale.toString()
+ + "\".equals(runtimeLocale)");
+ }
+ writer.println(") {");
+ writer.println(" return new " + generatedClass + "();");
+ writer.println("}");
+ }
+ // TODO: if we get here, there was an unexpected runtime locale --
+ // should we have an assert or throw an exception? Currently it
+ // just falls through to the default implementation.
+ }
+ writer.println("return GWT.create(" + typeName + ".class);");
+ writer.outdent();
+ }
+
+ /**
+ * @param logger
+ * @param context
+ * @param localizableGenerator
+ * @param typeName
+ * @param localeMap
+ * @param locale
+ * @throws UnableToCompleteException
+ */
+ private void generateOneLocale(TreeLogger logger, GeneratorContext context,
+ LocalizableGenerator localizableGenerator, String typeName,
+ Map<String, Set<GwtLocale>> localeMap, GwtLocale locale)
+ throws UnableToCompleteException {
+ String generatedClass = localizableGenerator.generate(logger, context,
+ typeName, locale.toString());
+ if (generatedClass == null) {
+ logger.log(TreeLogger.ERROR, "Failed to generate " + typeName
+ + " in locale " + locale.toString());
+ // skip failed locale
+ return;
+ }
+ Set<GwtLocale> locales = localeMap.get(generatedClass);
+ if (locales == null) {
+ locales = new HashSet<GwtLocale>();
+ localeMap.put(generatedClass, locales);
+ }
+ locales.add(locale);
+ }
}
diff --git a/user/src/com/google/gwt/i18n/rebind/LocaleUtils.java b/user/src/com/google/gwt/i18n/rebind/LocaleUtils.java
new file mode 100644
index 0000000..eedb41c
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/rebind/LocaleUtils.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2009 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.BadPropertyValueException;
+import com.google.gwt.core.ext.PropertyOracle;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.i18n.server.GwtLocaleFactoryImpl;
+import com.google.gwt.i18n.shared.GwtLocale;
+import com.google.gwt.i18n.shared.GwtLocaleFactory;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Utility methods for dealing with locales.
+ */
+public class LocaleUtils {
+ // TODO(jat): rewrite to avoid statics
+
+ private static GwtLocaleFactory factory = new GwtLocaleFactoryImpl();
+
+ /**
+ * The token representing the locale property controlling Localization.
+ */
+ private static final String PROP_LOCALE = "locale";
+
+ /**
+ * The token representing the runtime.locales configuration property.
+ */
+ private static final String PROP_RUNTIME_LOCALES = "runtime.locales";
+
+ private static GwtLocale compileLocale;
+
+ private static Set<GwtLocale> allLocales = new HashSet<GwtLocale>();
+
+ private static Set<GwtLocale> allCompileLocales = new HashSet<GwtLocale>();
+
+ private static Set<GwtLocale> runtimeLocales = new HashSet<GwtLocale>();
+
+ /**
+ * Returns the set of all compile-time locales.
+ *
+ * @return unmodifiable set of all compile-time locales
+ */
+ public static Set<GwtLocale> getAllCompileLocales() {
+ return Collections.unmodifiableSet(allCompileLocales);
+ }
+
+ /**
+ * Returns the set of all available locales, whether compile-time locales or
+ * runtime locales.
+ *
+ * @return unmodifiable set of all locales
+ */
+ public static Set<GwtLocale> getAllLocales() {
+ return Collections.unmodifiableSet(allLocales);
+ }
+
+ /**
+ * @return the static compile-time locale for this permutation.
+ */
+ public static GwtLocale getCompileLocale() {
+ return compileLocale;
+ }
+
+ /**
+ * Get a shared GwtLocale factory so instances are cached between all uses.
+ *
+ * @return singleton GwtLocaleFactory instance.
+ */
+ public static GwtLocaleFactory getLocaleFactory() {
+ return factory;
+ }
+
+ /**
+ * Returns a list of locales which are children of the current compile-time
+ * locale.
+ *
+ * @return unmodifiable list of matching locales
+ */
+ public static Set<GwtLocale> getRuntimeLocales() {
+ return Collections.unmodifiableSet(runtimeLocales);
+ }
+
+ /**
+ * Initialize from properties. Only needs to be called once, before any other
+ * calls.
+ *
+ * @param logger
+ * @param propertyOracle
+ */
+ public static void init(TreeLogger logger, PropertyOracle propertyOracle) {
+ try {
+ String localeName = propertyOracle.getPropertyValue(logger, PROP_LOCALE);
+ GwtLocale newCompileLocale = factory.fromString(localeName);
+ if (newCompileLocale.equals(compileLocale)) {
+ return;
+ }
+ compileLocale = newCompileLocale;
+ allLocales = new HashSet<GwtLocale>();
+ allCompileLocales = new HashSet<GwtLocale>();
+ runtimeLocales = new HashSet<GwtLocale>();
+ String[] localeValues = propertyOracle.getPropertyValueSet(logger,
+ PROP_LOCALE);
+ String rtLocaleNames = propertyOracle.getPropertyValue(logger,
+ PROP_RUNTIME_LOCALES);
+ for (String localeValue : localeValues) {
+ allCompileLocales.add(factory.fromString(localeValue));
+ }
+ allLocales.addAll(allCompileLocales);
+ if (rtLocaleNames != null && rtLocaleNames.length() > 0) {
+ String[] rtLocales = rtLocaleNames.split(",");
+ for (String rtLocale : rtLocales) {
+ GwtLocale locale = factory.fromString(rtLocale);
+ // TODO(jat): remove use of labels
+ existingLocales:
+ for (GwtLocale existing : allCompileLocales) {
+ for (GwtLocale alias : existing.getAliases()) {
+ if (!alias.isDefault() && locale.inheritsFrom(alias)
+ && locale.usesSameScript(alias)) {
+ allLocales.add(locale);
+ break existingLocales;
+ }
+ }
+ }
+ if (!compileLocale.isDefault()
+ && locale.inheritsFrom(compileLocale)
+ && locale.usesSameScript(compileLocale)) {
+ // TODO(jat): don't include runtime locales which also inherit
+ // from a more-specific compile locale than this one
+ runtimeLocales.add(locale);
+ }
+ }
+ }
+ } catch (BadPropertyValueException e) {
+ logger.log(TreeLogger.TRACE,
+ "Unable to get locale properties, using defaults", e);
+ compileLocale = factory.fromString("default");
+ allLocales.add(compileLocale);
+ return;
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/i18n/rebind/LocalizableGenerator.java b/user/src/com/google/gwt/i18n/rebind/LocalizableGenerator.java
index 2f8295b..0003bab 100644
--- a/user/src/com/google/gwt/i18n/rebind/LocalizableGenerator.java
+++ b/user/src/com/google/gwt/i18n/rebind/LocalizableGenerator.java
@@ -28,6 +28,7 @@
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.i18n.client.ConstantsWithLookup;
import com.google.gwt.i18n.client.Messages;
+import com.google.gwt.i18n.shared.GwtLocale;
/**
* Generator used to bind classes extending the <code>Localizable</code> and
@@ -65,14 +66,7 @@
@Override
public final String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {
- // Clear cache if reset was done.
- TypeOracle typeOracle = context.getTypeOracle();
- if (lastReloadCount != typeOracle.getReloadCount()) {
- ResourceFactory.clearCache();
- lastReloadCount = typeOracle.getReloadCount();
- }
-
- // Get the current locale and interface type.
+ // Get the current locale
PropertyOracle propertyOracle = context.getPropertyOracle();
String locale;
try {
@@ -99,6 +93,17 @@
logger.log(TreeLogger.ERROR, "Could not parse specified locale", e);
throw new UnableToCompleteException();
}
+ return generate(logger, context, typeName, locale);
+ }
+
+ public final String generate(TreeLogger logger, GeneratorContext context,
+ String typeName, String localeName) throws UnableToCompleteException {
+ // Clear cache if reset was done.
+ TypeOracle typeOracle = context.getTypeOracle();
+ if (lastReloadCount != typeOracle.getReloadCount()) {
+ ResourceFactory.clearCache();
+ lastReloadCount = typeOracle.getReloadCount();
+ }
JClassType targetClass;
try {
@@ -114,6 +119,8 @@
"Checking for deprecated metadata", null);
}
+ GwtLocale locale = LocaleUtils.getLocaleFactory().fromString(localeName);
+
// Link current locale and interface type to correct implementation class.
String generatedClass = AbstractLocalizableImplCreator.generateConstantOrMessageClass(
logger, deprecatedLogger , context, locale, targetClass);
diff --git a/user/src/com/google/gwt/i18n/rebind/LocalizableLinkageCreator.java b/user/src/com/google/gwt/i18n/rebind/LocalizableLinkageCreator.java
index 0e098c0..df3c14c 100644
--- a/user/src/com/google/gwt/i18n/rebind/LocalizableLinkageCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/LocalizableLinkageCreator.java
@@ -18,6 +18,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.AbstractSourceCreator;
import java.util.HashMap;
@@ -34,7 +35,7 @@
Map<String, JClassType> matchingClasses = new HashMap<String, JClassType>();
// Add base class if possible.
if (baseClass.isInterface() == null && baseClass.isAbstract() == false) {
- matchingClasses.put(ResourceFactory.DEFAULT_TOKEN, baseClass);
+ matchingClasses.put(GwtLocale.DEFAULT_LOCALE, baseClass);
}
String baseName = baseClass.getSimpleSourceName();
@@ -54,16 +55,16 @@
if (matches) {
boolean isDefault = localeIndex == -1
|| localeIndex == name.length() - 1
- || ResourceFactory.DEFAULT_TOKEN.equals(name.substring(localeIndex + 1));
+ || GwtLocale.DEFAULT_LOCALE.equals(name.substring(localeIndex + 1));
if (isDefault) {
// Don't override base as default if present.
JClassType defaultClass =
- matchingClasses.get(ResourceFactory.DEFAULT_TOKEN);
+ matchingClasses.get(GwtLocale.DEFAULT_LOCALE);
if (defaultClass != null) {
throw error(logger, defaultClass + " and " + baseName
+ " are both potential default classes for " + baseClass);
} else {
- matchingClasses.put(ResourceFactory.DEFAULT_TOKEN, subType);
+ matchingClasses.put(GwtLocale.DEFAULT_LOCALE, subType);
}
} else {
// Don't allow a locale to be ambiguous. Very similar to default
@@ -103,14 +104,13 @@
* @throws UnableToCompleteException
*/
String linkWithImplClass(TreeLogger logger, JClassType baseClass,
- String locale) throws UnableToCompleteException {
-
+ GwtLocale locale) throws UnableToCompleteException {
String baseName = baseClass.getQualifiedSourceName();
/**
* Try to find implementation class, as the current class is not a Constant
* or Message.
*/
- String className = implCache.get(baseName + locale);
+ String className = implCache.get(baseName + locale.toString());
if (className != null) {
return className;
}
@@ -122,23 +122,16 @@
Map<String, JClassType> matchingClasses =
findDerivedClasses(logger, baseClass);
// Now that we have all matches, find best class
- String localeSuffix = locale;
JClassType result = null;
- while (true) {
- // Check for current result.
- result = matchingClasses.get(localeSuffix);
+ for (GwtLocale search : locale.getCompleteSearchList()) {
+ result = matchingClasses.get(search.toString());
if (result != null) {
- break;
+ implCache.put(baseName + locale.toString(), className);
+ return result.getQualifiedSourceName();
}
- if (localeSuffix.equals(ResourceFactory.DEFAULT_TOKEN)) {
- // No classes matched.
- throw error(logger, "Cannot find a class to bind to argument type "
- + baseClass.getQualifiedSourceName());
- }
-
- localeSuffix = ResourceFactory.getParentLocaleName(localeSuffix);
}
- implCache.put(baseName + locale, className);
- return result.getQualifiedSourceName();
+ // No classes matched.
+ throw error(logger, "Cannot find a class to bind to argument type "
+ + baseClass.getQualifiedSourceName());
}
}
diff --git a/user/src/com/google/gwt/i18n/rebind/LocalizedPropertiesResource.java b/user/src/com/google/gwt/i18n/rebind/LocalizedPropertiesResource.java
index 22d9f17..9cd4928 100644
--- a/user/src/com/google/gwt/i18n/rebind/LocalizedPropertiesResource.java
+++ b/user/src/com/google/gwt/i18n/rebind/LocalizedPropertiesResource.java
@@ -16,6 +16,7 @@
package com.google.gwt.i18n.rebind;
import com.google.gwt.dev.util.Util;
+import com.google.gwt.i18n.shared.GwtLocale;
import org.apache.tapestry.util.text.LocalizedProperties;
@@ -35,15 +36,17 @@
}
@Override
- public AbstractResource load(InputStream m) {
- LocalizedPropertiesResource bundle = new LocalizedPropertiesResource(m);
+ public AbstractResource load(InputStream m, GwtLocale locale) {
+ LocalizedPropertiesResource bundle = new LocalizedPropertiesResource(m,
+ locale);
return bundle;
}
}
private LocalizedProperties props;
- public LocalizedPropertiesResource(InputStream m) {
+ public LocalizedPropertiesResource(InputStream m, GwtLocale locale) {
+ super(locale);
props = new LocalizedProperties();
try {
props.load(m, Util.DEFAULT_ENCODING);
diff --git a/user/src/com/google/gwt/i18n/rebind/LookupMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/LookupMethodCreator.java
index cb59124..a9a9dd7 100644
--- a/user/src/com/google/gwt/i18n/rebind/LookupMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/LookupMethodCreator.java
@@ -20,6 +20,7 @@
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.AbstractGeneratorClassCreator;
import com.google.gwt.user.rebind.AbstractMethodCreator;
import com.google.gwt.user.rebind.AbstractSourceCreator;
@@ -46,7 +47,7 @@
@Override
public void createMethodFor(TreeLogger logger, JMethod targetMethod,
- String key, ResourceList resourceList, String locale) {
+ String key, ResourceList resourceList, GwtLocale locale) {
createMethodFor(targetMethod);
}
diff --git a/user/src/com/google/gwt/i18n/rebind/MessagesImplCreator.java b/user/src/com/google/gwt/i18n/rebind/MessagesImplCreator.java
index 3332695..53eb9a5 100644
--- a/user/src/com/google/gwt/i18n/rebind/MessagesImplCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/MessagesImplCreator.java
@@ -22,6 +22,7 @@
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.SourceWriter;
/**
@@ -31,7 +32,7 @@
class MessagesImplCreator extends AbstractLocalizableImplCreator {
/**
- * Constructor for <code>ConstantsImplCreator</code>.
+ * Constructor for <code>MessagesImplCreator</code>.
*
* @param writer <code>Writer</code> to print to
* @param localizableClass Class/Interface to conform to
@@ -41,10 +42,12 @@
* @param deprecatedLogger logger for deprecated metadata warnings
* @throws UnableToCompleteException
*/
- public MessagesImplCreator(TreeLogger logger, TreeLogger deprecatedLogger, SourceWriter writer,
- JClassType localizableClass, ResourceList resourceList,
- TypeOracle oracle) throws UnableToCompleteException {
- super(logger, deprecatedLogger, writer, localizableClass, resourceList, false);
+ public MessagesImplCreator(TreeLogger logger, TreeLogger deprecatedLogger,
+ SourceWriter writer, JClassType localizableClass,
+ ResourceList resourceList, TypeOracle oracle)
+ throws UnableToCompleteException {
+ super(logger, deprecatedLogger, writer, localizableClass, resourceList,
+ false);
try {
JClassType stringClass = oracle.getType(String.class.getName());
register(stringClass, new MessagesMethodCreator(this));
@@ -65,8 +68,7 @@
throws UnableToCompleteException {
if (!method.getReturnType().getQualifiedSourceName().equals(
"java.lang.String")) {
- throw error(
- logger,
+ throw error(logger,
"All methods in interfaces extending Messages must have a return type of String.");
}
}
@@ -79,7 +81,7 @@
* @throws UnableToCompleteException
*/
@Override
- protected void emitMethodBody(TreeLogger logger, JMethod m, String locale)
+ protected void emitMethodBody(TreeLogger logger, JMethod m, GwtLocale locale)
throws UnableToCompleteException {
checkMessagesMethod(logger, m);
delegateToCreator(logger, m, locale);
diff --git a/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
index 9a31104..340bc6d 100644
--- a/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
@@ -34,14 +34,13 @@
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
import com.google.gwt.i18n.rebind.MessageFormatParser.ArgumentChunk;
import com.google.gwt.i18n.rebind.MessageFormatParser.TemplateChunk;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.AbstractGeneratorClassCreator;
import com.google.gwt.user.rebind.AbstractMethodCreator;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* Creator for methods of the form String getX(arg0,...,argN).
@@ -263,11 +262,6 @@
}
/**
- * Pattern to find MessageFormat argument references, including format and
- * subformat pieces, if present.
- */
- private static final Pattern argPattern = Pattern.compile("\\{(\\d+)(,(\\w+)(,([^\\}]+))?)?\\}");
- /**
* Class names, in a refactor-friendly manner.
*/
private static final String dtFormatClassName = DateTimeFormat.class.getCanonicalName();
@@ -300,7 +294,7 @@
@Override
public void createMethodFor(TreeLogger logger, JMethod m, String key,
- ResourceList resourceList, String locale)
+ ResourceList resourceList, GwtLocale locale)
throws UnableToCompleteException {
JParameter[] params = m.getParameters();
int pluralParamIndex = -1;
@@ -406,17 +400,15 @@
* TODO: consider impact of possibly having multiple TypeOracles
*/
private PluralRule createLocalizedPluralRule(TreeLogger logger,
- TypeOracle oracle, Class<? extends PluralRule> ruleClass, String locale)
+ TypeOracle oracle, Class<? extends PluralRule> ruleClass,
+ GwtLocale locale)
throws UnableToCompleteException {
- if (locale.length() == 0) {
- locale = ResourceFactory.DEFAULT_TOKEN;
- }
String baseName = ruleClass.getCanonicalName();
JClassType ruleJClassType = oracle.findType(baseName);
Map<String, JClassType> matchingClasses = LocalizableLinkageCreator.findDerivedClasses(
logger, ruleJClassType);
- while (true) {
- JClassType localizedType = matchingClasses.get(locale);
+ for (GwtLocale search : locale.getCompleteSearchList()) {
+ JClassType localizedType = matchingClasses.get(search.toString());
if (localizedType != null) {
try {
Class<?> testClass = Class.forName(
@@ -435,12 +427,9 @@
// ignore inaccessible classes
}
}
- if (locale.equals(ResourceFactory.DEFAULT_TOKEN)) {
- // default of last resort
- return new DefaultRule();
- }
- locale = ResourceFactory.getParentLocaleName(locale);
}
+ // default of last resort
+ return new DefaultRule();
}
/**
@@ -458,7 +447,6 @@
JParameter[] params, boolean[] seenFlag, StringBuffer outputBuf)
throws UnableToCompleteException {
StringGenerator buf = new StringGenerator(outputBuf);
- Matcher match = argPattern.matcher(template);
try {
for (TemplateChunk chunk : MessageFormatParser.parse(template)) {
if (chunk.isLiteral()) {
diff --git a/user/src/com/google/gwt/i18n/rebind/ResourceFactory.java b/user/src/com/google/gwt/i18n/rebind/ResourceFactory.java
index f404f24..3433a40 100644
--- a/user/src/com/google/gwt/i18n/rebind/ResourceFactory.java
+++ b/user/src/com/google/gwt/i18n/rebind/ResourceFactory.java
@@ -18,8 +18,10 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.i18n.client.LocalizableResource.DefaultLocale;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
import com.google.gwt.i18n.rebind.AnnotationsResource.AnnotationsError;
+import com.google.gwt.i18n.shared.GwtLocale;
import java.io.InputStream;
import java.util.ArrayList;
@@ -130,10 +132,6 @@
}
}
- /**
- * Represents default locale.
- */
- public static final String DEFAULT_TOKEN = "default";
public static final char LOCALE_SEPARATOR = '_';
private static Map<String, ResourceList> cache = new HashMap<String, ResourceList>();
@@ -150,11 +148,15 @@
cache.clear();
}
- public static ResourceList getBundle(Class<?> clazz, String locale, boolean isConstants) {
+ public static ResourceList getBundle(Class<?> clazz, GwtLocale locale,
+ boolean isConstants) {
+ assert locale != null;
return getBundle(TreeLogger.NULL, clazz, locale, isConstants);
}
- public static ResourceList getBundle(String path, String locale, boolean isConstants) {
+ public static ResourceList getBundle(String path, GwtLocale locale,
+ boolean isConstants) {
+ assert locale != null;
return getBundle(TreeLogger.NULL, path, locale, isConstants);
}
@@ -166,7 +168,7 @@
* @return the resource
*/
public static ResourceList getBundle(TreeLogger logger, Class<?> javaInterface,
- String locale, boolean isConstants) {
+ GwtLocale locale, boolean isConstants) {
if (javaInterface.isInterface() == false) {
throw new IllegalArgumentException(javaInterface
+ " should be an interface.");
@@ -182,10 +184,10 @@
* @param locale locale name
* @return the resource
*/
- public static ResourceList getBundle(TreeLogger logger, JClassType javaInterface,
- String locale, boolean isConstants) {
- return getBundleAux(logger, new JClassTypePathTree(javaInterface), javaInterface, locale,
- true, isConstants);
+ public static ResourceList getBundle(TreeLogger logger,
+ JClassType javaInterface, GwtLocale locale, boolean isConstants) {
+ return getBundleAux(logger, new JClassTypePathTree(javaInterface),
+ javaInterface, locale, true, isConstants);
}
/**
@@ -195,33 +197,10 @@
* @param locale locale name
* @return the resource
*/
- public static ResourceList getBundle(TreeLogger logger, String path, String locale,
- boolean isConstants) {
- return getBundleAux(logger, new SimplePathTree(path), null, locale, true, isConstants);
- }
-
- /**
- * Given a locale name, derives the parent's locale name. For example, if
- * the locale name is "en_US", the parent locale name would be "en". If the
- * locale name is that of a top level locale (i.e. no '_' characters, such
- * as "fr"), then the the parent locale name is that of the default locale.
- * If the locale name is null, the empty string, or is already that of the
- * default locale, then null is returned.
- *
- * @param localeName the locale name
- * @return the parent's locale name
- */
- public static String getParentLocaleName(String localeName) {
- if (localeName == null ||
- localeName.length() == 0 ||
- localeName.equals(DEFAULT_TOKEN)) {
- return null;
- }
- int pos = localeName.lastIndexOf(LOCALE_SEPARATOR);
- if (pos != -1) {
- return localeName.substring(0, pos);
- }
- return DEFAULT_TOKEN;
+ public static ResourceList getBundle(TreeLogger logger, String path,
+ GwtLocale locale, boolean isConstants) {
+ return getBundleAux(logger, new SimplePathTree(path), null, locale, true,
+ isConstants);
}
public static String getResourceName(JClassType targetClass) {
@@ -233,7 +212,7 @@
}
private static void addAlternativeParents(TreeLogger logger,
- ResourceFactory.AbstractPathTree tree, JClassType clazz, String locale,
+ ResourceFactory.AbstractPathTree tree, JClassType clazz, GwtLocale locale,
boolean useAlternativeParents, boolean isConstants,
ResourceList resources, Set<String> seenPaths) {
if (tree != null) {
@@ -246,24 +225,26 @@
}
private static void addPrimaryParent(TreeLogger logger,
- ResourceFactory.AbstractPathTree tree, JClassType clazz, String locale,
+ ResourceFactory.AbstractPathTree tree, JClassType clazz, GwtLocale locale,
boolean isConstants, ResourceList resources, Set<String> seenPaths) {
-
- // If we are not in the default case, calculate parent
- if (!DEFAULT_TOKEN.equals(locale)) {
- addResources(logger, tree, clazz, getParentLocaleName(locale),
- false, isConstants, resources, seenPaths);
+ for (GwtLocale search : locale.getCompleteSearchList()) {
+ // This relies on addResources exiting if it has seen a given path
+ // (derived from the locale) to avoid infinite loops, since the search
+ // list includes this locale as well as aliases which will refer back
+ // to this locale.
+ addResources(logger, tree, clazz, search, false, isConstants, resources,
+ seenPaths);
}
}
private static void addResources(TreeLogger logger,
- ResourceFactory.AbstractPathTree tree, JClassType clazz, String locale,
+ ResourceFactory.AbstractPathTree tree, JClassType clazz, GwtLocale locale,
boolean useAlternateParents, boolean isConstants,
ResourceList resources, Set<String> seenPaths) {
String targetPath = tree.getPath();
String localizedPath = targetPath;
- if (!DEFAULT_TOKEN.equals(locale)) {
- localizedPath = targetPath + LOCALE_SEPARATOR + locale;
+ if (!locale.isDefault()) {
+ localizedPath = targetPath + LOCALE_SEPARATOR + locale.getAsString();
}
if (seenPaths.contains(localizedPath)) {
return;
@@ -279,7 +260,15 @@
* In this case, we specifically want to be able to look at the interface
* instead of just implementations.
*/
- matchingClasses.put(ResourceFactory.DEFAULT_TOKEN, clazz);
+ String defLocaleValue = DefaultLocale.DEFAULT_LOCALE;
+ DefaultLocale defLocale = clazz.getAnnotation(DefaultLocale.class);
+ if (defLocale != null) {
+ defLocaleValue = defLocale.value();
+ if (!GwtLocale.DEFAULT_LOCALE.equals(defLocaleValue)) {
+ matchingClasses.put(defLocaleValue, clazz);
+ }
+ }
+ matchingClasses.put(GwtLocale.DEFAULT_LOCALE, clazz);
} catch (UnableToCompleteException e) {
// ignore error, fall through
}
@@ -289,17 +278,6 @@
matchingClasses = new HashMap<String, JClassType>();
}
- if (locale == null || locale.length() == 0) {
- // This should never happen, since the only legitimate user of this
- // method traces back to AbstractLocalizableImplCreator. The locale
- // that is passed in from AbstractLocalizableImplCreator is produced
- // by the I18N property provider, which guarantees that the locale
- // will not be of zero length or null. However, we add this check
- // in here in the event that a future user of ResourceFactory does
- // not obey this constraint.
- locale = DEFAULT_TOKEN;
- }
-
// Check for file-based resources.
String partialPath = localizedPath.replace('.', '/');
for (int i = 0; i < loaders.size(); i++) {
@@ -314,14 +292,14 @@
m = loader.getResourceAsStream(path);
}
if (m != null) {
- AbstractResource found = element.load(m);
+ AbstractResource found = element.load(m, locale);
found.setPath(path);
resources.add(found);
}
}
// Check for annotations
- JClassType currentClass = matchingClasses.get(locale);
+ JClassType currentClass = matchingClasses.get(locale.toString());
if (currentClass != null) {
AnnotationsResource resource;
try {
@@ -348,9 +326,9 @@
}
private static ResourceList getBundleAux(TreeLogger logger,
- ResourceFactory.AbstractPathTree tree, JClassType clazz, String locale,
+ ResourceFactory.AbstractPathTree tree, JClassType clazz, GwtLocale locale,
boolean required, boolean isConstants) {
- String cacheKey = tree.getPath() + "_" + locale;
+ String cacheKey = tree.getPath() + "_" + locale.getAsString();
if (cache.containsKey(cacheKey)) {
return cache.get(cacheKey);
}
@@ -373,5 +351,5 @@
abstract String getExt();
- abstract AbstractResource load(InputStream m);
+ abstract AbstractResource load(InputStream m, GwtLocale locale);
}
diff --git a/user/src/com/google/gwt/i18n/rebind/SimpleValueMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/SimpleValueMethodCreator.java
index b28b2a5..e8bc925 100644
--- a/user/src/com/google/gwt/i18n/rebind/SimpleValueMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/SimpleValueMethodCreator.java
@@ -19,6 +19,7 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
+import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.rebind.AbstractGeneratorClassCreator;
/**
@@ -89,7 +90,8 @@
@Override
public void createMethodFor(TreeLogger logger, JMethod targetMethod,
- String key, ResourceList resource, String locale) throws UnableToCompleteException {
+ String key, ResourceList resource, GwtLocale locale)
+ throws UnableToCompleteException {
String value = resource.getRequiredStringExt(key, null);
try {
String translatedValue = valueCreator.getValue(value);
diff --git a/user/src/com/google/gwt/i18n/server/DefaultLanguageScripts.java b/user/src/com/google/gwt/i18n/server/DefaultLanguageScripts.java
new file mode 100644
index 0000000..1b5c83c
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/server/DefaultLanguageScripts.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2009 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.server;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Encodes the mapping of languages to their default script.
+ */
+public class DefaultLanguageScripts {
+
+ /**
+ * Maps languages to their default script.
+ */
+ private static Map<String, String> defaultScripts;
+
+ static {
+ // From http://www.iana.org/assignments/language-subtag-registry
+ defaultScripts = new HashMap<String, String>();
+ defaultScripts.put("ab", "Cyrl");
+ defaultScripts.put("af", "Latn");
+ defaultScripts.put("am", "Ethi");
+ defaultScripts.put("ar", "Arab");
+ defaultScripts.put("as", "Beng");
+ defaultScripts.put("ay", "Latn");
+ defaultScripts.put("be", "Cyrl");
+ defaultScripts.put("bg", "Cyrl");
+ defaultScripts.put("bn", "Beng");
+ defaultScripts.put("bs", "Latn");
+ defaultScripts.put("ca", "Latn");
+ defaultScripts.put("ch", "Latn");
+ defaultScripts.put("cs", "Latn");
+ defaultScripts.put("cy", "Latn");
+ defaultScripts.put("da", "Latn");
+ defaultScripts.put("de", "Latn");
+ defaultScripts.put("dv", "Thaa");
+ defaultScripts.put("dz", "Tibt");
+ defaultScripts.put("el", "Grek");
+ defaultScripts.put("en", "Latn");
+ defaultScripts.put("eo", "Latn");
+ defaultScripts.put("es", "Latn");
+ defaultScripts.put("et", "Latn");
+ defaultScripts.put("eu", "Latn");
+ defaultScripts.put("fa", "Arab");
+ defaultScripts.put("fi", "Latn");
+ defaultScripts.put("fj", "Latn");
+ defaultScripts.put("fo", "Latn");
+ defaultScripts.put("fr", "Latn");
+ defaultScripts.put("frr", "Latn");
+ defaultScripts.put("fy", "Latn");
+ defaultScripts.put("ga", "Latn");
+ defaultScripts.put("gl", "Latn");
+ defaultScripts.put("gn", "Latn");
+ defaultScripts.put("gu", "Latn");
+ defaultScripts.put("gv", "Latn");
+ defaultScripts.put("he", "Hebr");
+ defaultScripts.put("hi", "Deva");
+ defaultScripts.put("hr", "Latn");
+ defaultScripts.put("ht", "Latn");
+ defaultScripts.put("hu", "Latn");
+ defaultScripts.put("hy", "Armn");
+ defaultScripts.put("id", "Latn");
+ defaultScripts.put("in", "Latn");
+ defaultScripts.put("is", "Latn");
+ defaultScripts.put("it", "Latn");
+ defaultScripts.put("iw", "Hebr");
+ defaultScripts.put("ja", "Jpan");
+ defaultScripts.put("ka", "Geor");
+ defaultScripts.put("kk", "Cyrl");
+ defaultScripts.put("kl", "Latn");
+ defaultScripts.put("km", "Khmr");
+ defaultScripts.put("kn", "Knda");
+ defaultScripts.put("ko", "Kore");
+ defaultScripts.put("la", "Latn");
+ defaultScripts.put("lb", "Latn");
+ defaultScripts.put("ln", "Latn");
+ defaultScripts.put("lo", "Laoo");
+ defaultScripts.put("lt", "Latn");
+ defaultScripts.put("lv", "Latn");
+ defaultScripts.put("mg", "Latn");
+ defaultScripts.put("mh", "Latn");
+ defaultScripts.put("mk", "Cyrl");
+ defaultScripts.put("ml", "Mlym");
+ defaultScripts.put("mo", "Latn");
+ defaultScripts.put("mr", "Deva");
+ defaultScripts.put("ms", "Latn");
+ defaultScripts.put("mt", "Latn");
+ defaultScripts.put("my", "Mymr");
+ defaultScripts.put("na", "Latn");
+ defaultScripts.put("nb", "Latn");
+ defaultScripts.put("nd", "Latn");
+ defaultScripts.put("ne", "Deva");
+ defaultScripts.put("nl", "Latn");
+ defaultScripts.put("nn", "Latn");
+ defaultScripts.put("no", "Latn");
+ defaultScripts.put("nr", "Latn");
+ defaultScripts.put("ny", "Latn");
+ defaultScripts.put("om", "Latn");
+ defaultScripts.put("or", "Latn");
+ defaultScripts.put("pa", "Guru");
+ defaultScripts.put("pl", "Latn");
+ defaultScripts.put("ps", "Arab");
+ defaultScripts.put("pt", "Latn");
+ defaultScripts.put("qu", "Latn");
+ defaultScripts.put("rn", "Latn");
+ defaultScripts.put("ro", "Latn");
+ defaultScripts.put("ru", "Cyrl");
+ defaultScripts.put("rw", "Latn");
+ defaultScripts.put("sg", "Latn");
+ defaultScripts.put("si", "Sinh");
+ defaultScripts.put("sk", "Latn");
+ defaultScripts.put("sl", "Latn");
+ defaultScripts.put("sm", "Latn");
+ defaultScripts.put("so", "Latn");
+ defaultScripts.put("sq", "Latn");
+ defaultScripts.put("ss", "Latn");
+ defaultScripts.put("st", "Latn");
+ defaultScripts.put("sv", "Latn");
+ defaultScripts.put("sw", "Latn");
+ defaultScripts.put("ta", "Taml");
+ defaultScripts.put("te", "Telu");
+ defaultScripts.put("th", "Thai");
+ defaultScripts.put("ti", "Ethi");
+ defaultScripts.put("tl", "Latn");
+ defaultScripts.put("tn", "Latn");
+ defaultScripts.put("to", "Latn");
+ defaultScripts.put("tr", "Latn");
+ defaultScripts.put("ts", "Latn");
+ defaultScripts.put("uk", "Cyrl");
+ defaultScripts.put("ur", "Arab");
+ defaultScripts.put("ve", "Latn");
+ defaultScripts.put("vi", "Latn");
+ defaultScripts.put("wo", "Latn");
+ defaultScripts.put("xh", "Latn");
+ defaultScripts.put("yi", "Hebr");
+ defaultScripts.put("zu", "Latn");
+ defaultScripts.put("dsb", "Latn");
+ defaultScripts.put("frs", "Latn");
+ defaultScripts.put("gsw", "Latn");
+ defaultScripts.put("hsb", "Latn");
+ defaultScripts.put("kok", "Deva");
+ defaultScripts.put("mai", "Deva");
+ defaultScripts.put("men", "Latn");
+ defaultScripts.put("nds", "Latn");
+ defaultScripts.put("niu", "Latn");
+ defaultScripts.put("nqo", "Nkoo");
+ defaultScripts.put("nso", "Latn");
+ defaultScripts.put("tem", "Latn");
+ defaultScripts.put("tkl", "Latn");
+ defaultScripts.put("tmh", "Latn");
+ defaultScripts.put("tpi", "Latn");
+ defaultScripts.put("tvl", "Latn");
+ defaultScripts.put("zbl", "Blis");
+ }
+
+ /**
+ * Returns the default script for a language, or null if none.
+ *
+ * @param language
+ * @return
+ */
+ public static String getDefaultScript(String language) {
+ return defaultScripts.get(language);
+ }
+}
diff --git a/user/src/com/google/gwt/i18n/server/GwtLocaleFactoryImpl.java b/user/src/com/google/gwt/i18n/server/GwtLocaleFactoryImpl.java
new file mode 100644
index 0000000..47b2a93
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/server/GwtLocaleFactoryImpl.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2009 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.server;
+
+import com.google.gwt.i18n.shared.GwtLocale;
+import com.google.gwt.i18n.shared.GwtLocaleFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Creates server-side GwtLocale instances.
+ */
+public class GwtLocaleFactoryImpl implements GwtLocaleFactory {
+
+ // TODO(jat): remove code duplication here by combining these
+ private static boolean isAlpha(String str, int min, int max) {
+ int len = str.length();
+ if (len < min || len > max) {
+ return false;
+ }
+ for (int i = 0; i < len; ++i) {
+ if (!Character.isLetter(str.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean isDigit(String str, int min, int max) {
+ int len = str.length();
+ if (len < min || len > max) {
+ return false;
+ }
+ for (int i = 0; i < len; ++i) {
+ if (!Character.isDigit(str.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static String titleCase(String str) {
+ if (str.length() < 2) {
+ return str.toUpperCase(Locale.ENGLISH);
+ }
+ return String.valueOf(Character.toTitleCase(str.charAt(0))) +
+ str.substring(1).toLowerCase(Locale.ENGLISH);
+ }
+
+ // Locales are stored pointing at themselves. A new instance is created,
+ // which is pretty cheap, then looked up here. If it exists, the old
+ // one is used instead to preserved cached data structures.
+ private Map<GwtLocaleImpl, GwtLocaleImpl> instanceCache = new HashMap<GwtLocaleImpl, GwtLocaleImpl>();
+
+ public GwtLocale fromComponents(String language, String script,
+ String region, String variant) {
+ if (language != null && language.length() == 0) {
+ language = null;
+ }
+ if (language != null) {
+ language = language.toLowerCase(Locale.ENGLISH);
+ }
+ if (script != null && script.length() == 0) {
+ script = null;
+ }
+ if (script != null) {
+ script = titleCase(script);
+ }
+ if (region != null && region.length() == 0) {
+ region = null;
+ }
+ if (region != null) {
+ region = region.toUpperCase(Locale.ENGLISH);
+ }
+ if (variant != null && variant.length() == 0) {
+ variant = null;
+ }
+ if (variant != null) {
+ variant = variant.toUpperCase(Locale.ENGLISH);
+ }
+ GwtLocaleImpl locale = new GwtLocaleImpl(this, language, region, script,
+ variant);
+ if (instanceCache.containsKey(locale)) {
+ return instanceCache.get(locale);
+ }
+ instanceCache.put(locale, locale);
+ return locale;
+ }
+
+ /**
+ * @throws IllegalArgumentException if the supplied locale does not match
+ * BCP47 structural requirements.
+ */
+ public GwtLocale fromString(String localeName) {
+ String language = null;
+ String script = null;
+ String region = null;
+ String variant = null;
+ if (localeName != null && !GwtLocale.DEFAULT_LOCALE.equals(localeName)) {
+ // split into component parts
+ ArrayList<String> localeParts = new ArrayList<String>();
+ String[] parts = localeName.split("[-_]");
+ for (int i = 0; i < parts.length; ++i) {
+ if (parts[i].length() == 1 && i + 1 < parts.length) {
+ localeParts.add(parts[i] + '-' + parts[++i]);
+ } else {
+ localeParts.add(parts[i]);
+ }
+ }
+
+ // figure out the role of each part
+ int partIdx = 1;
+ int numParts = localeParts.size();
+ if (numParts > 0) {
+ // Treat an initial private-use tag as the language tag
+ // Otherwise, language tags are 2-3 characters plus up to three
+ // 3-letter extensions, or 4-8 characters.
+ language = localeParts.get(0);
+ int len = language.length();
+ // TODO: verify language tag length
+ // See if we have extended language tags
+ if ((len == 2 || len == 3) && partIdx < numParts) {
+ String part = localeParts.get(partIdx);
+ while (partIdx < numParts && partIdx < 4
+ && isAlpha(part, 3, 3)) {
+ language += '-' + part;
+ if (++partIdx >= numParts) {
+ break;
+ }
+ part = localeParts.get(partIdx);
+ }
+ }
+ }
+ if (numParts > partIdx
+ && isAlpha(localeParts.get(partIdx), 4, 4)) {
+ // Scripts are exactly 4 letters
+ script = localeParts.get(partIdx++);
+ }
+ if (partIdx < numParts) {
+ // Regions may be 2 letters or 3 digits
+ String part = localeParts.get(partIdx);
+ if (isAlpha(part, 2, 2) || isDigit(part, 3, 3)) {
+ region = part;
+ ++partIdx;
+ }
+ }
+ if (partIdx < numParts) {
+ // Variants are 5-8 alphanum, or 4 alphanum if first is digit
+ String part = localeParts.get(partIdx);
+ int len = part.length();
+ if ((len >= 5 && len <= 8) || (len == 4
+ && Character.isDigit(part.charAt(0)))) {
+ variant = part;
+ ++partIdx;
+ }
+ }
+ if (partIdx < numParts) {
+ throw new IllegalArgumentException("Unrecognized locale format: "
+ + localeName);
+ }
+ }
+ return fromComponents(language, script, region, variant);
+ }
+
+ public GwtLocale getDefault() {
+ return fromComponents(null, null, null, null);
+ }
+
+}
diff --git a/user/src/com/google/gwt/i18n/server/GwtLocaleImpl.java b/user/src/com/google/gwt/i18n/server/GwtLocaleImpl.java
new file mode 100644
index 0000000..448512b
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/server/GwtLocaleImpl.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2009 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.server;
+
+import com.google.gwt.i18n.shared.GwtLocale;
+import com.google.gwt.i18n.shared.GwtLocaleFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Class representing GWT locales and conversion to/from other formats.
+ *
+ * These locales correspond to BCP47.
+ */
+public class GwtLocaleImpl implements GwtLocale {
+ // TODO(jat): implement a version of this suitable for client-side use,
+ // probably using a generator to include only the information relevant to
+ // the set of locales supported, and then figure out a way to get that into
+ // the property provider to handle inheritance there.
+
+ /**
+ * Add in the missing locale of a deprecated pair.
+ *
+ * @param factory GwtLocaleFactory to create new instances with
+ * @param locale locale to add deprecated pair for
+ * @param aliases where to store the alias if present
+ */
+ private static void addDeprecatedPairs(GwtLocaleFactory factory,
+ GwtLocale locale, List<GwtLocale> aliases) {
+ if ("he".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("iw", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ } else if ("iw".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("he", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ } else if ("id".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("in", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ } else if ("in".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("id", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ } else if ("mo".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("ro", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ } else if ("ro".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("mo", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ } else if ("jv".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("jw", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ } else if ("jw".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("jv", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ } else if ("ji".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("yi", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ } else if ("yi".equals(locale.getLanguage())) {
+ aliases.add(factory.fromComponents("ji", locale.getScript(),
+ locale.getRegion(), locale.getVariant()));
+ }
+ }
+
+ private static void addImmediateParentRegions(GwtLocaleFactory factory,
+ GwtLocale locale, Collection<GwtLocale> work) {
+ String language = locale.getLanguage();
+ String script = locale.getScript();
+ String region = locale.getRegion();
+ String variant = locale.getVariant();
+ if (variant != null) {
+ work.add(factory.fromComponents(language, script, region, null));
+ }
+ Set<String> immediateParents = RegionInheritance.getImmediateParents(region);
+ for (String parent : immediateParents) {
+ work.add(factory.fromComponents(language, script, parent, variant));
+ if (variant != null) {
+ work.add(factory.fromComponents(language, script, parent, null));
+ }
+ }
+ if (immediateParents.isEmpty()) {
+ work.add(factory.fromComponents(language, script, null, variant));
+ if (variant != null) {
+ work.add(factory.fromComponents(language, script, null, null));
+ }
+ }
+ if (script != null) {
+ work.add(factory.fromComponents(language, null, region, variant));
+ if (variant != null) {
+ work.add(factory.fromComponents(language, null, region, null));
+ }
+ }
+ }
+
+ /**
+ * Add inherited regions for a given locale.
+ *
+ * @param factory
+ * @param inherits
+ * @param language
+ * @param script
+ * @param region
+ * @param variant
+ */
+ private static void addParentRegionLocales(GwtLocaleFactory factory,
+ List<GwtLocale> inherits, String language, String script, String region,
+ String variant) {
+ for (String parent : RegionInheritance.getAllAncestors(region)) {
+ inherits.add(factory.fromComponents(language, script, parent, variant));
+ }
+ }
+
+ /**
+ * Add special aliases for a given locale.
+ *
+ * This includes things like choosing the default script/region for Chinese
+ * based on the other one, handling Norwegian language changes, and treating
+ * pt_BR as the default pt type.
+ *
+ * @param factory GwtLocaleFactory to create new instances with
+ * @param locale locale to add deprecated pair for
+ * @param aliases where to store the alias if present
+ */
+ private static void addSpecialAliases(GwtLocaleFactory factory,
+ GwtLocale locale, List<GwtLocale> aliases) {
+ String language = locale.getLanguage();
+ String script = locale.getScript();
+ String region = locale.getRegion();
+ String variant = locale.getVariant();
+ if ("zh".equals(language)) {
+ if (script == null) {
+ // infer script from region
+ if ("TW".equals(region)) {
+ aliases.add(factory.fromComponents("zh", "Hant", region, variant));
+ } else if ("CN".equals(region)) {
+ aliases.add(factory.fromComponents("zh", "Hans", region, variant));
+ }
+ } else {
+ if (region == null) {
+ // Add aliases for main users of particular scripts
+ aliases.add(factory.fromComponents("zh", script,
+ "Hant".equals(script) ? "TW" : "CN", variant));
+ }
+ }
+ } else if ("no".equals(language)) {
+ if ("BOKMAL".equals(variant)) {
+ aliases.add(factory.fromComponents("nb", script, region, null));
+ } else if ("NYNORSK".equals(variant)) {
+ aliases.add(factory.fromComponents("nn", script, region, null));
+ }
+ } else if ("nb".equals(language)) {
+ aliases.add(factory.fromComponents("no", script, region, "BOKMAL"));
+ } else if ("nn".equals(language)) {
+ aliases.add(factory.fromComponents("no", script, region, "NYNORSK"));
+ } else if ("pt".equals(language)) {
+ if (region == null) {
+ aliases.add(factory.fromComponents("pt", script, "BR", variant));
+ } else if ("BR".equals(region)) {
+ aliases.add(factory.fromComponents("pt", script, null, variant));
+ }
+ }
+ }
+
+ private static boolean equalsNullCheck(String str1, String str2) {
+ if (str1 == null) {
+ return str2 == null;
+ }
+ return str1.equals(str2);
+ }
+
+ /**
+ * Compare strings, accounting for nulls (which are treated as before any
+ * other value).
+ *
+ * @param a first string
+ * @param b second string
+ *
+ * @return positive if a>b, negative if a<b, 0 if equal
+ */
+ private static int stringCompare(String a, String b) {
+ if (a == null) {
+ return b == null ? 0 : -1;
+ }
+ if (b == null) {
+ return 1;
+ }
+ return a.compareTo(b);
+ }
+
+ private final GwtLocaleFactory factory;
+
+ private final String language;
+
+ private final String region;
+
+ private final String script;
+
+ private final String variant;
+
+ private ArrayList<GwtLocale> cachedSearchList;
+
+ private ArrayList<GwtLocale> cachedAliases;
+
+ /**
+ * Must only be called from a factory to preserve instance caching.
+ */
+ GwtLocaleImpl(GwtLocaleFactory factory, String language, String region,
+ String script, String variant) {
+ this.factory = factory;
+ this.language = language;
+ this.region = region;
+ this.script = script;
+ this.variant = variant;
+ }
+
+ public int compareTo(GwtLocale o) {
+ int c = stringCompare(language, o.getLanguage());
+ if (c == 0) {
+ c = stringCompare(script, o.getScript());
+ }
+ if (c == 0) {
+ c = stringCompare(region, o.getRegion());
+ }
+ if (c == 0) {
+ c = stringCompare(variant, o.getVariant());
+ }
+ return c;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof GwtLocale)) {
+ return false;
+ }
+ GwtLocale other = (GwtLocale) obj;
+ return equalsNullCheck(language, other.getLanguage())
+ && equalsNullCheck(region, other.getRegion())
+ && equalsNullCheck(script, other.getScript())
+ && equalsNullCheck(variant, other.getVariant());
+ }
+
+ public List<GwtLocale> getAliases() {
+ // TODO(jat): more locale aliases? better way to encode them?
+ if (cachedAliases == null) {
+ cachedAliases = new ArrayList<GwtLocale>();
+ Set<GwtLocale> seen = new HashSet<GwtLocale>();
+ ArrayList<GwtLocale> nextGroup = new ArrayList<GwtLocale>();
+ nextGroup.add(this);
+ // Account for default script
+ String defaultScript = DefaultLanguageScripts.getDefaultScript(language);
+ if (defaultScript != null) {
+ if (script == null) {
+ nextGroup.add(factory.fromComponents(language, defaultScript, region,
+ variant));
+ } else if (script.equals(defaultScript)) {
+ nextGroup.add(factory.fromComponents(language, null, region, variant));
+ }
+ }
+ while (!nextGroup.isEmpty()) {
+ List<GwtLocale> thisGroup = nextGroup;
+ nextGroup = new ArrayList<GwtLocale>();
+ for (GwtLocale locale : thisGroup) {
+ if (seen.contains(locale)) {
+ continue;
+ }
+ seen.add(locale);
+ cachedAliases.add(locale);
+ addDeprecatedPairs(factory, locale, nextGroup);
+ addSpecialAliases(factory, locale, nextGroup);
+ }
+ }
+ }
+ return Collections.unmodifiableList(cachedAliases);
+ }
+
+ public String getAsString() {
+ StringBuilder buf = new StringBuilder();
+ if (language != null) {
+ buf.append(language);
+ }
+ if (script != null) {
+ buf.append('_');
+ buf.append(script);
+ }
+ if (region != null) {
+ buf.append('_');
+ buf.append(region);
+ }
+ if (variant != null) {
+ buf.append('_');
+ buf.append(variant);
+ }
+ return buf.toString();
+ }
+
+ public List<GwtLocale> getCompleteSearchList() {
+ // TODO(jat): get zh_Hant to come before zh in search list for zh_TW
+ if (cachedSearchList == null) {
+ cachedSearchList = new ArrayList<GwtLocale>();
+ Set<GwtLocale> seen = new HashSet<GwtLocale>();
+ List<GwtLocale> thisGroup = new ArrayList<GwtLocale>(this.getAliases());
+ seen.addAll(thisGroup);
+ GwtLocale defLocale = factory.getDefault();
+ seen.add(defLocale);
+ while (!thisGroup.isEmpty()) {
+ cachedSearchList.addAll(thisGroup);
+ List<GwtLocale> nextGroup = new ArrayList<GwtLocale>();
+ for (GwtLocale locale : thisGroup) {
+ List<GwtLocale> work = new ArrayList<GwtLocale>(locale.getAliases());
+ work.removeAll(seen);
+ nextGroup.addAll(work);
+ seen.addAll(work);
+ work.clear();
+ if (locale.getRegion() != null) {
+ addImmediateParentRegions(factory, locale, work);
+ } else if (locale.getVariant() != null) {
+ work.add(factory.fromComponents(locale.getLanguage(),
+ locale.getScript(), null, null));
+ } else if (locale.getScript() != null) {
+ work.add(factory.fromComponents(locale.getLanguage(), null, null,
+ null));
+ }
+ work.removeAll(seen);
+ nextGroup.addAll(work);
+ seen.addAll(work);
+ }
+ thisGroup = nextGroup;
+ }
+ cachedSearchList.add(defLocale);
+ }
+ return cachedSearchList;
+ }
+
+ /**
+ * Return a list of locales to search for, in order of preference. The
+ * current locale is always first on the list. Aliases are not included
+ * in the list -- use {@link #getAliases} to expand those.
+ *
+ * @return inheritance list
+ */
+ public List<GwtLocale> getInheritanceChain() {
+ List<GwtLocale> inherits = new ArrayList<GwtLocale>();
+ inherits.add(this);
+ if (variant != null) {
+ inherits.add(factory.fromComponents(language, script, region, null));
+ }
+ if (region != null) {
+ addParentRegionLocales(factory, inherits, language, script, region,
+ null);
+ inherits.add(factory.fromComponents(language, script, null, null));
+ }
+ if (script != null) {
+ inherits.add(factory.fromComponents(language, null, region, null));
+ addParentRegionLocales(factory, inherits, language, null, region, null);
+ if (region != null) {
+ inherits.add(factory.fromComponents(language, null, null, null));
+ }
+ }
+ if (language != null) {
+ inherits.add(factory.fromComponents(null, null, null, null));
+ }
+ return inherits;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getLanguageNotNull() {
+ return language == null ? "" : language;
+ }
+
+ public String getRegion() {
+ return region;
+ }
+
+ public String getRegionNotNull() {
+ return region == null ? "" : region;
+ }
+
+ public String getScript() {
+ return script;
+ }
+
+ public String getScriptNotNull() {
+ return script == null ? "" : script;
+ }
+
+ public String getVariant() {
+ return variant;
+ }
+
+ public String getVariantNotNull() {
+ return variant == null ? "" : variant;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = ((language == null) ? 0 : language.hashCode());
+ result = 37 * result + ((region == null) ? 0 : region.hashCode());
+ result = 43 * result + ((script == null) ? 0 : script.hashCode());
+ result = 53 * result + ((variant == null) ? 0 : variant.hashCode());
+ return result;
+ }
+
+ /**
+ * Return true if this locale inherits from the specified locale. Note that
+ * locale.inheritsFrom(locale) is false -- if you want that to be true, you
+ * should just use locale.getInheritanceChain().contains(x).
+ *
+ * @param parent locale to test against
+ * @return true if parent is an ancestor of this locale
+ */
+ public boolean inheritsFrom(GwtLocale parent) {
+ if (equals(parent)) {
+ return false;
+ }
+ return getInheritanceChain().contains(parent);
+ }
+
+ public boolean isDefault() {
+ return language == null;
+ }
+
+ @Override
+ public String toString() {
+ if (language == null) {
+ return DEFAULT_LOCALE;
+ }
+ return getAsString();
+ }
+
+ /**
+ * Checks if this locale uses the same script as another locale, taking into
+ * account default scripts.
+ *
+ * @param other
+ * @return true if the scripts are the same
+ */
+ public boolean usesSameScript(GwtLocale other) {
+ // The number of aliases is very small, so n^2 isn't a problem here.
+ List<GwtLocale> myAliases = getAliases();
+ List<GwtLocale> otherAliases = other.getAliases();
+ for (GwtLocale alias : myAliases) {
+ for (GwtLocale otherAlias : otherAliases) {
+ if (equalsNullCheck(alias.getScript(), otherAlias.getScript())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/user/src/com/google/gwt/i18n/server/RegionInheritance.java b/user/src/com/google/gwt/i18n/server/RegionInheritance.java
new file mode 100644
index 0000000..55ae583
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/server/RegionInheritance.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2009 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.server;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Generated maps of regions into parent regions, used for locale inheritance.
+ *
+ * TODO(jat): make this actually be generated.
+ */
+public class RegionInheritance {
+
+ private static Map<String, String> parentRegionMap;
+
+ static {
+ // TODO(jat): add support for multiple parent regions
+ parentRegionMap = new HashMap<String, String>();
+ // Data from CLDR supplementalData/territoryContainment
+ // manually edited to remove multiple parents and non-UN data
+ addChildren("001", "002", "009", "019", "142", "150"); // World
+ addChildren("011", "BF", "BJ", "CI", "CV", "GH", "GM", "GN", "GW", "LR",
+ "ML", "MR", "NE", "NG", "SH", "SL", "SN", "TG"); // Western", "Africa
+ addChildren("013", "BZ", "CR", "GT", "HN", "MX", "NI", "PA",
+ "SV"); // Central America
+ addChildren("014", "BI", "DJ", "ER", "ET", "KE", "KM", "MG", "MU", "MW",
+ "MZ", "RE", "RW", "SC", "SO", "TZ", "UG", "YT", "ZM",
+ "ZW"); // Eastern Africa
+ addChildren("142", "030", "035", "143", "145", "034", "062"); // Asia
+ addChildren("143", "TM", "TJ", "KG", "KZ", "UZ"); // Central Asia
+ addChildren("145", "AE", "AM", "AZ", "BH", "CY", "GE", "IL", "IQ", "JO",
+ "KW", "LB", "OM", "PS", "QA", "SA", "NT", "SY", "TR", "YE",
+ "YD"); // Western Asia
+ addChildren("015", "DZ", "EG", "EH", "LY", "MA", "SD",
+ "TN"); //Northern Africa
+ addChildren("150", "039", "151", "154", "155"); // Europe
+ addChildren("151", "BG", "BY", "CZ", "HU", "MD", "PL", "RO", "RU", "SU",
+ "SK", "UA"); // Eastern Europe
+ addChildren("154", "GG", "JE", "AX", "DK", "EE", "FI", "FO", "GB",
+ "IE", "IM", "IS", "LT", "LV", "NO", "SE", "SJ"); // Northern Europe
+ addChildren("155", "AT", "BE", "CH", "DE", "DD", "FR", "FX", "LI", "LU",
+ "MC", "NL"); // Western Europe
+ addChildren("017", "AO", "CD", "ZR", "CF", "CG", "CM", "GA", "GQ", "ST",
+ "TD"); // Middle Africa
+ addChildren("018", "BW", "LS", "NA", "SZ", "ZA"); // Southern Africa
+ addChildren("019", "021", "419"); // Americas
+ addChildren("002", "011", "014", "015", "017", "018"); // Africa
+ addChildren("021", "BM", "CA", "GL", "PM", "US"); // Northern America
+ addChildren("029", "AG", "AI", "AN", "AW", "BB", "BL", "BS", "CU", "DM",
+ "DO", "GD", "GP", "HT", "JM", "KN", "KY", "LC", "MF", "MQ", "MS", "PR",
+ "TC", "TT", "VC", "VG", "VI"); // Caribbean
+ addChildren("030", "CN", "HK", "JP", "KP", "KR", "MN", "MO",
+ "TW"); // Eastern Asia
+ addChildren("035", "BN", "ID", "KH", "LA", "MM", "BU", "MY", "PH", "SG",
+ "TH", "TL", "TP", "VN"); // South-Eastern Asia
+ addChildren("039", "AD", "AL", "BA", "ES", "GI", "GR", "HR", "IT", "ME",
+ "MK", "MT", "CS", "RS", "PT", "SI", "SM", "VA",
+ "YU"); // Southern Europe
+ addChildren("419", "005", "013", "029"); //Latin America and the Caribbean
+ addChildren("005", "AR", "BO", "BR", "CL", "CO", "EC", "FK", "GF", "GY",
+ "PE", "PY", "SR", "UY", "VE"); // South America
+ addChildren("053", "AU", "NF", "NZ"); // Australia and New Zealand
+ addChildren("054", "FJ", "NC", "PG", "SB", "VU"); // Melanesia
+ addChildren("057", "FM", "GU", "KI", "MH", "MP", "NR", "PW"); // Micronesia
+ addChildren("061", "AS", "CK", "NU", "PF", "PN", "TK", "TO", "TV", "WF",
+ "WS"); // Polynesia
+ addChildren("034", "AF", "BD", "BT", "IN", "IR", "LK", "MV", "NP",
+ "PK"); // Southern Asia
+ addChildren("009", "053", "054", "057", "061", "QO"); // Oceania
+ addChildren("QO", "AQ", "BV", "CC", "CX", "GS", "HM", "IO", "TF",
+ "UM"); // Outlying Oceania
+ }
+
+ /**
+ * Finds the first region which is a common parent of two regions. If either
+ * region is null or if there is no common parent, returns null. Otherwise,
+ * returns the region which contains both regions.
+ *
+ * @param region1
+ * @param region2
+ * @return common parent or null if none
+ */
+ public static String findCommonParent(String region1, String region2) {
+ if (region1 == null || region2 == null) {
+ return null;
+ }
+ List<String> parents1 = new ArrayList<String>();
+ for (String parent = region1; parent != null;
+ parent = parentRegionMap.get(parent)) {
+ parents1.add(parent);
+ }
+ for (String parent = region2; parent != null;
+ parent = parentRegionMap.get(parent)) {
+ if (parents1.contains(parent)) {
+ return parent;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a set of all ancestors of a given region, including the region
+ * itself, in order of inheritance (ie, this region first, top-most region
+ * last).
+ *
+ * @param child
+ * @return list of ancestors
+ */
+ public static List<String> getAllAncestors(String child) {
+ List<String> returnVal = new ArrayList<String>();
+ Set<String> nextGroup = new HashSet<String>();
+ if (child != null) {
+ nextGroup.add(child);
+ }
+ while (!nextGroup.isEmpty()) {
+ Set<String> ancestors = new HashSet<String>();
+ for (String region : nextGroup) {
+ ancestors.addAll(getImmediateParents(region));
+ }
+ ancestors.removeAll(returnVal);
+ nextGroup.clear();
+ nextGroup.addAll(ancestors);
+ returnVal.addAll(ancestors);
+ }
+ return returnVal;
+ }
+
+ /**
+ * Returns the set of immediate parents of a given region, not including
+ * this region.
+ *
+ * @param region
+ * @return set of immediate parents
+ */
+ public static Set<String> getImmediateParents(String region) {
+ Set<String> returnVal = new HashSet<String>();
+ if (parentRegionMap.containsKey(region)) {
+ returnVal.add(parentRegionMap.get(region));
+ }
+ return returnVal;
+ }
+
+ /**
+ * Returns true if parent is equal to the child or is an ancestor. If both
+ * are null, true is returned; otherwise if either is null false is returned.
+ *
+ * @param parent
+ * @param child
+ * @return true if parent is an ancestor of child
+ */
+ public static boolean isParentOf(String parent, String child) {
+ if (parent == child) {
+ return true;
+ }
+ while (child != null) {
+ if (child.equals(parent)) {
+ return true;
+ }
+ child = parentRegionMap.get(child);
+ }
+ return false;
+ }
+
+ // @VisibleForTesting
+ static Map<String, String> getInheritanceMap() {
+ return parentRegionMap;
+ }
+
+ private static void addChildren(String parent, String... children) {
+ for (String child : children) {
+ String oldParent = parentRegionMap.put(child, parent);
+ assert oldParent == null;
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/i18n/shared/GwtLocale.java b/user/src/com/google/gwt/i18n/shared/GwtLocale.java
new file mode 100644
index 0000000..35ca036
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/shared/GwtLocale.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2009 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.shared;
+
+import java.util.List;
+
+/**
+ * Class representing GWT locales and conversion to/from other formats.
+ *
+ * These locales correspond to BCP47.
+ */
+public interface GwtLocale extends Comparable<GwtLocale> {
+
+ String DEFAULT_LOCALE = "default";
+
+ /**
+ * The default comparison is a lexical ordering.
+ */
+ int compareTo(GwtLocale o);
+
+ /**
+ * Return the list of aliases for this locale. The current locale is always
+ * first on the list.
+ *
+ * Language/region codes have changed over time, so some systems continue to
+ * use the older codes. Aliases allow GWT to use the official Unicode CLDR
+ * locales while still interoperating with such systems.
+ *
+ * @return alias list
+ */
+ List<GwtLocale> getAliases();
+
+ String getAsString();
+
+ List<GwtLocale> getCompleteSearchList();
+
+ /**
+ * Return a list of locales to search for, in order of preference. The
+ * current locale is always first on the list. Aliases are not included
+ * in the list -- use {@link #getAliases} to expand those.
+ *
+ * @return inheritance list
+ */
+ List<GwtLocale> getInheritanceChain();
+
+ String getLanguage();
+
+ String getLanguageNotNull();
+
+ String getRegion();
+
+ String getRegionNotNull();
+
+ String getScript();
+
+ String getScriptNotNull();
+
+ String getVariant();
+
+ String getVariantNotNull();
+
+ /**
+ * Return true if this locale inherits from the specified locale. Note that
+ * locale.inheritsFrom(locale) is false -- if you want that to be true, you
+ * should just use locale.getInheritanceChain().contains(x).
+ *
+ * @param parent locale to test against
+ * @return true if parent is an ancestor of this locale
+ */
+ boolean inheritsFrom(GwtLocale parent);
+
+ boolean isDefault();
+
+ String toString();
+
+ /**
+ * Checks if this locale uses the same script as another locale.
+ *
+ * @param other
+ * @return true if the scripts are the same
+ */
+ boolean usesSameScript(GwtLocale other);
+}
diff --git a/user/src/com/google/gwt/i18n/shared/GwtLocaleFactory.java b/user/src/com/google/gwt/i18n/shared/GwtLocaleFactory.java
new file mode 100644
index 0000000..dc5a47e
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/shared/GwtLocaleFactory.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2009 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.shared;
+
+/**
+ * Factories that know how to create GwtLocale instances.
+ */
+public interface GwtLocaleFactory {
+
+ /**
+ * Construct a GWT locale from its component parts.
+ *
+ * Null or empty strings are accepted for parts not present.
+ *
+ * @param language
+ * @param script
+ * @param region
+ * @param variant
+ * @return GwtLocale instance, unique for a given set of values
+ */
+ GwtLocale fromComponents(String language, String script, String region,
+ String variant);
+
+ /**
+ * Get a GWT locale from a string conforming to a subset of BCP47
+ * (specifically assuming extension tags are not present, at most
+ * one variant is present, and grandfathered tags are not supported;
+ * also private-use tags are only supported for the entire tag).
+ * Only minimal validation of BCP47 tags is performed, and will continue
+ * with what it is able to parse if unexpected input is encountered.
+ *
+ * A null or empty string is treated as the default locale.
+ *
+ * @param localeName
+ * @return a locale instance, always the same one for a given localeName
+ */
+ GwtLocale fromString(String localeName);
+
+ /**
+ * @return an instance of the default locale.
+ */
+ GwtLocale getDefault();
+}
diff --git a/user/src/com/google/gwt/json/client/JSONObject.java b/user/src/com/google/gwt/json/client/JSONObject.java
index bb6867a..77080a3 100644
--- a/user/src/com/google/gwt/json/client/JSONObject.java
+++ b/user/src/com/google/gwt/json/client/JSONObject.java
@@ -17,6 +17,7 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsonUtils;
import java.util.AbstractSet;
import java.util.ArrayList;
@@ -178,7 +179,7 @@
} else {
sb.append(", ");
}
- sb.append(JSONString.escapeValue(key));
+ sb.append(JsonUtils.escapeValue(key));
sb.append(":");
sb.append(get(key));
}
diff --git a/user/src/com/google/gwt/json/client/JSONString.java b/user/src/com/google/gwt/json/client/JSONString.java
index 5ad02d0..abdb44d 100644
--- a/user/src/com/google/gwt/json/client/JSONString.java
+++ b/user/src/com/google/gwt/json/client/JSONString.java
@@ -16,39 +16,13 @@
package com.google.gwt.json.client;
import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsonUtils;
/**
* Represents a JSON string.
*/
public class JSONString extends JSONValue {
- static JavaScriptObject escapeTable = initEscapeTable();
-
- static native String escapeChar(String c) /*-{
- var lookedUp = @com.google.gwt.json.client.JSONString::escapeTable[c.charCodeAt(0)];
- return (lookedUp == null) ? c : lookedUp;
- }-*/;
-
- static native String escapeValue(String toEscape) /*-{
- var s = toEscape.replace(/[\x00-\x1F"\\]/g, function(x) {
- return @com.google.gwt.json.client.JSONString::escapeChar(Ljava/lang/String;)(x);
- });
- return "\"" + s + "\"";
- }-*/;
-
- private static native JavaScriptObject initEscapeTable() /*-{
- var out = [
- "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005",
- "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000B",
- "\\f", "\\r", "\\u000E", "\\u000F", "\\u0010", "\\u0011",
- "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017",
- "\\u0018", "\\u0019", "\\u001A", "\\u001B", "\\u001C", "\\u001D",
- "\\u001E", "\\u001F"];
- out[34] = '\\"';
- out[92] = '\\\\';
- return out;
- }-*/;
-
/**
* Called from {@link #getUnwrapper()}.
*/
@@ -107,7 +81,7 @@
*/
@Override
public String toString() {
- return escapeValue(value);
+ return JsonUtils.escapeValue(value);
}
@Override
diff --git a/user/src/com/google/gwt/junit/JUnitMessageQueue.java b/user/src/com/google/gwt/junit/JUnitMessageQueue.java
index 373d004..e45ac3f 100644
--- a/user/src/com/google/gwt/junit/JUnitMessageQueue.java
+++ b/user/src/com/google/gwt/junit/JUnitMessageQueue.java
@@ -88,6 +88,17 @@
}
/**
+ * Gets a human-readable string.
+ * @return Fetches a human-readable representation of the current test object
+ */
+ public String getCurrentTestName() {
+ if (currentTest == null) {
+ return "(no test)";
+ }
+ return currentTest.toString();
+ }
+
+ /**
* Called by the servlet to query for for the next method to test.
*
* @param timeout how long to wait for an answer
@@ -135,6 +146,39 @@
}
/**
+ * Returns a human-formatted message identifying what clients have connected
+ * but have not yet reported results for this test. It is used in a timeout
+ * condition, to identify what we're still waiting on.
+ *
+ * @return human readable message
+ */
+ public String getWorkingClients() {
+ synchronized (clientStatusesLock) {
+ StringBuilder buf = new StringBuilder();
+ int itemCount = 0;
+ for (ClientStatus clientStatus : clientStatuses.values()) {
+ if (clientStatus.hasRequestedCurrentTest
+ && clientStatus.currentTestResults == null) {
+ if (itemCount > 0) {
+ buf.append(", ");
+ }
+ buf.append(clientStatus.clientId);
+ ++itemCount;
+ }
+ }
+ int difference = numClients - itemCount;
+ if (difference > 0) {
+ if (itemCount > 0) {
+ buf.append('\n');
+ }
+ buf.append(difference +
+ " other client(s) haven't responded back to JUnitShell since the start of the test.");
+ }
+ return buf.toString();
+ }
+ }
+
+ /**
* Called by the servlet to report the results of the last test to run.
*
* @param testInfo the testInfo the result is for
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index 9e06b9e..700acd4 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -311,11 +311,19 @@
/**
* The amount of time to wait for all clients to have contacted the server and
- * begin running the test.
+ * begin running the test. "Contacted" does not necessarily mean "the test
+ * has begun," e.g. for linker errors stopping the test initialization.
*/
private static final int TEST_BEGIN_TIMEOUT_MILLIS = 60000;
/**
+ * The amount of time to wait for all clients to complete a single test
+ * method, in milliseconds, measured from when the <i>last</i> client
+ * connects (and thus starts the test). 5 minutes.
+ */
+ private static final long TEST_METHOD_TIMEOUT_MILLIS = 300000;
+
+ /**
* Singleton object for hosting unit tests. All test case instances executed
* by the TestRunner will use the single unitTestShell.
*/
@@ -476,6 +484,14 @@
private long testBeginTimeout;
/**
+ * Timeout for individual test method. If System.currentTimeMillis() is later
+ * than this timestamp, then we need to pack up and go home. Zero for "not
+ * yet set" (at the start of a test). This interval begins when the
+ * testBeginTimeout interval is done.
+ */
+ private long testMethodTimeout;
+
+ /**
* Enforce the singleton pattern. The call to {@link GWTShell}'s ctor forces
* server mode and disables processing extra arguments as URLs to be shown.
*/
@@ -546,6 +562,17 @@
* clients have transitioned to the current module.
*/
lastModule = currentModule;
+ if (testMethodTimeout == 0) {
+ testMethodTimeout = currentTimeMillis + TEST_METHOD_TIMEOUT_MILLIS;
+ } else if (testMethodTimeout < currentTimeMillis) {
+ double elapsed = (currentTimeMillis - testBeginTime) / 1000.0;
+ throw new TimeoutException(
+ "The browser did not complete the test method "
+ + messageQueue.getCurrentTestName() + " in "
+ + TEST_METHOD_TIMEOUT_MILLIS + "ms.\n We have no results from: "
+ + messageQueue.getWorkingClients()
+ + "\n Actual time elapsed: " + elapsed + " seconds.\n");
+ }
} else if (testBeginTimeout < currentTimeMillis) {
double elapsed = (currentTimeMillis - testBeginTime) / 1000.0;
throw new TimeoutException(
@@ -649,6 +676,7 @@
// contacted; something probably went wrong (the module failed to load?)
testBeginTime = System.currentTimeMillis();
testBeginTimeout = testBeginTime + TEST_BEGIN_TIMEOUT_MILLIS;
+ testMethodTimeout = 0; // wait until test execution begins
pumpEventLoop();
} catch (TimeoutException e) {
lastLaunchFailed = true;
diff --git a/user/src/com/google/gwt/junit/client/GWTTestCase.java b/user/src/com/google/gwt/junit/client/GWTTestCase.java
index 9c8fa25..ab71cf0 100644
--- a/user/src/com/google/gwt/junit/client/GWTTestCase.java
+++ b/user/src/com/google/gwt/junit/client/GWTTestCase.java
@@ -216,6 +216,10 @@
*/
@Override
protected void runTest() throws Throwable {
+ if (this.getName() == null) {
+ throw new IllegalArgumentException("GWTTestCases require a name; \"" + this.toString()
+ + "\" has none. Perhaps you used TestSuite.addTest() instead of addTestClass()?");
+ }
JUnitShell.runTest(getModuleName(), this, testResult);
}
diff --git a/user/src/com/google/gwt/junit/rebind/GWTRunnerGenerator.java b/user/src/com/google/gwt/junit/rebind/GWTRunnerGenerator.java
index b4ed8af..7058dd5 100644
--- a/user/src/com/google/gwt/junit/rebind/GWTRunnerGenerator.java
+++ b/user/src/com/google/gwt/junit/rebind/GWTRunnerGenerator.java
@@ -166,6 +166,8 @@
sw.println();
sw.println("protected final GWTTestCase createNewTestCase(String testClass) {");
sw.indent();
+ sw.println("try {");
+ sw.indent();
boolean isFirst = true;
for (String className : testClasses) {
if (isFirst) {
@@ -178,6 +180,11 @@
sw.indentln("return GWT.create(" + className + ".class);");
sw.println("}");
}
+ sw.outdent();
+ sw.println("} catch (Throwable t) {");
+ sw.indentln("// Crash in a useful manner");
+ sw.indentln("GWT.log(\"Unable to construct TestCase: \" + testClass, t);");
+ sw.println("}");
sw.println("return null;");
sw.outdent();
sw.println("}");
diff --git a/user/src/com/google/gwt/user/AsyncProxy.gwt.xml b/user/src/com/google/gwt/user/AsyncProxy.gwt.xml
new file mode 100644
index 0000000..5cc92d2
--- /dev/null
+++ b/user/src/com/google/gwt/user/AsyncProxy.gwt.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <!--
+ 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.
+ -->
+
+<module>
+ <generate-with class="com.google.gwt.user.rebind.AsyncProxyGenerator">
+ <when-type-assignable class="com.google.gwt.user.client.AsyncProxy" />
+ </generate-with>
+</module>
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/FileUpload.gwt.xml b/user/src/com/google/gwt/user/FileUpload.gwt.xml
new file mode 100644
index 0000000..56cfadd
--- /dev/null
+++ b/user/src/com/google/gwt/user/FileUpload.gwt.xml
@@ -0,0 +1,28 @@
+<!-- -->
+<!-- Copyright 2007 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<!-- Deferred binding rules for FileUpload. -->
+<!-- -->
+<!-- This module is typically inherited via com.google.gwt.user.User -->
+<!-- -->
+<module>
+ <inherits name="com.google.gwt.core.Core"/>
+ <inherits name="com.google.gwt.user.UserAgent"/>
+
+ <!-- Opera fires change events on every character typed -->
+ <replace-with class="com.google.gwt.user.client.ui.FileUpload.FileUploadImplOpera">
+ <when-type-is class="com.google.gwt.user.client.ui.FileUpload.FileUploadImpl"/>
+ <when-property-is name="user.agent" value="opera"/>
+ </replace-with>
+</module>
diff --git a/user/src/com/google/gwt/user/HTTPRequest.gwt.xml b/user/src/com/google/gwt/user/HTTPRequest.gwt.xml
index 3401614..f0f5133 100644
--- a/user/src/com/google/gwt/user/HTTPRequest.gwt.xml
+++ b/user/src/com/google/gwt/user/HTTPRequest.gwt.xml
@@ -18,16 +18,5 @@
<!-- -->
<module>
<inherits name="com.google.gwt.core.Core"/>
- <inherits name="com.google.gwt.user.UserAgent"/>
-
- <!-- Fall through to this rule is the browser isn't IE -->
- <replace-with class="com.google.gwt.user.client.impl.HTTPRequestImpl">
- <when-type-is class="com.google.gwt.user.client.impl.HTTPRequestImpl"/>
- </replace-with>
-
- <!-- IE differs slightly in how XmlHttpRequest gets instantiated -->
- <replace-with class="com.google.gwt.user.client.impl.HTTPRequestImplIE6">
- <when-type-is class="com.google.gwt.user.client.impl.HTTPRequestImpl"/>
- <when-property-is name="user.agent" value="ie6"/>
- </replace-with>
+ <inherits name="com.google.gwt.xhr.XMLHttpRequest"/>
</module>
diff --git a/user/src/com/google/gwt/user/RemoteService.gwt.xml b/user/src/com/google/gwt/user/RemoteService.gwt.xml
index 32649e5..d067669 100644
--- a/user/src/com/google/gwt/user/RemoteService.gwt.xml
+++ b/user/src/com/google/gwt/user/RemoteService.gwt.xml
@@ -30,6 +30,11 @@
-->
<set-property name="gwt.suppressNonStaticFinalFieldWarnings" value="false" />
+ <!--
+ If this is ever turned on by default, fix up RPCSuiteWithElision
+ -->
+ <set-configuration-property name="gwt.elideTypeNamesFromRPC" value="false" />
+
<generate-with class="com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator">
<when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService"/>
</generate-with>
diff --git a/user/src/com/google/gwt/user/RemoteServiceObfuscateTypeNames.gwt.xml b/user/src/com/google/gwt/user/RemoteServiceObfuscateTypeNames.gwt.xml
new file mode 100644
index 0000000..db872dd
--- /dev/null
+++ b/user/src/com/google/gwt/user/RemoteServiceObfuscateTypeNames.gwt.xml
@@ -0,0 +1,28 @@
+<!-- -->
+<!-- Copyright 2009 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<!--
+ Inheriting this module will remove type names from the RPC payload. This
+ requires the server to be configured to use the RPC whitelist file.
+ -->
+<module>
+ <inherits name="com.google.gwt.user.RemoteService" />
+
+ <!--
+ Do not simply copy this. It is likely that the mechanism used to enable
+ elision will change in the future, and it may be the case that elision
+ will be automatically enabled in a future release.
+ -->
+ <set-configuration-property name="gwt.elideTypeNamesFromRPC" value="true" />
+</module>
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/User.gwt.xml b/user/src/com/google/gwt/user/User.gwt.xml
index d701223..87c4bb7 100644
--- a/user/src/com/google/gwt/user/User.gwt.xml
+++ b/user/src/com/google/gwt/user/User.gwt.xml
@@ -21,6 +21,7 @@
<inherits name="com.google.gwt.core.Core"/>
<inherits name="com.google.gwt.event.Event"/>
<inherits name="com.google.gwt.animation.Animation"/>
+ <inherits name="com.google.gwt.user.AsyncProxy"/>
<inherits name="com.google.gwt.user.RemoteService"/>
<inherits name="com.google.gwt.user.DocumentRoot" />
<inherits name="com.google.gwt.user.DOM"/>
@@ -40,6 +41,7 @@
<inherits name="com.google.gwt.user.Window" />
<inherits name="com.google.gwt.user.Tree"/>
<inherits name="com.google.gwt.user.Hyperlink"/>
+ <inherits name="com.google.gwt.user.FileUpload"/>
<inherits name="com.google.gwt.user.datepicker.DatePicker"/>
<super-source path="translatable"/>
diff --git a/user/src/com/google/gwt/user/UserAgent.gwt.xml b/user/src/com/google/gwt/user/UserAgent.gwt.xml
index 6e4a49f..d073cd7 100644
--- a/user/src/com/google/gwt/user/UserAgent.gwt.xml
+++ b/user/src/com/google/gwt/user/UserAgent.gwt.xml
@@ -51,4 +51,5 @@
<!-- Deferred binding to optimize JRE classes based on user agent. -->
<inherits name="com.google.gwt.emul.EmulationWithUserAgent"/>
+ <inherits name="com.google.gwt.core.CoreWithUserAgent"/>
</module>
diff --git a/user/src/com/google/gwt/user/client/AsyncProxy.java b/user/src/com/google/gwt/user/client/AsyncProxy.java
new file mode 100644
index 0000000..e4b7a3c
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/AsyncProxy.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client;
+
+import com.google.gwt.core.client.GWT;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * The AsyncProxy type is used to provide a reachability barrier between classes
+ * intended to be used with runAsync while maintaining a simple,
+ * deferred-synchronous API. The first invocation of an instance method on the
+ * AsyncProxy will trigger the instantiation of a concrete object via runAsync.
+ * All method invocations on the proxy will be recorded and played back on the
+ * newly-instantiated object after the call to runAsync returns.
+ * <p>
+ * Once method playback has finished, the proxy will continue to forward
+ * invocations onto the instantiated object, although it is recommended that the
+ * developer use {@link ProxyCallback#onComplete} to reassign the field
+ * containing the proxy.
+ * <p>
+ * Example use:
+ *
+ * <pre>
+ * interface IFoo {
+ * void doSomething(int a, int b);
+ * void anotherMethad(Object o);
+ * }
+ * class FooImpl implements IFoo { .... }
+ *
+ * {@literal @}ConcreteType(FooImpl.class)
+ * interface FooProxy extends AsyncProxy<IFoo>, IFoo {}
+ *
+ * class UserOfIFoo {
+ * private IFoo fooOrProxy = GWT.create(FooProxy.class);
+ *
+ * public UserOfIFoo() {
+ * // When the load, initialization, and playback are done, get rid of the proxy.
+ * // This is actually optional, but will improve subsequent function dispatch speed.
+ * ((AsyncProxy<IFoo>) fooOrProxy).setProxyCallback(new ProxyCallback<IFoo>() {
+ * public void onComplete(IFoo instance) {
+ * fooOrProxy = instance;
+ * }
+ * });
+ * }
+ *
+ * void makeTrouble() {
+ * // This first call triggers a runAsync load
+ * fooOrProxy.doSomething(1, 2);
+ *
+ * // and this second will also be replayed before the above onComplete is called
+ * fooOrProxy.anotherMethod("A string");
+ * }
+ * }
+ * </pre>
+ *
+ * @param <T> the type of interface that must be implemented by the derivative
+ * class.
+ */
+@AsyncProxy.DefaultValue()
+public interface AsyncProxy<T> {
+ /*
+ * NB: This type is annotated with the DefaultValue annotation so that we can
+ * always fall back on getting the default values from an instance of the
+ * annotation, as opposed to maintaining the default in two places.
+ */
+
+ /**
+ * If this annotation is applied to an AsyncProxy type, it will be legal for
+ * the parameterized type <code>T</code> to declare non-void methods. These
+ * methods will immediately return a default value of 0, false, or null if the
+ * proxy has not yet instantiated the backing object. The use of this
+ * annotation may cause surprising operation if the consuming code does not
+ * expect this behavior; for example a call to a property setter followed by a
+ * call to the getter could return null,
+ *
+ * @see DefaultValue
+ */
+ @Documented
+ @Target(ElementType.TYPE)
+ public @interface AllowNonVoid {
+ }
+
+ /**
+ * This interface should be applied to the AsyncProxy subtype in order to
+ * specify the Class literal that will be passed to {@link GWT#create(Class)}.
+ */
+ @Documented
+ @Target(ElementType.TYPE)
+ public @interface ConcreteType {
+ Class<?> value();
+ }
+
+ /**
+ * This annotation specifies the return value for primitive methods when the
+ * {@link AllowNonVoid} annotation has been applied to an AsyncProxy.
+ *
+ * The annotation may be applied to the definition of the AsyncProxy type or
+ * individual methods defined on the target interface. If the annotation is
+ * applied to the AsyncProxy type, then it will apply to all methods
+ * implemented by the proxy.
+ *
+ * The correct default value will be chosen from the value methods defined in
+ * this type based on the return type of the method.
+ */
+ @Documented
+ @Target(value = {ElementType.METHOD, ElementType.TYPE})
+ public @interface DefaultValue {
+ /*
+ * Consider adding an additional flag value that would make the generated
+ * type fail an assertion on uninitialized access. Also consider whether or
+ * not allowing a class literal to be specified for reference types would be
+ * useful.
+ */
+
+ boolean booleanValue() default false;
+
+ byte byteValue() default 0;
+
+ char charValue() default 0;
+
+ double doubleValue() default 0;
+
+ float floatValue() default 0;
+
+ int intValue() default 0;
+
+ long longValue() default 0;
+
+ short shortValue() default 0;
+ }
+
+ /**
+ * The callback used by
+ * {@link AsyncProxy#setAsyncProxyCallback(AsyncProxyCallback)}.
+ *
+ * @param <T> the interface parameterization of AsyncProxy.
+ */
+ public abstract static class ProxyCallback<T> {
+ /**
+ * This method will be invoked by the AsyncProxy after method playback is
+ * complete.
+ */
+ public void onComplete(T instance) {
+ }
+
+ /**
+ * Invokes the global uncaught exception handler.
+ */
+ public void onFailure(Throwable t) {
+ GWT.getUncaughtExceptionHandler().onUncaughtException(t);
+ }
+
+ /**
+ * This method will be called with the instance object before method replay
+ * starts. This provides the developer with the opportunity to perform
+ * secondary initialization of the backing object.
+ */
+ public void onInit(T instance) {
+ }
+ }
+
+ /**
+ * Returns the underlying proxied object if it has been instantiated or
+ * <code>null</code>.
+ */
+ T getProxiedInstance();
+
+ /**
+ * Sets a callback that can be used to influence the initialization process.
+ */
+ void setProxyCallback(ProxyCallback<T> callback);
+}
diff --git a/user/src/com/google/gwt/user/client/HTTPRequest.java b/user/src/com/google/gwt/user/client/HTTPRequest.java
index 0ff0e44..50acb62 100644
--- a/user/src/com/google/gwt/user/client/HTTPRequest.java
+++ b/user/src/com/google/gwt/user/client/HTTPRequest.java
@@ -15,9 +15,6 @@
*/
package com.google.gwt.user.client;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.impl.HTTPRequestImpl;
-
/**
* This class allows you to make asynchronous HTTP requests to the originating
* server.
@@ -28,8 +25,6 @@
@Deprecated
public class HTTPRequest {
- private static final HTTPRequestImpl httpRequest = GWT.create(HTTPRequestImpl.class);
-
/**
* Makes an asynchronous HTTP GET to a remote server.
*
@@ -39,7 +34,7 @@
* @return <code>false</code> if the invocation fails to issue
*/
public static boolean asyncGet(String url, ResponseTextHandler handler) {
- return httpRequest.asyncGet(url, handler);
+ return asyncGetImpl(null, null, url, handler);
}
/**
@@ -52,7 +47,7 @@
*/
public static boolean asyncGet(String user, String pwd, String url,
ResponseTextHandler handler) {
- return httpRequest.asyncGet(user, pwd, url, handler);
+ return asyncGetImpl(user, pwd, url, handler);
}
/**
@@ -66,7 +61,7 @@
*/
public static boolean asyncPost(String url, String postData,
ResponseTextHandler handler) {
- return httpRequest.asyncPost(url, postData, handler);
+ return asyncPostImpl(null, null, url, postData, handler);
}
/**
@@ -80,6 +75,51 @@
*/
public static boolean asyncPost(String user, String pwd, String url,
String postData, ResponseTextHandler handler) {
- return httpRequest.asyncPost(user, pwd, url, postData, handler);
+ return asyncPostImpl(user, pwd, url, postData, handler);
}
+
+ private static native boolean asyncGetImpl(String user, String pwd, String url,
+ ResponseTextHandler handler) /*-{
+ var xmlHttp = @com.google.gwt.xhr.client.XMLHttpRequest::create()();
+ try {
+ xmlHttp.open("GET", url, true);
+ xmlHttp.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
+ xmlHttp.onreadystatechange = function() {
+ if (xmlHttp.readyState == 4) {
+ $wnd.setTimeout(function() {
+ xmlHttp.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
+ }, 0);
+ handler.@com.google.gwt.user.client.ResponseTextHandler::onCompletion(Ljava/lang/String;)(xmlHttp.responseText || "");
+ }
+ };
+ xmlHttp.send('');
+ return true;
+ } catch (e) {
+ xmlHttp.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
+ return false;
+ }
+ }-*/;
+
+ private static native boolean asyncPostImpl(String user, String pwd, String url,
+ String postData, ResponseTextHandler handler) /*-{
+ var xmlHttp = @com.google.gwt.xhr.client.XMLHttpRequest::create()();
+ try {
+ xmlHttp.open("POST", url, true);
+ xmlHttp.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
+ xmlHttp.onreadystatechange = function() {
+ if (xmlHttp.readyState == 4) {
+ $wnd.setTimeout(function() {
+ xmlHttp.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
+ }, 0);
+ handler.@com.google.gwt.user.client.ResponseTextHandler::onCompletion(Ljava/lang/String;)(xmlHttp.responseText || "");
+ }
+ };
+ xmlHttp.send(postData);
+ return true;
+ }
+ catch (e) {
+ xmlHttp.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
+ return false;
+ }
+ }-*/;
}
diff --git a/user/src/com/google/gwt/user/client/impl/AsyncProxyBase.java b/user/src/com/google/gwt/user/client/impl/AsyncProxyBase.java
new file mode 100644
index 0000000..d295483
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/impl/AsyncProxyBase.java
@@ -0,0 +1,147 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.AsyncProxy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The base implementation for AsyncProxy instances.
+ *
+ * @param <T> the type to be returned from the GWT.create call
+ */
+public abstract class AsyncProxyBase<T> implements AsyncProxy<T> {
+ /**
+ * Simple parameterized command type.
+ *
+ * @param <T> as above
+ */
+ protected interface ParamCommand<T> {
+ void execute(T instance);
+ }
+
+ /*
+ * These fields are package-protected to allow for easier testing.
+ */
+ private List<ParamCommand<T>> commands = new ArrayList<ParamCommand<T>>();
+ private boolean hasAsyncBeenIssued = false;
+ private boolean hasAsyncFailed = false;
+ private boolean hasAsyncReturned = false;
+ private T instance = null;
+
+ /**
+ * Testing method to enable enqueue0 from firing the runAsync call.
+ */
+ public void enableLoadForTest0() {
+ hasAsyncBeenIssued = false;
+ hasAsyncFailed = false;
+ hasAsyncReturned = false;
+ }
+
+ public final T getProxiedInstance() {
+ return instance;
+ }
+
+ /**
+ * To be implemented by the subtype.
+ */
+ public abstract void setProxyCallback(ProxyCallback<T> callback);
+
+ /**
+ * Testing method to prevent enqueue0 from actually firing the runAsync call.
+ */
+ public void suppressLoadForTest0() {
+ hasAsyncBeenIssued = true;
+ hasAsyncFailed = false;
+ hasAsyncReturned = false;
+ }
+
+ /**
+ * To be implemented by the subtype to give the code-splitter a new starting
+ * point.
+ */
+ protected abstract void doAsync0();
+
+ /**
+ * Called by the generated subtype if the runAsync invocation fails.
+ */
+ protected final void doFailure0(Throwable t) {
+ hasAsyncFailed = true;
+ getCallback0().onFailure(t);
+ }
+
+ /**
+ * Called by the generated subtype to enqueue an action for later replay.
+ */
+ protected final void enqueue0(ParamCommand<T> cmd) {
+ try {
+ if (hasAsyncFailed) {
+ throw new IllegalStateException("runAsync load previously failed");
+
+ } else if (!hasAsyncBeenIssued) {
+ hasAsyncBeenIssued = true;
+ commands.add(cmd);
+ doAsync0();
+
+ } else if (hasAsyncReturned) {
+ assert instance != null;
+ cmd.execute(instance);
+
+ } else {
+ assert instance == null;
+ commands.add(cmd);
+ }
+ } catch (Throwable t) {
+ if (getCallback0() != null) {
+ getCallback0().onFailure(t);
+ } else {
+ GWT.getUncaughtExceptionHandler().onUncaughtException(t);
+ }
+ }
+ }
+
+ /**
+ * The callback is maintained by the generated subtype to take advantage of
+ * type-tightening.
+ */
+ protected abstract ProxyCallback<T> getCallback0();
+
+ /**
+ * Called by the generated subtype with the new instance of the object.
+ */
+ protected final void setInstance0(T instance) {
+ assert commands != null : "No commands";
+ assert hasAsyncBeenIssued : "async request not yet started";
+ hasAsyncReturned = true;
+ this.instance = instance;
+ List<ParamCommand<T>> localCommands = commands;
+ commands = null;
+
+ // Can fail below
+ if (getCallback0() != null) {
+ getCallback0().onInit(instance);
+ }
+ for (ParamCommand<T> cmd : localCommands) {
+ cmd.execute(instance);
+ }
+ if (getCallback0() != null) {
+ getCallback0().onComplete(instance);
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java b/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java
deleted file mode 100644
index 1bea53c..0000000
--- a/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may 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.impl;
-
-import com.google.gwt.core.client.JavaScriptObject;
-
-/**
- * Internet Explorer 6 implementation of {@link HTTPRequestImpl}.
- */
-class HTTPRequestImplIE6 extends HTTPRequestImpl {
-
- @Override
- protected native JavaScriptObject doCreateXmlHTTPRequest() /*-{
- if ($wnd.XMLHttpRequest) {
- return new XMLHttpRequest();
- } else {
- try {
- return new ActiveXObject('MSXML2.XMLHTTP.3.0');
- } catch (e) {
- return new ActiveXObject("Microsoft.XMLHTTP");
- }
- }
- }-*/;
-}
diff --git a/user/src/com/google/gwt/user/client/rpc/GwtTransient.java b/user/src/com/google/gwt/user/client/rpc/GwtTransient.java
new file mode 100644
index 0000000..376e055
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/GwtTransient.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.user.client.rpc;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation means the same thing as the <code>transient</code> keyword,
+ * but it is ignored by all serialization systems other than GWT's. Usually the
+ * <code>transient</code> keyword should be used in preference to this
+ * annotation. However, for types used with multiple serialization systems, it
+ * can be useful.
+ */
+@Documented
+@Target(ElementType.FIELD)
+public @interface GwtTransient {
+}
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 2177020..fec3660 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,6 +23,11 @@
public abstract class AbstractSerializationStream {
/**
+ * The default flags to be used by serialization streams.
+ */
+ public static final int DEFAULT_FLAGS = 0;
+
+ /**
* The character used to separate fields in client->server RPC messages.
*
* Note that this character is referenced in the following places not using
@@ -39,7 +44,12 @@
*/
public static final int SERIALIZATION_STREAM_VERSION = 5;
- private int flags = 0;
+ /**
+ * Indicates that obfuscated type names should be used in the RPC payload.
+ */
+ public static final int FLAG_ELIDE_TYPE_NAMES = 0x1;
+
+ private int flags = DEFAULT_FLAGS;
private int version = SERIALIZATION_STREAM_VERSION;
public final void addFlags(int flags) {
@@ -54,6 +64,10 @@
return version;
}
+ public final boolean hasFlags(int flags) {
+ return (getFlags() & flags) == flags;
+ }
+
public final void setFlags(int flags) {
this.flags = flags;
}
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStreamWriter.java b/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStreamWriter.java
index c8aaf0a..7c28259 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStreamWriter.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStreamWriter.java
@@ -183,7 +183,8 @@
* @param instance the instance to inspect
* @return the type signature of the instance
*/
- protected abstract String getObjectTypeSignature(Object instance);
+ protected abstract String getObjectTypeSignature(Object instance)
+ throws SerializationException;
/**
* Gets the string table.
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 f760109..fe14d16 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
@@ -69,13 +69,13 @@
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;
+ // 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;
+ // other WebKit-based browsers need some additional quoting
+ return /[\u0000\|\\\u0300-\u036F\u0590-\u05FF\uD800-\uFFFF]/g;
} else {
- return /[\u0000\|\\\uD800-\uFFFF]/g;
+ return /[\u0000\|\\\uD800-\uFFFF]/g;
}
}-*/;
@@ -201,13 +201,7 @@
clazz = e.getDeclaringClass();
}
- String typeName = clazz.getName();
-
- String serializationSignature = serializer.getSerializationSignature(typeName);
- if (serializationSignature != null) {
- typeName += "/" + serializationSignature;
- }
- return typeName;
+ return serializer.getSerializationSignature(clazz);
}
@Override
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/Serializer.java b/user/src/com/google/gwt/user/client/rpc/impl/Serializer.java
index 323391a..7a24b57 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/Serializer.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/Serializer.java
@@ -32,9 +32,9 @@
String typeSignature) throws SerializationException;
/**
- * Return the serialization signature for the given type name.
+ * Return the serialization signature for the given type.
*/
- String getSerializationSignature(String typeName);
+ String getSerializationSignature(Class<?> clazz);
/**
* Instantiate an object of the given typeName from the serialized stream.
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java b/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java
new file mode 100644
index 0000000..69f5361
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2009 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.impl;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.core.client.JsArrayString;
+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.IdentityHashMap;
+import java.util.Map;
+
+/**
+ * Maps class literals to type signatures and type signatures to serialization
+ * methods. Relies on monotonic behavior of hashcodes in web mode defined in
+ * {@link com.google.gwt.core.client.impl.Impl#getHashCode(Object)} In hosted
+ * mode, we map the underlying signature JsArray onto a proper IdentityHashMap.
+ */
+public abstract class SerializerBase implements Serializer {
+
+ /**
+ * Represents a collection of functions that perform type-specific functions.
+ */
+ protected static final class MethodMap extends JavaScriptObject {
+ protected MethodMap() {
+ }
+
+ native void deserialize(SerializationStreamReader stream, Object instance,
+ String signature) throws SerializationException /*-{
+ this[signature][1](stream, instance);
+ }-*/;
+
+ native JsArray<JavaScriptObject> get(String signature) /*-{
+ return this[signature];
+ }-*/;
+
+ native Object instantiate(SerializationStreamReader stream, String signature)
+ throws SerializationException /*-{
+ return this[signature][0](stream);
+ }-*/;
+
+ native void put(String signature, JsArray<JavaScriptObject> methods) /*-{
+ this[signature] = methods;
+ }-*/;
+
+ native void serialize(SerializationStreamWriter stream, Object instance,
+ String signature) throws SerializationException /*-{
+ this[signature][2](stream, instance);
+ }-*/;
+ }
+
+ private static final Map<JsArrayString, Map<Class<?>, String>> hostedSignatureMaps;
+
+ static {
+ if (GWT.isScript()) {
+ hostedSignatureMaps = null;
+ } else {
+ hostedSignatureMaps = new IdentityHashMap<JsArrayString, Map<Class<?>, String>>();
+ }
+ }
+
+ protected static final void registerMethods(MethodMap methodMap,
+ String signature, JsArray<JavaScriptObject> methods) {
+ assert signature != null : "signature";
+ assert methodMap.get(signature) == null : "Duplicate signature "
+ + signature;
+
+ methodMap.put(signature, methods);
+ }
+
+ protected static final void registerSignature(JsArrayString signatureMap,
+ Class<?> clazz, String signature) {
+ assert clazz != null : "clazz";
+ assert signature != null : "signature";
+
+ if (GWT.isScript()) {
+ assert signatureMap.get(clazz.hashCode()) == null : "Duplicate signature "
+ + signature;
+ signatureMap.set(clazz.hashCode(), signature);
+
+ } else {
+ Map<Class<?>, String> subMap = getSubMap(signatureMap);
+
+ assert !subMap.containsKey(clazz);
+ subMap.put(clazz, signature);
+ }
+ }
+
+ /**
+ * Hashcodes in hosted mode are unpredictable. Each signature map is
+ * associated with a proper IdentityHashMap. This method should only be used
+ * in hosted mode.
+ */
+ private static Map<Class<?>, String> getSubMap(JsArrayString signatureMap) {
+ assert !GWT.isScript() : "Should only use this in hosted mode";
+ Map<Class<?>, String> subMap = hostedSignatureMaps.get(signatureMap);
+ if (subMap == null) {
+ subMap = new IdentityHashMap<Class<?>, String>();
+ hostedSignatureMaps.put(signatureMap, subMap);
+ }
+ return subMap;
+ }
+
+ public final void deserialize(SerializationStreamReader stream,
+ Object instance, String typeSignature) throws SerializationException {
+ check(typeSignature, 2);
+
+ getMethodMap().deserialize(stream, instance, typeSignature);
+ }
+
+ public final String getSerializationSignature(Class<?> clazz) {
+ assert clazz != null : "clazz";
+ if (GWT.isScript()) {
+ return getSignatureMap().get(clazz.hashCode());
+ } else {
+ return getSubMap(getSignatureMap()).get(clazz);
+ }
+ }
+
+ public final Object instantiate(SerializationStreamReader stream,
+ String typeSignature) throws SerializationException {
+ check(typeSignature, 1);
+
+ return getMethodMap().instantiate(stream, typeSignature);
+ }
+
+ public final void serialize(SerializationStreamWriter stream,
+ Object instance, String typeSignature) throws SerializationException {
+ check(typeSignature, 3);
+
+ getMethodMap().serialize(stream, instance, typeSignature);
+ }
+
+ protected abstract MethodMap getMethodMap();
+
+ protected abstract JsArrayString getSignatureMap();
+
+ private void check(String typeSignature, int length)
+ throws SerializationException {
+ /*
+ * Probably trying to serialize a type that isn't supposed to be
+ * serializable.
+ */
+ if (getMethodMap().get(typeSignature) == null) {
+ throw new SerializationException(typeSignature);
+ }
+
+ assert getMethodMap().get(typeSignature).length() >= length : "Not enough methods, expecting "
+ + length + " saw " + getMethodMap().get(typeSignature).length();
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/CheckBox.java b/user/src/com/google/gwt/user/client/ui/CheckBox.java
index 549107c..09be6ff 100644
--- a/user/src/com/google/gwt/user/client/ui/CheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/CheckBox.java
@@ -385,8 +385,7 @@
// Clear out the old input element
setEventListener(asOld(inputElem), null);
- getElement().removeChild(inputElem);
- getElement().insertBefore(newInputElem, null);
+ getElement().replaceChild(newInputElem, inputElem);
// Sink events on the new element
Event.sinkEvents(elem, Event.getEventsSunk(inputElem));
diff --git a/user/src/com/google/gwt/user/client/ui/FileUpload.java b/user/src/com/google/gwt/user/client/ui/FileUpload.java
index f1bbf02..dba1f02 100644
--- a/user/src/com/google/gwt/user/client/ui/FileUpload.java
+++ b/user/src/com/google/gwt/user/client/ui/FileUpload.java
@@ -15,9 +15,15 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.event.dom.client.ChangeEvent;
+import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.event.dom.client.HasChangeHandlers;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.Event;
/**
* A widget that wraps the HTML <input type='file'> element. This widget
@@ -29,7 +35,70 @@
* {@example com.google.gwt.examples.FormPanelExample}
* </p>
*/
-public class FileUpload extends Widget implements HasName {
+public class FileUpload extends Widget implements HasName, HasChangeHandlers {
+ /**
+ * Implementation class for {@link FileUpload}.
+ */
+ private static class FileUploadImpl {
+ /**
+ * Initialize the impl class.
+ *
+ * @param fileUpload the {@link FileUpload} to handle
+ */
+ public void init(FileUpload fileUpload) {
+ }
+
+ /**
+ * Handle the browser event.
+ *
+ * @param event the native event
+ * @return true to fire the event normally, false to ignore it
+ */
+ public boolean onBrowserEvent(Event event) {
+ return true;
+ }
+ }
+
+ /**
+ * Opera fires an onChange event every time a character is typed, but we only
+ * want to fire one when the input element is blurred.
+ */
+ @SuppressWarnings("unused")
+ private static class FileUploadImplOpera extends FileUploadImpl {
+ private FileUpload fileUpload;
+ private boolean eventPending;
+ private boolean allowEvent;
+
+ @Override
+ public void init(FileUpload fileUpload) {
+ this.fileUpload = fileUpload;
+ fileUpload.sinkEvents(Event.ONBLUR);
+ }
+
+ @Override
+ public boolean onBrowserEvent(Event event) {
+ switch (event.getTypeInt()) {
+ case Event.ONCHANGE:
+ // When we fire the change event onBlur, we allow it to pass to
+ // Widget#onBrowserEvent().
+ if (!allowEvent) {
+ eventPending = true;
+ return false;
+ }
+ break;
+ case Event.ONBLUR:
+ // Trigger a change event now.
+ if (eventPending) {
+ allowEvent = true;
+ fileUpload.getElement().dispatchEvent(Document.get().createChangeEvent());
+ allowEvent = false;
+ eventPending = false;
+ }
+ break;
+ }
+ return true;
+ }
+ }
/**
* Creates a FileUpload widget that wraps an existing <input
@@ -54,12 +123,16 @@
return fileUpload;
}
+ private FileUploadImpl impl;
+
/**
* Constructs a new file upload widget.
*/
public FileUpload() {
setElement(Document.get().createFileInputElement());
setStyleName("gwt-FileUpload");
+ impl = GWT.create(FileUploadImpl.class);
+ impl.init(this);
}
/**
@@ -74,6 +147,10 @@
setElement(element);
}
+ public HandlerRegistration addChangeHandler(ChangeHandler handler) {
+ return addDomHandler(handler, ChangeEvent.getType());
+ }
+
/**
* Gets the filename selected by the user. This property has no mutator, as
* browser security restrictions preclude setting it.
@@ -88,6 +165,13 @@
return getInputElement().getName();
}
+ @Override
+ public void onBrowserEvent(Event event) {
+ if (impl.onBrowserEvent(event)) {
+ super.onBrowserEvent(event);
+ }
+ }
+
public void setName(String name) {
getInputElement().setName(name);
}
diff --git a/user/src/com/google/gwt/user/datepicker/client/CalendarUtil.java b/user/src/com/google/gwt/user/datepicker/client/CalendarUtil.java
index 0df0427..8e533f4 100644
--- a/user/src/com/google/gwt/user/datepicker/client/CalendarUtil.java
+++ b/user/src/com/google/gwt/user/datepicker/client/CalendarUtil.java
@@ -17,6 +17,7 @@
package com.google.gwt.user.datepicker.client;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.i18n.client.constants.DateTimeConstants;
import java.util.Date;
@@ -35,7 +36,7 @@
static {
if (GWT.isClient()) {
- intlConstants = (DateTimeConstants) GWT.create(DateTimeConstants.class);
+ intlConstants = LocaleInfo.getCurrentLocale().getDateTimeConstants();
// Finding the start and end of weekend
firstDayOfWeekend = Integer.parseInt(intlConstants.weekendRange()[0]) - 1;
lastDayOfWeekend = Integer.parseInt(intlConstants.weekendRange()[1]) - 1;
diff --git a/user/src/com/google/gwt/user/rebind/AbstractGeneratorClassCreator.java b/user/src/com/google/gwt/user/rebind/AbstractGeneratorClassCreator.java
index 02fd860..45e23c4 100644
--- a/user/src/com/google/gwt/user/rebind/AbstractGeneratorClassCreator.java
+++ b/user/src/com/google/gwt/user/rebind/AbstractGeneratorClassCreator.java
@@ -23,6 +23,7 @@
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.i18n.rebind.AbstractResource;
import com.google.gwt.i18n.rebind.AbstractResource.MissingResourceException;
+import com.google.gwt.i18n.shared.GwtLocale;
import java.util.HashMap;
import java.util.Iterator;
@@ -108,7 +109,8 @@
* @param locale
* @throws UnableToCompleteException
*/
- public void emitClass(TreeLogger logger, String locale) throws UnableToCompleteException {
+ public void emitClass(TreeLogger logger, GwtLocale locale)
+ throws UnableToCompleteException {
logger = branch(logger, branchMessage());
classPrologue();
emitMethods(logger, targetClass, locale);
@@ -180,8 +182,8 @@
* @param locale locale for this generation
* @throws UnableToCompleteException
*/
- protected abstract void emitMethodBody(TreeLogger logger, JMethod method, String locale)
- throws UnableToCompleteException;
+ protected abstract void emitMethodBody(TreeLogger logger, JMethod method,
+ GwtLocale locale) throws UnableToCompleteException;
/**
* Gets the method creator associated with the return type of the method.
@@ -224,7 +226,7 @@
return writer;
}
- private void emitMethods(TreeLogger logger, JClassType cur, String locale)
+ private void emitMethods(TreeLogger logger, JClassType cur, GwtLocale locale)
throws UnableToCompleteException {
JMethod[] x = getAllInterfaceMethods(cur);
for (int i = 0; i < x.length; i++) {
@@ -240,7 +242,7 @@
* @param locale
* @throws UnableToCompleteException
*/
- private void genMethod(TreeLogger logger, JMethod method, String locale)
+ private void genMethod(TreeLogger logger, JMethod method, GwtLocale locale)
throws UnableToCompleteException {
String name = method.getName();
String returnType = method.getReturnType().getParameterizedQualifiedSourceName();
diff --git a/user/src/com/google/gwt/user/rebind/AbstractMethodCreator.java b/user/src/com/google/gwt/user/rebind/AbstractMethodCreator.java
index b81e7eb..17b1bbd 100644
--- a/user/src/com/google/gwt/user/rebind/AbstractMethodCreator.java
+++ b/user/src/com/google/gwt/user/rebind/AbstractMethodCreator.java
@@ -19,6 +19,7 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
+import com.google.gwt.i18n.shared.GwtLocale;
/**
* Creates method factories depending upon the method type. Includes the core
@@ -51,7 +52,8 @@
* @throws UnableToCompleteException
*/
public abstract void createMethodFor(TreeLogger logger, JMethod targetMethod,
- String key, ResourceList resourceList, String locale) throws UnableToCompleteException;
+ String key, ResourceList resourceList, GwtLocale locale)
+ throws UnableToCompleteException;
/**
* Prints to the current <code>AbstractGeneratorClassCreator</code>.
diff --git a/user/src/com/google/gwt/user/rebind/AsyncProxyGenerator.java b/user/src/com/google/gwt/user/rebind/AsyncProxyGenerator.java
new file mode 100644
index 0000000..4bc1d21
--- /dev/null
+++ b/user/src/com/google/gwt/user/rebind/AsyncProxyGenerator.java
@@ -0,0 +1,350 @@
+/*
+ * 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.rebind;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
+import com.google.gwt.core.ext.Generator;
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JParameter;
+import com.google.gwt.core.ext.typeinfo.JParameterizedType;
+import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.user.client.AsyncProxy;
+import com.google.gwt.user.client.AsyncProxy.AllowNonVoid;
+import com.google.gwt.user.client.AsyncProxy.ConcreteType;
+import com.google.gwt.user.client.AsyncProxy.DefaultValue;
+import com.google.gwt.user.client.impl.AsyncProxyBase;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Iterator;
+
+/**
+ * Generates implementation of AsyncProxy interfaces.
+ */
+public class AsyncProxyGenerator extends Generator {
+
+ public String generate(TreeLogger logger, GeneratorContext generatorContext,
+ String typeName) throws UnableToCompleteException {
+
+ // The TypeOracle knows about all types in the type system
+ TypeOracle typeOracle = generatorContext.getTypeOracle();
+
+ // Get a reference to the type that the generator should implement
+ JClassType asyncProxyType = typeOracle.findType(AsyncProxy.class.getName());
+ JClassType asyncProxyBaseType = typeOracle.findType(AsyncProxyBase.class.getName());
+ JClassType sourceType = typeOracle.findType(typeName);
+
+ // Ensure that the requested type exists
+ if (sourceType == null) {
+ logger.log(TreeLogger.ERROR, "Could not find requested typeName");
+ throw new UnableToCompleteException();
+ } else if (sourceType.isInterface() == null) {
+ // The incoming type wasn't a plain interface, we don't support
+ // abstract base classes
+ logger.log(TreeLogger.ERROR, sourceType.getQualifiedSourceName()
+ + " is not an interface.", null);
+ throw new UnableToCompleteException();
+ }
+
+ JClassType concreteType = getConcreteType(logger, typeOracle, sourceType);
+ JClassType paramType = getParamType(logger, asyncProxyType, sourceType);
+
+ validate(logger, sourceType, concreteType, paramType);
+
+ // com.foo.Bar$Proxy -> com_foo_Bar_ProxyImpl
+ String generatedSimpleSourceName = sourceType.getQualifiedSourceName().replace(
+ '.', '_').replace('$', '_')
+ + "Impl";
+
+ // Begin writing the generated source.
+ ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
+ sourceType.getPackage().getName(), generatedSimpleSourceName);
+ String createdClassName = f.getCreatedClassName();
+
+ // The generated class needs to be able to determine the module base URL
+ f.addImport(GWT.class.getName());
+ f.addImport(RunAsyncCallback.class.getName());
+
+ // Used by the map methods
+ f.setSuperclass(asyncProxyBaseType.getQualifiedSourceName() + "<"
+ + paramType.getQualifiedSourceName() + ">");
+
+ // The whole point of this exercise
+ f.addImplementedInterface(sourceType.getQualifiedSourceName());
+
+ // All source gets written through this Writer
+ PrintWriter out = generatorContext.tryCreate(logger,
+ sourceType.getPackage().getName(), generatedSimpleSourceName);
+
+ // If an implementation already exists, we don't need to do any work
+ if (out != null) {
+ SourceWriter sw = f.createSourceWriter(generatorContext, out);
+
+ // The invocation of runAsync, with a unique class for the split point
+ sw.println("protected void doAsync0() {");
+ sw.indent();
+ sw.println("GWT.runAsync(new RunAsyncCallback() {");
+ sw.indentln("public void onFailure(Throwable caught) {doFailure0(caught);}");
+ sw.indentln("public void onSuccess() {setInstance0(doCreate0());}");
+ sw.println("});");
+ sw.outdent();
+ sw.println("}");
+
+ // Field for callback, plus getter and setter
+ String proxyCallback = "ProxyCallback<"
+ + paramType.getQualifiedSourceName() + ">";
+ sw.println("private " + proxyCallback + " callback;");
+ sw.println("public void setProxyCallback(" + proxyCallback
+ + " callback) {this.callback = callback;}");
+ sw.println("protected " + proxyCallback
+ + " getCallback0() {return callback;}");
+
+ // doCreate0() method to invoke GWT.create()
+ sw.println("private " + paramType.getQualifiedSourceName()
+ + " doCreate0() {");
+ sw.indent();
+ sw.println("return GWT.create(" + concreteType.getQualifiedSourceName()
+ + ".class);");
+ sw.outdent();
+ sw.println("}");
+
+ boolean allowNonVoid = sourceType.getAnnotation(AllowNonVoid.class) != null;
+ for (JMethod method : paramType.getOverridableMethods()) {
+ DefaultValue defaults = getDefaultValue(sourceType, method);
+
+ if (method.getReturnType() != JPrimitiveType.VOID && !allowNonVoid) {
+ logger.log(TreeLogger.ERROR, "The method " + method.getName()
+ + " returns a type other than void, but "
+ + sourceType.getQualifiedSourceName() + " does not define the "
+ + AllowNonVoid.class.getSimpleName() + " annotation.");
+ throw new UnableToCompleteException();
+ }
+
+ // Print the method decl
+ sw.print("public " + method.getReturnType().getQualifiedSourceName()
+ + " " + method.getName() + "(");
+ for (Iterator<JParameter> i = Arrays.asList(method.getParameters()).iterator(); i.hasNext();) {
+ JParameter param = i.next();
+ sw.print("final " + param.getType().getQualifiedSourceName() + " "
+ + param.getName());
+ if (i.hasNext()) {
+ sw.print(", ");
+ }
+ }
+ sw.println(") {");
+ {
+ sw.indent();
+
+ // Try a direct dispatch if we have a proxy instance
+ sw.println("if (getProxiedInstance() != null) {");
+ {
+ sw.indent();
+ if (method.getReturnType() != JPrimitiveType.VOID) {
+ sw.print("return ");
+ }
+ writeInvocation(sw, "getProxiedInstance()", method);
+ sw.outdent();
+ }
+
+ // Otherwise queue up a parameterized command object
+ sw.println("} else {");
+ {
+ sw.indent();
+ sw.println("enqueue0(new ParamCommand<"
+ + paramType.getQualifiedSourceName() + ">() {");
+ {
+ sw.indent();
+ sw.println("public void execute("
+ + paramType.getQualifiedSourceName() + " t) {");
+ {
+ sw.indent();
+ writeInvocation(sw, "t", method);
+ sw.outdent();
+ }
+ sw.println("}");
+ sw.outdent();
+ }
+ sw.println("});");
+
+ if (method.getReturnType() != JPrimitiveType.VOID) {
+ sw.println("return "
+ + getDefaultExpression(defaults, method.getReturnType())
+ + ";");
+ }
+
+ sw.outdent();
+ }
+ sw.println("}");
+ sw.outdent();
+ }
+ sw.println("}");
+ }
+
+ sw.commit(logger);
+ }
+
+ // Return the name of the concrete class
+ return createdClassName;
+ }
+
+ private JClassType getConcreteType(TreeLogger logger, TypeOracle typeOracle,
+ JClassType sourceType) throws UnableToCompleteException {
+ JClassType concreteType;
+ ConcreteType concreteTypeAnnotation = sourceType.getAnnotation(ConcreteType.class);
+ if (concreteTypeAnnotation == null) {
+ logger.log(TreeLogger.ERROR, "AsnycProxy subtypes must specify a "
+ + ConcreteType.class.getSimpleName() + " annotation.");
+ throw new UnableToCompleteException();
+ }
+
+ String concreteTypeName = concreteTypeAnnotation.value().getName().replace(
+ '$', '.');
+ concreteType = typeOracle.findType(concreteTypeName);
+
+ if (concreteType == null) {
+ logger.log(TreeLogger.ERROR,
+ "Unable to find concrete type; is it in the GWT source path?");
+ throw new UnableToCompleteException();
+ }
+ return concreteType;
+ }
+
+ /**
+ * Returns a useful default expression for a type. It is an error to pass
+ * JPrimitiveType.VOID into this method.
+ */
+ private String getDefaultExpression(DefaultValue defaultValue, JType type) {
+ if (!(type instanceof JPrimitiveType)) {
+ return "null";
+ } else if (type == JPrimitiveType.BOOLEAN) {
+ return String.valueOf(defaultValue.booleanValue());
+ } else if (type == JPrimitiveType.BYTE) {
+ return String.valueOf(defaultValue.byteValue());
+ } else if (type == JPrimitiveType.CHAR) {
+ return String.valueOf((int) defaultValue.charValue());
+ } else if (type == JPrimitiveType.DOUBLE) {
+ return String.valueOf(defaultValue.doubleValue());
+ } else if (type == JPrimitiveType.FLOAT) {
+ return String.valueOf(defaultValue.floatValue()) + "F";
+ } else if (type == JPrimitiveType.INT) {
+ return String.valueOf(defaultValue.intValue());
+ } else if (type == JPrimitiveType.LONG) {
+ return String.valueOf(defaultValue.longValue());
+ } else if (type == JPrimitiveType.SHORT) {
+ return String.valueOf(defaultValue.shortValue());
+ } else if (type == JPrimitiveType.VOID) {
+ assert false : "Should not pass VOID into this method";
+ }
+ assert false : "Should never reach here";
+ return null;
+ }
+
+ private DefaultValue getDefaultValue(JClassType sourceType, JMethod method) {
+ DefaultValue toReturn = method.getAnnotation(DefaultValue.class);
+ if (toReturn == null) {
+ toReturn = sourceType.getAnnotation(DefaultValue.class);
+ }
+
+ if (toReturn == null) {
+ JClassType proxyType = sourceType.getOracle().findType(
+ AsyncProxy.class.getName());
+ toReturn = proxyType.getAnnotation(DefaultValue.class);
+ }
+
+ assert toReturn != null : "Could not find any DefaultValue instance";
+ return toReturn;
+ }
+
+ private JClassType getParamType(TreeLogger logger, JClassType asyncProxyType,
+ JClassType sourceType) throws UnableToCompleteException {
+ JClassType paramType = null;
+ for (JClassType intr : sourceType.getImplementedInterfaces()) {
+ JParameterizedType isParameterized = intr.isParameterized();
+ if (isParameterized == null) {
+ continue;
+ }
+ if (isParameterized.getBaseType().equals(asyncProxyType)) {
+ paramType = isParameterized.getTypeArgs()[0];
+ break;
+ }
+ }
+
+ if (paramType == null) {
+ logger.log(TreeLogger.ERROR, "Unable to determine parameterization type.");
+ throw new UnableToCompleteException();
+ }
+ return paramType;
+ }
+
+ private void validate(TreeLogger logger, JClassType sourceType,
+ JClassType concreteType, JClassType paramType)
+ throws UnableToCompleteException {
+ // sourceType may not define any methods
+ if (sourceType.getMethods().length > 0) {
+ logger.log(TreeLogger.ERROR,
+ "AsyncProxy subtypes may not define any additional methods");
+ throw new UnableToCompleteException();
+ }
+
+ // Make sure that sourceType implements paramType to assignments work
+ if (!sourceType.isAssignableTo(paramType)) {
+ logger.log(TreeLogger.ERROR, "Expecting "
+ + sourceType.getQualifiedSourceName() + " to implement "
+ + paramType.getQualifiedSourceName());
+ throw new UnableToCompleteException();
+ }
+
+ // Make sure that concreteType is assignable to paramType
+ if (!concreteType.isAssignableTo(paramType)) {
+ logger.log(TreeLogger.ERROR, "Expecting concrete type"
+ + concreteType.getQualifiedSourceName() + " to implement "
+ + paramType.getQualifiedSourceName());
+ throw new UnableToCompleteException();
+ }
+
+ // Must be able to GWT.create()
+ if (!concreteType.isStatic()) {
+ logger.log(TreeLogger.ERROR, "Expecting concrete type"
+ + concreteType.getQualifiedSourceName() + " to be static.");
+ throw new UnableToCompleteException();
+ }
+ }
+
+ /**
+ * Given a method and a qualifier expression, construct an invocation of the
+ * method using its default parameter names.
+ */
+ private void writeInvocation(SourceWriter sw, String qualifier, JMethod method) {
+ sw.print(qualifier + "." + method.getName() + "(");
+
+ for (Iterator<JParameter> i = Arrays.asList(method.getParameters()).iterator(); i.hasNext();) {
+ JParameter param = i.next();
+ sw.print(param.getName());
+ if (i.hasNext()) {
+ sw.print(", ");
+ }
+ }
+
+ sw.println(");");
+ }
+}
diff --git a/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
index a0bcd41..e21bf52 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
@@ -24,6 +24,8 @@
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.TypeOracleMediator;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
@@ -49,34 +51,41 @@
private final JField[] serializableFields;
- private final SerializableTypeOracle serializationOracle;
-
private SourceWriter sourceWriter;
+ private final SerializableTypeOracle typesSentFromBrowser;
+
+ private final SerializableTypeOracle typesSentToBrowser;
+
+ private final TypeOracle typeOracle;
+
/**
* Constructs a field serializer for the class.
- *
- * @param serializationOracle
- * @param requestedClass
*/
- public FieldSerializerCreator(SerializableTypeOracle serializationOracle,
- JClassType requestedClass) {
+ public FieldSerializerCreator(TypeOracle typeOracle,
+ SerializableTypeOracle typesSentFromBrowser,
+ SerializableTypeOracle typesSentToBrowser, JClassType requestedClass) {
assert (requestedClass != null);
assert (requestedClass.isClass() != null || requestedClass.isArray() != null);
- this.serializationOracle = serializationOracle;
+ this.typeOracle = typeOracle;
+ this.typesSentFromBrowser = typesSentFromBrowser;
+ this.typesSentToBrowser = typesSentToBrowser;
serializableClass = requestedClass;
- serializableFields = serializationOracle.getSerializableFields(requestedClass);
+ serializableFields = SerializationUtils.getSerializableFields(typeOracle,
+ requestedClass);
}
public String realize(TreeLogger logger, GeneratorContext ctx) {
assert (ctx != null);
- assert (serializationOracle.isSerializable(serializableClass));
+ assert (typesSentFromBrowser.isSerializable(serializableClass) || typesSentToBrowser.isSerializable(serializableClass));
logger = logger.branch(TreeLogger.DEBUG,
"Generating a field serializer for type '"
+ serializableClass.getQualifiedSourceName() + "'", null);
- String fieldSerializerName = serializationOracle.getFieldSerializerName(serializableClass);
+
+ String fieldSerializerName = SerializationUtils.getFieldSerializerName(
+ typeOracle, serializableClass);
sourceWriter = getSourceWriter(logger, ctx);
if (sourceWriter == null) {
@@ -111,7 +120,8 @@
}
private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) {
- String qualifiedSerializerName = serializationOracle.getFieldSerializerName(serializableClass);
+ String qualifiedSerializerName = SerializationUtils.getFieldSerializerName(
+ typeOracle, serializableClass);
int packageNameEnd = qualifiedSerializerName.lastIndexOf('.');
String className;
String packageName;
@@ -137,8 +147,8 @@
private void maybeSuppressLongWarnings(JType fieldType) {
if (fieldType == JPrimitiveType.LONG) {
/**
- * Accessing long from JSNI causes a error, but field serializers need
- * to be able to do just that in order to bypass java accessibility
+ * Accessing long from JSNI causes a error, but field serializers need to
+ * be able to do just that in order to bypass java accessibility
* restrictions.
*/
sourceWriter.println("@" + UnsafeNativeLong.class.getName());
@@ -281,8 +291,10 @@
sourceWriter.println();
JClassType superClass = serializableClass.getSuperclass();
- if (superClass != null && serializationOracle.isSerializable(superClass)) {
- String fieldSerializerName = serializationOracle.getFieldSerializerName(superClass);
+ if (superClass != null
+ && (typesSentFromBrowser.isSerializable(superClass) || typesSentToBrowser.isSerializable(superClass))) {
+ String fieldSerializerName = SerializationUtils.getFieldSerializerName(
+ typeOracle, superClass);
sourceWriter.print(fieldSerializerName);
sourceWriter.println(".deserialize(streamReader, instance);");
}
@@ -311,8 +323,10 @@
sourceWriter.println();
JClassType superClass = serializableClass.getSuperclass();
- if (superClass != null && serializationOracle.isSerializable(superClass)) {
- String fieldSerializerName = serializationOracle.getFieldSerializerName(superClass);
+ if (superClass != null
+ && (typesSentFromBrowser.isSerializable(superClass) || typesSentToBrowser.isSerializable(superClass))) {
+ String fieldSerializerName = SerializationUtils.getFieldSerializerName(
+ typeOracle, superClass);
sourceWriter.print(fieldSerializerName);
sourceWriter.println(".serialize(streamWriter, instance);");
}
@@ -384,7 +398,7 @@
sourceWriter.indent();
sourceWriter.print("return instance.@");
- sourceWriter.print(serializationOracle.getSerializedTypeName(serializableClass));
+ sourceWriter.print(TypeOracleMediator.computeBinaryClassName(serializableClass));
sourceWriter.print("::");
sourceWriter.print(fieldName);
sourceWriter.println(";");
@@ -415,7 +429,7 @@
sourceWriter.indent();
sourceWriter.print("instance.@");
- sourceWriter.print(serializationOracle.getSerializedTypeName(serializableClass));
+ sourceWriter.print(TypeOracleMediator.computeBinaryClassName(serializableClass));
sourceWriter.print("::");
sourceWriter.print(fieldName);
sourceWriter.println(" = value;");
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
index e64f883..627f774 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
@@ -16,6 +16,7 @@
package com.google.gwt.user.rebind.rpc;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
@@ -30,6 +31,7 @@
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.generator.GenUtil;
import com.google.gwt.dev.generator.NameFactory;
+import com.google.gwt.dev.javac.TypeOracleMediator;
import com.google.gwt.dev.util.Util;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
@@ -42,6 +44,7 @@
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.gwt.user.server.rpc.SerializationPolicyLoader;
+import com.google.gwt.user.server.rpc.impl.TypeNameObfuscator;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -49,8 +52,11 @@
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
/**
* Creates a client-side proxy for a
@@ -69,8 +75,10 @@
* methods.
*/
private static void addRemoteServiceRootTypes(TreeLogger logger,
- TypeOracle typeOracle, SerializableTypeOracleBuilder stob,
- JClassType remoteService) throws NotFoundException {
+ TypeOracle typeOracle,
+ SerializableTypeOracleBuilder typesSentFromBrowser,
+ SerializableTypeOracleBuilder typesSentToBrowser, JClassType remoteService)
+ throws NotFoundException {
logger = logger.branch(TreeLogger.DEBUG, "Analyzing '"
+ remoteService.getParameterizedQualifiedSourceName()
+ "' for serializable types", null);
@@ -89,7 +97,7 @@
TreeLogger returnTypeLogger = methodLogger.branch(TreeLogger.DEBUG,
"Return type: " + returnType.getParameterizedQualifiedSourceName(),
null);
- stob.addRootType(returnTypeLogger, returnType);
+ typesSentToBrowser.addRootType(returnTypeLogger, returnType);
}
JParameter[] params = method.getParameters();
@@ -97,7 +105,7 @@
TreeLogger paramLogger = methodLogger.branch(TreeLogger.DEBUG,
"Parameter: " + param.toString(), null);
JType paramType = param.getType();
- stob.addRootType(paramLogger, paramType);
+ typesSentFromBrowser.addRootType(paramLogger, paramType);
}
JType[] exs = method.getThrows();
@@ -114,7 +122,7 @@
null);
}
- stob.addRootType(throwsLogger, ex);
+ typesSentToBrowser.addRootType(throwsLogger, ex);
}
}
}
@@ -138,6 +146,28 @@
stob.addRootType(logger, icseType);
}
+ /**
+ * Take the union of two type arrays, and then sort the results
+ * alphabetically.
+ */
+ private static JType[] unionOfTypeArrays(JType[]... types) {
+ Set<JType> typesList = new HashSet<JType>();
+ for (JType[] a : types) {
+ typesList.addAll(Arrays.asList(a));
+ }
+ JType[] serializableTypes = typesList.toArray(new JType[0]);
+ Arrays.sort(serializableTypes,
+ SerializableTypeOracleBuilder.JTYPE_COMPARATOR);
+ return serializableTypes;
+ }
+
+ private boolean elideTypeNames;
+
+ /**
+ * The possibly obfuscated type signatures used to represent a type.
+ */
+ private Map<JType, String> typeStrings;
+
private JClassType serviceIntf;
{
@@ -207,40 +237,68 @@
serviceIntf, serviceAsync);
// Determine the set of serializable types
- SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+ SerializableTypeOracleBuilder typesSentFromBrowserBuilder = new SerializableTypeOracleBuilder(
+ logger, context.getPropertyOracle(), typeOracle);
+ SerializableTypeOracleBuilder typesSentToBrowserBuilder = new SerializableTypeOracleBuilder(
logger, context.getPropertyOracle(), typeOracle);
try {
- addRequiredRoots(logger, typeOracle, stob);
+ addRequiredRoots(logger, typeOracle, typesSentFromBrowserBuilder);
+ addRequiredRoots(logger, typeOracle, typesSentToBrowserBuilder);
- addRemoteServiceRootTypes(logger, typeOracle, stob, serviceIntf);
+ addRemoteServiceRootTypes(logger, typeOracle,
+ typesSentFromBrowserBuilder, typesSentToBrowserBuilder, serviceIntf);
} catch (NotFoundException e) {
logger.log(TreeLogger.ERROR, "", e);
throw new UnableToCompleteException();
}
+ try {
+ elideTypeNames = Boolean.parseBoolean(context.getPropertyOracle().getPropertyValue(
+ logger, TypeSerializerCreator.GWT_ELIDE_TYPE_NAMES_FROM_RPC));
+ } catch (BadPropertyValueException e) {
+ logger.log(TreeLogger.ERROR, "Configuration property "
+ + TypeSerializerCreator.GWT_ELIDE_TYPE_NAMES_FROM_RPC
+ + " is not defined. Is RemoteService.gwt.xml inherited?");
+ throw new UnableToCompleteException();
+ }
+
// Create a resource file to receive all of the serialization information
// computed by STOB and mark it as private so it does not end up in the
// output.
OutputStream pathInfo = context.tryCreateResource(logger,
serviceIntf.getQualifiedSourceName() + ".rpc.log");
- stob.setLogOutputStream(pathInfo);
- SerializableTypeOracle sto = stob.build(logger);
+ typesSentFromBrowserBuilder.setLogOutputStream(pathInfo);
+ SerializableTypeOracle typesSentFromBrowser = typesSentFromBrowserBuilder.build(logger);
+ SerializableTypeOracle typesSentToBrowser = typesSentToBrowserBuilder.build(logger);
if (pathInfo != null) {
context.commitResource(logger, pathInfo).setPrivate(true);
}
- TypeSerializerCreator tsc = new TypeSerializerCreator(logger, sto, context,
- sto.getTypeSerializerQualifiedName(serviceIntf));
+ TypeSerializerCreator tsc = new TypeSerializerCreator(logger,
+ typesSentFromBrowser, typesSentToBrowser, context,
+ SerializationUtils.getTypeSerializerQualifiedName(serviceIntf));
tsc.realize(logger);
- String serializationPolicyStrongName = writeSerializationPolicyFile(logger,
- context, sto);
+ typeStrings = new HashMap<JType, String>(tsc.getTypeStrings());
+ typeStrings.put(serviceIntf, TypeNameObfuscator.SERVICE_INTERFACE_ID);
- generateProxyFields(srcWriter, sto, serializationPolicyStrongName);
+ String serializationPolicyStrongName = writeSerializationPolicyFile(logger,
+ context, typesSentFromBrowser, typesSentToBrowser);
+
+ String remoteServiceInterfaceName = elideTypeNames
+ ? TypeNameObfuscator.SERVICE_INTERFACE_ID
+ : TypeOracleMediator.computeBinaryClassName(serviceIntf);
+ generateProxyFields(srcWriter, typesSentFromBrowser,
+ serializationPolicyStrongName, remoteServiceInterfaceName);
generateProxyContructor(javadocAnnotationDeprecationBranch, srcWriter);
- generateProxyMethods(srcWriter, sto, syncMethToAsyncMethMap);
+ generateProxyMethods(srcWriter, typesSentFromBrowser,
+ syncMethToAsyncMethMap);
+
+ if (elideTypeNames) {
+ generateStreamWriterOverride(srcWriter);
+ }
srcWriter.commit(logger);
@@ -272,13 +330,13 @@
*/
private void generateProxyFields(SourceWriter srcWriter,
SerializableTypeOracle serializableTypeOracle,
- String serializationPolicyStrongName) {
+ String serializationPolicyStrongName, String remoteServiceInterfaceName) {
// Initialize a field with binary name of the remote service interface
- srcWriter.println("private static final String REMOTE_SERVICE_INTERFACE_NAME = \""
- + serializableTypeOracle.getSerializedTypeName(serviceIntf) + "\";");
+ srcWriter.println("private static final String REMOTE_SERVICE_INTERFACE_NAME = "
+ + "\"" + remoteServiceInterfaceName + "\";");
srcWriter.println("private static final String SERIALIZATION_POLICY =\""
+ serializationPolicyStrongName + "\";");
- String typeSerializerName = serializableTypeOracle.getTypeSerializerQualifiedName(serviceIntf);
+ String typeSerializerName = SerializationUtils.getTypeSerializerQualifiedName(serviceIntf);
srcWriter.println("private static final " + typeSerializerName
+ " SERIALIZER = new " + typeSerializerName + "();");
srcWriter.println();
@@ -343,7 +401,8 @@
String statsMethodExpr = getProxySimpleName() + "." + syncMethod.getName();
String tossName = nameFactory.createName("toss");
w.println("boolean " + tossName + " = isStatsAvailable() && stats("
- + "timeStat(\"" + statsMethodExpr + "\", getRequestId(), \"begin\"));");
+ + "timeStat(\"" + statsMethodExpr + "\", " + requestIdName
+ + ", \"begin\"));");
w.print(ClientSerializationStreamWriter.class.getSimpleName());
w.print(" ");
@@ -364,10 +423,16 @@
JParameter[] syncParams = syncMethod.getParameters();
w.println(streamWriterName + ".writeInt(" + syncParams.length + ");");
for (JParameter param : syncParams) {
- w.println(streamWriterName
- + ".writeString(\""
- + serializableTypeOracle.getSerializedTypeName(param.getType().getErasedType())
- + "\");");
+ JType paramType = param.getType().getErasedType();
+ String typeName;
+ if (typeStrings.containsKey(paramType)) {
+ typeName = typeStrings.get(paramType);
+ } else {
+ typeName = TypeOracleMediator.computeBinaryClassName(paramType);
+ }
+ assert typeName != null : "Could not compute a type name for "
+ + paramType.getQualifiedSourceName();
+ w.println(streamWriterName + ".writeString(\"" + typeName + "\");");
}
// Encode all of the arguments to the asynchronous method, but exclude the
@@ -400,7 +465,8 @@
+ ".toString();");
w.println(tossName + " = isStatsAvailable() && stats(" + "timeStat(\""
- + statsMethodExpr + "\", getRequestId(), \"requestSerialized\"));");
+ + statsMethodExpr + "\", " + requestIdName
+ + ", \"requestSerialized\"));");
/*
* Depending on the return type for the async method, return a
@@ -423,7 +489,8 @@
JType returnType = syncMethod.getReturnType();
w.print("ResponseReader." + getResponseReaderFor(returnType).name());
w.println(", \"" + getProxySimpleName() + "." + syncMethod.getName()
- + "\", getRequestId(), " + payloadName + ", " + callbackName + ");");
+ + "\", " + requestIdName + ", " + payloadName + ", " + callbackName
+ + ");");
w.outdent();
w.println("}");
}
@@ -456,6 +523,17 @@
}
}
+ private void generateStreamWriterOverride(SourceWriter srcWriter) {
+ srcWriter.println("@Override");
+ srcWriter.println("public ClientSerializationStreamWriter createStreamWriter() {");
+ srcWriter.indent();
+ srcWriter.println("ClientSerializationStreamWriter toReturn = super.createStreamWriter();");
+ srcWriter.println("toReturn.addFlags(ClientSerializationStreamWriter.FLAG_ELIDE_TYPE_NAMES);");
+ srcWriter.println("return toReturn;");
+ srcWriter.outdent();
+ srcWriter.println("}");
+ }
+
private String getProxyQualifiedName() {
String[] name = Shared.synthesizeTopLevelClassName(serviceIntf,
PROXY_SUFFIX);
@@ -530,21 +608,40 @@
}
private String writeSerializationPolicyFile(TreeLogger logger,
- GeneratorContext ctx, SerializableTypeOracle sto)
+ GeneratorContext ctx, SerializableTypeOracle serializationSto,
+ SerializableTypeOracle deserializationSto)
throws UnableToCompleteException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(baos,
SerializationPolicyLoader.SERIALIZATION_POLICY_FILE_ENCODING);
+ TypeOracle oracle = ctx.getTypeOracle();
PrintWriter pw = new PrintWriter(osw);
- JType[] serializableTypes = sto.getSerializableTypes();
+ JType[] serializableTypes = unionOfTypeArrays(
+ serializationSto.getSerializableTypes(),
+ deserializationSto.getSerializableTypes(), new JType[] {serviceIntf});
+
for (int i = 0; i < serializableTypes.length; ++i) {
- JType serializableType = serializableTypes[i];
- String binaryTypeName = sto.getSerializedTypeName(serializableType);
- boolean maybeInstantiated = sto.maybeInstantiated(serializableType);
- pw.print(binaryTypeName + ", " + Boolean.toString(maybeInstantiated)
- + '\n');
+ JType type = serializableTypes[i];
+ String binaryTypeName = TypeOracleMediator.computeBinaryClassName(type);
+ pw.print(binaryTypeName);
+ pw.print(", "
+ + Boolean.toString(deserializationSto.isSerializable(type)));
+ pw.print(", "
+ + Boolean.toString(deserializationSto.maybeInstantiated(type)));
+ pw.print(", " + Boolean.toString(serializationSto.isSerializable(type)));
+ pw.print(", "
+ + Boolean.toString(serializationSto.maybeInstantiated(type)));
+ pw.print(", " + typeStrings.get(type));
+
+ /*
+ * Include the serialization signature to bump the RPC file name if
+ * obfuscated identifiers are used.
+ */
+ pw.print(", "
+ + SerializationUtils.getSerializationSignature(oracle, type));
+ pw.print('\n');
}
// Closes the wrapped streams.
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracle.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracle.java
index 1dde20d..942e68a 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracle.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracle.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.user.rebind.rpc;
-import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JType;
/**
@@ -25,24 +23,6 @@
* {@link com.google.gwt.user.client.rpc.RemoteService RemoteService}.
*/
public interface SerializableTypeOracle {
- /**
- * Returns the name of the field serializer for a particular type. This name
- * can be either the name of a custom field serializer or that of a generated
- * field serializer. If the type is not serializable then it can return null.
- *
- * @param type the type that is going to be serialized
- * @return the fully qualified name of the field serializer for the given type
- */
- String getFieldSerializerName(JType type);
-
- /**
- * Returns the set of fields that are serializable for a given class type.
- * This method does not consider any superclass fields.
- *
- * @param classType the class for which we want serializable fields
- * @return array of fields that meet the serialization criteria.
- */
- JField[] getSerializableFields(JClassType classType);
/**
* Returns the list of all types that are considered serializable.
@@ -52,50 +32,6 @@
JType[] getSerializableTypes();
/**
- * Returns the serialization signature for a type.
- *
- * @param instanceType
- * @return a string representing the serialization signature of a type
- */
- String getSerializationSignature(JType instanceType);
-
- /**
- * Returns the serialized name of a type. The serialized name of a type is the
- * name that would be returned by {@link Class#getName()}.
- *
- * @param type
- * @return serialized name of a type
- */
- String getSerializedTypeName(JType type);
-
- /**
- * Returns the qualified name of the type serializer class for the given
- * service interface.
- *
- * @param serviceIntf service interface
- * @return name of the type serializer that handles the service interface
- */
- String getTypeSerializerQualifiedName(JClassType serviceIntf);
-
- /**
- * Returns the simple name of the type serializer class for the given service
- * interface.
- *
- * @param serviceIntf service interface
- * @return the simple name of the type serializer class
- */
- String getTypeSerializerSimpleName(JClassType serviceIntf);
-
- /**
- * Returns the custom field serializer associated with the given type. If
- * there is none, null is returned.
- *
- * @param type type that may have a custom field serializer
- * @return custom field serializer or null if there is none
- */
- JClassType hasCustomFieldSerializer(JType type);
-
- /**
* Returns true if the type is serializable. If a type is serializable then
* there is a secondary type called a FieldSerializer that provides the
* behavior necessary to serialize or deserialize the fields of an instance.
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
index 4a13edb..fa8eb9e 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
@@ -31,6 +31,7 @@
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.user.client.rpc.GwtTransient;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.google.gwt.user.rebind.rpc.TypeParameterExposureComputer.TypeParameterFlowInfo;
import com.google.gwt.user.rebind.rpc.TypePaths.TypePath;
@@ -87,14 +88,14 @@
private class TypeInfoComputed {
/**
- * <code>true</code> if the type is assignable to {@link IsSerializable}
- * or {@link java.io.Serializable Serializable}.
+ * <code>true</code> if the type is assignable to {@link IsSerializable} or
+ * {@link java.io.Serializable Serializable}.
*/
private final boolean autoSerializable;
/**
- * <code>true</code> if the this type directly implements one of the
- * marker interfaces.
+ * <code>true</code> if the this type directly implements one of the marker
+ * interfaces.
*/
private final boolean directlyImplementsMarker;
@@ -380,8 +381,8 @@
/**
* Return <code>true</code> if a class's fields should be considered for
- * serialization. If it returns <code>false</code> then none of the fields
- * of this class should be serialized.
+ * serialization. If it returns <code>false</code> then none of the fields of
+ * this class should be serialized.
*/
static boolean shouldConsiderFieldsForSerialization(TreeLogger logger,
JClassType type, boolean isSpeculative, TypeFilter filter) {
@@ -446,8 +447,8 @@
}
/**
- * Returns <code>true</code> if the field qualifies for serialization
- * without considering its type.
+ * Returns <code>true</code> if the field qualifies for serialization without
+ * considering its type.
*/
static boolean shouldConsiderForSerialization(TreeLogger logger,
boolean suppressNonStaticFinalFieldWarnings, JField field) {
@@ -455,6 +456,10 @@
return false;
}
+ if (field.isAnnotationPresent(GwtTransient.class)) {
+ return false;
+ }
+
if (field.isFinal()) {
logger.branch(suppressNonStaticFinalFieldWarnings ? TreeLogger.DEBUG
: TreeLogger.WARN, "Field '" + field.toString()
@@ -707,7 +712,7 @@
logSerializableTypes(logger, fieldSerializableTypes);
- return new SerializableTypeOracleImpl(typeOracle, fieldSerializableTypes,
+ return new SerializableTypeOracleImpl(fieldSerializableTypes,
possiblyInstantiatedTypes);
}
@@ -745,8 +750,8 @@
/**
* Same as
- * {@link #checkTypeInstantiable(TreeLogger, JType, boolean, com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.TypePath)},
- * except that returns the set of instantiable subtypes.
+ * {@link #checkTypeInstantiable(TreeLogger, JType, boolean, com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.TypePath)}
+ * , except that returns the set of instantiable subtypes.
*/
boolean checkTypeInstantiable(TreeLogger logger, JType type,
boolean isSpeculative, TypePath path, Set<JClassType> instSubtypes) {
@@ -1061,9 +1066,8 @@
/*
* If my super type did not check out, then I am not instantiable and we
- * should error out... UNLESS I am *directly* serializable myself, in
- * which case it's ok for me to be the root of a new instantiable
- * hierarchy.
+ * should error out... UNLESS I amdirectly serializable myself, in which
+ * case it's ok for me to be the root of a new instantiable hierarchy.
*/
if (!superTypeOk && !isDirectlySerializable(classOrInterface)) {
return false;
@@ -1321,7 +1325,7 @@
return;
}
- logger.log(TreeLogger.INFO, path.toString());
+ logger.log(TreeLogger.DEBUG, path.toString());
logPath(logger, path.getParent());
}
@@ -1336,7 +1340,7 @@
logger = printWriterTreeLogger;
}
- logger.log(TreeLogger.INFO, "Reachable types computed on: "
+ logger.log(TreeLogger.DEBUG, "Reachable types computed on: "
+ new Date().toString());
Set<JType> keySet = typeToTypeInfoComputed.keySet();
JType[] types = keySet.toArray(new JType[0]);
@@ -1346,24 +1350,24 @@
TypeInfoComputed tic = typeToTypeInfoComputed.get(type);
assert (tic != null);
- TreeLogger typeLogger = logger.branch(TreeLogger.INFO,
+ TreeLogger typeLogger = logger.branch(TreeLogger.DEBUG,
tic.getType().getParameterizedQualifiedSourceName());
- TreeLogger serializationStatus = typeLogger.branch(TreeLogger.INFO,
+ TreeLogger serializationStatus = typeLogger.branch(TreeLogger.DEBUG,
"Serialization status");
if (tic.isInstantiable()) {
- serializationStatus.branch(TreeLogger.INFO, "Instantiable");
+ serializationStatus.branch(TreeLogger.DEBUG, "Instantiable");
} else {
if (tic.isFieldSerializable()) {
- serializationStatus.branch(TreeLogger.INFO, "Field serializable");
+ serializationStatus.branch(TreeLogger.DEBUG, "Field serializable");
} else {
- serializationStatus.branch(TreeLogger.INFO, "Not serializable");
+ serializationStatus.branch(TreeLogger.DEBUG, "Not serializable");
}
}
- TreeLogger pathLogger = typeLogger.branch(TreeLogger.INFO, "Path");
+ TreeLogger pathLogger = typeLogger.branch(TreeLogger.DEBUG, "Path");
logPath(pathLogger, tic.getPath());
- logger.log(TreeLogger.INFO, "");
+ logger.log(TreeLogger.DEBUG, "");
}
if (printWriter != null) {
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java
index 993987d..5baa7f9 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java
@@ -15,232 +15,39 @@
*/
package com.google.gwt.user.rebind.rpc;
-import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.JField;
-import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.javac.TypeOracleMediator;
-import com.google.gwt.dev.util.Util;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
import java.util.Set;
-import java.util.zip.CRC32;
final class SerializableTypeOracleImpl implements SerializableTypeOracle {
- private static final Comparator<JField> FIELD_COMPARATOR = new Comparator<JField>() {
- public int compare(JField f1, JField f2) {
- return f1.getName().compareTo(f2.getName());
- }
- };
-
- private static final String GENERATED_FIELD_SERIALIZER_SUFFIX = "_FieldSerializer";
- private static final String TYPE_SERIALIZER_SUFFIX = "_TypeSerializer";
- private static final Set<String> TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES = new HashSet<String>();
-
- static {
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Boolean");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Byte");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Character");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Double");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Exception");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Float");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Integer");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Long");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Object");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Short");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.String");
- TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Throwable");
- }
-
- private final Set<JClassType> serializableTypesSet;
- private final TypeOracle typeOracle;
private final Set<JClassType> possiblyInstantiatedTypes;
+ private final Set<JClassType> serializableTypesSet;
- public SerializableTypeOracleImpl(TypeOracle typeOracle,
- Set<JClassType> serializableTypes,
+ public SerializableTypeOracleImpl(Set<JClassType> serializableTypes,
Set<JClassType> possiblyInstantiatedTypes) {
serializableTypesSet = serializableTypes;
- this.typeOracle = typeOracle;
-
this.possiblyInstantiatedTypes = possiblyInstantiatedTypes;
}
- public String getFieldSerializerName(JType type) {
- if (!isSerializable(type)) {
- return null;
- }
-
- JClassType customSerializer = hasCustomFieldSerializer(type);
- if (customSerializer != null) {
- return customSerializer.getQualifiedSourceName();
- }
-
- assert (type.isClassOrInterface() != null || type.isArray() != null);
- JClassType classType = (JClassType) type;
- String[] name = Shared.synthesizeTopLevelClassName(classType,
- GENERATED_FIELD_SERIALIZER_SUFFIX);
- if (name[0].length() > 0) {
- String serializerName = name[0] + "." + name[1];
- if (SerializableTypeOracleBuilder.isInStandardJavaPackage(type.getQualifiedSourceName())) {
- /*
- * Don't generate code into java packages. If you do hosted mode
- * CompilingClassLoader will fail to resolve references to the generated
- * code.
- */
- serializerName = "com.google.gwt.user.client.rpc.core."
- + serializerName;
- }
-
- return serializerName;
- } else {
- return name[1];
- }
- }
-
- /**
- * Returns the fields which qualify for serialization.
- */
- public JField[] getSerializableFields(JClassType classType) {
- assert (classType != null);
-
- List<JField> fields = new ArrayList<JField>();
- JField[] declFields = classType.getFields();
- assert (declFields != null);
- for (JField field : declFields) {
- // TODO(mmendez): this is shared with the serializable type oracle
- // builder, join with that
- if (field.isStatic() || field.isTransient() || field.isFinal()) {
- continue;
- }
-
- fields.add(field);
- }
-
- Collections.sort(fields, FIELD_COMPARATOR);
- return fields.toArray(new JField[fields.size()]);
- }
-
- /**
- *
- */
public JType[] getSerializableTypes() {
return serializableTypesSet.toArray(new JType[serializableTypesSet.size()]);
}
- public String getSerializationSignature(JType type) {
- CRC32 crc = new CRC32();
-
- try {
- generateSerializationSignature(type, crc);
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(
- "Could not compute the serialization signature", e);
- }
-
- return Long.toString(crc.getValue());
- }
-
- public String getSerializedTypeName(JType type) {
- return TypeOracleMediator.computeBinaryClassName(type);
- }
-
- public String getTypeSerializerQualifiedName(JClassType serviceIntf) {
- if (serviceIntf.isInterface() == null) {
- throw new IllegalArgumentException(serviceIntf.getQualifiedSourceName()
- + " is not a service interface");
- }
-
- String[] name = Shared.synthesizeTopLevelClassName(serviceIntf,
- TYPE_SERIALIZER_SUFFIX);
- if (name[0].length() > 0) {
- return name[0] + "." + name[1];
- } else {
- return name[1];
- }
- }
-
- public String getTypeSerializerSimpleName(JClassType serviceIntf) {
- if (serviceIntf.isInterface() == null) {
- throw new IllegalArgumentException(serviceIntf.getQualifiedSourceName()
- + " is not a service interface");
- }
-
- String[] name = Shared.synthesizeTopLevelClassName(serviceIntf,
- TYPE_SERIALIZER_SUFFIX);
- return name[1];
- }
-
- public JClassType hasCustomFieldSerializer(JType type) {
- return SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle,
- type);
- }
-
/**
- * Returns <code>true</code> if the type is serializable.
+ * Returns <code>true</code> if the type's fields can be serializede.
*/
public boolean isSerializable(JType type) {
return serializableTypesSet.contains(type);
}
+ /**
+ * Returns <code>true</code> if the type can be serialized and then
+ * instantiated on the other side.
+ */
public boolean maybeInstantiated(JType type) {
return possiblyInstantiatedTypes.contains(type);
}
-
- private boolean excludeImplementationFromSerializationSignature(
- JType instanceType) {
- if (TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.contains(instanceType.getQualifiedSourceName())) {
- return true;
- }
-
- return false;
- }
-
- private void generateSerializationSignature(JType type, CRC32 crc)
- throws UnsupportedEncodingException {
- JParameterizedType parameterizedType = type.isParameterized();
- if (parameterizedType != null) {
- generateSerializationSignature(parameterizedType.getRawType(), crc);
-
- return;
- }
-
- String serializedTypeName = getSerializedTypeName(type);
- crc.update(serializedTypeName.getBytes(Util.DEFAULT_ENCODING));
-
- if (excludeImplementationFromSerializationSignature(type)) {
- return;
- }
-
- JClassType customSerializer = hasCustomFieldSerializer(type);
- if (customSerializer != null) {
- generateSerializationSignature(customSerializer, crc);
- } else if (type.isArray() != null) {
- JArrayType isArray = type.isArray();
- generateSerializationSignature(isArray.getComponentType(), crc);
- } else if (type.isClassOrInterface() != null) {
- JClassType isClassOrInterface = type.isClassOrInterface();
- JField[] fields = getSerializableFields(isClassOrInterface);
- for (JField field : fields) {
- assert (field != null);
-
- crc.update(field.getName().getBytes(Util.DEFAULT_ENCODING));
- crc.update(getSerializedTypeName(field.getType()).getBytes(
- Util.DEFAULT_ENCODING));
- }
-
- JClassType superClass = isClassOrInterface.getSuperclass();
- if (superClass != null) {
- generateSerializationSignature(superClass, crc);
- }
- }
- }
}
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializationUtils.java b/user/src/com/google/gwt/user/rebind/rpc/SerializationUtils.java
new file mode 100644
index 0000000..8936d73
--- /dev/null
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializationUtils.java
@@ -0,0 +1,242 @@
+/*
+ * 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.rebind.rpc;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.typeinfo.JArrayType;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JField;
+import com.google.gwt.core.ext.typeinfo.JParameterizedType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.TypeOracleMediator;
+import com.google.gwt.dev.util.Util;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.CRC32;
+
+/**
+ * Utilities used for implementing serialization.
+ */
+class SerializationUtils {
+ static final Comparator<JField> FIELD_COMPARATOR = new Comparator<JField>() {
+ public int compare(JField f1, JField f2) {
+ return f1.getName().compareTo(f2.getName());
+ }
+ };
+ static final String GENERATED_FIELD_SERIALIZER_SUFFIX = "_FieldSerializer";
+ static final String TYPE_SERIALIZER_SUFFIX = "_TypeSerializer";
+ static final Set<String> TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES = new HashSet<String>();
+
+ static {
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Boolean");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Byte");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Character");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Double");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Exception");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Float");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Integer");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Long");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Object");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Short");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.String");
+ TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Throwable");
+ }
+
+ /**
+ * Returns the name of the field serializer for a particular type. This name
+ * can be either the name of a custom field serializer or that of a generated
+ * field serializer. If the type is not serializable then it can return null.
+ *
+ * @param type the type that is going to be serialized
+ *
+ * @return the fully qualified name of the field serializer for the given type
+ */
+ static String getFieldSerializerName(TypeOracle typeOracle, JType type) {
+ JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(
+ typeOracle, type);
+ if (customSerializer != null) {
+ return customSerializer.getQualifiedSourceName();
+ }
+
+ assert (type.isClassOrInterface() != null || type.isArray() != null);
+ JClassType classType = (JClassType) type;
+ String[] name = Shared.synthesizeTopLevelClassName(classType,
+ SerializationUtils.GENERATED_FIELD_SERIALIZER_SUFFIX);
+ if (name[0].length() > 0) {
+ String serializerName = name[0] + "." + name[1];
+ if (SerializableTypeOracleBuilder.isInStandardJavaPackage(type.getQualifiedSourceName())) {
+ /*
+ * Don't generate code into java packages. If you do hosted mode
+ * CompilingClassLoader will fail to resolve references to the generated
+ * code.
+ */
+ serializerName = "com.google.gwt.user.client.rpc.core."
+ + serializerName;
+ }
+
+ return serializerName;
+ } else {
+ return name[1];
+ }
+ }
+
+ /**
+ * Returns the set of fields that are serializable for a given class type.
+ * This method does not consider any superclass fields.
+ *
+ * @param classType the class for which we want serializable fields
+ * @return array of fields that meet the serialization criteria.
+ */
+ static JField[] getSerializableFields(TypeOracle typeOracle,
+ JClassType classType) {
+ assert (classType != null);
+
+ List<JField> fields = new ArrayList<JField>();
+ JField[] declFields = classType.getFields();
+ assert (declFields != null);
+ for (JField field : declFields) {
+ if (SerializableTypeOracleBuilder.shouldConsiderForSerialization(
+ TreeLogger.NULL, true, field)) {
+ fields.add(field);
+ }
+ }
+
+ Collections.sort(fields, FIELD_COMPARATOR);
+ return fields.toArray(new JField[fields.size()]);
+ }
+
+ /**
+ * Returns the serialization signature for a type.
+ *
+ * @param instanceType
+ * @return a string representing the serialization signature of a type
+ */
+ static String getSerializationSignature(TypeOracle typeOracle, JType type)
+ throws RuntimeException {
+ CRC32 crc = new CRC32();
+
+ try {
+ generateSerializationSignature(typeOracle, type, crc);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(
+ "Could not compute the serialization signature", e);
+ }
+
+ return Long.toString(crc.getValue());
+ }
+
+ /**
+ * Returns the qualified name of the type serializer class for the given
+ * service interface.
+ *
+ * @param serviceIntf service interface
+ * @return name of the type serializer that handles the service interface
+ */
+ static String getTypeSerializerQualifiedName(JClassType serviceIntf)
+ throws IllegalArgumentException {
+ if (serviceIntf.isInterface() == null) {
+ throw new IllegalArgumentException(serviceIntf.getQualifiedSourceName()
+ + " is not a service interface");
+ }
+
+ String[] name = Shared.synthesizeTopLevelClassName(serviceIntf,
+ TYPE_SERIALIZER_SUFFIX);
+ if (name[0].length() > 0) {
+ return name[0] + "." + name[1];
+ } else {
+ return name[1];
+ }
+ }
+
+ /**
+ * Returns the simple name of the type serializer class for the given service
+ * interface.
+ *
+ * @param serviceIntf service interface
+ * @return the simple name of the type serializer class
+ */
+ static String getTypeSerializerSimpleName(TypeOracle typeOracle,
+ JClassType serviceIntf) throws IllegalArgumentException {
+ if (serviceIntf.isInterface() == null) {
+ throw new IllegalArgumentException(serviceIntf.getQualifiedSourceName()
+ + " is not a service interface");
+ }
+
+ String[] name = Shared.synthesizeTopLevelClassName(serviceIntf,
+ TYPE_SERIALIZER_SUFFIX);
+ return name[1];
+ }
+
+ private static boolean excludeImplementationFromSerializationSignature(
+ JType instanceType) {
+ if (TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.contains(instanceType.getQualifiedSourceName())) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static void generateSerializationSignature(TypeOracle typeOracle,
+ JType type, CRC32 crc) throws UnsupportedEncodingException {
+ JParameterizedType parameterizedType = type.isParameterized();
+ if (parameterizedType != null) {
+ generateSerializationSignature(typeOracle,
+ parameterizedType.getRawType(), crc);
+
+ return;
+ }
+
+ String serializedTypeName = TypeOracleMediator.computeBinaryClassName(type);
+ crc.update(serializedTypeName.getBytes(Util.DEFAULT_ENCODING));
+
+ if (excludeImplementationFromSerializationSignature(type)) {
+ return;
+ }
+
+ JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(
+ typeOracle, type);
+ if (customSerializer != null) {
+ generateSerializationSignature(typeOracle, customSerializer, crc);
+ } else if (type.isArray() != null) {
+ JArrayType isArray = type.isArray();
+ generateSerializationSignature(typeOracle, isArray.getComponentType(),
+ crc);
+ } else if (type.isClassOrInterface() != null) {
+ JClassType isClassOrInterface = type.isClassOrInterface();
+ JField[] fields = getSerializableFields(typeOracle, isClassOrInterface);
+ for (JField field : fields) {
+ assert (field != null);
+
+ crc.update(field.getName().getBytes(Util.DEFAULT_ENCODING));
+ crc.update(TypeOracleMediator.computeBinaryClassName(field.getType()).getBytes(
+ Util.DEFAULT_ENCODING));
+ }
+
+ JClassType superClass = isClassOrInterface.getSuperclass();
+ if (superClass != null) {
+ generateSerializationSignature(typeOracle, superClass, crc);
+ }
+ }
+ }
+
+}
diff --git a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
index 206ed81..19f311d 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -17,21 +17,34 @@
package com.google.gwt.user.rebind.rpc;
import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.TypeOracleMediator;
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 com.google.gwt.user.client.rpc.impl.Serializer;
+import com.google.gwt.user.client.rpc.impl.SerializerBase;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* This class generates a class with name 'typeSerializerClassName' that is able
@@ -40,44 +53,108 @@
*/
public class TypeSerializerCreator {
- private static final String DESERIALIZE_METHOD_SIGNATURE = "public native void deserialize("
- + "SerializationStreamReader streamReader, Object instance, String typeSignature)"
- + " throws SerializationException";
+ /**
+ * Configuration property to use type indices instead of type signatures.
+ */
+ public static final String GWT_ELIDE_TYPE_NAMES_FROM_RPC = "gwt.elideTypeNamesFromRPC";
- private static final String INSTANTIATE_METHOD_SIGNATURE = "public native Object instantiate("
- + "SerializationStreamReader streamReader, String typeSignature)"
- + " throws SerializationException";
+ /**
+ * Default number of types to split createMethodMap entries into. Zero means
+ * no sharding occurs. Stored as a string since it is used as a default
+ * property value.
+ *
+ * Note that the inliner will likely reassemble the shards if it is used in
+ * web mode, but it isn't needed there anyway.
+ *
+ * TODO: remove this (and related code) when it is no longer needed.
+ */
+ private static final String DEFAULT_CREATEMETHODMAP_SHARD_SIZE = "0";
- private static final String SERIALIZE_METHOD_SIGNATURE = "public native void serialize("
- + "SerializationStreamWriter streamWriter, Object instance, String typeSignature)"
- + " throws SerializationException";
+ /**
+ * Java system property name to override the above.
+ */
+ private static final String GWT_CREATEMETHODMAP_SHARD_SIZE = "gwt.typecreator.shard.size";
+
+ private static int shardSize = -1;
+
+ private static void computeShardSize(TreeLogger logger)
+ throws UnableToCompleteException {
+ String shardSizeProperty = System.getProperty(
+ GWT_CREATEMETHODMAP_SHARD_SIZE, DEFAULT_CREATEMETHODMAP_SHARD_SIZE);
+ try {
+ shardSize = Integer.valueOf(shardSizeProperty);
+ if (shardSize < 0) {
+ logger.log(TreeLogger.ERROR, GWT_CREATEMETHODMAP_SHARD_SIZE
+ + " must be non-negative: " + shardSizeProperty);
+ throw new UnableToCompleteException();
+ }
+ } catch (NumberFormatException e) {
+ logger.log(TreeLogger.ERROR, "Property " + GWT_CREATEMETHODMAP_SHARD_SIZE
+ + " not a number: " + shardSizeProperty, e);
+ throw new UnableToCompleteException();
+ }
+ }
private final GeneratorContext context;
- private final JType[] serializableTypes;
+ private final SerializableTypeOracle deserializationOracle;
+
+ private final boolean elideTypeNames;
private final SerializableTypeOracle serializationOracle;
+ private final JType[] serializableTypes;
+
private final SourceWriter srcWriter;
private final TypeOracle typeOracle;
private final String typeSerializerClassName;
+ private final Map<JType, String> typeStrings = new IdentityHashMap<JType, String>();
+
public TypeSerializerCreator(TreeLogger logger,
- SerializableTypeOracle serializationOracle, GeneratorContext context,
- String typeSerializerClassName) {
+ SerializableTypeOracle serializationOracle,
+ SerializableTypeOracle deserializationOracle, GeneratorContext context,
+ String typeSerializerClassName) throws UnableToCompleteException {
this.context = context;
this.typeSerializerClassName = typeSerializerClassName;
this.serializationOracle = serializationOracle;
+ this.deserializationOracle = deserializationOracle;
+
this.typeOracle = context.getTypeOracle();
- serializableTypes = serializationOracle.getSerializableTypes();
+ Set<JType> typesSet = new HashSet<JType>();
+ typesSet.addAll(Arrays.asList(serializationOracle.getSerializableTypes()));
+ typesSet.addAll(Arrays.asList(deserializationOracle.getSerializableTypes()));
+ serializableTypes = typesSet.toArray(new JType[0]);
+ Arrays.sort(serializableTypes,
+ SerializableTypeOracleBuilder.JTYPE_COMPARATOR);
srcWriter = getSourceWriter(logger, context);
+ if (shardSize < 0) {
+ computeShardSize(logger);
+ }
+ logger.log(TreeLogger.TRACE, "Using a shard size of " + shardSize
+ + " for TypeSerializerCreator createMethodMap");
+
+ try {
+ String value = context.getPropertyOracle().getPropertyValue(logger,
+ GWT_ELIDE_TYPE_NAMES_FROM_RPC);
+ elideTypeNames = Boolean.parseBoolean(value);
+ } catch (BadPropertyValueException e) {
+ logger.log(TreeLogger.ERROR, "The configuration property "
+ + GWT_ELIDE_TYPE_NAMES_FROM_RPC
+ + " was not defined. Is RemoteService.gwt.xml inherited?");
+ throw new UnableToCompleteException();
+ }
}
- public String realize(TreeLogger logger) {
+ public Map<JType, String> getTypeStrings() {
+ return Collections.unmodifiableMap(typeStrings);
+ }
+
+ public String realize(TreeLogger logger) throws UnableToCompleteException {
logger = logger.branch(TreeLogger.DEBUG,
"Generating TypeSerializer for service interface '"
+ getTypeSerializerClassName() + "'", null);
@@ -90,22 +167,16 @@
writeStaticFields();
+ writeStaticInitializer();
+
writeCreateMethods();
- writeCreateMethodMapMethod();
+ writeRegisterSignatures();
- writeCreateSignatureMapMethod();
+ writeRegisterMethods();
writeRaiseSerializationException();
- writeDeserializeMethod();
-
- writeGetSerializationSignatureMethod();
-
- writeInstantiateMethod();
-
- writeSerializeMethod();
-
srcWriter.commit(logger);
return typeSerializerName;
@@ -118,7 +189,7 @@
private void createFieldSerializer(TreeLogger logger, GeneratorContext ctx,
JType type) {
assert (type != null);
- assert (serializationOracle.isSerializable(type));
+ assert (serializationOracle.isSerializable(type) || deserializationOracle.isSerializable(type));
JParameterizedType parameterizedType = type.isParameterized();
if (parameterizedType != null) {
@@ -126,7 +197,8 @@
return;
}
- JClassType customFieldSerializer = serializationOracle.hasCustomFieldSerializer(type);
+ JClassType customFieldSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(
+ typeOracle, type);
if (customFieldSerializer != null) {
return;
}
@@ -139,8 +211,8 @@
*/
assert (type.isClass() != null || type.isArray() != null);
- FieldSerializerCreator creator = new FieldSerializerCreator(
- serializationOracle, (JClassType) type);
+ FieldSerializerCreator creator = new FieldSerializerCreator(typeOracle,
+ serializationOracle, deserializationOracle, (JClassType) type);
creator.realize(logger, ctx);
}
@@ -162,7 +234,8 @@
assert (type.isArray() == null);
return "create_"
- + serializationOracle.getFieldSerializerName(type).replace('.', '_');
+ + SerializationUtils.getFieldSerializerName(typeOracle, type).replace(
+ '.', '_');
}
private String[] getPackageAndClassName(String fullClassName) {
@@ -173,13 +246,13 @@
packageName = className.substring(0, index);
className = className.substring(index + 1, className.length());
}
- return new String[]{packageName, className};
+ return new String[] {packageName, className};
}
-
+
private JType[] getSerializableTypes() {
return serializableTypes;
}
-
+
private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) {
String name[] = getPackageAndClassName(getTypeSerializerClassName());
String packageName = name[0];
@@ -193,12 +266,13 @@
packageName, className);
composerFactory.addImport(JavaScriptObject.class.getName());
+ composerFactory.addImport(JsArrayString.class.getName());
composerFactory.addImport(Serializer.class.getName());
composerFactory.addImport(SerializationException.class.getName());
composerFactory.addImport(SerializationStreamReader.class.getName());
composerFactory.addImport(SerializationStreamWriter.class.getName());
- composerFactory.addImplementedInterface("Serializer");
+ composerFactory.setSuperclass(SerializerBase.class.getName());
return composerFactory.createSourceWriter(ctx, printWriter);
}
@@ -207,6 +281,16 @@
}
/**
+ * @param type
+ * @return
+ */
+ private String getTypeString(JType type) {
+ String typeString = TypeOracleMediator.computeBinaryClassName(type) + "/"
+ + SerializationUtils.getSerializationSignature(typeOracle, type);
+ return typeString;
+ }
+
+ /**
* Return <code>true</code> if this type is concrete and has a custom field
* serializer that does not declare an instantiate method.
*
@@ -216,7 +300,7 @@
private boolean needsCreateMethod(JType type) {
// If this type is abstract it will not be serialized into the stream
//
- if (!serializationOracle.maybeInstantiated(type)) {
+ if (!deserializationOracle.maybeInstantiated(type)) {
return false;
}
@@ -224,7 +308,8 @@
return false;
}
- JClassType customSerializer = serializationOracle.hasCustomFieldSerializer(type);
+ JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(
+ typeOracle, type);
if (customSerializer == null) {
return false;
}
@@ -239,106 +324,11 @@
return true;
}
- private void writeCreateMethodMapMethod() {
- srcWriter.println("@SuppressWarnings(\"restriction\")");
- srcWriter.println("private static native JavaScriptObject createMethodMap() /*-" + '{');
- {
- srcWriter.indent();
- srcWriter.println("return {");
- JType[] types = getSerializableTypes();
- boolean needComma = false;
- for (int index = 0; index < types.length; ++index) {
- JType type = types[index];
- if (!serializationOracle.maybeInstantiated(type)) {
- continue;
- }
-
- if (needComma) {
- srcWriter.println(",");
- } else {
- needComma = true;
- }
-
- String typeString = serializationOracle.getSerializedTypeName(type)
- + "/" + serializationOracle.getSerializationSignature(type);
-
- srcWriter.print("\"" + typeString + "\":");
-
- // Make a JSON array
- srcWriter.println("[");
- {
- srcWriter.indent();
- String serializerName = serializationOracle.getFieldSerializerName(type);
-
- // First the initialization method
- {
- srcWriter.print("@");
- if (needsCreateMethod(type)) {
- srcWriter.print(getTypeSerializerClassName());
- srcWriter.print("::");
- srcWriter.print(getCreateMethodName(type));
- } else {
- srcWriter.print(serializerName);
- srcWriter.print("::instantiate");
- }
- srcWriter.print("(L"
- + SerializationStreamReader.class.getName().replace('.', '/')
- + ";)");
- srcWriter.println(",");
- }
-
- JClassType customSerializer = serializationOracle.hasCustomFieldSerializer(type);
-
- // Now the deserialization method
- {
- // Assume param type is the concrete type of the serialized type.
- JType paramType = type;
- if (customSerializer != null) {
- // But a custom serializer may specify a looser type.
- JMethod deserializationMethod = CustomFieldSerializerValidator.getDeserializationMethod(
- customSerializer, (JClassType) type);
- paramType = deserializationMethod.getParameters()[1].getType();
- }
- srcWriter.print("@" + serializerName);
- srcWriter.print("::deserialize(L"
- + SerializationStreamReader.class.getName().replace('.', '/')
- + ";" + paramType.getJNISignature() + ")");
- srcWriter.println(",");
- }
-
- // Now the serialization method
- {
- // Assume param type is the concrete type of the serialized type.
- JType paramType = type;
- if (customSerializer != null) {
- // But a custom serializer may specify a looser type.
- JMethod serializationMethod = CustomFieldSerializerValidator.getSerializationMethod(
- customSerializer, (JClassType) type);
- paramType = serializationMethod.getParameters()[1].getType();
- }
- srcWriter.print("@" + serializerName);
- srcWriter.print("::serialize(L"
- + SerializationStreamWriter.class.getName().replace('.', '/')
- + ";" + paramType.getJNISignature() + ")");
- srcWriter.println();
- }
- srcWriter.outdent();
- }
- srcWriter.print("]");
- }
- srcWriter.println();
- srcWriter.println("};");
- srcWriter.outdent();
- }
- srcWriter.println("}-*/;");
- srcWriter.println();
- }
-
private void writeCreateMethods() {
JType[] types = getSerializableTypes();
for (int typeIndex = 0; typeIndex < types.length; ++typeIndex) {
JType type = types[typeIndex];
- assert (serializationOracle.isSerializable(type));
+ assert (serializationOracle.isSerializable(type) || deserializationOracle.isSerializable(type));
if (!needsCreateMethod(type)) {
continue;
@@ -363,85 +353,6 @@
}
}
- private void writeCreateSignatureMapMethod() {
- srcWriter.println("private static native JavaScriptObject createSignatureMap() /*-" + '{');
- {
- srcWriter.indent();
- srcWriter.println("return {");
- JType[] types = getSerializableTypes();
- boolean needComma = false;
- for (int index = 0; index < types.length; ++index) {
- JType type = types[index];
- if (!serializationOracle.maybeInstantiated(type)) {
- continue;
- }
- if (needComma) {
- srcWriter.println(",");
- } else {
- needComma = true;
- }
-
- srcWriter.print("\"" + serializationOracle.getSerializedTypeName(type)
- + "\":\"" + serializationOracle.getSerializationSignature(type)
- + "\"");
- }
- srcWriter.println();
- srcWriter.println("};");
- srcWriter.outdent();
- }
- srcWriter.println("}-*/;");
- srcWriter.println();
- }
-
- private void writeDeserializeMethod() {
- srcWriter.print(DESERIALIZE_METHOD_SIGNATURE);
- srcWriter.println(" /*-" + '{');
- {
- String serializerTypeName = getTypeSerializerClassName();
- srcWriter.indent();
- srcWriter.println("var methodTable = @" + serializerTypeName
- + "::methodMap[typeSignature];");
- srcWriter.println("if (!methodTable) {");
- srcWriter.indentln("@" + serializerTypeName
- + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);");
- srcWriter.println("}");
- srcWriter.println("methodTable[1](streamReader, instance);");
- srcWriter.outdent();
- }
- srcWriter.println("}-*/;");
- srcWriter.println();
- }
-
- private void writeGetSerializationSignatureMethod() {
- String serializerTypeName = getTypeSerializerClassName();
- srcWriter.println("public native String getSerializationSignature(String typeName) /*-" + '{');
- srcWriter.indent();
- srcWriter.println("return @" + serializerTypeName
- + "::signatureMap[typeName];");
- srcWriter.outdent();
- srcWriter.println("}-*/;");
- srcWriter.println();
- }
-
- private void writeInstantiateMethod() {
- srcWriter.print(INSTANTIATE_METHOD_SIGNATURE);
- srcWriter.println(" /*-" + '{');
- {
- String serializerTypeName = getTypeSerializerClassName();
- srcWriter.indent();
- srcWriter.println("var methodTable = @" + serializerTypeName
- + "::methodMap[typeSignature];");
- srcWriter.println("if (!methodTable) {");
- srcWriter.indentln("@" + serializerTypeName
- + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);");
- srcWriter.println("}");
- srcWriter.println("return methodTable[0](streamReader);");
- srcWriter.outdent();
- }
- srcWriter.println("}-*/;");
- srcWriter.println();
- }
-
private void writeRaiseSerializationException() {
srcWriter.println("private static void raiseSerializationException(String msg) throws SerializationException {");
srcWriter.indentln("throw new SerializationException(msg);");
@@ -449,28 +360,169 @@
srcWriter.println();
}
- private void writeSerializeMethod() {
- srcWriter.print(SERIALIZE_METHOD_SIGNATURE);
- srcWriter.println(" /*-" + '{');
- {
- String serializerTypeName = getTypeSerializerClassName();
- srcWriter.indent();
- srcWriter.println("var methodTable = @" + serializerTypeName
- + "::methodMap[typeSignature];");
- srcWriter.println("if (!methodTable) {");
- srcWriter.indentln("@" + serializerTypeName
- + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);");
- srcWriter.println("}");
- srcWriter.println("methodTable[2](streamWriter, instance);");
- srcWriter.outdent();
+ private void writeRegisterMethods() {
+ srcWriter.println("private static native void registerMethods() /*-{");
+ srcWriter.indent();
+
+ List<JType> filteredTypes = new ArrayList<JType>();
+ JType[] types = getSerializableTypes();
+ int n = types.length;
+ for (int index = 0; index < n; ++index) {
+ JType type = types[index];
+ if (serializationOracle.maybeInstantiated(type)
+ || deserializationOracle.maybeInstantiated(type)) {
+ filteredTypes.add(type);
+ }
}
+
+ for (JType type : filteredTypes) {
+
+ srcWriter.println("@com.google.gwt.user.client.rpc.impl.SerializerBase"
+ + "::registerMethods("
+ + "Lcom/google/gwt/user/client/rpc/impl/SerializerBase$MethodMap;"
+ + "Ljava/lang/String;" + "Lcom/google/gwt/core/client/JsArray;)(");
+
+ srcWriter.indentln("@" + typeSerializerClassName + "::methodMap,");
+
+ String typeString = typeStrings.get(type);
+ assert typeString != null : "Missing type signature for "
+ + type.getQualifiedSourceName();
+ srcWriter.indentln("\"" + typeString + "\" , [");
+
+ srcWriter.indent();
+ writeTypeMethods(type);
+ srcWriter.outdent();
+
+ srcWriter.indentln("]);");
+ srcWriter.println();
+ }
+
+ srcWriter.outdent();
+ srcWriter.println("}-*/;");
+ srcWriter.println();
+ }
+
+ private void writeRegisterSignatures() {
+ srcWriter.println("private static native void registerSignatures() /*-{");
+ srcWriter.indent();
+
+ int index = 0;
+
+ for (JType type : getSerializableTypes()) {
+
+ String typeString;
+ if (elideTypeNames) {
+ typeString = Integer.toString(++index, Character.MAX_RADIX);
+ } else {
+ typeString = getTypeString(type);
+ }
+ typeStrings.put(type, typeString);
+
+ if (!serializationOracle.maybeInstantiated(type)
+ && !deserializationOracle.maybeInstantiated(type)) {
+ continue;
+ }
+
+ String jsniTypeRef;
+ jsniTypeRef = TypeOracleMediator.computeBinaryClassName(type.getLeafType());
+ while (type.isArray() != null) {
+ jsniTypeRef += "[]";
+ type = type.isArray().getComponentType();
+ }
+ srcWriter.println("@com.google.gwt.user.client.rpc.impl.SerializerBase"
+ + "::registerSignature("
+ + "Lcom/google/gwt/core/client/JsArrayString;" + "Ljava/lang/Class;"
+ + "Ljava/lang/String;)(");
+ srcWriter.indent();
+ srcWriter.println("@" + typeSerializerClassName + "::signatureMap,");
+ srcWriter.println("@" + jsniTypeRef + "::class,");
+ srcWriter.println("\"" + typeString + "\");");
+ srcWriter.outdent();
+ srcWriter.println();
+ }
+
+ srcWriter.outdent();
srcWriter.println("}-*/;");
srcWriter.println();
}
private void writeStaticFields() {
- srcWriter.println("private static final JavaScriptObject methodMap = createMethodMap();");
- srcWriter.println("private static final JavaScriptObject signatureMap = createSignatureMap();");
+ srcWriter.println("private static final MethodMap methodMap = JavaScriptObject.createObject().cast();");
+ srcWriter.println("private static final JsArrayString signatureMap = JavaScriptObject.createArray().cast();");
+ srcWriter.println("protected MethodMap getMethodMap() { return methodMap; }");
+ srcWriter.println("protected JsArrayString getSignatureMap() { return signatureMap; }");
srcWriter.println();
}
-}
\ No newline at end of file
+
+ private void writeStaticInitializer() {
+ srcWriter.println("static {");
+ srcWriter.indentln("registerMethods();");
+ srcWriter.indentln("registerSignatures();");
+ srcWriter.println("}");
+ }
+
+ /**
+ * Write an entry in the createMethodMap method for one type.
+ *
+ * @param type type to generate entry for
+ */
+ private void writeTypeMethods(JType type) {
+ srcWriter.indent();
+ String serializerName = SerializationUtils.getFieldSerializerName(
+ typeOracle, type);
+
+ // First the initialization method
+ if (deserializationOracle.maybeInstantiated(type)) {
+ srcWriter.print("@");
+ if (needsCreateMethod(type)) {
+ srcWriter.print(getTypeSerializerClassName());
+ srcWriter.print("::");
+ srcWriter.print(getCreateMethodName(type));
+ } else {
+ srcWriter.print(serializerName);
+ srcWriter.print("::instantiate");
+ }
+ srcWriter.print("(L"
+ + SerializationStreamReader.class.getName().replace('.', '/') + ";)");
+ }
+ srcWriter.println(",");
+
+ JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(
+ typeOracle, type);
+
+ // Now the deserialization method
+ if (deserializationOracle.isSerializable(type)) {
+ // Assume param type is the concrete type of the serialized type.
+ JType paramType = type;
+ if (customSerializer != null) {
+ // But a custom serializer may specify a looser type.
+ JMethod deserializationMethod = CustomFieldSerializerValidator.getDeserializationMethod(
+ customSerializer, (JClassType) type);
+ paramType = deserializationMethod.getParameters()[1].getType();
+ }
+ srcWriter.print("@" + serializerName);
+ srcWriter.print("::deserialize(L"
+ + SerializationStreamReader.class.getName().replace('.', '/') + ";"
+ + paramType.getJNISignature() + ")");
+ }
+ srcWriter.println(",");
+
+ // Now the serialization method
+ if (serializationOracle.isSerializable(type)) {
+ // Assume param type is the concrete type of the serialized type.
+ JType paramType = type;
+ if (customSerializer != null) {
+ // But a custom serializer may specify a looser type.
+ JMethod serializationMethod = CustomFieldSerializerValidator.getSerializationMethod(
+ customSerializer, (JClassType) type);
+ paramType = serializationMethod.getParameters()[1].getType();
+ }
+ srcWriter.print("@" + serializerName);
+ srcWriter.print("::serialize(L"
+ + SerializationStreamWriter.class.getName().replace('.', '/') + ";"
+ + paramType.getJNISignature() + ")");
+ srcWriter.println();
+ }
+ srcWriter.outdent();
+ }
+}
diff --git a/user/src/com/google/gwt/user/server/rpc/RPC.java b/user/src/com/google/gwt/user/server/rpc/RPC.java
index 20ee0ef..5a6ffa7 100644
--- a/user/src/com/google/gwt/user/server/rpc/RPC.java
+++ b/user/src/com/google/gwt/user/server/rpc/RPC.java
@@ -18,9 +18,11 @@
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.RemoteService;
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.LegacySerializationPolicy;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter;
+import com.google.gwt.user.server.rpc.impl.TypeNameObfuscator;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -37,14 +39,14 @@
* reused by framework implementors such as Spring and G4jsf to support a wide
* range of service invocation policies.
*
- * <h3>Canonical Example</h3>
- * The following example demonstrates the canonical way to use this class.
+ * <h3>Canonical Example</h3> The following example demonstrates the canonical
+ * way to use this class.
*
- * {@example com.google.gwt.examples.rpc.server.CanonicalExample#processCall(String)}
+ * {@example
+ * com.google.gwt.examples.rpc.server.CanonicalExample#processCall(String)}
*
- * <h3>Advanced Example</h3>
- * The following example shows a more advanced way of using this class to create
- * an adapter between GWT RPC entities and POJOs.
+ * <h3>Advanced Example</h3> The following example shows a more advanced way of
+ * using this class to create an adapter between GWT RPC entities and POJOs.
*
* {@example com.google.gwt.examples.rpc.server.AdvancedExample#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
*/
@@ -124,14 +126,14 @@
/**
* Returns an {@link RPCRequest} that is built by decoding the contents of an
* encoded RPC request and optionally validating that type can handle the
- * request. If the type parameter is not <code>null</code>, the
- * implementation checks that the type is assignable to the
- * {@link RemoteService} interface requested in the encoded request string.
+ * request. If the type parameter is not <code>null</code>, the implementation
+ * checks that the type is assignable to the {@link RemoteService} interface
+ * requested in the encoded request string.
*
* <p>
* Invoking this method with <code>null</code> for the type parameter,
- * <code>decodeRequest(encodedRequest, null)</code>, is equivalent to
- * calling <code>decodeRequest(encodedRequest)</code>.
+ * <code>decodeRequest(encodedRequest, null)</code>, is equivalent to calling
+ * <code>decodeRequest(encodedRequest)</code>.
* </p>
*
* @param encodedRequest a string that encodes the {@link RemoteService}
@@ -167,13 +169,13 @@
/**
* Returns an {@link RPCRequest} that is built by decoding the contents of an
* encoded RPC request and optionally validating that type can handle the
- * request. If the type parameter is not <code>null</code>, the
- * implementation checks that the type is assignable to the
- * {@link RemoteService} interface requested in the encoded request string.
+ * request. If the type parameter is not <code>null</code>, the implementation
+ * checks that the type is assignable to the {@link RemoteService} interface
+ * requested in the encoded request string.
*
* <p>
- * If the serializationPolicyProvider parameter is not <code>null</code>,
- * it is asked for a {@link SerializationPolicy} to use to restrict the set of
+ * If the serializationPolicyProvider parameter is not <code>null</code>, it
+ * is asked for a {@link SerializationPolicy} to use to restrict the set of
* types that can be decoded from the request. If this parameter is
* <code>null</code>, then only subtypes of
* {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
@@ -182,8 +184,8 @@
*
* <p>
* Invoking this method with <code>null</code> for the type parameter,
- * <code>decodeRequest(encodedRequest, null)</code>, is equivalent to
- * calling <code>decodeRequest(encodedRequest)</code>.
+ * <code>decodeRequest(encodedRequest, null)</code>, is equivalent to calling
+ * <code>decodeRequest(encodedRequest)</code>.
* </p>
*
* @param encodedRequest a string that encodes the {@link RemoteService}
@@ -234,7 +236,8 @@
streamReader.prepareToRead(encodedRequest);
// Read the name of the RemoteService interface
- String serviceIntfName = streamReader.readString();
+ String serviceIntfName = maybeDeobfuscate(streamReader,
+ streamReader.readString());
if (type != null) {
if (!implementsInterface(type, serviceIntfName)) {
@@ -269,7 +272,9 @@
Class<?>[] parameterTypes = new Class[paramCount];
for (int i = 0; i < parameterTypes.length; i++) {
- String paramClassName = streamReader.readString();
+ String paramClassName = maybeDeobfuscate(streamReader,
+ streamReader.readString());
+
try {
parameterTypes[i] = getClassFromSerializedName(paramClassName,
classLoader);
@@ -287,7 +292,8 @@
parameterValues[i] = streamReader.deserializeValue(parameterTypes[i]);
}
- return new RPCRequest(method, parameterValues, serializationPolicy);
+ return new RPCRequest(method, parameterValues, serializationPolicy,
+ streamReader.getFlags());
} catch (NoSuchMethodException e) {
throw new IncompatibleRemoteServiceException(
@@ -301,8 +307,8 @@
/**
* Returns a string that encodes an exception. If method is not
- * <code>null</code>, it is an error if the exception is not in the
- * method's list of checked exceptions.
+ * <code>null</code>, it is an error if the exception is not in the method's
+ * list of checked exceptions.
*
* @param serviceMethod the method that threw the exception, may be
* <code>null</code>
@@ -322,13 +328,13 @@
/**
* Returns a string that encodes an exception. If method is not
- * <code>null</code>, it is an error if the exception is not in the
- * method's list of checked exceptions.
+ * <code>null</code>, it is an error if the exception is not in the method's
+ * list of checked exceptions.
*
* <p>
- * If the serializationPolicy parameter is not <code>null</code>, it is
- * used to determine what types can be encoded as part of this response. If
- * this parameter is <code>null</code>, then only subtypes of
+ * If the serializationPolicy parameter is not <code>null</code>, it is used
+ * to determine what types can be encoded as part of this response. If this
+ * parameter is <code>null</code>, then only subtypes of
* {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
* types which have custom field serializers may be encoded.
* </p>
@@ -348,6 +354,13 @@
public static String encodeResponseForFailure(Method serviceMethod,
Throwable cause, SerializationPolicy serializationPolicy)
throws SerializationException {
+ return encodeResponseForFailure(serviceMethod, cause, serializationPolicy,
+ AbstractSerializationStream.DEFAULT_FLAGS);
+ }
+
+ public static String encodeResponseForFailure(Method serviceMethod,
+ Throwable cause, SerializationPolicy serializationPolicy, int flags)
+ throws SerializationException {
if (cause == null) {
throw new NullPointerException("cause cannot be null");
}
@@ -362,7 +375,8 @@
+ "' threw an unexpected exception: " + cause.toString(), cause);
}
- return encodeResponse(cause.getClass(), cause, true, serializationPolicy);
+ return encodeResponse(cause.getClass(), cause, true, flags,
+ serializationPolicy);
}
/**
@@ -390,9 +404,9 @@
* an object that is not assignable to the service method's return type.
*
* <p>
- * If the serializationPolicy parameter is not <code>null</code>, it is
- * used to determine what types can be encoded as part of this response. If
- * this parameter is <code>null</code>, then only subtypes of
+ * If the serializationPolicy parameter is not <code>null</code>, it is used
+ * to determine what types can be encoded as part of this response. If this
+ * parameter is <code>null</code>, then only subtypes of
* {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
* types which have custom field serializers may be encoded.
* </p>
@@ -412,6 +426,13 @@
public static String encodeResponseForSuccess(Method serviceMethod,
Object object, SerializationPolicy serializationPolicy)
throws SerializationException {
+ return encodeResponseForSuccess(serviceMethod, object, serializationPolicy,
+ AbstractSerializationStream.DEFAULT_FLAGS);
+ }
+
+ public static String encodeResponseForSuccess(Method serviceMethod,
+ Object object, SerializationPolicy serializationPolicy, int flags)
+ throws SerializationException {
if (serviceMethod == null) {
throw new NullPointerException("serviceMethod cannot be null");
}
@@ -438,7 +459,8 @@
}
}
- return encodeResponse(methodReturnType, object, false, serializationPolicy);
+ return encodeResponse(methodReturnType, object, false, flags,
+ serializationPolicy);
}
/**
@@ -483,9 +505,9 @@
* could be the value returned by the method or an exception thrown by it.
*
* <p>
- * If the serializationPolicy parameter is not <code>null</code>, it is
- * used to determine what types can be encoded as part of this response. If
- * this parameter is <code>null</code>, then only subtypes of
+ * If the serializationPolicy parameter is not <code>null</code>, it is used
+ * to determine what types can be encoded as part of this response. If this
+ * parameter is <code>null</code>, then only subtypes of
* {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
* types which have custom field serializers may be encoded.
* </p>
@@ -514,6 +536,14 @@
public static String invokeAndEncodeResponse(Object target,
Method serviceMethod, Object[] args,
SerializationPolicy serializationPolicy) throws SerializationException {
+ return invokeAndEncodeResponse(target, serviceMethod, args,
+ serializationPolicy, AbstractSerializationStream.DEFAULT_FLAGS);
+ }
+
+ public static String invokeAndEncodeResponse(Object target,
+ Method serviceMethod, Object[] args,
+ SerializationPolicy serializationPolicy, int flags)
+ throws SerializationException {
if (serviceMethod == null) {
throw new NullPointerException("serviceMethod");
}
@@ -527,7 +557,7 @@
Object result = serviceMethod.invoke(target, args);
responsePayload = encodeResponseForSuccess(serviceMethod, result,
- serializationPolicy);
+ serializationPolicy, flags);
} catch (IllegalAccessException e) {
SecurityException securityException = new SecurityException(
formatIllegalAccessErrorMessage(target, serviceMethod));
@@ -544,7 +574,7 @@
Throwable cause = e.getCause();
responsePayload = encodeResponseForFailure(serviceMethod, cause,
- serializationPolicy);
+ serializationPolicy, flags);
}
return responsePayload;
@@ -562,11 +592,12 @@
* @throws SerializationException if the object cannot be serialized
*/
private static String encodeResponse(Class<?> responseClass, Object object,
- boolean wasThrown, SerializationPolicy serializationPolicy)
+ boolean wasThrown, int flags, SerializationPolicy serializationPolicy)
throws SerializationException {
ServerSerializationStreamWriter stream = new ServerSerializationStreamWriter(
serializationPolicy);
+ stream.setFlags(flags);
stream.prepareToWrite();
if (responseClass != void.class) {
@@ -781,6 +812,34 @@
}
/**
+ * Given a type identifier in the stream, attempt to deobfuscate it. Retuns
+ * the original identifier if deobfuscation is unnecessary or no mapping is
+ * known.
+ */
+ private static String maybeDeobfuscate(
+ ServerSerializationStreamReader streamReader, String name)
+ throws SerializationException {
+ int index;
+ if (streamReader.hasFlags(AbstractSerializationStream.FLAG_ELIDE_TYPE_NAMES)) {
+ SerializationPolicy serializationPolicy = streamReader.getSerializationPolicy();
+ if (!(serializationPolicy instanceof TypeNameObfuscator)) {
+ throw new IncompatibleRemoteServiceException(
+ "RPC request was encoded with obfuscated type names, "
+ + "but the SerializationPolicy in use does not implement "
+ + TypeNameObfuscator.class.getName());
+ }
+
+ String maybe = ((TypeNameObfuscator) serializationPolicy).getClassNameForTypeId(name);
+ if (maybe != null) {
+ return maybe;
+ }
+ } else if ((index = name.indexOf('/')) != -1) {
+ return name.substring(0, index);
+ }
+ return name;
+ }
+
+ /**
* Straight copy from
* {@link com.google.gwt.dev.util.TypeInfo#getSourceRepresentation(Class)} to
* avoid runtime dependency on gwt-dev.
diff --git a/user/src/com/google/gwt/user/server/rpc/RPCRequest.java b/user/src/com/google/gwt/user/server/rpc/RPCRequest.java
index 8663454..8f14fdd 100644
--- a/user/src/com/google/gwt/user/server/rpc/RPCRequest.java
+++ b/user/src/com/google/gwt/user/server/rpc/RPCRequest.java
@@ -24,6 +24,11 @@
public final class RPCRequest {
/**
+ * The flags associated with the RPC request.
+ */
+ private final int flags;
+
+ /**
* The method for this request.
*/
private final Method method;
@@ -43,10 +48,15 @@
* Construct an RPCRequest.
*/
public RPCRequest(Method method, Object[] parameters,
- SerializationPolicy serializationPolicy) {
+ SerializationPolicy serializationPolicy, int flags) {
this.method = method;
this.parameters = parameters;
this.serializationPolicy = serializationPolicy;
+ this.flags = flags;
+ }
+
+ public int getFlags() {
+ return flags;
}
/**
@@ -96,6 +106,8 @@
String escapedStrParam = strParam.replaceAll("\\\"", "\\\\\"");
callSignature.append(escapedStrParam);
callSignature.append('"');
+ } else if (param == null) {
+ callSignature.append("null");
} else {
// We assume that anyone who wants to use this method will implement
// toString on his serializable objects.
diff --git a/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java b/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java
index c43128c..16dde6f 100644
--- a/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java
+++ b/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java
@@ -164,7 +164,8 @@
RPCRequest rpcRequest = RPC.decodeRequest(payload, this.getClass(), this);
onAfterRequestDeserialized(rpcRequest);
return RPC.invokeAndEncodeResponse(this, rpcRequest.getMethod(),
- rpcRequest.getParameters(), rpcRequest.getSerializationPolicy());
+ rpcRequest.getParameters(), rpcRequest.getSerializationPolicy(),
+ rpcRequest.getFlags());
} catch (IncompatibleRemoteServiceException ex) {
log(
"An IncompatibleRemoteServiceException was thrown while processing this call.",
diff --git a/user/src/com/google/gwt/user/server/rpc/SerializationPolicy.java b/user/src/com/google/gwt/user/server/rpc/SerializationPolicy.java
index 064d7dd..f4d2f63 100644
--- a/user/src/com/google/gwt/user/server/rpc/SerializationPolicy.java
+++ b/user/src/com/google/gwt/user/server/rpc/SerializationPolicy.java
@@ -21,6 +21,8 @@
* This is an abstract class for representing the serialization policy for a
* given module and
* {@link com.google.gwt.user.client.rpc.RemoteService RemoteService}.
+ * The serialize and deserialize queries are from the perspective
+ * of the server, not the web browser.
*/
public abstract class SerializationPolicy {
/**
diff --git a/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java b/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java
index 7141141..6755414 100644
--- a/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java
+++ b/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java
@@ -16,6 +16,7 @@
package com.google.gwt.user.server.rpc;
import com.google.gwt.user.server.rpc.impl.StandardSerializationPolicy;
+import com.google.gwt.user.server.rpc.impl.TypeNameObfuscator;
import java.io.BufferedReader;
import java.io.IOException;
@@ -36,7 +37,8 @@
*/
public static final String SERIALIZATION_POLICY_FILE_ENCODING = "UTF-8";
- private static final String FORMAT_ERROR_MESSAGE = "Expected: className, [true | false]";
+ private static final String FORMAT_ERROR_MESSAGE = "Expected: className, "
+ + "[true | false], [true | false], [true | false], [true | false], typeId, signature";
/**
* Returns the serialization policy file name from the from the serialization
@@ -99,7 +101,9 @@
throw new NullPointerException("inputStream");
}
- Map<Class<?>, Boolean> whitelist = new HashMap<Class<?>, Boolean>();
+ Map<Class<?>, Boolean> whitelistSer = new HashMap<Class<?>, Boolean>();
+ Map<Class<?>, Boolean> whitelistDeser = new HashMap<Class<?>, Boolean>();
+ Map<Class<?>, String> typeIds = new HashMap<Class<?>, String>();
InputStreamReader isr = new InputStreamReader(inputStream,
SERIALIZATION_POLICY_FILE_ENCODING);
@@ -112,24 +116,57 @@
if (line.length() > 0) {
String[] components = line.split(",");
- if (components.length != 2) {
+ if (components.length != 2 && components.length != 7) {
throw new ParseException(FORMAT_ERROR_MESSAGE, lineNum);
}
- String binaryTypeName = components[0].trim();
- String instantiable = components[1].trim();
+ for (int i = 0; i < components.length; i++) {
+ components[i] = components[i].trim();
+ if (components[i].length() == 0) {
+ throw new ParseException(FORMAT_ERROR_MESSAGE, lineNum);
+ }
+ }
- if (binaryTypeName.length() == 0 || instantiable.length() == 0) {
- throw new ParseException(FORMAT_ERROR_MESSAGE, lineNum);
+ String binaryTypeName = components[0].trim();
+ boolean fieldSer;
+ boolean instantSer;
+ boolean fieldDeser;
+ boolean instantDeser;
+ String typeId;
+
+ if (components.length == 2) {
+ fieldSer = fieldDeser = true;
+ instantSer = instantDeser = Boolean.valueOf(components[1]);
+ typeId = binaryTypeName;
+ } else {
+ int idx = 1;
+ // TODO: Validate the instantiable string better.
+ fieldSer = Boolean.valueOf(components[idx++]);
+ instantSer = Boolean.valueOf(components[idx++]);
+ fieldDeser = Boolean.valueOf(components[idx++]);
+ instantDeser = Boolean.valueOf(components[idx++]);
+ typeId = components[idx++];
+
+ if (!fieldSer && !fieldDeser
+ && !TypeNameObfuscator.SERVICE_INTERFACE_ID.equals(typeId)) {
+ throw new ParseException("Type " + binaryTypeName
+ + " is neither field serializable, field deserializable "
+ + "nor the service interface", lineNum);
+ }
}
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
try {
- Class<?> clazz = Class.forName(binaryTypeName, false,
+ Class<?> clazz = Class.forName(binaryTypeName, false,
contextClassLoader);
- // TODO: Validate the instantiable string better.
- whitelist.put(clazz, Boolean.valueOf(instantiable));
+ if (fieldSer) {
+ whitelistSer.put(clazz, instantSer);
+ }
+ if (fieldDeser) {
+ whitelistDeser.put(clazz, instantDeser);
+ }
+ typeIds.put(clazz, typeId);
} catch (ClassNotFoundException ex) {
// Ignore the error, but add it to the list of errors if one was
// provided.
@@ -143,7 +180,8 @@
lineNum++;
}
- return new StandardSerializationPolicy(whitelist);
+ return new StandardSerializationPolicy(whitelistSer, whitelistDeser,
+ typeIds);
}
private SerializationPolicyLoader() {
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/LegacySerializationPolicy.java b/user/src/com/google/gwt/user/server/rpc/impl/LegacySerializationPolicy.java
index 9155533..6357467 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/LegacySerializationPolicy.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/LegacySerializationPolicy.java
@@ -43,7 +43,11 @@
* serialized as super types of a legal type.
* </p>
*/
-public class LegacySerializationPolicy extends SerializationPolicy {
+public class LegacySerializationPolicy extends SerializationPolicy implements
+ TypeNameObfuscator {
+
+ private static final String ELISION_ERROR = "Type name elision in RPC "
+ + "payloads is only supported if the RPC whitelist file is used.";
/**
* Many JRE types would appear to be {@link Serializable} on the server.
@@ -55,27 +59,26 @@
* be serializable via a custom serializer.
*/
private static final Class<?>[] JRE_BLACKLIST = {
- java.lang.ArrayStoreException.class, java.lang.AssertionError.class,
- java.lang.Boolean.class, java.lang.Byte.class, java.lang.Character.class,
- java.lang.Class.class, java.lang.ClassCastException.class,
- java.lang.Double.class, java.lang.Error.class,
- java.lang.Float.class, java.lang.IllegalArgumentException.class,
- java.lang.IllegalStateException.class,
- java.lang.IndexOutOfBoundsException.class, java.lang.Integer.class,
- java.lang.Long.class, java.lang.NegativeArraySizeException.class,
- java.lang.NullPointerException.class, java.lang.Number.class,
- java.lang.NumberFormatException.class,
- java.lang.Short.class, java.lang.StackTraceElement.class,
- java.lang.String.class, java.lang.StringBuffer.class,
- java.lang.StringIndexOutOfBoundsException.class,
- java.lang.UnsupportedOperationException.class,
- java.util.ArrayList.class,
- java.util.ConcurrentModificationException.class, java.util.Date.class,
- java.util.EmptyStackException.class, java.util.EventObject.class,
- java.util.HashMap.class, java.util.HashSet.class,
- java.util.MissingResourceException.class,
- java.util.NoSuchElementException.class, java.util.Stack.class,
- java.util.TooManyListenersException.class, java.util.Vector.class};
+ java.lang.ArrayStoreException.class, java.lang.AssertionError.class,
+ java.lang.Boolean.class, java.lang.Byte.class, java.lang.Character.class,
+ java.lang.Class.class, java.lang.ClassCastException.class,
+ java.lang.Double.class, java.lang.Error.class, java.lang.Float.class,
+ java.lang.IllegalArgumentException.class,
+ java.lang.IllegalStateException.class,
+ java.lang.IndexOutOfBoundsException.class, java.lang.Integer.class,
+ java.lang.Long.class, java.lang.NegativeArraySizeException.class,
+ java.lang.NullPointerException.class, java.lang.Number.class,
+ java.lang.NumberFormatException.class, java.lang.Short.class,
+ java.lang.StackTraceElement.class, java.lang.String.class,
+ java.lang.StringBuffer.class,
+ java.lang.StringIndexOutOfBoundsException.class,
+ java.lang.UnsupportedOperationException.class, java.util.ArrayList.class,
+ java.util.ConcurrentModificationException.class, java.util.Date.class,
+ java.util.EmptyStackException.class, java.util.EventObject.class,
+ java.util.HashMap.class, java.util.HashSet.class,
+ java.util.MissingResourceException.class,
+ java.util.NoSuchElementException.class, java.util.Stack.class,
+ java.util.TooManyListenersException.class, java.util.Vector.class};
private static final Set<Class<?>> JRE_BLACKSET = new HashSet<Class<?>>(
Arrays.asList(JRE_BLACKLIST));
@@ -92,57 +95,49 @@
private LegacySerializationPolicy() {
}
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.user.server.rpc.SerializationPolicy#shouldDerializeFields(java.lang.String)
+ /**
+ * Implemented to fail with a useful error message.
*/
+ public final String getClassNameForTypeId(String id)
+ throws SerializationException {
+ throw new SerializationException(ELISION_ERROR);
+ }
+
+ /**
+ * Implemented to fail with a useful error message.
+ */
+ public final String getTypeIdForClass(Class<?> clazz)
+ throws SerializationException {
+ throw new SerializationException(ELISION_ERROR);
+ }
+
@Override
public boolean shouldDeserializeFields(Class<?> clazz) {
return isFieldSerializable(clazz);
}
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.user.server.rpc.SerializationPolicy#shouldSerializeFields(java.lang.String)
- */
@Override
public boolean shouldSerializeFields(Class<?> clazz) {
return isFieldSerializable(clazz);
}
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.user.server.rpc.SerializationPolicy#validateDeserialize(java.lang.String)
- */
@Override
public void validateDeserialize(Class<?> clazz) throws SerializationException {
if (!isInstantiable(clazz)) {
- throw new SerializationException(
- "Type '"
- + clazz.getName()
- + "' was not assignable to '"
- + IsSerializable.class.getName()
- + "' and did not have a custom field serializer. For security purposes, this type will not be deserialized.");
+ throw new SerializationException("Type '" + clazz.getName()
+ + "' was not assignable to '" + IsSerializable.class.getName()
+ + "' and did not have a custom field serializer. "
+ + "For security purposes, this type will not be deserialized.");
}
}
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.user.server.rpc.SerializationPolicy#validateSerialize(java.lang.String)
- */
@Override
public void validateSerialize(Class<?> clazz) throws SerializationException {
if (!isInstantiable(clazz)) {
- throw new SerializationException(
- "Type '"
- + clazz.getName()
- + "' was not assignable to '"
- + IsSerializable.class.getName()
- + "' and did not have a custom field serializer. For security purposes, this type will not be serialized.");
+ throw new SerializationException("Type '" + clazz.getName()
+ + "' was not assignable to '" + IsSerializable.class.getName()
+ + "' and did not have a custom field serializer."
+ + "For security purposes, this type will not be serialized.");
}
}
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 92e1cd3..3dfc3d9 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
@@ -400,7 +400,7 @@
if (idx == 0) {
throw new IncompatibleRemoteServiceException(
"Malformed or old RPC message received - expecting version "
- + SERIALIZATION_STREAM_VERSION);
+ + SERIALIZATION_STREAM_VERSION);
} else {
int version = Integer.valueOf(encodedTokens.substring(0, idx));
throw new IncompatibleRemoteServiceException("Expecting version "
@@ -479,18 +479,31 @@
protected Object deserialize(String typeSignature)
throws SerializationException {
Object instance = null;
- SerializedInstanceReference serializedInstRef = SerializabilityUtil.decodeSerializedInstanceReference(typeSignature);
try {
- Class<?> instanceClass = Class.forName(serializedInstRef.getName(),
- false, classLoader);
+ Class<?> instanceClass;
+ if (hasFlags(FLAG_ELIDE_TYPE_NAMES)) {
+ if (getSerializationPolicy() instanceof TypeNameObfuscator) {
+ TypeNameObfuscator obfuscator = (TypeNameObfuscator) getSerializationPolicy();
+ String instanceClassName = obfuscator.getClassNameForTypeId(typeSignature);
+ instanceClass = Class.forName(instanceClassName, false, classLoader);
+ } else {
+ throw new SerializationException(
+ "The GWT module was compiled with RPC type name elision enabled, but "
+ + getSerializationPolicy().getClass().getName()
+ + " does not implement " + TypeNameObfuscator.class.getName());
+ }
+ } else {
+ SerializedInstanceReference serializedInstRef = SerializabilityUtil.decodeSerializedInstanceReference(typeSignature);
+ instanceClass = Class.forName(serializedInstRef.getName(), false,
+ classLoader);
+ validateTypeVersions(instanceClass, serializedInstRef);
+ }
assert (serializationPolicy != null);
serializationPolicy.validateDeserialize(instanceClass);
- validateTypeVersions(instanceClass, serializedInstRef);
-
Class<?> customSerializer = SerializabilityUtil.hasCustomFieldSerializer(instanceClass);
int index = reserveDecodedObjectIndex();
@@ -625,8 +638,8 @@
while (idx >= 0) {
buf.append(str.substring(pos, idx));
if (++idx == str.length()) {
- throw new SerializationException("Unmatched backslash: \""
- + str + "\"");
+ throw new SerializationException("Unmatched backslash: \"" + str
+ + "\"");
}
char ch = str.charAt(idx);
pos = idx + 1;
@@ -642,7 +655,8 @@
break;
case 'u':
try {
- ch = (char) Integer.parseInt(str.substring(idx + 1, idx + 5), 16);
+ ch = (char) Integer.parseInt(str.substring(idx + 1, idx + 5),
+ 16);
} catch (NumberFormatException e) {
throw new SerializationException(
"Invalid Unicode escape sequence in \"" + str + "\"");
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 8f837cd..bb9d203 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
@@ -404,14 +404,10 @@
* consumed and/or interpreted as a special character when the JSON encoded
* response is evaluated. For example, 0x2028 and 0x2029 are alternate line
* endings for JS per ECMA-232, which are respected by Firefox and Mozilla.
- *
- * @param ch character to check
- * @return <code>true</code> if the character requires the \\uXXXX unicode
- * character escape
- *
+ * <p>
* Notes:
* <ol>
- * <li> The following cases are a more conservative set of cases which are are
+ * <li>The following cases are a more conservative set of cases which are are
* in the future proofing space as opposed to the required minimal set. We
* could remove these and still pass our tests.
* <ul>
@@ -426,18 +422,20 @@
* <li>Total Characters Escaped: 13515</li>
* </ul>
* </li>
- * <li> The following cases are the minimal amount of escaping required to
+ * <li>The following cases are the minimal amount of escaping required to
* prevent test failure.
* <ul>
* <li>LINE_SEPARATOR - 1</li>
* <li>PARAGRAPH_SEPARATOR - 1</li>
* <li>FORMAT - 32</li>
* <li>SURROGATE - 2048</li>
- * <li>Total Characters Escaped: 2082</li>
- * </li>
- * </ul>
- * </li>
+ * <li>Total Characters Escaped: 2082</li></li>
+ * </ul> </li>
* </ol>
+ *
+ * @param ch character to check
+ * @return <code>true</code> if the character requires the \\uXXXX unicode
+ * character escape
*/
private static boolean needsUnicodeEscape(char ch) {
switch (ch) {
@@ -450,8 +448,8 @@
// these must be quoted or they will break the protocol
return true;
case NON_BREAKING_HYPHEN:
- // This can be expanded into a break followed by a hyphen
- return true;
+ // This can be expanded into a break followed by a hyphen
+ return true;
default:
switch (Character.getType(ch)) {
// Conservative
@@ -479,9 +477,9 @@
}
/**
- * 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.
+ * 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
@@ -574,11 +572,23 @@
}
@Override
- protected String getObjectTypeSignature(Object instance) {
+ protected String getObjectTypeSignature(Object instance)
+ throws SerializationException {
assert (instance != null);
Class<?> clazz = getClassForSerialization(instance);
- return SerializabilityUtil.encodeSerializedInstanceReference(clazz);
+ if (hasFlags(FLAG_ELIDE_TYPE_NAMES)) {
+ if (serializationPolicy instanceof TypeNameObfuscator) {
+ return ((TypeNameObfuscator) serializationPolicy).getTypeIdForClass(clazz);
+ }
+
+ throw new SerializationException("The GWT module was compiled with RPC "
+ + "type name elision enabled, but "
+ + serializationPolicy.getClass().getName() + " does not implement "
+ + TypeNameObfuscator.class.getName());
+ } else {
+ return SerializabilityUtil.encodeSerializedInstanceReference(clazz);
+ }
}
@Override
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicy.java b/user/src/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicy.java
index e7373bf..8665980 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicy.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicy.java
@@ -18,53 +18,118 @@
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.SerializationPolicy;
+import java.util.HashMap;
import java.util.Map;
/**
* Standard implementation of a {@link SerializationPolicy}.
*/
-public class StandardSerializationPolicy extends SerializationPolicy {
- private final Map<Class<?>, Boolean> whitelist;
+public class StandardSerializationPolicy extends SerializationPolicy implements
+ TypeNameObfuscator {
+ /**
+ * Field serializable types are primitives and types on the specified
+ * whitelist.
+ */
+ private static boolean isFieldSerializable(Class<?> clazz,
+ Map<Class<?>, Boolean> whitelist) {
+ if (clazz.isPrimitive()) {
+ return true;
+ }
+ return whitelist.containsKey(clazz);
+ }
+
+ /**
+ * Instantiable types are primitives and types on the specified whitelist
+ * which can be instantiated.
+ */
+ private static boolean isInstantiable(Class<?> clazz,
+ Map<Class<?>, Boolean> whitelist) {
+ if (clazz.isPrimitive()) {
+ return true;
+ }
+ Boolean instantiable = whitelist.get(clazz);
+ return (instantiable != null && instantiable);
+ }
+
+ private final Map<Class<?>, Boolean> deserializationWhitelist;
+ private final Map<Class<?>, Boolean> serializationWhitelist;
+ private final Map<Class<?>, String> typeIds;
+ private final Map<String, Class<?>> typeIdsToClasses = new HashMap<String, Class<?>>();
/**
* Constructs a {@link SerializationPolicy} from a {@link Map}.
*/
- public StandardSerializationPolicy(Map<Class<?>, Boolean> whitelist) {
- if (whitelist == null) {
+ public StandardSerializationPolicy(
+ Map<Class<?>, Boolean> serializationWhitelist,
+ Map<Class<?>, Boolean> deserializationWhitelist,
+ Map<Class<?>, String> obfuscatedTypeIds) {
+ if (serializationWhitelist == null || deserializationWhitelist == null) {
throw new NullPointerException("whitelist");
}
- this.whitelist = whitelist;
+ this.serializationWhitelist = serializationWhitelist;
+ this.deserializationWhitelist = deserializationWhitelist;
+ this.typeIds = obfuscatedTypeIds;
+
+ for (Map.Entry<Class<?>, String> entry : obfuscatedTypeIds.entrySet()) {
+ assert entry.getKey() != null : "null key";
+ assert entry.getValue() != null : "null value for "
+ + entry.getKey().getName();
+ assert !typeIdsToClasses.containsKey(entry.getValue()) : "Duplicate type id "
+ + entry.getValue();
+ typeIdsToClasses.put(entry.getValue(), entry.getKey());
+ }
+ }
+
+ public final String getClassNameForTypeId(String id)
+ throws SerializationException {
+ Class<?> clazz = typeIdsToClasses.get(id);
+ if (clazz == null) {
+ return null;
+ }
+
+ return clazz.getName();
+ }
+
+ public final String getTypeIdForClass(Class<?> clazz)
+ throws SerializationException {
+ return typeIds.get(clazz);
}
/*
* (non-Javadoc)
*
- * @see com.google.gwt.user.server.rpc.SerializationPolicy#shouldDerializeFields(java.lang.String)
+ * @see
+ * com.google.gwt.user.server.rpc.SerializationPolicy#shouldDerializeFields
+ * (java.lang.String)
*/
@Override
public boolean shouldDeserializeFields(Class<?> clazz) {
- return isFieldSerializable(clazz);
+ return isFieldSerializable(clazz, deserializationWhitelist);
}
/*
* (non-Javadoc)
*
- * @see com.google.gwt.user.server.rpc.SerializationPolicy#shouldSerializeFields(java.lang.String)
+ * @see
+ * com.google.gwt.user.server.rpc.SerializationPolicy#shouldSerializeFields
+ * (java.lang.String)
*/
@Override
public boolean shouldSerializeFields(Class<?> clazz) {
- return isFieldSerializable(clazz);
+ return isFieldSerializable(clazz, serializationWhitelist);
}
/*
* (non-Javadoc)
*
- * @see com.google.gwt.user.server.rpc.SerializationPolicy#validateDeserialize(java.lang.String)
+ * @see
+ * com.google.gwt.user.server.rpc.SerializationPolicy#validateDeserialize(
+ * java.lang.String)
*/
@Override
public void validateDeserialize(Class<?> clazz) throws SerializationException {
- if (!isInstantiable(clazz)) {
+ if (!isInstantiable(clazz, deserializationWhitelist)) {
throw new SerializationException(
"Type '"
+ clazz.getName()
@@ -75,37 +140,17 @@
/*
* (non-Javadoc)
*
- * @see com.google.gwt.user.server.rpc.SerializationPolicy#validateSerialize(java.lang.String)
+ * @see
+ * com.google.gwt.user.server.rpc.SerializationPolicy#validateSerialize(java
+ * .lang.String)
*/
@Override
public void validateSerialize(Class<?> clazz) throws SerializationException {
- if (!isInstantiable(clazz)) {
+ if (!isInstantiable(clazz, serializationWhitelist)) {
throw new SerializationException(
"Type '"
+ clazz.getName()
+ "' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.");
}
}
-
- /**
- * Field serializable types are primitives and types on the whitelist.
- */
- private boolean isFieldSerializable(Class<?> clazz) {
- if (clazz.isPrimitive()) {
- return true;
- }
- return whitelist.containsKey(clazz);
- }
-
- /**
- * Instantiable types are primitives and types on the whitelist which can be
- * instantiated.
- */
- private boolean isInstantiable(Class<?> clazz) {
- if (clazz.isPrimitive()) {
- return true;
- }
- Boolean instantiable = whitelist.get(clazz);
- return (instantiable != null && instantiable);
- }
}
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/TypeNameObfuscator.java b/user/src/com/google/gwt/user/server/rpc/impl/TypeNameObfuscator.java
new file mode 100644
index 0000000..53f1d62
--- /dev/null
+++ b/user/src/com/google/gwt/user/server/rpc/impl/TypeNameObfuscator.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2009 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.server.rpc.impl;
+
+import com.google.gwt.user.client.rpc.SerializationException;
+
+/**
+ * This is a private interface that allows ProxyCreator to provide obfuscated
+ * type names to the server components via {@link StandardSerializationPolicy}.
+ * <p>
+ * The particulars of the implementation are deeply tied to the specifics of the
+ * RPC wire format and the code generated by TypeSerializerCreator.
+ * <p>
+ * This interface is not public in order to allow the API to be switched from
+ * Strings to ints in a future revision.
+ */
+public interface TypeNameObfuscator {
+ /**
+ * A reserved ID for specifying the identifier for the service interface
+ * itself.
+ */
+ String SERVICE_INTERFACE_ID = "_";
+
+ /*
+ * TODO: Replace strings with integral constants once the RPC whitelist can be
+ * given as a hard requirement for deploying GWT-RPC.
+ */
+ /**
+ * Returns the name of the class that should be instantiated based on an
+ * obfuscated identifier.
+ *
+ * @param id the type id that was present in the RPC payload
+ * @return the name of the class, suitable for use by {@link Class#forName},
+ * to be instantiated
+ * @throws SerializationException if there is no class that corresponds to the
+ * obfuscated id
+ */
+ String getClassNameForTypeId(String id) throws SerializationException;
+
+ /**
+ * Returns the obfuscated identifier to be used to encode a class in the RPC
+ * wire format.
+ *
+ * @param clazz the class to be transmitted
+ * @return the obfuscated type identifier.
+ * @throws SerializationException
+ */
+ String getTypeIdForClass(Class<?> clazz) throws SerializationException;
+}
diff --git a/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml b/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml
new file mode 100644
index 0000000..214dc42
--- /dev/null
+++ b/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml
@@ -0,0 +1,22 @@
+<!-- -->
+<!-- Copyright 2009 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<!-- Types and resources required to support HTTP requests. -->
+<!-- -->
+<!-- Any user application that wishes to use the types declared in the http -->
+<!-- package must inherit this module. -->
+<!-- -->
+<module>
+ <inherits name="com.google.gwt.core.Core"/>
+</module>
diff --git a/user/src/com/google/gwt/xhr/client/ReadyStateChangeHandler.java b/user/src/com/google/gwt/xhr/client/ReadyStateChangeHandler.java
new file mode 100644
index 0000000..feec633
--- /dev/null
+++ b/user/src/com/google/gwt/xhr/client/ReadyStateChangeHandler.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2009 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.xhr.client;
+
+/**
+ * A ready-state callback for an {@Link XMLHttpRequest} object.
+ */
+public interface ReadyStateChangeHandler {
+
+ /**
+ * This is called whenever the state of the XMLHttpRequest changes. See
+ * {@link XMLHttpRequest#setOnReadyStateHandler}.
+ *
+ * @param xhr the object whose state has changed.
+ */
+ void onReadyStateChange(XMLHttpRequest xhr);
+}
diff --git a/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java b/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java
new file mode 100644
index 0000000..ae63a6d
--- /dev/null
+++ b/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2009 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.xhr.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+/**
+ * The native XMLHttpRequest object. Most applications should use the higher-
+ * level {@link RequestBuilder} class unless they need specific functionality
+ * provided by the XMLHttpRequest object.
+ *
+ * @see http://www.w3.org/TR/XMLHttpRequest/
+ */
+public class XMLHttpRequest extends JavaScriptObject {
+
+ /*
+ * NOTE: Testing discovered that for some bizarre reason, on Mozilla, the
+ * JavaScript <code>XmlHttpRequest.onreadystatechange</code> handler
+ * function maybe still be called after it is deleted. The theory is that the
+ * callback is cached somewhere. Setting it to null or an empty function does
+ * seem to work properly, though.
+ *
+ * On IE, there are two problems: Setting onreadystatechange to null (as
+ * opposed to an empty function) sometimes throws an exception. With
+ * particular (rare) versions of jscript.dll, setting onreadystatechange from
+ * within onreadystatechange causes a crash. Setting it from within a timeout
+ * fixes this bug (see issue 1610).
+ *
+ * End result: *always* set onreadystatechange to an empty function (never to
+ * null). Never set onreadystatechange from within onreadystatechange (always
+ * in a setTimeout()).
+ */
+
+ /**
+ * When constructed, the XMLHttpRequest object must be in the UNSENT state.
+ */
+ public static final int UNSENT = 0;
+
+ /**
+ * The OPENED state is the state of the object when the open() method has been
+ * successfully invoked. During this state request headers can be set using
+ * setRequestHeader() and the request can be made using send().
+ */
+ public static final int OPENED = 1;
+
+ /**
+ * The HEADERS_RECEIVED state is the state of the object when all response
+ * headers have been received.
+ */
+ public static final int HEADERS_RECEIVED = 2;
+
+ /**
+ * The LOADING state is the state of the object when the response entity body
+ * is being received.
+ */
+ public static final int LOADING = 3;
+
+ /**
+ * The DONE state is the state of the object when either the data transfer has
+ * been completed or something went wrong during the transfer (infinite
+ * redirects for instance).
+ */
+ public static final int DONE = 4;
+
+ /**
+ * Creates an XMLHttpRequest object.
+ *
+ * @return the created object
+ */
+ public static native XMLHttpRequest create() /*-{
+ if ($wnd.XMLHttpRequest) {
+ return new XMLHttpRequest();
+ } else {
+ try {
+ return new ActiveXObject('MSXML2.XMLHTTP.3.0');
+ } catch (e) {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ }
+ }-*/;
+
+ protected XMLHttpRequest() {
+ }
+
+ /**
+ * Aborts the current request.
+ *
+ * @see http://www.w3.org/TR/XMLHttpRequest/#abort
+ */
+ public final native void abort() /*-{
+ this.abort();
+ }-*/;
+
+ /**
+ * Clears the {@link ReadyStateChangeHandler}.
+ *
+ * @see #clearOnReadyStateChange()
+ * @see http://www.w3.org/TR/XMLHttpRequest/#onreadystatechange
+ */
+ public final native void clearOnReadyStateChange() /*-{
+ $wnd.setTimeout(function() {
+ this.onreadystatechange = function(){};
+ }, 0);
+ }-*/;
+
+ /**
+ * Gets all the HTTP response headers, as a single string.
+ *
+ * @return the response headers.
+ * @see http://www.w3.org/TR/XMLHttpRequest/#getallresponseheaders
+ */
+ public final native String getAllResponseHeaders() /*-{
+ return this.getAllResponseHeaders();
+ }-*/;
+
+ /**
+ * Get's the current ready-state.
+ *
+ * @return the ready-state constant
+ * @see http://www.w3.org/TR/XMLHttpRequest/#readystate
+ */
+ public final native int getReadyState() /*-{
+ return this.readyState;
+ }-*/;
+
+ /**
+ * Gets an HTTP response header.
+ *
+ * @param header the response header to be retrieved
+ * @return the header value
+ * @see http://www.w3.org/TR/XMLHttpRequest/#getresponseheader
+ */
+ public final native String getResponseHeader(String header) /*-{
+ return this.getResponseHeader(header);
+ }-*/;
+
+ /**
+ * Gets the response text.
+ *
+ * @return the response text
+ * @see http://www.w3.org/TR/XMLHttpRequest/#responsetext
+ */
+ public final native String getResponseText() /*-{
+ return this.responseText;
+ }-*/;
+
+ /**
+ * Gets the status code.
+ *
+ * @return the status code
+ * @see http://www.w3.org/TR/XMLHttpRequest/#status
+ */
+ public final native int getStatus() /*-{
+ return this.status;
+ }-*/;
+
+ /**
+ * Gets the status text.
+ *
+ * @return the status text
+ * @see http://www.w3.org/TR/XMLHttpRequest/#statustext
+ */
+ public final native String getStatusText() /*-{
+ return this.statusText;
+ }-*/;
+
+ /**
+ * Opens an asynchronous connection.
+ *
+ * @param httpMethod the HTTP method to use
+ * @param url the URL to be opened
+ * @see http://www.w3.org/TR/XMLHttpRequest/#open
+ */
+ public final native void open(String httpMethod, String url) /*-{
+ this.open(httpMethod, url, true);
+ }-*/;
+
+ /**
+ * Opens an asynchronous connection.
+ *
+ * @param httpMethod the HTTP method to use
+ * @param url the URL to be opened
+ * @param user user to use in the URL
+ * @see http://www.w3.org/TR/XMLHttpRequest/#open
+ */
+ public final native void open(String httpMethod, String url, String user) /*-{
+ this.open(httpMethod, url, true, user);
+ }-*/;
+
+ /**
+ * Opens an asynchronous connection.
+ *
+ * @param httpMethod the HTTP method to use
+ * @param url the URL to be opened
+ * @param user user to use in the URL
+ * @param password password to use in the URL
+ * @see http://www.w3.org/TR/XMLHttpRequest/#open
+ */
+ public final native void open(String httpMethod, String url, String user,
+ String password) /*-{
+ this.open(httpMethod, url, true, user, password);
+ }-*/;
+
+ /**
+ * Initiates a request.
+ *
+ * @see http://www.w3.org/TR/XMLHttpRequest/#send
+ */
+ public final native void send() /*-{
+ this.send();
+ }-*/;
+
+ /**
+ * Initiates a request with data.
+ *
+ * @param requestData the data to be sent with the request
+ * @see http://www.w3.org/TR/XMLHttpRequest/#send
+ */
+ public final native void send(String requestData) /*-{
+ this.send(requestData);
+ }-*/;
+
+ /**
+ * Sets the {@link ReadyStateChangeHandler} to be notified when the object's
+ * ready-state changes.
+ *
+ * <p>
+ * Note: Applications <em>must</em> call {@link #clearOnReadyStateChange()}
+ * when they no longer need this object, to ensure that it is cleaned up
+ * properly. Failure to do so will result in memory leaks on some browsers.
+ * </p>
+ *
+ * @param handler the handler to be called when the ready state changes
+ * @see #clearOnReadyStateChange()
+ * @see http://www.w3.org/TR/XMLHttpRequest/#onreadystatechange
+ */
+ public final native void setOnReadyStateChange(ReadyStateChangeHandler handler) /*-{
+ // The 'this' context is always supposed to point to the xhr object in the
+ // onreadystatechange handler, but we reference it via closure to be extra sure.
+ var _this = this;
+ this.onreadystatechange = function() {
+ handler.@com.google.gwt.xhr.client.ReadyStateChangeHandler::onReadyStateChange(Lcom/google/gwt/xhr/client/XMLHttpRequest;)(_this);
+ };
+ }-*/;
+
+ /**
+ * Sets a request header.
+ *
+ * @param header the header to be set
+ * @param value the header's value
+ * @see http://www.w3.org/TR/XMLHttpRequest/#setrequestheader
+ */
+ public final native void setRequestHeader(String header, String value) /*-{
+ this.setRequestHeader(header, value);
+ }-*/;
+}
diff --git a/user/src/com/google/gwt/xml/client/impl/XMLParserImplSafari.java b/user/src/com/google/gwt/xml/client/impl/XMLParserImplSafari.java
index 1eee56e..817cf4e 100644
--- a/user/src/com/google/gwt/xml/client/impl/XMLParserImplSafari.java
+++ b/user/src/com/google/gwt/xml/client/impl/XMLParserImplSafari.java
@@ -33,6 +33,11 @@
return ((result) ? parseInt(result[1]) : 0) || 0;
}-*/;
+ @SuppressWarnings("unused")
+ private static void throwDOMParseException(String message) {
+ throw new DOMParseException(message);
+ }
+
@Override
protected native JavaScriptObject getElementsByTagNameImpl(JavaScriptObject o,
String tagName) /*-{
@@ -73,9 +78,8 @@
var parseerrors = result.getElementsByTagName("parsererror");
if (parseerrors.length > 0) {
var err = parseerrors.item(0);
- var safariErrStyle = "white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black";
- if(err.getAttribute("style") == safariErrStyle) {
- throw new Error(err.item(1).innerHTML);
+ if (err.parentNode.tagName == 'body') {
+ @com.google.gwt.xml.client.impl.XMLParserImplSafari::throwDOMParseException(Ljava/lang/String;)(err.childNodes[1].innerHTML);
}
}
return result;
diff --git a/user/super/com/google/gwt/emul/java/lang/Class.java b/user/super/com/google/gwt/emul/java/lang/Class.java
index 807358d..515fecf 100644
--- a/user/super/com/google/gwt/emul/java/lang/Class.java
+++ b/user/super/com/google/gwt/emul/java/lang/Class.java
@@ -35,12 +35,13 @@
*
* @skip
*/
- static <T> Class<T> createForArray(String packageName, String className) {
+ static <T> Class<T> createForArray(String packageName, String className, Class<?> componentType) {
// Initialize here to avoid method inliner
Class<T> clazz = new Class<T>();
clazz.typeName = packageName + className;
clazz.modifiers = ARRAY;
clazz.superclass = Object.class;
+ clazz.componentType = componentType;
return clazz;
}
@@ -68,8 +69,8 @@
// Initialize here to avoid method inliner
Class<T> clazz = new Class<T>();
clazz.typeName = packageName + className;
- clazz.modifiers = ENUM;
- clazz.superclass = superclass;
+ clazz.modifiers = (enumConstantsFunc != null) ? ENUM : 0;
+ clazz.superclass = clazz.enumSuperclass = superclass;
clazz.enumConstantsFunc = enumConstantsFunc;
return clazz;
}
@@ -99,11 +100,15 @@
clazz.modifiers = PRIMITIVE;
return clazz;
}
+
+ int modifiers;
+
+ private Class<?> componentType;
@SuppressWarnings("unused")
private JavaScriptObject enumConstantsFunc;
-
- private int modifiers;
+
+ private Class<? super T> enumSuperclass;
private String typeName;
@@ -123,16 +128,29 @@
return false;
}
+ public Class<?> getComponentType() {
+ return componentType;
+ }
+
public native T[] getEnumConstants() /*-{
return this.@java.lang.Class::enumConstantsFunc
&& (this.@java.lang.Class::enumConstantsFunc)();
}-*/;
+ /**
+ * Used by Enum to allow getSuperclass() to be pruned.
+ */
+ public Class<? super T> getEnumSuperclass() {
+ return enumSuperclass;
+ }
+
public String getName() {
+ // This body may be replaced by the compiler
return typeName;
}
public Class<? super T> getSuperclass() {
+ // This body may be replaced by the compiler
return superclass;
}
diff --git a/user/super/com/google/gwt/emul/java/lang/Enum.java b/user/super/com/google/gwt/emul/java/lang/Enum.java
index cfbac7e..4469adf 100644
--- a/user/super/com/google/gwt/emul/java/lang/Enum.java
+++ b/user/super/com/google/gwt/emul/java/lang/Enum.java
@@ -93,7 +93,12 @@
@SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass() {
Class clazz = getClass();
- Class superclass = clazz.getSuperclass();
+ assert clazz != null : "clazz";
+
+ // Don't use getSuperclass() to allow that method to be pruned for most
+ // class types
+ Class superclass = clazz.getEnumSuperclass();
+ assert superclass != null : "superclass";
return (superclass == Enum.class) ? clazz : superclass;
}
diff --git a/user/super/com/google/gwt/emul/java/lang/StackTraceElement.java b/user/super/com/google/gwt/emul/java/lang/StackTraceElement.java
index 9f3c915..90abbba 100644
--- a/user/super/com/google/gwt/emul/java/lang/StackTraceElement.java
+++ b/user/super/com/google/gwt/emul/java/lang/StackTraceElement.java
@@ -32,6 +32,17 @@
private String methodName;
+ public StackTraceElement() {
+ }
+
+ public StackTraceElement(String className, String methodName, String fileName,
+ int lineNumber) {
+ this.className = className;
+ this.methodName = methodName;
+ this.fileName = fileName;
+ this.lineNumber = lineNumber;
+ }
+
public String getClassName() {
return className;
}
diff --git a/user/super/com/google/gwt/emul/java/lang/System.java b/user/super/com/google/gwt/emul/java/lang/System.java
index a6d22e1..8567ef6 100644
--- a/user/super/com/google/gwt/emul/java/lang/System.java
+++ b/user/super/com/google/gwt/emul/java/lang/System.java
@@ -43,14 +43,17 @@
if (src == null || dest == null) {
throw new NullPointerException();
}
-
- // TODO: use Class objects when Class.getComponentType() is supported.
- String srcTypeName = src.getClass().getName();
- String destTypeName = dest.getClass().getName();
- if (srcTypeName.charAt(0) != '[' || destTypeName.charAt(0) != '[') {
+
+ Class<?> srcType = src.getClass();
+ Class<?> destType = dest.getClass();
+ if (!srcType.isArray() || !destType.isArray()) {
throw new ArrayStoreException("Must be array types");
}
- if (srcTypeName.charAt(1) != destTypeName.charAt(1)) {
+
+ Class<?> srcComp = srcType.getComponentType();
+ Class<?> destComp = destType.getComponentType();
+ if (srcComp.modifiers != destComp.modifiers
+ || (srcComp.isPrimitive() && !srcComp.equals(destComp))) {
throw new ArrayStoreException("Array types must match");
}
int srclen = getArrayLength(src);
@@ -64,8 +67,8 @@
* can copy them in native code for speed. Otherwise, we have to copy them
* in Java so we get appropriate errors.
*/
- if ((srcTypeName.charAt(1) == 'L' || srcTypeName.charAt(1) == '[')
- && !srcTypeName.equals(destTypeName)) {
+ if ((!srcComp.isPrimitive() || srcComp.isArray())
+ && !srcType.equals(destType)) {
// copy in Java to make sure we get ArrayStoreExceptions if the values
// aren't compatible
Object[] srcArray = (Object[]) src;
@@ -125,7 +128,7 @@
/**
* Copy an array using native Javascript. The destination array must be a real
- * Java array (ie, already has the GWT type info on it). No error checking is
+ * Java array (ie, already has the GWT type info on it). No error checking is
* performed -- the caller is expected to have verified everything first.
*
* @param src source array for copy
diff --git a/user/super/com/google/gwt/emul/java/lang/Throwable.java b/user/super/com/google/gwt/emul/java/lang/Throwable.java
index f212156..b41223c 100644
--- a/user/super/com/google/gwt/emul/java/lang/Throwable.java
+++ b/user/super/com/google/gwt/emul/java/lang/Throwable.java
@@ -15,6 +15,9 @@
*/
package java.lang;
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.core.client.impl.StackTraceCreator;
+
import java.io.PrintStream;
import java.io.Serializable;
@@ -40,6 +43,10 @@
private String detailMessage;
private transient StackTraceElement[] stackTrace;
+ {
+ fillInStackTrace();
+ }
+
public Throwable() {
}
@@ -58,11 +65,17 @@
}
/**
- * Stack traces are not currently populated by GWT. This method does nothing.
+ * Populates the stack trace information for the Throwable.
*
* @return this
*/
public Throwable fillInStackTrace() {
+ JsArrayString stack = StackTraceCreator.createStackTrace();
+ stackTrace = new StackTraceElement[stack.length()];
+ for (int i = 0, j = stackTrace.length; i < j; i++) {
+ stackTrace[i] = new StackTraceElement("Unknown", stack.get(i),
+ "Unknown source", 0);
+ }
return this;
}
diff --git a/user/super/com/google/gwt/emul/java/util/Arrays.java b/user/super/com/google/gwt/emul/java/util/Arrays.java
index 56d1778..a7a2a70 100644
--- a/user/super/com/google/gwt/emul/java/util/Arrays.java
+++ b/user/super/com/google/gwt/emul/java/util/Arrays.java
@@ -411,14 +411,14 @@
if (obj1.equals(obj2)) {
continue;
}
- String class1 = obj1.getClass().getName();
- String class2 = obj2.getClass().getName();
+ Class<?> class1 = obj1.getClass();
+ Class<?> class2 = obj2.getClass();
// We have to test and see if these are two arrays of the same type,
// then see what types of arrays they are and dispatch to the
// appropriate equals
- if (!class1.startsWith("[") || !class1.equals(class2)) {
+ if (!class1.isArray() || !class1.equals(class2)) {
return false;
}
@@ -1165,7 +1165,7 @@
Object obj = a[i];
if (obj == null) {
b.append("null");
- } else if (obj.getClass().getName().startsWith("[")) {
+ } else if (obj.getClass().isArray()) {
if (obj instanceof Object[]) {
if (arraysIveSeen.contains(obj)) {
b.append("[...]");
diff --git a/user/test/com/google/gwt/core/CoreSuite.java b/user/test/com/google/gwt/core/CoreSuite.java
index 0bc8039..18e67ad 100644
--- a/user/test/com/google/gwt/core/CoreSuite.java
+++ b/user/test/com/google/gwt/core/CoreSuite.java
@@ -16,8 +16,10 @@
package com.google.gwt.core;
import com.google.gwt.core.client.GWTTest;
+import com.google.gwt.core.client.HttpThrowableReporterTest;
import com.google.gwt.core.client.JavaScriptExceptionTest;
import com.google.gwt.core.client.JsArrayTest;
+import com.google.gwt.core.client.impl.StackTraceCreatorTest;
import com.google.gwt.junit.tools.GWTTestSuite;
import junit.framework.Test;
@@ -30,9 +32,11 @@
GWTTestSuite suite = new GWTTestSuite("All core tests");
// $JUnit-BEGIN$
+ suite.addTestSuite(HttpThrowableReporterTest.class);
suite.addTestSuite(JavaScriptExceptionTest.class);
suite.addTestSuite(JsArrayTest.class);
suite.addTestSuite(GWTTest.class);
+ suite.addTestSuite(StackTraceCreatorTest.class);
// $JUnit-END$
return suite;
diff --git a/user/test/com/google/gwt/core/client/HttpThrowableReporterTest.java b/user/test/com/google/gwt/core/client/HttpThrowableReporterTest.java
new file mode 100644
index 0000000..58ccfa0
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/HttpThrowableReporterTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009 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.core.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests the HttpThrowableReporter.
+ */
+public class HttpThrowableReporterTest extends GWTTestCase {
+ private static final class Payload extends JavaScriptObject {
+ protected Payload() {
+ }
+
+ public native String getMessage() /*-{
+ return this.message;
+ }-*/;
+
+ public native JsArrayString getStackTrace() /*-{
+ return this.stackTrace;
+ }-*/;
+
+ public native String getStrongName() /*-{
+ return this.strongName;
+ }-*/;
+ }
+
+ public String getModuleName() {
+ return "com.google.gwt.core.Core";
+ }
+
+ public void testPayload() {
+ String payload;
+ Throwable e;
+
+ try {
+ throw new RuntimeException("foo");
+ } catch (Throwable t) {
+ e = t;
+ payload = HttpThrowableReporter.buildPayload(t);
+ }
+
+ assertNotNull(payload);
+ Payload p = JsonUtils.unsafeEval(payload);
+
+ assertEquals("foo", p.getMessage());
+ assertEquals(GWT.getPermutationStrongName(), p.getStrongName());
+
+ JsArrayString stack = p.getStackTrace();
+ assertNotNull(stack);
+ assertEquals(e.getStackTrace().length, stack.length());
+
+ for (int i = 0, j = e.getStackTrace().length; i < j; i++) {
+ assertEquals(e.getStackTrace()[i].getMethodName(), stack.get(i));
+ }
+ }
+}
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java
new file mode 100644
index 0000000..c47fc6b
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2009 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.core.client.impl;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JavaScriptException;
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests StackTraceCreator in web mode. The methods in this test class are
+ * static so that their names can be reliably determined in web mode.
+ */
+public class StackTraceCreatorTest extends GWTTestCase {
+ public static void testJavaScriptException() {
+ Throwable t = null;
+ try {
+ throwNative();
+ fail("No exception thrown");
+ } catch (JavaScriptException e) {
+ /*
+ * Some browsers may or may not be able to implement this at all, so we'll
+ * at least make sure that an array is returned;
+ */
+ assertNotNull(e.getStackTrace());
+ if (e.getStackTrace().length == 0) {
+ assertTrue("hosted mode", GWT.isScript());
+ return;
+ } else {
+ t = e;
+ }
+ }
+
+ String myName = null;
+ if (!GWT.isScript()) {
+ myName = "testJavaScriptException";
+ } else {
+ myName = testJavaScriptExceptionName();
+ }
+
+ checkStack(myName, t);
+ }
+
+ /**
+ * Just make sure that reentrant behavior doesn't fail.
+ */
+ public static void testReentrantCalls() {
+ if (!GWT.isScript()) {
+ // StackTraceCreator.createStackTrace() is useless in hosted mode
+ return;
+ }
+
+ JsArrayString stack = countDown(5);
+ assertNotNull(stack);
+ assertTrue(stack.length() > 0);
+ }
+
+ public static void testStackTraces() {
+ Throwable t;
+ try {
+ throw new RuntimeException();
+ } catch (Throwable t2) {
+ t = t2;
+ }
+
+ String myName = null;
+ if (!GWT.isScript()) {
+ myName = "testStackTraces";
+ } else {
+ myName = testStackTracesName();
+ }
+
+ checkStack(myName, t);
+ }
+
+ private static void checkStack(String myName, Throwable t) {
+ assertNotNull("myName", myName);
+ assertNotNull("t", t);
+
+ assertEquals("Needs a trim()", myName.trim(), myName);
+ assertFalse("function", myName.startsWith("function"));
+ assertFalse("(", myName.contains("("));
+
+ StackTraceElement[] stack = t.getStackTrace();
+ assertNotNull("stack", stack);
+ assertTrue("stack.length", stack.length > 0);
+
+ boolean found = false;
+ StringBuilder observedStack = new StringBuilder();
+ for (int i = 0, j = stack.length; i < j; i++) {
+ StackTraceElement elt = stack[i];
+ String value = elt.getMethodName();
+
+ assertNotNull("value", value);
+ assertTrue("value.length", value.length() > 0);
+ assertEquals("value.trim()", value.length(), value.trim().length());
+
+ observedStack.append("\n").append(value);
+ found |= myName.equals(value);
+ }
+
+ assertTrue("Did not find " + myName + " in the stack " + observedStack,
+ found);
+ }
+
+ private static JsArrayString countDown(int count) {
+ if (count > 0) {
+ return countDown(count - 1);
+ } else {
+ return StackTraceCreator.createStackTrace();
+ }
+ }
+
+ private static native String testJavaScriptExceptionName() /*-{
+ var fn = @com.google.gwt.core.client.impl.StackTraceCreatorTest::testJavaScriptException();
+ return @com.google.gwt.core.client.impl.StackTraceCreator::extractNameFromToString(Ljava/lang/String;)(fn.toString());
+ }-*/;
+
+ private static native String testStackTracesName() /*-{
+ var fn = @com.google.gwt.core.client.impl.StackTraceCreatorTest::testStackTraces();
+ return @com.google.gwt.core.client.impl.StackTraceCreator::extractNameFromToString(Ljava/lang/String;)(fn.toString());
+ }-*/;
+
+ private static native void throwNative() /*-{
+ null.a();
+ }-*/;
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.Core";
+ }
+
+ public void testExtractName() {
+ assertEquals("anonymous",
+ StackTraceCreator.extractNameFromToString("function(){}"));
+ assertEquals("anonymous",
+ StackTraceCreator.extractNameFromToString("function (){}"));
+ assertEquals("anonymous",
+ StackTraceCreator.extractNameFromToString(" function (){}"));
+ assertEquals("anonymous",
+ StackTraceCreator.extractNameFromToString("function (){}"));
+ assertEquals("foo",
+ StackTraceCreator.extractNameFromToString("function foo(){}"));
+ assertEquals("foo",
+ StackTraceCreator.extractNameFromToString("function foo (){}"));
+ assertEquals("foo",
+ StackTraceCreator.extractNameFromToString(" function foo (){}"));
+ }
+}
diff --git a/user/test/com/google/gwt/core/ext/IFrameLinkerTest.gwt.xml b/user/test/com/google/gwt/core/ext/IFrameLinkerTest.gwt.xml
new file mode 100644
index 0000000..5aa3448
--- /dev/null
+++ b/user/test/com/google/gwt/core/ext/IFrameLinkerTest.gwt.xml
@@ -0,0 +1,18 @@
+<!-- -->
+<!-- Copyright 2008 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <inherits name='com.google.gwt.core.ext.LinkerTest' />
+ <add-linker name='std' />
+</module>
diff --git a/user/test/com/google/gwt/core/ext/LinkerSuite.java b/user/test/com/google/gwt/core/ext/LinkerSuite.java
new file mode 100644
index 0000000..f679fde
--- /dev/null
+++ b/user/test/com/google/gwt/core/ext/LinkerSuite.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.core.ext;
+
+import com.google.gwt.core.ext.test.IFrameLinkerTest;
+import com.google.gwt.core.ext.test.XSLinkerTest;
+import com.google.gwt.junit.tools.GWTTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * Runs the linker tests. See the subclasses of {@link LinkerTest}.
+ */
+public class LinkerSuite {
+
+ public static Test suite() {
+ GWTTestSuite suite = new GWTTestSuite("Smoke test for linkers");
+
+ // $JUnit-BEGIN$
+ suite.addTestSuite(IFrameLinkerTest.class);
+ suite.addTestSuite(XSLinkerTest.class);
+ /*
+ * Note: Single-script linking is disabled by default, because
+ * it only works when the test is run for a single permutation.
+ */
+ // suite.addTestSuite(SingleScriptLinkerTest.class);
+ // $JUnit-END$
+ return suite;
+ }
+}
diff --git a/user/test/com/google/gwt/core/ext/LinkerTest.gwt.xml b/user/test/com/google/gwt/core/ext/LinkerTest.gwt.xml
new file mode 100644
index 0000000..c015e0c
--- /dev/null
+++ b/user/test/com/google/gwt/core/ext/LinkerTest.gwt.xml
@@ -0,0 +1,21 @@
+<!-- -->
+<!-- Copyright 2008 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<!-- This is an abstract module. Specific linker tests should inherit -->
+<!-- from this module and specify a linker. -->
+
+<module>
+ <inherits name='com.google.gwt.junit.JUnit' />
+ <source path='test' />
+</module>
diff --git a/user/test/com/google/gwt/core/ext/SingleScriptLinkerTest.gwt.xml b/user/test/com/google/gwt/core/ext/SingleScriptLinkerTest.gwt.xml
new file mode 100644
index 0000000..6216202
--- /dev/null
+++ b/user/test/com/google/gwt/core/ext/SingleScriptLinkerTest.gwt.xml
@@ -0,0 +1,18 @@
+<!-- -->
+<!-- Copyright 2008 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <inherits name='com.google.gwt.core.ext.LinkerTest' />
+ <add-linker name='sso' />
+</module>
diff --git a/user/test/com/google/gwt/core/ext/XSLinkerTest.gwt.xml b/user/test/com/google/gwt/core/ext/XSLinkerTest.gwt.xml
new file mode 100644
index 0000000..5490500
--- /dev/null
+++ b/user/test/com/google/gwt/core/ext/XSLinkerTest.gwt.xml
@@ -0,0 +1,18 @@
+<!-- -->
+<!-- Copyright 2008 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <inherits name='com.google.gwt.core.ext.LinkerTest' />
+ <add-linker name='xs' />
+</module>
diff --git a/user/test/com/google/gwt/core/ext/test/IFrameLinkerTest.java b/user/test/com/google/gwt/core/ext/test/IFrameLinkerTest.java
new file mode 100644
index 0000000..d4b8f88
--- /dev/null
+++ b/user/test/com/google/gwt/core/ext/test/IFrameLinkerTest.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.core.ext.test;
+
+
+/**
+ * Tests the iframe-based linker.
+ */
+public class IFrameLinkerTest extends LinkerTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.ext.IFrameLinkerTest";
+ }
+}
diff --git a/user/test/com/google/gwt/core/ext/test/LinkerTest.java b/user/test/com/google/gwt/core/ext/test/LinkerTest.java
new file mode 100644
index 0000000..0f08376
--- /dev/null
+++ b/user/test/com/google/gwt/core/ext/test/LinkerTest.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.core.ext.test;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests that all the linkers work well enough to run the
+ * JUnit testing infrastructure.
+ */
+public abstract class LinkerTest extends GWTTestCase {
+ public void testSomethingTrivial() {
+ assertTrue(true);
+ }
+}
diff --git a/user/test/com/google/gwt/core/ext/test/SingleScriptLinkerTest.java b/user/test/com/google/gwt/core/ext/test/SingleScriptLinkerTest.java
new file mode 100644
index 0000000..4f9a3ac
--- /dev/null
+++ b/user/test/com/google/gwt/core/ext/test/SingleScriptLinkerTest.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.core.ext.test;
+
+
+/**
+ * Tests the single-script linker.
+ */
+public class SingleScriptLinkerTest extends LinkerTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.ext.SingleScriptLinkerTest";
+ }
+}
diff --git a/user/test/com/google/gwt/core/ext/test/XSLinkerTest.java b/user/test/com/google/gwt/core/ext/test/XSLinkerTest.java
new file mode 100644
index 0000000..d9bf3ac
--- /dev/null
+++ b/user/test/com/google/gwt/core/ext/test/XSLinkerTest.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.core.ext.test;
+
+
+/**
+ * Tests the cross-site linker.
+ */
+public class XSLinkerTest extends LinkerTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.ext.XSLinkerTest";
+ }
+}
diff --git a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
index b079d19..9f0c603 100644
--- a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
+++ b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
@@ -39,6 +39,8 @@
import com.google.gwt.dev.jjs.test.MiscellaneousTest;
import com.google.gwt.dev.jjs.test.NativeLongTest;
import com.google.gwt.dev.jjs.test.ObjectIdentityTest;
+import com.google.gwt.dev.jjs.test.RunAsyncTest;
+import com.google.gwt.dev.jjs.test.SingleJsoImplTest;
import com.google.gwt.dev.jjs.test.UnstableGeneratorTest;
import com.google.gwt.dev.jjs.test.VarargsTest;
import com.google.gwt.junit.tools.GWTTestSuite;
@@ -78,6 +80,8 @@
suite.addTestSuite(MiscellaneousTest.class);
suite.addTestSuite(NativeLongTest.class);
suite.addTestSuite(ObjectIdentityTest.class);
+ suite.addTestSuite(RunAsyncTest.class);
+ suite.addTestSuite(SingleJsoImplTest.class);
suite.addTestSuite(UnstableGeneratorTest.class);
suite.addTestSuite(VarargsTest.class);
// $JUnit-END$
diff --git a/user/test/com/google/gwt/dev/jjs/test/ClassObjectTest.java b/user/test/com/google/gwt/dev/jjs/test/ClassObjectTest.java
index 8cb569a..94a3d54 100644
--- a/user/test/com/google/gwt/dev/jjs/test/ClassObjectTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/ClassObjectTest.java
@@ -52,11 +52,13 @@
public void testArray() {
Object o = new Foo[3];
assertEquals(Foo[].class, o.getClass());
- assertEquals(Object.class, o.getClass().getSuperclass());
- assertEquals("[Lcom.google.gwt.dev.jjs.test.ClassObjectTest$Foo;",
- o.getClass().getName());
- assertEquals("class [Lcom.google.gwt.dev.jjs.test.ClassObjectTest$Foo;",
- o.getClass().toString());
+ if (expectClassMetadata()) {
+ assertEquals(Object.class, o.getClass().getSuperclass());
+ assertEquals("[Lcom.google.gwt.dev.jjs.test.ClassObjectTest$Foo;",
+ o.getClass().getName());
+ assertEquals("class [Lcom.google.gwt.dev.jjs.test.ClassObjectTest$Foo;",
+ o.getClass().toString());
+ }
assertTrue(o.getClass().isArray());
assertFalse(o.getClass().isEnum());
assertFalse(o.getClass().isInterface());
@@ -81,11 +83,13 @@
public void testClass() {
Object o = new Foo();
assertEquals(Foo.class, o.getClass());
- assertEquals(Object.class, o.getClass().getSuperclass());
- assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$Foo",
- Foo.class.getName());
- assertEquals("class com.google.gwt.dev.jjs.test.ClassObjectTest$Foo",
- Foo.class.toString());
+ if (expectClassMetadata()) {
+ assertEquals(Object.class, o.getClass().getSuperclass());
+ assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$Foo",
+ Foo.class.getName());
+ assertEquals("class com.google.gwt.dev.jjs.test.ClassObjectTest$Foo",
+ Foo.class.toString());
+ }
assertFalse(Foo.class.isArray());
assertFalse(Foo.class.isEnum());
assertFalse(Foo.class.isInterface());
@@ -95,18 +99,22 @@
public void testCloneClassLiteral() {
// getBarClass() should inline, causing a clone of a class literal
- assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$Bar",
- getBarClass().getName());
+ if (expectClassMetadata()) {
+ assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$Bar",
+ getBarClass().getName());
+ }
}
public void testEnum() {
Object o = Bar.BAR;
assertEquals(Bar.class, o.getClass());
- assertEquals(Enum.class, o.getClass().getSuperclass());
- assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$Bar",
- o.getClass().getName());
- assertEquals("class com.google.gwt.dev.jjs.test.ClassObjectTest$Bar",
- o.getClass().toString());
+ if (expectClassMetadata()) {
+ assertEquals(Enum.class, o.getClass().getSuperclass());
+ assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$Bar",
+ o.getClass().getName());
+ assertEquals("class com.google.gwt.dev.jjs.test.ClassObjectTest$Bar",
+ o.getClass().toString());
+ }
assertFalse(o.getClass().isArray());
assertTrue(o.getClass().isEnum());
assertFalse(o.getClass().isInterface());
@@ -116,27 +124,32 @@
public void testEnumSubclass() {
Object o = Bar.BAZ;
- assertNotSame(Bar.class, o.getClass());
- assertEquals(Bar.class, o.getClass().getSuperclass());
- /*
- * TODO: implement
- */
- // assertEquals(Bar.class, o.getClass().getDeclaringClass());
- assertTrue(o.getClass().getName().endsWith("$1"));
- assertTrue(o.getClass().toString().endsWith("$1"));
- assertFalse(o.getClass().isArray());
- assertFalse(o.getClass().isEnum());
- assertFalse(o.getClass().isInterface());
- assertFalse(o.getClass().isPrimitive());
- assertNull(o.getClass().getEnumConstants());
+ assertNotSame("Classes unexpectedly the same", Bar.class, o.getClass());
+ if (expectClassMetadata()) {
+ assertEquals(Bar.class, o.getClass().getSuperclass());
+ /*
+ * TODO: implement
+ */
+ // assertEquals(Bar.class, o.getClass().getDeclaringClass());
+ assertTrue(o.getClass().getName().endsWith("$1"));
+ assertTrue(o.getClass().toString().endsWith("$1"));
+ }
+ assertFalse("Should not be array", o.getClass().isArray());
+ assertFalse("Should not be enum", o.getClass().isEnum());
+ assertFalse("Should not be interface", o.getClass().isInterface());
+ assertFalse("Should not be primitive", o.getClass().isPrimitive());
+ assertNull("Constands should be null", o.getClass().getEnumConstants());
}
public void testInterface() {
assertNull(IFoo.class.getSuperclass());
- assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$IFoo",
- IFoo.class.getName());
- assertEquals("interface com.google.gwt.dev.jjs.test.ClassObjectTest$IFoo",
- IFoo.class.toString());
+ if (expectClassMetadata()) {
+ assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$IFoo",
+ IFoo.class.getName());
+ assertEquals(
+ "interface com.google.gwt.dev.jjs.test.ClassObjectTest$IFoo",
+ IFoo.class.toString());
+ }
assertFalse(IFoo.class.isArray());
assertFalse(IFoo.class.isEnum());
assertTrue(IFoo.class.isInterface());
@@ -146,8 +159,10 @@
public void testPrimitive() {
assertNull(int.class.getSuperclass());
- assertEquals("int", int.class.getName());
- assertEquals("int", int.class.toString());
+ if (expectClassMetadata()) {
+ assertEquals("int", int.class.getName());
+ assertEquals("int", int.class.toString());
+ }
assertFalse(int.class.isArray());
assertFalse(int.class.isEnum());
assertFalse(int.class.isInterface());
@@ -155,6 +170,18 @@
assertNull(int.class.getEnumConstants());
}
+ private boolean expectClassMetadata() {
+ String name = Object.class.getName();
+
+ if (name.equals("java.lang.Object")) {
+ return true;
+ } else if (name.startsWith("Class$")) {
+ return false;
+ }
+
+ throw new RuntimeException("Unexpected class name " + name);
+ }
+
private Class<? extends Bar> getBarClass() {
return Bar.class;
}
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 a383f0b..97ad1f0 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
@@ -235,6 +235,38 @@
assertEquals(49, bytes[0]);
}
+ /**
+ * Issue 3064: when the implementation of an interface comes from a
+ * superclass, it can be necessary to add a bridge method that overrides the
+ * interface method and calls the inherited method.
+ */
+ public void testBridgeMethods() {
+ abstract class AbstractFoo {
+ public int compareTo(AbstractFoo o) {
+ return 0;
+ }
+ }
+
+ class MyFoo extends AbstractFoo implements Comparable<AbstractFoo> {
+ }
+
+ /*
+ * This subclass adds an extra curve ball: only one bridge method should be
+ * created, in class MyFoo. MyFooSub should not get its own but instead use
+ * the inherited one. Otherwise, two final methods with identical signatures
+ * would override each other.
+ */
+ class MyFooSub extends MyFoo {
+ }
+
+ Comparable<AbstractFoo> comparable1 = new MyFooSub();
+ assertEquals(0, comparable1.compareTo(new MyFoo()));
+
+
+ Comparable<AbstractFoo> comparable2 = new MyFoo();
+ assertEquals(0, comparable2.compareTo(new MyFooSub()));
+}
+
public void testCastOptimizer() {
Granny g = new Granny();
Apple a = g;
@@ -245,6 +277,11 @@
}
public void testClassLiterals() {
+ if (Object.class.getName().startsWith("Class$")) {
+ // If class metadata is disabled
+ return;
+ }
+
assertEquals("void", void.class.toString());
assertEquals("int", int.class.toString());
assertEquals("class java.lang.String", String.class.toString());
@@ -827,8 +864,8 @@
assertEquals("1bar", 1 + barShouldInline());
assertEquals("fbar", 'f' + barShouldInline());
assertEquals("truebar", true + barShouldInline());
- assertEquals("3.3bar", 3.3 + barShouldInline());
- assertEquals("3.3bar", 3.3f + barShouldInline());
+ assertEquals("3.5bar", 3.5 + barShouldInline());
+ assertEquals("3.5bar", 3.5f + barShouldInline());
assertEquals("27bar", 27L + barShouldInline());
assertEquals("nullbar", null + barShouldInline());
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
index 9d161ce..17f21bd 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
@@ -335,8 +335,13 @@
private void testClassLiteralAccess() {
// ClassLiteralAccess
o = Super.class;
- assertEquals("class com.google.gwt.dev.jjs.test.CoverageTest$Super",
- o.toString());
+ String str = o.toString();
+
+ // Class metadata could be disabled
+ if (!str.startsWith("class Class$")) {
+ assertEquals("class com.google.gwt.dev.jjs.test.CoverageTest$Super",
+ str);
+ }
}
private void testCompoundAssignment() {
diff --git a/user/test/com/google/gwt/dev/jjs/test/JsoTest.java b/user/test/com/google/gwt/dev/jjs/test/JsoTest.java
index c5a4a1b..5bf60b0 100644
--- a/user/test/com/google/gwt/dev/jjs/test/JsoTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/JsoTest.java
@@ -52,6 +52,13 @@
public static native String staticNative() /*-{
return "nativeFoo";
}-*/;
+
+ /**
+ * Ensure that a supertype can refer to members of a subtype.
+ */
+ public static native String staticNativeToSub() /*-{
+ return @com.google.gwt.dev.jjs.test.JsoTest.FooSub::staticValueSub()();
+ }-*/;
public static String staticValue() {
return "Foo" + field;
@@ -70,6 +77,10 @@
}
static class FooSub extends Foo {
+ static String staticValueSub() {
+ return "FooSub";
+ }
+
protected FooSub() {
}
@@ -419,8 +430,11 @@
assertEquals(JavaScriptObject.class, Bar.class);
assertEquals(Foo.class, Bar.class);
- assertEquals("com.google.gwt.core.client.JavaScriptObject$",
- JavaScriptObject.class.getName());
+ if (!JavaScriptObject.class.getName().startsWith("Class$")) {
+ // Class metadata could be disabled
+ assertEquals("com.google.gwt.core.client.JavaScriptObject$",
+ JavaScriptObject.class.getName());
+ }
}
public void testClassLiteralsArray() {
@@ -440,8 +454,11 @@
assertEquals(JavaScriptObject[][].class, Bar[][].class);
assertEquals(Foo[][].class, Bar[][].class);
- assertEquals("[[Lcom.google.gwt.core.client.JavaScriptObject$;",
- JavaScriptObject[][].class.getName());
+ if (!JavaScriptObject.class.getName().startsWith("Class$")) {
+ // Class metadata could be disabled
+ assertEquals("[[Lcom.google.gwt.core.client.JavaScriptObject$;",
+ JavaScriptObject[][].class.getName());
+ }
}
public void testEquality() {
@@ -608,6 +625,7 @@
assertEquals(3, Foo.field--);
assertEquals("Foo2", Foo.staticValue());
assertEquals("nativeFoo", Foo.staticNative());
+ assertEquals("FooSub", Foo.staticNativeToSub());
Bar.field = 10;
assertEquals(11, ++Bar.field);
diff --git a/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java b/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java
index ad114c5..121934f 100644
--- a/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java
@@ -101,8 +101,10 @@
{
// thwart optimizer
Object f1 = FALSE ? (Object) new PolyA() : (Object) new IFoo[1];
- assertEquals("[Lcom.google.gwt.dev.jjs.test.MiscellaneousTest$IFoo;",
- f1.getClass().getName());
+ if (expectClassMetadata()) {
+ assertEquals("[Lcom.google.gwt.dev.jjs.test.MiscellaneousTest$IFoo;",
+ f1.getClass().getName());
+ }
assertFalse(f1 instanceof PolyA[][]);
assertFalse(f1 instanceof IFoo[][]);
assertFalse(f1 instanceof PolyA[]);
@@ -121,8 +123,10 @@
{
// thwart optimizer
Object a1 = FALSE ? (Object) new PolyA() : (Object) new PolyA[1];
- assertEquals("[Lcom.google.gwt.dev.jjs.test.MiscellaneousTest$PolyA;",
- a1.getClass().getName());
+ if (expectClassMetadata()) {
+ assertEquals("[Lcom.google.gwt.dev.jjs.test.MiscellaneousTest$PolyA;",
+ a1.getClass().getName());
+ }
assertFalse(a1 instanceof PolyA[][]);
assertFalse(a1 instanceof IFoo[][]);
assertTrue(a1 instanceof PolyA[]);
@@ -140,8 +144,10 @@
{
// thwart optimizer
Object f2 = FALSE ? (Object) new PolyA() : (Object) new IFoo[1][];
- assertEquals("[[Lcom.google.gwt.dev.jjs.test.MiscellaneousTest$IFoo;",
- f2.getClass().getName());
+ if (expectClassMetadata()) {
+ assertEquals("[[Lcom.google.gwt.dev.jjs.test.MiscellaneousTest$IFoo;",
+ f2.getClass().getName());
+ }
assertFalse(f2 instanceof PolyA[][]);
assertTrue(f2 instanceof IFoo[][]);
assertFalse(f2 instanceof PolyA[]);
@@ -159,8 +165,10 @@
{
// thwart optimizer
Object a2 = FALSE ? (Object) new PolyA() : (Object) new PolyA[1][];
- assertEquals("[[Lcom.google.gwt.dev.jjs.test.MiscellaneousTest$PolyA;",
- a2.getClass().getName());
+ if (expectClassMetadata()) {
+ assertEquals("[[Lcom.google.gwt.dev.jjs.test.MiscellaneousTest$PolyA;",
+ a2.getClass().getName());
+ }
assertTrue(a2 instanceof PolyA[][]);
assertTrue(a2 instanceof IFoo[][]);
assertFalse(a2 instanceof PolyA[]);
@@ -178,14 +186,16 @@
public void testArrays() {
int[] c = new int[] {1, 2};
- assertEquals("[I", c.getClass().getName());
int[][] d = new int[][] { {1, 2}, {3, 4}};
- assertEquals("[[I", d.getClass().getName());
- assertEquals("[I", d[1].getClass().getName());
int[][][] e = new int[][][] { { {1, 2}, {3, 4}}, { {5, 6}, {7, 8}}};
- assertEquals("[[[I", e.getClass().getName());
- assertEquals("[[I", e[1].getClass().getName());
- assertEquals("[I", e[1][1].getClass().getName());
+ if (expectClassMetadata()) {
+ assertEquals("[I", c.getClass().getName());
+ assertEquals("[[I", d.getClass().getName());
+ assertEquals("[I", d[1].getClass().getName());
+ assertEquals("[[[I", e.getClass().getName());
+ assertEquals("[[I", e[1].getClass().getName());
+ assertEquals("[I", e[1][1].getClass().getName());
+ }
assertEquals(2, c[1]);
assertEquals(3, d[1][0]);
assertEquals(8, e[1][1][1]);
@@ -276,8 +286,9 @@
FALSE = false;
} else if (FALSE) {
TRUE = true;
- } else
+ } else {
noOp();
+ }
}
public void testString() {
@@ -335,4 +346,15 @@
return "com.google.gwt.dev.jjs.test.MiscellaneousTest";
}
+ private boolean expectClassMetadata() {
+ String name = Object.class.getName();
+
+ if (name.equals("java.lang.Object")) {
+ return true;
+ } else if (name.startsWith("Class$")) {
+ return false;
+ }
+
+ throw new RuntimeException("Unexpected class name " + name);
+ }
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java b/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java
new file mode 100644
index 0000000..e3a49e0
--- /dev/null
+++ b/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.test;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.RunAsyncCallback;
+import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests runAsync in various ways.
+ */
+public class RunAsyncTest extends GWTTestCase {
+ private static final String HELLO = "hello";
+
+ private static final int RUNASYNC_TIMEOUT = 10000;
+
+ private static String staticWrittenInBaseButReadLater;
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.dev.jjs.CompilerSuite";
+ }
+
+ public void testBasic() {
+ delayTestFinish(RUNASYNC_TIMEOUT);
+
+ GWT.runAsync(new RunAsyncCallback() {
+ public void onFailure(Throwable caught) {
+ throw new RuntimeException(caught);
+ }
+
+ public void onSuccess() {
+ finishTest();
+ }
+ });
+ }
+
+ /**
+ * Unlike with pruning, writing to a field should rescue it for code-splitting
+ * purposes.
+ */
+ public void testFieldWrittenButNotRead() {
+ delayTestFinish(RUNASYNC_TIMEOUT);
+
+ // This write happens in the base fragment
+ staticWrittenInBaseButReadLater = HELLO;
+
+ GWT.runAsync(new RunAsyncCallback() {
+ public void onFailure(Throwable caught) {
+ throw new RuntimeException(caught);
+ }
+
+ public void onSuccess() {
+ // This read happens later
+ assertEquals(HELLO, staticWrittenInBaseButReadLater);
+ finishTest();
+ }
+ });
+ }
+
+ /**
+ * Test that callbacks are called in the order they are posted.
+ */
+ public void testOrder() {
+ class Util {
+ int callNumber = 0;
+ int seen = 0;
+
+ void scheduleCallback() {
+ final int thisCallNumber = callNumber++;
+
+ GWT.runAsync(new RunAsyncCallback() {
+
+ public void onFailure(Throwable caught) {
+ throw new RuntimeException(caught);
+ }
+
+ public void onSuccess() {
+ assertEquals(seen, thisCallNumber);
+ seen++;
+ if (seen == 3) {
+ finishTest();
+ }
+ }
+ });
+ }
+ }
+ Util util = new Util();
+
+ delayTestFinish(RUNASYNC_TIMEOUT);
+
+ util.scheduleCallback();
+ util.scheduleCallback();
+ util.scheduleCallback();
+ }
+
+ public void testUnhandledExceptions() {
+ // Create an exception that will be thrown from an onSuccess method
+ final RuntimeException toThrow = new RuntimeException(
+ "Should be caught by the uncaught exception handler");
+
+ // save the original handler
+ final UncaughtExceptionHandler originalHandler = GWT.getUncaughtExceptionHandler();
+
+ // set a handler that catches toThrow and nothing else
+ GWT.setUncaughtExceptionHandler(new GWT.UncaughtExceptionHandler() {
+ public void onUncaughtException(Throwable e) {
+ GWT.setUncaughtExceptionHandler(originalHandler);
+
+ if (e == toThrow) {
+ // expected
+ finishTest();
+ } else {
+ // some other exception; pass it on
+ throw new RuntimeException(e);
+ }
+ }
+ });
+
+ delayTestFinish(RUNASYNC_TIMEOUT);
+
+ GWT.runAsync(new RunAsyncCallback() {
+ public void onFailure(Throwable caught) {
+ }
+
+ public void onSuccess() {
+ throw toThrow;
+ }
+ });
+ }
+}
diff --git a/user/test/com/google/gwt/dev/jjs/test/SingleJsoImplTest.java b/user/test/com/google/gwt/dev/jjs/test/SingleJsoImplTest.java
new file mode 100644
index 0000000..7f7f58b
--- /dev/null
+++ b/user/test/com/google/gwt/dev/jjs/test/SingleJsoImplTest.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright 2009 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.test;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.dev.jjs.test.SingleJsoImplTest.JsoHasInnerJsoType.InnerType;
+import com.google.gwt.dev.jjs.test.jsointfs.JsoInterfaceWithUnreferencedImpl;
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.io.IOException;
+
+/**
+ * Ensures that JavaScriptObjects may implement interfaces with methods.
+ */
+public class SingleJsoImplTest extends GWTTestCase {
+
+ interface Adder {
+ int ADDER_CONST = 6;
+
+ /**
+ * @see SameDescriptors#SAME_NAME
+ */
+ String SAME_NAME = "Same Name";
+
+ Object DIFFERENT_OBJECT = new Object();
+ Object SAME_OBJECT = new Object();
+ Object SAME_OBJECT2 = SAME_OBJECT;
+
+ /*
+ * NB: Picking a mix of double and int because doubles have size 2 on the
+ * stack, so this ensures that we're handling that case correctly.
+ */
+ double add(double a, int b);
+
+ /*
+ * Ensure that we can return types whose sizes are larger than the size of
+ * the arguments.
+ */
+ long returnLong();
+ }
+
+ interface CallsMethodInInnerType {
+ interface InnerInterface {
+ void call(int a);
+
+ int get();
+ }
+
+ InnerInterface call(InnerInterface o, int a);
+ }
+
+ interface CallsStaticMethodInSubclass {
+ String call(int a, int b);
+ }
+
+ interface Divider extends Multiplier {
+ int divide(int a, int b);
+ }
+
+ static class JavaAdder implements Adder {
+ public double add(double a, int b) {
+ return a + b;
+ }
+
+ public long returnLong() {
+ return 5L;
+ }
+ }
+
+ /**
+ * The extra declaration of implementing Multiplier should still be legal.
+ */
+ static class JavaDivider extends JavaMultiplier implements Divider,
+ Multiplier, Tag {
+ public int divide(int a, int b) {
+ return a / b;
+ }
+ }
+
+ /**
+ * Ensure that SingleJsoImpl interfaces can be extended and implemented by
+ * regular Java types.
+ */
+ static class JavaLog2 extends JavaDivider implements Log2 {
+ public double log2(int a) {
+ return Math.log(a) / Math.log(2);
+ }
+ }
+
+ static class JavaMultiplier implements Multiplier {
+ public int multiply(int a, int b) {
+ return a * b;
+ }
+ }
+
+ static class JsoAdder extends JavaScriptObject implements Adder {
+ protected JsoAdder() {
+ }
+
+ public final native double add(double a, int b) /*-{
+ return this.offset * (a + b);
+ }-*/;
+
+ public final long returnLong() {
+ return 5L;
+ }
+ }
+
+ static class JsoCallsStaticMethodInSubclass extends JavaScriptObject
+ implements CallsStaticMethodInSubclass {
+ protected JsoCallsStaticMethodInSubclass() {
+ }
+
+ public final native String call(int a, int b) /*-{
+ return "foo" + @com.google.gwt.dev.jjs.test.SingleJsoImplTest.JsoCallsStaticMethodInSubclassSubclass::actual(II)(a, b);
+ }-*/;
+ }
+
+ static class JsoCallsStaticMethodInSubclassSubclass extends
+ JsoCallsStaticMethodInSubclass {
+ public static String actual(int a, int b) {
+ return String.valueOf(a + b);
+ }
+
+ protected JsoCallsStaticMethodInSubclassSubclass() {
+ }
+ }
+
+ static class JsoDivider extends JsoMultiplier implements Divider, Tag {
+ protected JsoDivider() {
+ }
+
+ public final native int divide(int a, int b) /*-{
+ return this.offset * a / b;
+ }-*/;
+ }
+
+ static class JsoHasInnerJsoType extends JavaScriptObject implements
+ CallsMethodInInnerType {
+ static class InnerType extends JavaScriptObject implements InnerInterface {
+ protected InnerType() {
+ }
+
+ public final native void call(int a) /*-{
+ this.foo = a;
+ }-*/;
+
+ public final native int get() /*-{
+ return this.foo;
+ }-*/;
+ }
+
+ protected JsoHasInnerJsoType() {
+ }
+
+ public final InnerInterface call(InnerInterface o, int a) {
+ o.call(a);
+ return o;
+ }
+ }
+
+ static class JsoMultiplier extends JavaScriptObject implements Multiplier {
+ protected JsoMultiplier() {
+ }
+
+ public final native int multiply(int a, int b) /*-{
+ return this.offset * a * b;
+ }-*/;
+ }
+
+ /**
+ * Just a random JSO type for testing cross-casting.
+ */
+ final static class JsoRandom extends JavaScriptObject implements
+ SameDescriptors, Tag {
+ protected JsoRandom() {
+ }
+
+ public int add(int a, int b) {
+ return -1;
+ }
+
+ public int divide(int a, int b) {
+ return -1;
+ }
+
+ public int multiply(int a, int b) {
+ return -1;
+ }
+
+ String b() {
+ return "b";
+ }
+ }
+
+ final static class JsoSimple extends JavaScriptObject implements Simple {
+ protected JsoSimple() {
+ }
+
+ public String a() {
+ return "a";
+ }
+
+ public String ex() throws IOException {
+ throw new IOException();
+ }
+
+ public String rte() {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Ensure that SingleJsoImpl interfaces can be extended and implemented by
+ * regular Java types.
+ */
+ interface Log2 extends Divider {
+ double log2(int a);
+ }
+
+ interface Multiplier {
+ int multiply(int a, int b);
+ }
+
+ /**
+ * This interface makes sure that types with identical method signatures will
+ * still dispatch correctly.
+ */
+ interface SameDescriptors {
+ int SAME_NAME = 6;
+
+ int add(int a, int b);
+
+ int divide(int a, int b);
+
+ int multiply(int a, int b);
+ }
+
+ interface Simple {
+ String a();
+
+ String ex() throws IOException;
+
+ String rte();
+ }
+
+ /**
+ * Ensure that a Java-only implementation of a SingleJsoImpl interface works.
+ */
+ static class SimpleOnlyJava implements SimpleOnlyJavaInterface {
+ public String simpleOnlyJava() {
+ return "simpleOnlyJava";
+ }
+ }
+
+ interface SimpleOnlyJavaInterface {
+ String simpleOnlyJava();
+ }
+
+ interface Tag {
+ }
+
+ private static native JsoAdder makeAdder(int offset) /*-{
+ return {offset:offset};
+ }-*/;
+
+ private static native JsoDivider makeDivider(int offset) /*-{
+ return {offset:offset};
+ }-*/;
+
+ private static native JsoMultiplier makeMultiplier(int offset) /*-{
+ return {offset:offset};
+ }-*/;
+
+ private static native JsoSimple makeSimple() /*-{
+ return {};
+ }-*/;
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.dev.jjs.CompilerSuite";
+ }
+
+ public void testCallsToInnerTypes() {
+ CallsMethodInInnerType a = (CallsMethodInInnerType) JavaScriptObject.createObject();
+ InnerType i = (InnerType) JavaScriptObject.createObject();
+ assertEquals(5, a.call(i, 5).get());
+ assertEquals(5, i.get());
+ }
+
+ public void testDualCase() {
+ // Direct dispatch
+ {
+ JavaAdder java = new JavaAdder();
+ assertEquals(2.0, java.add(1, 1));
+
+ JsoAdder jso = makeAdder(2);
+ assertEquals(4.0, jso.add(1, 1));
+ assertEquals(5L, jso.returnLong());
+ }
+
+ // Just check dispatch via the interface
+ {
+ Adder a = new JavaAdder();
+ assertEquals(2.0, a.add(1, 1));
+
+ a = makeAdder(2);
+ assertEquals(4.0, a.add(1, 1));
+ assertEquals(5L, a.returnLong());
+ }
+
+ // Check casting
+ {
+ Object a = new JavaAdder();
+ assertEquals(2.0, ((Adder) a).add(1, 1));
+ assertEquals(2.0, ((JavaAdder) a).add(1, 1));
+ assertEquals(5L, ((Adder) a).returnLong());
+ assertEquals(5L, ((JavaAdder) a).returnLong());
+ assertTrue(a instanceof JavaAdder);
+ assertFalse(a instanceof JsoAdder);
+ assertFalse(a instanceof Tag);
+ try {
+ ((JsoAdder) a).add(1, 1);
+ fail("Should have thrown CCE");
+ } catch (ClassCastException e) {
+ // OK
+ }
+
+ a = makeAdder(2);
+ assertEquals(4.0, ((Adder) a).add(1, 1));
+ assertEquals(4.0, ((JsoAdder) a).add(1, 1));
+ assertEquals(5L, ((Adder) a).returnLong());
+ assertEquals(5L, ((JsoAdder) a).returnLong());
+ assertTrue(a instanceof JsoAdder);
+ assertFalse(a instanceof JavaAdder);
+ // NB: This is unexpected until you consider JSO$ as a roll-up type
+ assertTrue(a instanceof Tag);
+ try {
+ ((JavaAdder) a).add(1, 1);
+ fail("Should have thrown CCE");
+ } catch (ClassCastException e) {
+ // OK
+ }
+ }
+ }
+
+ public void testFields() {
+ assertEquals(6, Adder.ADDER_CONST);
+ assertEquals("Same Name", Adder.SAME_NAME);
+ assertEquals(6, SameDescriptors.SAME_NAME);
+ assertSame(Adder.SAME_OBJECT, Adder.SAME_OBJECT2);
+ assertNotSame(Adder.DIFFERENT_OBJECT, Adder.SAME_OBJECT);
+ }
+
+ @SuppressWarnings("cast")
+ public void testSimpleCase() {
+ {
+ JsoSimple asJso = makeSimple();
+ assertTrue(asJso instanceof Object);
+ assertTrue(asJso instanceof Simple);
+ assertEquals("a", asJso.a());
+ try {
+ asJso.ex();
+ fail("Should have thrown IOException");
+ } catch (IOException e) {
+ // OK
+ }
+ try {
+ asJso.rte();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // OK
+ }
+ }
+
+ {
+ Simple asSimple = makeSimple();
+ assertTrue(asSimple instanceof Object);
+ assertTrue(asSimple instanceof JavaScriptObject);
+ assertTrue(asSimple instanceof JsoSimple);
+ assertEquals("a", asSimple.a());
+ assertEquals("a", ((JsoSimple) asSimple).a());
+ try {
+ asSimple.ex();
+ fail("Should have thrown IOException");
+ } catch (IOException e) {
+ // OK
+ }
+ try {
+ asSimple.rte();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // OK
+ }
+ }
+
+ {
+ Object asObject = "Defeat type-tightening";
+ assertTrue(asObject instanceof String);
+
+ asObject = makeSimple();
+ assertTrue(asObject instanceof Object);
+ assertTrue(asObject instanceof JavaScriptObject);
+ assertTrue(asObject instanceof JsoSimple);
+ assertTrue(asObject instanceof Simple);
+ assertEquals("a", ((Simple) asObject).a());
+ assertEquals("a", ((JsoSimple) asObject).a());
+
+ // Test a cross-cast that's normally not allowed by the type system
+ assertTrue(asObject instanceof JsoRandom);
+ assertEquals("b", ((JsoRandom) asObject).b());
+ assertEquals(-1, ((JsoRandom) asObject).add(1, 1));
+ }
+
+ {
+ Object o = "Defeat type-tightening";
+ assertTrue(o instanceof String);
+ o = new SimpleOnlyJava();
+ assertTrue(o instanceof SimpleOnlyJavaInterface);
+ assertEquals("simpleOnlyJava", ((SimpleOnlyJava) o).simpleOnlyJava());
+ }
+ }
+
+ public void testStaticCallsToSubclasses() {
+ Object o = "String";
+ assertEquals(String.class, o.getClass());
+ o = JavaScriptObject.createObject();
+ assertTrue(o instanceof CallsStaticMethodInSubclass);
+ assertEquals("foo5", ((CallsStaticMethodInSubclass) o).call(2, 3));
+ }
+
+ @SuppressWarnings("cast")
+ public void testSubclassing() {
+ {
+ JsoDivider d = makeDivider(1);
+ assertTrue(d instanceof Divider);
+ assertTrue(d instanceof Multiplier);
+ assertTrue(d instanceof Tag);
+ assertEquals(5, d.divide(10, 2));
+ assertEquals(10, d.multiply(5, 2));
+ assertEquals(10, ((JsoMultiplier) d).multiply(5, 2));
+ }
+
+ {
+ Object d = makeDivider(1);
+ assertTrue(d instanceof Divider);
+ assertTrue(d instanceof Multiplier);
+ assertTrue(d instanceof JsoDivider);
+ assertTrue(d instanceof JsoMultiplier);
+ assertFalse(d instanceof JavaDivider);
+ assertFalse(d instanceof JavaMultiplier);
+ assertTrue(d instanceof Tag);
+
+ assertEquals(5, ((Divider) d).divide(10, 2));
+ assertEquals(10, ((Divider) d).multiply(5, 2));
+ assertEquals(10, ((Multiplier) d).multiply(5, 2));
+ assertEquals(5, ((JsoDivider) d).divide(10, 2));
+ assertEquals(10, ((JsoMultiplier) d).multiply(5, 2));
+
+ d = new JavaDivider();
+ assertTrue(d instanceof Divider);
+ assertTrue(d instanceof Multiplier);
+ assertTrue(d instanceof JavaDivider);
+ assertTrue(d instanceof JavaMultiplier);
+ assertFalse(d instanceof JsoDivider);
+ assertFalse(d instanceof JsoMultiplier);
+ assertTrue(d instanceof Tag);
+
+ assertEquals(5, ((Divider) d).divide(10, 2));
+ assertEquals(10, ((Divider) d).multiply(5, 2));
+ assertEquals(10, ((Multiplier) d).multiply(5, 2));
+ assertEquals(5, ((JavaDivider) d).divide(10, 2));
+ assertEquals(10, ((JavaMultiplier) d).multiply(5, 2));
+ }
+
+ {
+ Object m = makeMultiplier(1);
+ // This only works because JSO$ implements every SingleJsoImpl interface
+ assertTrue(m instanceof Divider);
+ assertEquals(2, ((Divider) m).divide(10, 5));
+
+ m = new JavaMultiplier();
+ // but this should fail, since there's proper type information
+ assertFalse(m instanceof Divider);
+ try {
+ assertEquals(2, ((Divider) m).divide(10, 5));
+ fail("Should have thrown CCE");
+ } catch (ClassCastException e) {
+ // OK
+ }
+ }
+
+ {
+ Object l2 = "Prevent type-tightening";
+ assertTrue(l2 instanceof String);
+
+ l2 = new JavaLog2();
+ assertTrue(l2 instanceof Log2);
+ assertTrue(l2 instanceof Multiplier);
+ assertTrue(l2 instanceof Divider);
+ assertEquals(4.0, ((Log2) l2).log2(16));
+ }
+ }
+
+ public void testUnreferencedType() {
+ JsoInterfaceWithUnreferencedImpl o = (JsoInterfaceWithUnreferencedImpl) JavaScriptObject.createObject();
+ assertNotNull(o);
+ assertTrue(o.isOk());
+ }
+}
diff --git a/user/test/com/google/gwt/dev/jjs/test/jsoimpls/UnreferencedImplOfJsoInterface.java b/user/test/com/google/gwt/dev/jjs/test/jsoimpls/UnreferencedImplOfJsoInterface.java
new file mode 100644
index 0000000..d037a87
--- /dev/null
+++ b/user/test/com/google/gwt/dev/jjs/test/jsoimpls/UnreferencedImplOfJsoInterface.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 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.test.jsoimpls;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.dev.jjs.test.jsointfs.JsoInterfaceWithUnreferencedImpl;
+
+/**
+ * This class exists for the purpose of testing JSO implementation types that
+ * aren't specifically referenced in any Java source.
+ */
+public final class UnreferencedImplOfJsoInterface extends JavaScriptObject implements
+ JsoInterfaceWithUnreferencedImpl {
+ protected UnreferencedImplOfJsoInterface() {
+ }
+
+ public boolean isOk() {
+ if (2 + 2 == 4) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/user/test/com/google/gwt/dev/jjs/test/jsointfs/JsoInterfaceWithUnreferencedImpl.java b/user/test/com/google/gwt/dev/jjs/test/jsointfs/JsoInterfaceWithUnreferencedImpl.java
new file mode 100644
index 0000000..42a7e26
--- /dev/null
+++ b/user/test/com/google/gwt/dev/jjs/test/jsointfs/JsoInterfaceWithUnreferencedImpl.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2009 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.test.jsointfs;
+
+/**
+ * This class exists for the purpose of testing JSO implementation types that
+ * aren't specifically referenced in any Java source.
+ */
+public interface JsoInterfaceWithUnreferencedImpl {
+ boolean isOk();
+}
diff --git a/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java b/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java
index d32c01b..51129e3 100644
--- a/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java
@@ -27,6 +27,7 @@
*/
public class CompilerConstantStringTest extends GWTTestCase {
+ @Override
public String getModuleName() {
return "com.google.gwt.emultest.EmulSuite";
}
@@ -188,7 +189,12 @@
public void testNull() {
assertNull(returnNull());
- String a = returnNull() + returnNull();
+ /*
+ * The ""+ is there because GWT currently does not translate a+b
+ * defensively enough to handle the case that both a and b are null.
+ * Revisit this test if that is ever changed.
+ */
+ String a = "" + returnNull() + returnNull();
assertEquals("nullnull", a);
}
diff --git a/user/test/com/google/gwt/emultest/java/lang/StringBufferTest.java b/user/test/com/google/gwt/emultest/java/lang/StringBufferTest.java
index b5e2241..e92c177 100644
--- a/user/test/com/google/gwt/emultest/java/lang/StringBufferTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/StringBufferTest.java
@@ -27,6 +27,7 @@
* @return the module name.
* @see com.google.gwt.junit.client.GWTTestCase#getModuleName()
*/
+ @Override
public String getModuleName() {
return "com.google.gwt.emultest.EmulSuite";
}
@@ -350,6 +351,7 @@
bld = new StringBuilder();
bld.append(new Object() {
+ @Override
public String toString() {
return "obj";
}
@@ -423,12 +425,12 @@
assertEquals("01cd234", bld.toString());
bld = new StringBuilder("01234");
- bld.insert(2, 1.0);
- assertEquals("011.0234", bld.toString());
+ bld.insert(2, 1.5);
+ assertEquals("011.5234", bld.toString());
bld = new StringBuilder("01234");
- bld.insert(2, 1.0F);
- assertEquals("011.0234", bld.toString());
+ bld.insert(2, 1.5F);
+ assertEquals("011.5234", bld.toString());
bld = new StringBuilder("01234");
bld.insert(2, 99);
@@ -440,6 +442,7 @@
bld = new StringBuilder("01234");
bld.insert(2, new Object() {
+ @Override
public String toString() {
return "obj";
}
diff --git a/user/test/com/google/gwt/emultest/java/lang/StringTest.java b/user/test/com/google/gwt/emultest/java/lang/StringTest.java
index 20c1a77..a20a0b6 100644
--- a/user/test/com/google/gwt/emultest/java/lang/StringTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/StringTest.java
@@ -299,7 +299,12 @@
*/
public void testNull() {
assertNull(returnNull());
- String a = returnNull() + returnNull();
+ /*
+ * The ""+ is there because GWT currently does not translate a+b
+ * defensively enough to handle the case that both a and b are null.
+ * Revisit this test if that is ever changed.
+ */
+ String a = "" + returnNull() + returnNull();
assertEquals("nullnull", a);
}
diff --git a/user/test/com/google/gwt/emultest/java/util/DateTest.java b/user/test/com/google/gwt/emultest/java/util/DateTest.java
index 00d343f..46e952b 100644
--- a/user/test/com/google/gwt/emultest/java/util/DateTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/DateTest.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.emultest.java.util;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.junit.client.GWTTestCase;
import java.util.Date;
@@ -34,6 +35,7 @@
/**
* Sets module name so that javascript compiler can operate.
*/
+ @Override
public String getModuleName() {
return "com.google.gwt.emultest.EmulSuite";
}
@@ -484,59 +486,69 @@
/** Testing for public java.lang.String java.util.Date.toGMTString(). */
public void testToGMTString() {
- // /////////////////////////////
- // Past
- // /////////////////////////////
- Date accum1 = create(PAST);
- String a1 = accum1.toGMTString();
- assertEquals("5 Jan 1880 00:00:00 GMT", a1);
+ // We can't rely on the JRE's toString, as it is an implementation detail.
+ if (GWT.isScript()) {
+ // /////////////////////////////
+ // Past
+ // /////////////////////////////
+ Date accum1 = create(PAST);
+ String a1 = accum1.toGMTString();
+ assertEquals("5 Jan 1880 00:00:00 GMT", a1);
- // /////////////////////////////
- // Future
- // /////////////////////////////
- Date accum2 = create(FUTURE);
- String a2 = accum2.toGMTString();
- assertEquals("30 Dec 2010 03:04:05 GMT", a2);
+ // /////////////////////////////
+ // Future
+ // /////////////////////////////
+ Date accum2 = create(FUTURE);
+ String a2 = accum2.toGMTString();
+ assertEquals("30 Dec 2010 03:04:05 GMT", a2);
+ }
}
/** Testing for public java.lang.String java.util.Date.toLocaleString(). */
public void testToLocaleString() {
- // /////////////////////////////
- // Past
- // /////////////////////////////
- Date accum1 = create(PAST);
- String a1 = accum1.toLocaleString();
- assertTrue(a1.indexOf("1880") != -1);
- // /////////////////////////////
- // Future
- // /////////////////////////////
- Date accum2 = create(FUTURE);
- String a2 = accum2.toLocaleString();
- assertTrue(a2.indexOf("2010") != -1);
+ // We can't rely on the JRE's toString, as it is an implementation detail.
+ if (GWT.isScript()) {
+ // /////////////////////////////
+ // Past
+ // /////////////////////////////
+ Date accum1 = create(PAST);
+ String a1 = accum1.toLocaleString();
+ assertTrue(a1.indexOf("1880") != -1);
+ // /////////////////////////////
+ // Future
+ // /////////////////////////////
+ Date accum2 = create(FUTURE);
+ String a2 = accum2.toLocaleString();
+ assertTrue(a2.indexOf("2010") != -1);
+ }
}
/** Date docs specify an exact format for toString(). */
public void testToString() {
- // /////////////////////////////
- // Past
- // /////////////////////////////
- Date d = create(PAST);
- String s = d.toString();
- assertTrue("Bad format " + s, s.matches(TO_STRING_PATTERN));
- assertEquals("Parsing returned unequal dates from " + s, d, new Date(
- Date.parse(s)));
+ // We can't rely on the JRE's toString, as it is an implementation detail.
+ if (GWT.isScript()) {
+ // /////////////////////////////
+ // Past
+ // /////////////////////////////
+ Date d = create(PAST);
+ String s = d.toString();
- // /////////////////////////////
- // Future
- // /////////////////////////////
- d = create(FUTURE);
- s = d.toString();
+ assertTrue("Bad format " + s, s.matches(TO_STRING_PATTERN));
+ assertEquals("Parsing returned unequal dates from " + s, d, new Date(
+ Date.parse(s)));
- assertTrue("Bad format " + s, s.matches(TO_STRING_PATTERN));
- assertEquals("Parsing returned unequal dates from " + s, d, new Date(
- Date.parse(s)));
+ // /////////////////////////////
+ // Future
+ // /////////////////////////////
+ d = create(FUTURE);
+ s = d.toString();
+
+ assertTrue("Bad format " + s, s.matches(TO_STRING_PATTERN));
+ assertEquals("Parsing returned unequal dates from " + s, d, new Date(
+ Date.parse(s)));
+ }
}
/** Testing for public static long java.util.Date.UTC(int,int,int,int,int,int). */
diff --git a/user/test/com/google/gwt/http/HTTPSuite.java b/user/test/com/google/gwt/http/HTTPSuite.java
index 379a093..905f173 100644
--- a/user/test/com/google/gwt/http/HTTPSuite.java
+++ b/user/test/com/google/gwt/http/HTTPSuite.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.http;
+import com.google.gwt.http.client.HTTPRequestTest;
import com.google.gwt.http.client.RequestBuilderTest;
import com.google.gwt.http.client.RequestTest;
import com.google.gwt.http.client.ResponseTest;
@@ -26,11 +27,13 @@
/**
* TODO: document me.
*/
+@Deprecated
public class HTTPSuite {
public static Test suite() {
GWTTestSuite suite = new GWTTestSuite(
"Test for suite for the com.google.gwt.http module");
+ suite.addTestSuite(HTTPRequestTest.class);
suite.addTestSuite(URLTest.class);
suite.addTestSuite(RequestBuilderTest.class);
suite.addTestSuite(RequestTest.class);
diff --git a/user/test/com/google/gwt/http/client/HTTPRequestTest.java b/user/test/com/google/gwt/http/client/HTTPRequestTest.java
new file mode 100644
index 0000000..05cbe22
--- /dev/null
+++ b/user/test/com/google/gwt/http/client/HTTPRequestTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2009 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.http.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.HTTPRequest;
+import com.google.gwt.user.client.ResponseTextHandler;
+
+/**
+ * Test cases for the {@link HTTPRequest} class.
+ *
+ */
+@Deprecated
+public class HTTPRequestTest extends GWTTestCase {
+
+ private static final int TEST_TIMEOUT = 10000;
+
+ private static String getTestBaseURL() {
+ return GWT.getModuleBaseURL() + "testRequestBuilder/";
+ }
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.http.RequestBuilderTest";
+ }
+
+ public void testAsyncGet() {
+ delayTestFinish(TEST_TIMEOUT);
+ HTTPRequest.asyncGet(getTestBaseURL() + "send_GET",
+ new ResponseTextHandler() {
+ public void onCompletion(String responseText) {
+ assertEquals(RequestBuilderTest.SERVLET_GET_RESPONSE, responseText);
+ finishTest();
+ }
+ });
+ }
+
+ public void testAsyncPost() {
+ delayTestFinish(TEST_TIMEOUT);
+ HTTPRequest.asyncPost(getTestBaseURL() + "simplePost",
+ "method=test+request", new ResponseTextHandler() {
+ public void onCompletion(String responseText) {
+ assertEquals(RequestBuilderTest.SERVLET_POST_RESPONSE, responseText);
+ finishTest();
+ }
+ });
+ }
+}
diff --git a/user/test/com/google/gwt/http/client/RequestBuilderTest.java b/user/test/com/google/gwt/http/client/RequestBuilderTest.java
index 5a7d84e..5ade8cd 100644
--- a/user/test/com/google/gwt/http/client/RequestBuilderTest.java
+++ b/user/test/com/google/gwt/http/client/RequestBuilderTest.java
@@ -24,6 +24,11 @@
public class RequestBuilderTest extends GWTTestCase {
private static final int TEST_FINISH_DELAY = 10000;
+ public static final String SERVLET_GET_RESPONSE = "get";
+ public static final String SERVLET_POST_RESPONSE = "post";
+ public static final String SERVLET_HEAD_RESPONSE = "head";
+ public static final String SERVLET_PUT_RESPONSE = "put";
+
private static String getTestBaseURL() {
return GWT.getModuleBaseURL() + "testRequestBuilder/";
}
@@ -155,6 +160,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -177,6 +183,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_POST_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -200,6 +207,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -222,6 +230,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_POST_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -316,6 +325,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -345,6 +355,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -374,6 +385,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
fail("Test did not timeout");
}
diff --git a/user/test/com/google/gwt/http/client/RequestTest.java b/user/test/com/google/gwt/http/client/RequestTest.java
index b0c52df..8f3121f 100644
--- a/user/test/com/google/gwt/http/client/RequestTest.java
+++ b/user/test/com/google/gwt/http/client/RequestTest.java
@@ -17,7 +17,7 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.junit.client.GWTTestCase;
-import com.google.gwt.user.client.impl.HTTPRequestImpl;
+import com.google.gwt.xhr.client.XMLHttpRequest;
/**
* TODO: document me.
@@ -76,29 +76,28 @@
};
try {
- Request request = new Request(null, 0, callback);
+ new Request(null, 0, callback);
fail();
} catch (NullPointerException ex) {
- // Success.
+ // Success (The Request ctor explicitly throws an NPE).
}
- HTTPRequestImpl impl = (HTTPRequestImpl) GWT.create(HTTPRequestImpl.class);
try {
- Request request = new Request(impl.createXmlHTTPRequest(), -1, callback);
+ new Request(XMLHttpRequest.create(), -1, callback);
fail();
} catch (IllegalArgumentException ex) {
// Success.
}
try {
- Request request = new Request(impl.createXmlHTTPRequest(), -1, null);
+ new Request(XMLHttpRequest.create(), -1, null);
fail();
} catch (NullPointerException ex) {
- // Success.
+ // Success (The Request ctor explicitly throws an NPE).
}
try {
- Request request = new Request(impl.createXmlHTTPRequest(), 0, callback);
+ new Request(XMLHttpRequest.create(), 0, callback);
} catch (Throwable ex) {
fail(ex.getMessage());
}
diff --git a/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java b/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java
index f0efd75..4ba06c8 100644
--- a/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java
+++ b/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.http.server;
+import com.google.gwt.http.client.RequestBuilderTest;
+
import java.io.BufferedReader;
import java.io.IOException;
@@ -41,42 +43,46 @@
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
- String method = request.getMethod();
String pathInfo = request.getPathInfo();
if (pathInfo.equals(getPathInfoBase() + "setRequestHeader")) {
String value = request.getHeader("Foo");
- response.getWriter().print("Hello");
if (value.equals("Bar1")) {
response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE);
} else {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
} else if (pathInfo.equals(getPathInfoBase() + "send_GET")) {
response.setStatus(HttpServletResponse.SC_OK);
- response.getWriter().write("<html><body>hello</body></html>");
- response.setContentType("text/html");
+ response.getWriter().write(RequestBuilderTest.SERVLET_GET_RESPONSE);
} else if (pathInfo.equals(getPathInfoBase() + "sendRequest_GET")) {
response.setStatus(HttpServletResponse.SC_OK);
- response.getWriter().write("<html><body>hello</body></html>");
- response.setContentType("text/html");
+ response.getWriter().write(RequestBuilderTest.SERVLET_GET_RESPONSE);
} else if (pathInfo.equals(getPathInfoBase() + "setTimeout/timeout")) {
// cause a timeout on the client
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
- e.printStackTrace();
}
response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE);
} else if (pathInfo.equals(getPathInfoBase() + "setTimeout/noTimeout")) {
// wait but not long enough to timeout
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
}
- response.getWriter().print("setTimeout/noTimeout");
response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE);
+ } else if (pathInfo.equals(getPathInfoBase() + "user/pass")) {
+ String auth = request.getHeader("Authorization");
+ if (auth == null) {
+ response.setHeader("WWW-Authenticate", "BASIC");
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ } else {
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE);
+ }
} else {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
@@ -84,27 +90,35 @@
@Override
protected void doHead(HttpServletRequest request, HttpServletResponse response) {
- response.setStatus(HttpServletResponse.SC_OK);
+ try {
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_HEAD_RESPONSE);
+ } catch (IOException e) {
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
- String parameter = request.getParameter("method");
- if ("test request".equals(parameter)) {
- try {
+ try {
+ String parameter = request.getParameter("method");
+ if ("test request".equals(parameter)) {
/*
* On Safari 2.0.4, if the HTTP response does not include any response
* text the status message will be undefined. So, we make sure that the
* post returns some data. See
* http://bugs.webkit.org/show_bug.cgi?id=3810.
*/
- response.getWriter().println("Hello");
+ response.getWriter().print(RequestBuilderTest.SERVLET_POST_RESPONSE);
response.setStatus(HttpServletResponse.SC_OK);
- } catch (IOException e) {
- response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ } else if (request.getPathInfo().equals(getPathInfoBase() + "simplePost")) {
+ response.getWriter().print(RequestBuilderTest.SERVLET_POST_RESPONSE);
+ response.setStatus(HttpServletResponse.SC_OK);
+ } else {
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
- } else {
- response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ } catch (IOException e) {
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
@@ -114,6 +128,7 @@
BufferedReader reader = request.getReader();
String content = reader.readLine();
if (content.equals("<html><body>Put Me</body></html>")) {
+ response.getWriter().print(RequestBuilderTest.SERVLET_PUT_RESPONSE);
response.setStatus(HttpServletResponse.SC_OK);
} else {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
diff --git a/user/test/com/google/gwt/i18n/I18N2Test.gwt.xml b/user/test/com/google/gwt/i18n/I18N2Test.gwt.xml
index 3ab098d..c22dee5 100644
--- a/user/test/com/google/gwt/i18n/I18N2Test.gwt.xml
+++ b/user/test/com/google/gwt/i18n/I18N2Test.gwt.xml
@@ -14,8 +14,6 @@
<module>
<inherits name="com.google.gwt.i18n.I18N"/>
-
- <!-- Browser-sensitive code should use the 'user.agent' property -->
- <extend-property name = "locale" values ="piglatin,piglatin_UK, piglatin_UK_win,a,b,b_C,b_C_d"/>
- <set-property name="locale" value="b_C_d" />
+ <extend-property name = "locale" values ="piglatin,piglatin_UK, piglatin_UK_WINDOWS,aa,bb,bb_CC,bb_CC_DDDDD"/>
+ <set-property name="locale" value="bb_CC_DDDDD" />
</module>
diff --git a/user/test/com/google/gwt/i18n/I18NSuite.java b/user/test/com/google/gwt/i18n/I18NSuite.java
index 375f4f2..911a3f2 100644
--- a/user/test/com/google/gwt/i18n/I18NSuite.java
+++ b/user/test/com/google/gwt/i18n/I18NSuite.java
@@ -18,10 +18,13 @@
import com.google.gwt.i18n.client.AnnotationsTest;
import com.google.gwt.i18n.client.ArabicPluralsTest;
import com.google.gwt.i18n.client.DateTimeFormat_de_Test;
+import com.google.gwt.i18n.client.DateTimeFormat_en_Test;
import com.google.gwt.i18n.client.DateTimeParse_en_Test;
import com.google.gwt.i18n.client.DateTimeParse_zh_CN_Test;
import com.google.gwt.i18n.client.I18N2Test;
import com.google.gwt.i18n.client.I18NTest;
+import com.google.gwt.i18n.client.I18N_es_MX_Test;
+import com.google.gwt.i18n.client.I18N_iw_Test;
import com.google.gwt.i18n.client.LocaleInfoTest;
import com.google.gwt.i18n.client.LocaleInfo_ar_Test;
import com.google.gwt.i18n.client.NumberFormat_ar_Test;
@@ -29,10 +32,13 @@
import com.google.gwt.i18n.client.NumberFormat_fr_Test;
import com.google.gwt.i18n.client.NumberParse_en_Test;
import com.google.gwt.i18n.client.NumberParse_fr_Test;
+import com.google.gwt.i18n.client.RuntimeLocalesTest;
import com.google.gwt.i18n.client.TimeZoneInfoTest;
import com.google.gwt.i18n.client.TimeZoneTest;
import com.google.gwt.i18n.rebind.AbstractResourceTest;
import com.google.gwt.i18n.rebind.MessageFormatParserTest;
+import com.google.gwt.i18n.server.GwtLocaleTest;
+import com.google.gwt.i18n.server.RegionInheritanceTest;
import com.google.gwt.junit.tools.GWTTestSuite;
import junit.framework.Test;
@@ -50,10 +56,14 @@
suite.addTestSuite(AnnotationsTest.class);
suite.addTestSuite(ConstantMapTest.class);
suite.addTestSuite(DateTimeFormat_de_Test.class);
+ suite.addTestSuite(DateTimeFormat_en_Test.class);
suite.addTestSuite(DateTimeParse_en_Test.class);
suite.addTestSuite(DateTimeParse_zh_CN_Test.class);
+ suite.addTestSuite(GwtLocaleTest.class);
suite.addTestSuite(I18NTest.class);
suite.addTestSuite(I18N2Test.class);
+ suite.addTestSuite(I18N_iw_Test.class);
+ suite.addTestSuite(I18N_es_MX_Test.class);
suite.addTestSuite(LocaleInfo_ar_Test.class);
suite.addTestSuite(LocaleInfoTest.class);
suite.addTestSuite(MessageFormatParserTest.class);
@@ -62,6 +72,8 @@
suite.addTestSuite(NumberFormat_fr_Test.class);
suite.addTestSuite(NumberParse_en_Test.class);
suite.addTestSuite(NumberParse_fr_Test.class);
+ suite.addTestSuite(RegionInheritanceTest.class);
+ suite.addTestSuite(RuntimeLocalesTest.class);
suite.addTestSuite(TimeZoneInfoTest.class);
suite.addTestSuite(TimeZoneTest.class);
// $JUnit-END$
diff --git a/user/test/com/google/gwt/i18n/I18NTest.gwt.xml b/user/test/com/google/gwt/i18n/I18NTest.gwt.xml
index 2582b75..aaaf0d1 100644
--- a/user/test/com/google/gwt/i18n/I18NTest.gwt.xml
+++ b/user/test/com/google/gwt/i18n/I18NTest.gwt.xml
@@ -16,7 +16,6 @@
<inherits name="com.google.gwt.i18n.I18N"/>
<source path='resolutiontest' />
<source path = 'client'/>
- <!-- Browser-sensitive code should use the 'user.agent' property -->
- <extend-property name = "locale" values ="piglatin,piglatin_UK, piglatin_UK_win"/>
- <set-property name="locale" value="piglatin_UK_win" />
+ <extend-property name = "locale" values ="piglatin,piglatin_UK, piglatin_UK_WINDOWS"/>
+ <set-property name="locale" value="piglatin_UK_WINDOWS" />
</module>
diff --git a/user/test/com/google/gwt/i18n/I18NTest_en.gwt.xml b/user/test/com/google/gwt/i18n/I18NTest_en.gwt.xml
index 9e0002d..73cf0dc 100644
--- a/user/test/com/google/gwt/i18n/I18NTest_en.gwt.xml
+++ b/user/test/com/google/gwt/i18n/I18NTest_en.gwt.xml
@@ -18,6 +18,6 @@
<inherits name = 'com.google.gwt.i18n.I18N'/>
<!-- Include client-side source for the test cases -->
<source path="client"/>
- <extend-property name="locale" values="en"/>
- <set-property name = "locale" value = "en"/>
+ <extend-property name="locale" values="en_US"/>
+ <set-property name = "locale" value = "en_US"/>
</module>
diff --git a/user/test/com/google/gwt/i18n/I18NTest_es_MX.gwt.xml b/user/test/com/google/gwt/i18n/I18NTest_es_MX.gwt.xml
new file mode 100644
index 0000000..e981c96
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/I18NTest_es_MX.gwt.xml
@@ -0,0 +1,23 @@
+<!-- -->
+<!-- Copyright 2009 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <!-- Inherit the JUnit support -->
+ <inherits name='com.google.gwt.junit.JUnit'/>
+ <inherits name = 'com.google.gwt.i18n.I18N'/>
+ <!-- Include client-side source for the test cases -->
+ <source path="client"/>
+ <extend-property name="locale" values="es_MX"/>
+ <set-property name = "locale" value = "es_MX"/>
+</module>
diff --git a/user/test/com/google/gwt/i18n/I18NTest_iw.gwt.xml b/user/test/com/google/gwt/i18n/I18NTest_iw.gwt.xml
new file mode 100644
index 0000000..1b7ef8b
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/I18NTest_iw.gwt.xml
@@ -0,0 +1,23 @@
+<!-- -->
+<!-- Copyright 2009 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <!-- Inherit the JUnit support -->
+ <inherits name='com.google.gwt.junit.JUnit'/>
+ <inherits name = 'com.google.gwt.i18n.I18N'/>
+ <!-- Include client-side source for the test cases -->
+ <source path="client"/>
+ <extend-property name="locale" values="iw"/>
+ <set-property name = "locale" value = "iw"/>
+</module>
diff --git a/user/test/com/google/gwt/i18n/RuntimeLocalesTest.gwt.xml b/user/test/com/google/gwt/i18n/RuntimeLocalesTest.gwt.xml
new file mode 100644
index 0000000..a306827
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/RuntimeLocalesTest.gwt.xml
@@ -0,0 +1,20 @@
+<!-- -->
+<!-- Copyright 2007 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <inherits name="com.google.gwt.i18n.I18N"/>
+ <inherits name="com.google.gwt.i18n.CldrLocales"/>
+ <extend-property name = "locale" values ="en,es,es_419"/>
+ <set-property name = "locale" value ="es_419"/>
+ </module>
diff --git a/user/test/com/google/gwt/i18n/client/AnnotationsTest.java b/user/test/com/google/gwt/i18n/client/AnnotationsTest.java
index a26792a..d67e8d9 100644
--- a/user/test/com/google/gwt/i18n/client/AnnotationsTest.java
+++ b/user/test/com/google/gwt/i18n/client/AnnotationsTest.java
@@ -105,6 +105,9 @@
@DefaultMessage("You have {0} widgets.")
@PluralText({"one", "You have a widget."})
String getWidgetCount(@PluralCount int count);
+
+ @DefaultMessage("from en")
+ String leastDerived();
}
/**
@@ -140,4 +143,9 @@
assertEquals("You have 2 widgets.", m.getWidgetCount(2));
assertEquals("You have a widget.", m.getWidgetCount(1));
}
+
+ public void testLeastDerived() {
+ AllMessages m = GWT.create(AllMessages.class);
+ assertEquals("from en_US", m.leastDerived());
+ }
}
diff --git a/user/test/com/google/gwt/i18n/client/AnnotationsTest_Msg2_en_US.properties b/user/test/com/google/gwt/i18n/client/AnnotationsTest_Msg2_en_US.properties
new file mode 100644
index 0000000..5d28444
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/AnnotationsTest_Msg2_en_US.properties
@@ -0,0 +1 @@
+leastDerived=from en_US
\ No newline at end of file
diff --git a/user/test/com/google/gwt/i18n/client/ColorsAndShapesAndConcepts_piglatin_UK_win.properties b/user/test/com/google/gwt/i18n/client/ColorsAndShapesAndConcepts_piglatin_UK_WINDOWS.properties
similarity index 100%
rename from user/test/com/google/gwt/i18n/client/ColorsAndShapesAndConcepts_piglatin_UK_win.properties
rename to user/test/com/google/gwt/i18n/client/ColorsAndShapesAndConcepts_piglatin_UK_WINDOWS.properties
diff --git a/user/test/com/google/gwt/i18n/client/DateTimeFormat_en_Test.java b/user/test/com/google/gwt/i18n/client/DateTimeFormat_en_Test.java
new file mode 100644
index 0000000..df062fe
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/DateTimeFormat_en_Test.java
@@ -0,0 +1,418 @@
+/*
+ * 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.core.client.GWT;
+import com.google.gwt.i18n.client.constants.TimeZoneConstants;
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.util.Date;
+
+/**
+ * Tests formatting functionality in {@link DateTimeFormat} for the German
+ * language.
+ */
+public class DateTimeFormat_en_Test extends GWTTestCase {
+
+ public String getModuleName() {
+ return "com.google.gwt.i18n.I18NTest";
+ }
+
+ public void test_EEEEMMMddyy() {
+ Date date = new Date(2006 - 1900, 6, 27, 13, 10, 10);
+ assertEquals("Thursday,July 27, 2006", DateTimeFormat.getFormat(
+ "EEEE,MMMM dd, yyyy").format(date));
+ }
+
+ public void test_EEEMMMddyy() {
+ Date date = new Date(2006 - 1900, 6, 27, 13, 10, 10);
+ assertEquals("Thu, Jul 27, 06",
+ DateTimeFormat.getFormat("EEE, MMM d, yy").format(date));
+ }
+
+ public void test_HHmmss() {
+ Date date = new Date(2006 - 1900, 6, 27, 13, 10, 10);
+ assertEquals("13:10:10", DateTimeFormat.getFormat("HH:mm:ss").format(date));
+ }
+
+ public void test_hhmmssa() {
+ Date date = new Date(2006 - 1900, 6, 27, 13, 10, 10);
+ assertEquals("1:10:10 PM", DateTimeFormat.getFormat("h:mm:ss a").format(
+ date));
+ }
+
+ public void test_predefinedFormat() {
+ Date date = new Date(2006 - 1900, 7, 4, 13, 49, 24);
+
+ TimeZoneConstants timeZoneData = GWT.create(TimeZoneConstants.class);
+ String str = timeZoneData.americaLosAngeles();
+ TimeZone usPacific = TimeZone.createTimeZone(TimeZoneInfo.buildTimeZoneData(str));
+
+ String fullDateFormat = DateTimeFormat.getFullDateFormat().format(date);
+ assertEquals("Friday, August 4, 2006", fullDateFormat);
+
+ String longDateFormat = DateTimeFormat.getLongDateFormat().format(date);
+ assertEquals("August 4, 2006", longDateFormat);
+
+ String medDateFormat = DateTimeFormat.getMediumDateFormat().format(date);
+ assertEquals("Aug 4, 2006", medDateFormat);
+
+ String shortDateFormat = DateTimeFormat.getShortDateFormat().format(date);
+ assertEquals("8/4/06", shortDateFormat);
+
+ // When dealing with time zone, better use UTC time.
+ // And when UTC time is used, time zone must be given in "format".
+ date.setTime(Date.UTC(2006 - 1900, 7, 4, 20, 49, 24));
+ String fullTimeFormat = DateTimeFormat.getFullTimeFormat().format(date,
+ usPacific);
+ assertEquals("1:49:24 PM America/Los_Angeles", fullTimeFormat);
+
+ String longTimeFormat = DateTimeFormat.getLongTimeFormat().format(date,
+ usPacific);
+ assertEquals("1:49:24 PM PDT", longTimeFormat);
+
+ String medTimeFormat = DateTimeFormat.getMediumTimeFormat().format(date,
+ usPacific);
+ assertEquals("1:49:24 PM", medTimeFormat);
+
+ String shortTimeFormat = DateTimeFormat.getShortTimeFormat().format(date,
+ usPacific);
+ assertEquals("1:49 PM", shortTimeFormat);
+
+ String medFormat = DateTimeFormat.getMediumDateTimeFormat().format(date,
+ usPacific);
+ assertEquals("Aug 4, 2006 1:49:24 PM", medFormat);
+
+ String shortFormat = DateTimeFormat.getShortDateTimeFormat().format(date,
+ usPacific);
+ assertEquals("8/4/06 1:49 PM", shortFormat);
+ }
+
+ public void test_QQQQyy() {
+ Date date;
+
+ date = new Date(2006 - 1900, 0, 27, 13, 10, 10);
+ assertEquals("1st quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 1, 27, 13, 10, 10);
+ assertEquals("1st quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 2, 27, 13, 10, 10);
+ assertEquals("1st quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 3, 27, 13, 10, 10);
+ assertEquals("2nd quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 4, 27, 13, 10, 10);
+ assertEquals("2nd quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 5, 27, 13, 10, 10);
+ assertEquals("2nd quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 6, 27, 13, 10, 10);
+ assertEquals("3rd quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 7, 27, 13, 10, 10);
+ assertEquals("3rd quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 8, 27, 13, 10, 10);
+ assertEquals("3rd quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 9, 27, 13, 10, 10);
+ assertEquals("4th quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 10, 27, 13, 10, 10);
+ assertEquals("4th quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+
+ date = new Date(2006 - 1900, 11, 27, 13, 10, 10);
+ assertEquals("4th quarter 06", DateTimeFormat.getFormat("QQQQ yy").format(
+ date));
+ }
+
+ public void test_QQyyyy() {
+ Date date = new Date(2006 - 1900, 0, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q1 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 1, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q1 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 2, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q1 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 3, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q2 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 4, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q2 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 5, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q2 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 6, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q3 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 7, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q3 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 8, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q3 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 9, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q4 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 10, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q4 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ date = new Date(2006 - 1900, 11, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("Q4 2006", DateTimeFormat.getFormat("QQ yyyy").format(date));
+ }
+
+ public void test_quote() {
+ Date date = new Date(2006 - 1900, 6, 27);
+ date.setHours(13);
+ date.setMinutes(10);
+ date.setSeconds(10);
+ assertEquals("13 o'clock",
+ DateTimeFormat.getFormat("HH 'o''clock'").format(date));
+ assertEquals("13 oclock", DateTimeFormat.getFormat("HH 'oclock'").format(
+ date));
+ assertEquals("13 '", DateTimeFormat.getFormat("HH ''").format(date));
+ }
+
+ public void test_yyyyyMMMMM() {
+ Date date = new Date(2006 - 1900, 6, 27, 13, 10, 10);
+ assertEquals("2006.J.27 AD 01:10 PM", DateTimeFormat.getFormat(
+ "yyyyy.MMMMM.dd GGG hh:mm aaa").format(date));
+ }
+
+ public void test_timezonev() {
+ TimeZoneConstants timeZoneData = GWT.create(TimeZoneConstants.class);
+ String str = timeZoneData.americaLosAngeles();
+ TimeZone usPacific = TimeZone.createTimeZone(str);
+
+ Date date = new Date();
+ date.setTime(Date.UTC(2006 - 1900, 6, 27, 13, 10, 10));
+
+ assertEquals("07/27/2006 06:10:10 America/Los_Angeles",
+ DateTimeFormat.getFormat("MM/dd/yyyy HH:mm:ss v").format(date,
+ usPacific));
+
+ assertEquals("07/27/2006 06:10:10 America/Los_Angeles",
+ DateTimeFormat.getFormat("MM/dd/yyyy HH:mm:ss vv").format(date,
+ usPacific));
+
+ assertEquals("07/27/2006 06:10:10 America/Los_Angeles",
+ DateTimeFormat.getFormat("MM/dd/yyyy HH:mm:ss vvv").format(date,
+ usPacific));
+
+ assertEquals("07/27/2006 06:10:10 America/Los_Angeles",
+ DateTimeFormat.getFormat("MM/dd/yyyy HH:mm:ss vvvv").format(date,
+ usPacific));
+ }
+
+ public void test_simepleTimezonev() {
+ TimeZone simpleTimeZone = TimeZone.createTimeZone(480);
+
+ Date date = new Date();
+ date.setTime(Date.UTC(2006 - 1900, 6, 27, 14, 10, 10));
+
+ assertEquals("07/27/2006 06:10:10 Etc/GMT+8", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss v").format(date, simpleTimeZone));
+
+ assertEquals("07/27/2006 06:10:10 Etc/GMT+8", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss vv").format(date, simpleTimeZone));
+
+ assertEquals("07/27/2006 06:10:10 Etc/GMT+8", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss vvv").format(date, simpleTimeZone));
+
+ assertEquals("07/27/2006 06:10:10 Etc/GMT+8", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss vvvv").format(date, simpleTimeZone));
+ }
+
+ public void test_timezoneZ() {
+ TimeZoneConstants timeZoneData = GWT.create(TimeZoneConstants.class);
+ String str = timeZoneData.americaLosAngeles();
+ TimeZone usPacific = TimeZone.createTimeZone(str);
+
+ Date date = new Date();
+ date.setTime(Date.UTC(2006 - 1900, 6, 27, 13, 10, 10));
+
+ assertEquals("07/27/2006 06:10:10 -0700", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss Z").format(date, usPacific));
+
+ assertEquals("07/27/2006 06:10:10 -0700", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss ZZ").format(date, usPacific));
+
+ assertEquals("07/27/2006 06:10:10 -0700", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss ZZZ").format(date, usPacific));
+
+ assertEquals("07/27/2006 06:10:10 GMT-07:00", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss ZZZZ").format(date, usPacific));
+
+ date.setTime(Date.UTC(2006 - 1900, 1, 27, 13, 10, 10));
+ assertEquals("02/27/2006 05:10:10 -0800", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss Z").format(date, usPacific));
+
+ assertEquals("02/27/2006 05:10:10 -0800", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss ZZ").format(date, usPacific));
+
+ assertEquals("02/27/2006 05:10:10 -0800", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss ZZZ").format(date, usPacific));
+
+ assertEquals("02/27/2006 05:10:10 GMT-08:00", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss ZZZZ").format(date, usPacific));
+ }
+
+ public void test_simpleTimezoneZ() {
+ TimeZone simpleTimeZone = TimeZone.createTimeZone(420);
+ Date date = new Date();
+ date.setTime(Date.UTC(2006 - 1900, 6, 27, 13, 10, 10));
+
+ assertEquals("07/27/2006 06:10:10 -0700", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss Z").format(date, simpleTimeZone));
+
+ assertEquals("07/27/2006 06:10:10 -0700", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss ZZ").format(date, simpleTimeZone));
+
+ assertEquals("07/27/2006 06:10:10 -0700", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss ZZZ").format(date, simpleTimeZone));
+
+ assertEquals("07/27/2006 06:10:10 GMT-07:00", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss ZZZZ").format(date, simpleTimeZone));
+ }
+
+ public void test_timezonez() {
+ TimeZoneConstants timeZoneData = GWT.create(TimeZoneConstants.class);
+ String str = timeZoneData.americaLosAngeles();
+ TimeZone usPacific = TimeZone.createTimeZone(str);
+
+ Date date = new Date();
+ date.setTime(Date.UTC(2006 - 1900, 6, 27, 13, 10, 10));
+
+ assertEquals("07/27/2006 06:10:10 PDT", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss z").format(date, usPacific));
+
+ assertEquals("07/27/2006 06:10:10 PDT", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss zz").format(date, usPacific));
+
+ assertEquals("07/27/2006 06:10:10 PDT", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss zzz").format(date, usPacific));
+
+ assertEquals("07/27/2006 06:10:10 Pacific Daylight Time",
+ DateTimeFormat.getFormat("MM/dd/yyyy HH:mm:ss zzzz").format(date,
+ usPacific));
+
+ date.setTime(Date.UTC(2006 - 1900, 1, 27, 13, 10, 10));
+ assertEquals("02/27/2006 05:10:10 PST", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss z").format(date, usPacific));
+
+ assertEquals("02/27/2006 05:10:10 PST", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss zz").format(date, usPacific));
+
+ assertEquals("02/27/2006 05:10:10 PST", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss zzz").format(date, usPacific));
+
+ assertEquals("02/27/2006 05:10:10 Pacific Standard Time",
+ DateTimeFormat.getFormat("MM/dd/yyyy HH:mm:ss zzzz").format(date,
+ usPacific));
+ }
+
+ public void test_simpleTimezonez() {
+ TimeZone simpleTimeZone = TimeZone.createTimeZone(420);
+ Date date = new Date();
+ date.setTime(Date.UTC(2006 - 1900, 6, 27, 13, 10, 10));
+
+ assertEquals("07/27/2006 06:10:10 UTC-7", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss z").format(date, simpleTimeZone));
+
+ assertEquals("07/27/2006 06:10:10 UTC-7", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss zz").format(date, simpleTimeZone));
+
+ assertEquals("07/27/2006 06:10:10 UTC-7", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss zzz").format(date, simpleTimeZone));
+
+ assertEquals("07/27/2006 06:10:10 UTC-7", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss zzzz").format(date, simpleTimeZone));
+ }
+
+ public void test_daylightTimeTransition() {
+ // US PST transitioned to PDT on 2006/4/2 2:00am, jump to 2006/4/2 3:00am.
+ // That's UTC time 2006/4/2 10:00am
+
+ TimeZoneConstants timeZoneData = GWT.create(TimeZoneConstants.class);
+ String str = timeZoneData.americaLosAngeles();
+ TimeZone usPacific = TimeZone.createTimeZone(str);
+
+ Date date = new Date();
+ date.setTime(Date.UTC(2006 - 1900, 3, 2, 9, 59, 0));
+ assertEquals("04/02/2006 01:59:00 PST", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss z").format(date, usPacific));
+ date.setTime(Date.UTC(2006 - 1900, 3, 2, 10, 01, 0));
+ assertEquals("04/02/2006 03:01:00 PDT", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss z").format(date, usPacific));
+ date.setTime(Date.UTC(2006 - 1900, 3, 2, 10, 0, 0));
+ assertEquals("04/02/2006 03:00:00 PDT", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss z").format(date, usPacific));
+
+ // US PDT transition to PST on 2006/10/29 2:00am, jump back to PDT
+ // 2006/4/2 1:00am
+ date.setTime(Date.UTC(2006 - 1900, 10 - 1, 29, 8, 59, 0));
+ assertEquals("10/29/2006 01:59:00 PDT", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss z").format(date, usPacific));
+ date.setTime(Date.UTC(2006 - 1900, 10 - 1, 29, 9, 01, 0));
+ assertEquals("10/29/2006 01:01:00 PST", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss z").format(date, usPacific));
+ date.setTime(Date.UTC(2006 - 1900, 10 - 1, 29, 9, 0, 0));
+ assertEquals("10/29/2006 01:00:00 PST", DateTimeFormat.getFormat(
+ "MM/dd/yyyy HH:mm:ss z").format(date, usPacific));
+ }
+}
diff --git a/user/test/com/google/gwt/i18n/client/DateTimeParse_en_Test.java b/user/test/com/google/gwt/i18n/client/DateTimeParse_en_Test.java
index 3bfda95..8bc38a9 100644
--- a/user/test/com/google/gwt/i18n/client/DateTimeParse_en_Test.java
+++ b/user/test/com/google/gwt/i18n/client/DateTimeParse_en_Test.java
@@ -24,7 +24,10 @@
* Tests parsing functionality in {@link DateTimeFormat} for the English
* language.
*/
+@SuppressWarnings("deprecation")
public class DateTimeParse_en_Test extends GWTTestCase {
+ // TODO: replace the rest of the assertTrue calls to assertEquals
+ // for better error reporting, where possible.
@Override
public String getModuleName() {
@@ -45,13 +48,9 @@
String toParse = "July 11, 1938";
DateTimeFormat longDateFormat = DateTimeFormat.getLongDateFormat();
- try {
- Date actualDate = longDateFormat.parse(toParse);
- String actualFormat = longDateFormat.format(actualDate);
- assertEquals(toParse, actualFormat);
- } catch (IllegalArgumentException e) {
- fail("Should not have thrown an exception");
- }
+ Date actualDate = longDateFormat.parse(toParse);
+ String actualFormat = longDateFormat.format(actualDate);
+ assertEquals(toParse, actualFormat);
try {
String toParseMangled = toParse + " asdfasdfasdf";
@@ -66,42 +65,42 @@
Date date = new Date();
assertTrue(parse("hhmm", "1122", 0, date) > 0);
- assertTrue(date.getHours() == 11);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(11, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("hhmm", "122", 0, date) > 0);
- assertTrue(date.getHours() == 1);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(1, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("hhmmss", "112233", 0, date) > 0);
- assertTrue(date.getHours() == 11);
- assertTrue(date.getMinutes() == 22);
- assertTrue(date.getSeconds() == 33);
+ assertEquals(11, date.getHours());
+ assertEquals(22, date.getMinutes());
+ assertEquals(33, date.getSeconds());
assertTrue(parse("hhmmss", "12233", 0, date) > 0);
- assertTrue(date.getHours() == 1);
- assertTrue(date.getMinutes() == 22);
- assertTrue(date.getSeconds() == 33);
+ assertEquals(1, date.getHours());
+ assertEquals(22, date.getMinutes());
+ assertEquals(33, date.getSeconds());
assertTrue(parse("yyyyMMdd", "19991202", 0, date) > 0);
- assertTrue(date.getYear() == (1999 - 1900));
- assertTrue(date.getMonth() == 12 - 1);
- assertTrue(date.getDate() == 02);
+ assertEquals(1999 - 1900, date.getYear());
+ assertEquals(12 - 1, date.getMonth());
+ assertEquals(2, date.getDate());
assertTrue(parse("yyyyMMdd", "9991202", 0, date) > 0);
- assertTrue(date.getYear() == (999 - 1900));
- assertTrue(date.getMonth() == 12 - 1);
- assertTrue(date.getDate() == 02);
+ assertEquals(999 - 1900, date.getYear());
+ assertEquals(12 - 1, date.getMonth());
+ assertEquals(2, date.getDate());
assertTrue(parse("yyyyMMdd", "991202", 0, date) > 0);
- assertTrue(date.getYear() == (99 - 1900));
- assertTrue(date.getMonth() == 12 - 1);
- assertTrue(date.getDate() == 02);
+ assertEquals(99 - 1900, date.getYear());
+ assertEquals(12 - 1, date.getMonth());
+ assertEquals(2, date.getDate());
assertTrue(parse("yyyyMMdd", "91202", 0, date) > 0);
- assertTrue(date.getYear() == (9 - 1900));
- assertTrue(date.getMonth() == 12 - 1);
- assertTrue(date.getDate() == 02);
+ assertEquals(9 - 1900, date.getYear());
+ assertEquals(12 - 1,date.getMonth());
+ assertEquals(2, date.getDate());
}
public void testAmbiguousYear() {
@@ -120,27 +119,27 @@
orgDate.setDate(1);
String str = format("MM/dd/yy", orgDate);
assertTrue(parse("MM/dd/yy", str, 0, date) > 0);
- assertTrue(date.getYear() == orgDate.getYear());
+ assertEquals(date.getYear(), orgDate.getYear());
orgDate.setMonth(11);
orgDate.setDate(31);
str = format("MM/dd/yy", orgDate);
assertTrue(parse("MM/dd/yy", str, 0, date) > 0);
- assertTrue(date.getYear() + 100 == orgDate.getYear());
+ assertEquals(date.getYear() + 100, orgDate.getYear());
assertTrue(parse("yy,MM,dd", "2097,07,21", 0, date) > 0);
- assertTrue(date.getYear() == 2097 - 1900);
+ assertEquals(2097 - 1900, date.getYear());
}
public void testEnglishDate() {
Date date = new Date();
assertTrue(parse("yyyy MMM dd hh:mm", "2006 Jul 10 15:44", 0, date) > 0);
- assertTrue(date.getYear() == 2006 - 1900);
- assertTrue(date.getMonth() == 7 - 1);
- assertTrue(date.getDate() == 10);
- assertTrue(date.getHours() == 15);
- assertTrue(date.getMinutes() == 44);
+ assertEquals(2006 - 1900, date.getYear());
+ assertEquals(7 - 1, date.getMonth());
+ assertEquals(10, date.getDate());
+ assertEquals(15, date.getHours());
+ assertEquals(44, date.getMinutes());
}
/**
@@ -150,85 +149,85 @@
Date date = new Date();
assertTrue(parse("hh:mm:ss.SSS", "11:12:13.956", 0, date) > 0);
- assertTrue(date.getHours() == 11);
- assertTrue(date.getMinutes() == 12);
- assertTrue(date.getSeconds() == 13);
- assertTrue((date.getTime() % 1000) == 956);
+ assertEquals(11, date.getHours());
+ assertEquals(12, date.getMinutes());
+ assertEquals(13, date.getSeconds());
+ assertEquals(956, (date.getTime() % 1000));
assertTrue(parse("hh:mm:ss.SSS", "11:12:13.95", 0, date) > 0);
- assertTrue(date.getHours() == 11);
- assertTrue(date.getMinutes() == 12);
- assertTrue(date.getSeconds() == 13);
- assertTrue((date.getTime() % 1000) == 950);
+ assertEquals(11, date.getHours());
+ assertEquals(12, date.getMinutes());
+ assertEquals(13, date.getSeconds());
+ assertEquals(950, (date.getTime() % 1000));
assertTrue(parse("hh:mm:ss.SSS", "11:12:13.9", 0, date) > 0);
- assertTrue(date.getHours() == 11);
- assertTrue(date.getMinutes() == 12);
- assertTrue(date.getSeconds() == 13);
- assertTrue((date.getTime() % 1000) == 900);
+ assertEquals(11, date.getHours());
+ assertEquals(12, date.getMinutes());
+ assertEquals(13, date.getSeconds());
+ assertEquals(900, (date.getTime() % 1000));
}
public void testHourParsingFHH() {
Date date = new Date();
assertTrue(parse("HHmm", "0022", 0, date) > 0);
- assertTrue(date.getHours() == 00);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(0, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmm", "1122", 0, date) > 0);
- assertTrue(date.getHours() == 11);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(11, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmm", "1222", 0, date) > 0);
- assertTrue(date.getHours() == 12);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(12, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmm", "2322", 0, date) > 0);
- assertTrue(date.getHours() == 23);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(23, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmm", "2422", 0, date) > 0);
- assertTrue(date.getHours() == 0);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(0, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "0022am", 0, date) > 0);
- assertTrue(date.getHours() == 00);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(0, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "1122am", 0, date) > 0);
- assertTrue(date.getHours() == 11);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(11, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "1222am", 0, date) > 0);
- assertTrue(date.getHours() == 12);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(12, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "2322am", 0, date) > 0);
- assertTrue(date.getHours() == 23);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(23, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "2422am", 0, date) > 0);
- assertTrue(date.getHours() == 0);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(0, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "0022pm", 0, date) > 0);
- assertTrue(date.getHours() == 12);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(12, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "1122pm", 0, date) > 0);
- assertTrue(date.getHours() == 23);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(23, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "1222pm", 0, date) > 0);
- assertTrue(date.getHours() == 12);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(12, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "2322pm", 0, date) > 0);
- assertTrue(date.getHours() == 23);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(23, date.getHours());
+ assertEquals(22, date.getMinutes());
assertTrue(parse("HHmma", "2422pm", 0, date) > 0);
- assertTrue(date.getHours() == 0);
- assertTrue(date.getMinutes() == 22);
+ assertEquals(0, date.getHours());
+ assertEquals(22, date.getMinutes());
}
public void testHourParsingFhh() {
diff --git a/user/test/com/google/gwt/i18n/client/I18N2Test.java b/user/test/com/google/gwt/i18n/client/I18N2Test.java
index 89568ab..461cb43 100644
--- a/user/test/com/google/gwt/i18n/client/I18N2Test.java
+++ b/user/test/com/google/gwt/i18n/client/I18N2Test.java
@@ -28,6 +28,7 @@
* uses different locales.
*/
public class I18N2Test extends GWTTestCase {
+
@Override
public String getModuleName() {
return "com.google.gwt.i18n.I18N2Test";
@@ -54,7 +55,7 @@
}
public void testBadKeys() {
- TestBadKeys test = (TestBadKeys) GWT.create(TestBadKeys.class);
+ TestBadKeys test = GWT.create(TestBadKeys.class);
assertEquals("zh_spacer", test.zh_spacer());
assertEquals("zh_spacer", test.getString("zh_spacer"));
assertEquals("logger_org_hibernate_jdbc", test.logger_org_hibernate_jdbc());
@@ -112,13 +113,13 @@
}
public void testBinding() {
- TestBinding t = (TestBinding) GWT.create(TestBinding.class);
+ TestBinding t = GWT.create(TestBinding.class);
assertEquals("b_c_d", t.a());
assertEquals("default", t.b());
}
public void testCheckColorsAndShapes() {
- ColorsAndShapes s = (ColorsAndShapes) GWT.create(ColorsAndShapes.class);
+ ColorsAndShapes s = GWT.create(ColorsAndShapes.class);
// Red comes from Colors_b_C_d
assertEquals("red_b_C_d", s.red());
// Blue comes from Colors_b_C
@@ -144,7 +145,7 @@
}
public void testWalkUpColorTree() {
- Colors colors = (Colors) GWT.create(Colors.class);
+ Colors colors = GWT.create(Colors.class);
assertEquals("red_b_C_d", colors.red());
assertEquals("blue_b_C", colors.blue());
assertEquals("yellow_b", colors.yellow());
diff --git a/user/test/com/google/gwt/i18n/client/I18NTest.java b/user/test/com/google/gwt/i18n/client/I18NTest.java
index 394b090..e24ad99 100644
--- a/user/test/com/google/gwt/i18n/client/I18NTest.java
+++ b/user/test/com/google/gwt/i18n/client/I18NTest.java
@@ -134,16 +134,16 @@
}
public void testBindings() {
- TestBinding b = (TestBinding) GWT.create(TestBinding.class);
+ TestBinding b = GWT.create(TestBinding.class);
assertEquals("default", b.a());
- TestLeafBundle c = (TestLeafBundle) GWT.create(TestLeafBundle.class);
- assertEquals("TestLeafBundle_piglatin_UK_win", c.b());
- com.google.gwt.i18n.client.Wrapper2.TestBindingImpl d = (com.google.gwt.i18n.client.Wrapper2.TestBindingImpl) GWT.create(com.google.gwt.i18n.client.Wrapper2.TestBindingImpl.class);
+ TestLeafBundle c = GWT.create(TestLeafBundle.class);
+ assertEquals("TestLeafBundle_piglatin_UK_WINDOWS", c.b());
+ com.google.gwt.i18n.client.Wrapper2.TestBindingImpl d = GWT.create(com.google.gwt.i18n.client.Wrapper2.TestBindingImpl.class);
assertEquals("default", d.a());
}
public void testColors() {
- Colors colors = (Colors) GWT.create(Colors.class);
+ Colors colors = GWT.create(Colors.class);
assertNotNull(colors);
// No piglatin version exists for grey
assertEquals("ĝréý", colors.grey());
@@ -151,13 +151,13 @@
}
public void testConstantBooleans() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
assertEquals(false, types.booleanFalse());
assertEquals(true, types.booleanTrue());
}
public void testConstantDoubles() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
double delta = 0.0000001;
assertEquals(3.14159, types.doublePi(), delta);
assertEquals(0.0, types.doubleZero(), delta);
@@ -170,7 +170,7 @@
}
public void testConstantFloats() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
double delta = 0.0000001;
assertEquals(3.14159f, types.floatPi(), delta);
assertEquals(0.0f, types.floatZero(), delta);
@@ -186,7 +186,7 @@
* Exercises ConstantMap more than the other map tests.
*/
public void testConstantMapABCD() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
Map<String, String> map = types.mapABCD();
Map<String, String> expectedMap = getMapFromArrayUsingASimpleRule(new String[] {
@@ -288,7 +288,7 @@
* Tests exercise the cache.
*/
public void testConstantMapBACD() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
Map<String, String> map = types.mapBACD();
Map<String, String> expectedMap = getMapFromArrayUsingASimpleRule(new String[] {
"B", "A", "C", "D"});
@@ -299,7 +299,7 @@
* Tests exercise the cache.
*/
public void testConstantMapBBB() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
Map<String, String> map = types.mapBBB();
Map<String, String> expectedMap = getMapFromArrayUsingASimpleRule(new String[] {"B"});
compareMapsComprehensively(map, expectedMap);
@@ -311,7 +311,7 @@
*/
@SuppressWarnings("unchecked")
public void testConstantMapDCBA() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
Map<String, String> map = types.mapDCBA();
Map<String, String> expectedMap = getMapFromArrayUsingASimpleRule(new String[] {
"D", "C", "B", "A"});
@@ -322,7 +322,7 @@
* Tests focus on correctness of entries, since ABCD exercises the map.
*/
public void testConstantMapEmpty() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
Map<String, String> map = types.mapEmpty();
Map<String, String> expectedMap = new HashMap<String, String>();
compareMapsComprehensively(map, expectedMap);
@@ -333,7 +333,7 @@
* type.
*/
public void testConstantMapXYZ() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
Map<String, String> map = types.mapXYZ();
Map<String, String> expectedMap = new HashMap<String, String>();
expectedMap.put("keyX", "valueZ");
@@ -343,7 +343,7 @@
}
public void testConstantStringArrays() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
String[] s;
s = types.stringArrayABCDEFG();
@@ -372,7 +372,7 @@
}
public void testConstantStrings() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
assertEquals("string", types.getString());
assertEquals("stringTrimsLeadingWhitespace",
types.stringTrimsLeadingWhitespace());
@@ -388,7 +388,7 @@
}
public void testConstantsWithLookup() {
- TestConstantsWithLookup l = (TestConstantsWithLookup) GWT.create(TestConstantsWithLookup.class);
+ TestConstantsWithLookup l = GWT.create(TestConstantsWithLookup.class);
Map<String, String> map = l.getMap("mapABCD");
assertEquals("valueA", map.get("keyA"));
map = l.getMap("mapDCBA");
@@ -439,7 +439,7 @@
}
public void testIntConstant() {
- TestConstants types = (TestConstants) GWT.create(TestConstants.class);
+ TestConstants types = GWT.create(TestConstants.class);
assertEquals(0, types.intZero());
assertEquals(1, types.intOne());
assertEquals(-1, types.intNegOne());
@@ -449,14 +449,14 @@
public void testLocalizableInner() {
// Check simple inner
- LocalizableSimpleInner s = (LocalizableSimpleInner) GWT.create(Inners.LocalizableSimpleInner.class);
+ LocalizableSimpleInner s = GWT.create(Inners.LocalizableSimpleInner.class);
assertEquals("getLocalizableInner", s.getLocalizableInner());
- LocalizableInnerInner localizableInnerInner = (LocalizableInnerInner) GWT.create(Inners.InnerClass.LocalizableInnerInner.class);
+ LocalizableInnerInner localizableInnerInner = GWT.create(Inners.InnerClass.LocalizableInnerInner.class);
assertEquals("localizableInnerInner", localizableInnerInner.string());
// Check success of finding embedded
- OuterLoc lock = (OuterLoc) GWT.create(OuterLoc.class);
+ OuterLoc lock = GWT.create(OuterLoc.class);
assertEquals("piglatin", lock.string());
assertEquals("InnerLoc", Inners.testInnerLoc());
@@ -466,32 +466,32 @@
Inners inner = new Inners();
// Simple Inner
- SimpleInner simpleInner = (SimpleInner) GWT.create(Inners.SimpleInner.class);
+ SimpleInner simpleInner = GWT.create(Inners.SimpleInner.class);
assertEquals(0, simpleInner.intZero());
assertEquals("Simple Inner", simpleInner.simpleInner());
assertTrue(inner.testProtectedInner());
// Has Inner
- HasInner hasInner = (HasInner) GWT.create(Inners.HasInner.class);
+ HasInner hasInner = GWT.create(Inners.HasInner.class);
assertEquals("Has Inner", hasInner.hasInner());
assertEquals(0, hasInner.floatZero(), .0001);
// Is Inner
- IsInner isInner = (IsInner) GWT.create(IsInner.class);
+ IsInner isInner = GWT.create(IsInner.class);
assertEquals(2, isInner.isInner());
// Inner Inner
- InnerInner innerInner = (InnerInner) GWT.create(InnerInner.class);
+ InnerInner innerInner = GWT.create(InnerInner.class);
assertEquals(4.321, innerInner.innerInner(), .0001);
assertEquals("outer", innerInner.outer());
// Inner Inner Message
- InnerInnerMessages innerInnerMessages = (InnerInnerMessages) GWT.create(InnerInnerMessages.class);
+ InnerInnerMessages innerInnerMessages = GWT.create(InnerInnerMessages.class);
assertEquals("I am a person",
innerInnerMessages.innerClassMessages("person"));
// Extends Inner Inner
- ExtendsInnerInner extendsInnerInner = (ExtendsInnerInner) GWT.create(ExtendsInnerInner.class);
+ ExtendsInnerInner extendsInnerInner = GWT.create(ExtendsInnerInner.class);
assertEquals("Extends Inner Inner", extendsInnerInner.extendsInnerInner());
// Protected InnerClass
@@ -513,10 +513,10 @@
}
public void testShapesFamily() {
- Shapes shapes = (Shapes) GWT.create(Shapes.class);
+ Shapes shapes = GWT.create(Shapes.class);
// test overload
assertEquals("aya irclecay", shapes.circle());
- ColorsAndShapesAndConcepts s = (ColorsAndShapesAndConcepts) GWT.create(ColorsAndShapesAndConcepts.class);
+ ColorsAndShapesAndConcepts s = GWT.create(ColorsAndShapesAndConcepts.class);
assertEquals("aya irclecay", s.circle());
// test converge
assertEquals("any primary color", s.shapeColor());
@@ -524,7 +524,7 @@
}
public void testTestMessages() {
- TestMessages s = (TestMessages) GWT.create(TestMessages.class);
+ TestMessages s = GWT.create(TestMessages.class);
assertEquals("no args", s.args0());
assertEquals("a,b,c,d,e,f,g,h,i,j", s.args10("a", "b", "c", "d", "e", "f",
"g", "h", "i", "j"));
@@ -539,21 +539,21 @@
}
public void testTypedMessages() {
- TestTypedMessages typed = (TestTypedMessages) GWT.create(TestTypedMessages.class);
- String expected = "int(0) float(1.2), long(0), boolean(true), Object([], char(a), byte(127), short(-32768);";
- assertEquals(expected, typed.testAllTypes(0, (float) 1.2, 0, true,
+ TestTypedMessages typed = GWT.create(TestTypedMessages.class);
+ String expected = "int(0) float(1.5), long(0), boolean(true), Object([], char(a), byte(127), short(-32768);";
+ assertEquals(expected, typed.testAllTypes(0, (float) 1.5, 0, true,
new ArrayList<String>(), 'a', Byte.MAX_VALUE, Short.MIN_VALUE));
String lotsOfInts = typed.testLotsOfInts(1, 2, 3, 4);
assertEquals("1, 2,3,4 ", lotsOfInts);
- String oneFloat = typed.simpleMessageTest((float) 2.3);
- assertEquals("2.3", oneFloat);
+ String oneFloat = typed.simpleMessageTest((float) 2.25);
+ assertEquals("2.25", oneFloat);
String singleQuotes = typed.testSingleQuotes("arg");
assertEquals("'A', 'arg', ','", singleQuotes);
String testSomeObjectTypes = typed.testSomeObjectTypes(new I18NTest(),
new StringBuffer("hello"), new Integer("34"), null);
- assertEquals(
- "this(null(com.google.gwt.i18n.client.I18NTest)), StringBuffer(hello), Integer(34), "
- + "null(null);", testSomeObjectTypes);
+ assertEquals("this(null(" + I18NTest.class.getName()
+ + ")), StringBuffer(hello), Integer(34), " + "null(null);",
+ testSomeObjectTypes);
}
private void assertArrayEquals(String[] shouldBe, String[] test) {
diff --git a/user/test/com/google/gwt/i18n/client/I18N_es_MX_Test.java b/user/test/com/google/gwt/i18n/client/I18N_es_MX_Test.java
new file mode 100644
index 0000000..b7c78ed
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/I18N_es_MX_Test.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may 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.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests regional inheritance for es_MX.
+ */
+public class I18N_es_MX_Test extends GWTTestCase {
+
+ /**
+ * Test locale region inheritance with Messages.
+ */
+ public interface MyMessages extends Messages {
+ @DefaultMessage("default")
+ String getSourceLocale();
+ }
+
+ /**
+ * Test locale region inheritance with Constants.
+ */
+ public interface MyConstants extends Constants {
+ @DefaultStringValue("default")
+ String getSourceLocale();
+ }
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.i18n.I18NTest_es_MX";
+ }
+
+ public void testRegionalInheritance() {
+ MyMessages msg = GWT.create(MyMessages.class);
+ assertEquals("es_419", msg.getSourceLocale());
+ MyConstants cst = GWT.create(MyConstants.class);
+ assertEquals("es_013", cst.getSourceLocale());
+ }
+}
diff --git a/user/test/com/google/gwt/i18n/client/I18N_es_MX_Test_MyConstants_es_013.properties b/user/test/com/google/gwt/i18n/client/I18N_es_MX_Test_MyConstants_es_013.properties
new file mode 100644
index 0000000..c5cb305
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/I18N_es_MX_Test_MyConstants_es_013.properties
@@ -0,0 +1 @@
+getSourceLocale=es_013
\ No newline at end of file
diff --git a/user/test/com/google/gwt/i18n/client/I18N_es_MX_Test_MyMessages_es_419.properties b/user/test/com/google/gwt/i18n/client/I18N_es_MX_Test_MyMessages_es_419.properties
new file mode 100644
index 0000000..db781ff
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/I18N_es_MX_Test_MyMessages_es_419.properties
@@ -0,0 +1 @@
+getSourceLocale=es_419
\ No newline at end of file
diff --git a/user/test/com/google/gwt/i18n/client/I18N_iw_Test.java b/user/test/com/google/gwt/i18n/client/I18N_iw_Test.java
new file mode 100644
index 0000000..c9bcf9e
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/I18N_iw_Test.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may 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.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests Hebrew deprecated alias.
+ */
+public class I18N_iw_Test extends GWTTestCase {
+
+ /**
+ * Test deprecated locale aliases with Messages.
+ */
+ public interface MyMessages extends Messages {
+ @DefaultMessage("default")
+ String getSourceLocale();
+ }
+
+ /**
+ * Test deprecated locale aliases with Constants.
+ */
+ public interface MyConstants extends Constants {
+ @DefaultStringValue("default")
+ String getSourceLocale();
+ }
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.i18n.I18NTest_iw";
+ }
+
+ public void testIwAlias() {
+ MyMessages msg = GWT.create(MyMessages.class);
+ assertEquals("he", msg.getSourceLocale());
+ MyConstants cst = GWT.create(MyConstants.class);
+ assertEquals("he", cst.getSourceLocale());
+ }
+}
diff --git a/user/test/com/google/gwt/i18n/client/I18N_iw_Test_MyConstants_he.properties b/user/test/com/google/gwt/i18n/client/I18N_iw_Test_MyConstants_he.properties
new file mode 100644
index 0000000..3ffe99e
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/I18N_iw_Test_MyConstants_he.properties
@@ -0,0 +1 @@
+getSourceLocale=he
\ No newline at end of file
diff --git a/user/test/com/google/gwt/i18n/client/I18N_iw_Test_MyMessages_he.properties b/user/test/com/google/gwt/i18n/client/I18N_iw_Test_MyMessages_he.properties
new file mode 100644
index 0000000..3ffe99e
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/I18N_iw_Test_MyMessages_he.properties
@@ -0,0 +1 @@
+getSourceLocale=he
\ No newline at end of file
diff --git a/user/test/com/google/gwt/i18n/client/LocaleInfoTest.java b/user/test/com/google/gwt/i18n/client/LocaleInfoTest.java
index 2960af4..1b7c9e1 100644
--- a/user/test/com/google/gwt/i18n/client/LocaleInfoTest.java
+++ b/user/test/com/google/gwt/i18n/client/LocaleInfoTest.java
@@ -22,19 +22,20 @@
*/
public class LocaleInfoTest extends GWTTestCase {
+ @Override
public String getModuleName() {
return "com.google.gwt.i18n.I18NTest";
}
public void testCurrentLocale() {
String locale = LocaleInfo.getCurrentLocale().getLocaleName();
- assertEquals("piglatin_UK_win", locale);
+ assertEquals("piglatin_UK_WINDOWS", locale);
}
public void testAvailableLocales() {
String[] locales = LocaleInfo.getAvailableLocaleNames();
assertArrayEquals(new String[] {
- "default", "piglatin", "piglatin_UK", "piglatin_UK_win"}, locales);
+ "default", "piglatin", "piglatin_UK", "piglatin_UK_WINDOWS"}, locales);
}
public void testNativeDisplayNames() {
diff --git a/user/test/com/google/gwt/i18n/client/LocaleInfo_ar_Test.java b/user/test/com/google/gwt/i18n/client/LocaleInfo_ar_Test.java
index 39e1181..0dfdc16 100644
--- a/user/test/com/google/gwt/i18n/client/LocaleInfo_ar_Test.java
+++ b/user/test/com/google/gwt/i18n/client/LocaleInfo_ar_Test.java
@@ -17,11 +17,15 @@
import com.google.gwt.junit.client.GWTTestCase;
+import java.util.ArrayList;
+import java.util.Collections;
+
/**
* Tests the LocaleInfo class and the associated generator.
*/
public class LocaleInfo_ar_Test extends GWTTestCase {
+ @Override
public String getModuleName() {
return "com.google.gwt.i18n.I18NTest_ar";
}
@@ -33,7 +37,10 @@
public void testAvailableLocales() {
String[] locales = LocaleInfo.getAvailableLocaleNames();
- assertArrayEquals(new String[] {"ar", "default"}, locales);
+ ArrayList<String> localeList = new ArrayList<String>();
+ Collections.addAll(localeList, locales);
+ assertTrue(localeList.contains("ar"));
+ assertTrue(localeList.contains("default"));
}
public void testNativeDisplayNames() {
@@ -46,11 +53,4 @@
boolean isRTL = LocaleInfo.getCurrentLocale().isRTL();
assertTrue(isRTL);
}
-
- private void assertArrayEquals(String[] expected, String[] actual) {
- assertEquals(expected.length, actual.length);
- for (int i = 0; i < actual.length; i++) {
- assertEquals(expected[i], actual[i]);
- }
- }
}
diff --git a/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java b/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java
index 2eac1e6..4ed1cd9 100644
--- a/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java
+++ b/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java
@@ -173,7 +173,7 @@
str = NumberFormat.getFormat("##0.###E0").format(12345);
assertEquals("12.345E3", str);
- str = NumberFormat.getFormat("##0.####E0").format(789.12345e-9);
+ str = NumberFormat.getFormat("##0.####E0").format(789.12346e-9);
assertEquals("789.1235E-9", str);
str = NumberFormat.getFormat("##0.####E0").format(780.e-9);
assertEquals("780E-9", str);
@@ -267,6 +267,17 @@
assertEquals("-1,014.34 X", str);
}
+ public void testPercent() {
+ String str;
+
+ str = NumberFormat.getFormat("###.###%").format(0.4857);
+ assertEquals("48.57%", str);
+ str = NumberFormat.getFormat("###.### %").format(0.4857);
+ assertEquals("48.57 %", str);
+ str = NumberFormat.getFormat("0.00%").format(0.485);
+ assertEquals("48.50%", str);
+ }
+
public void testPerMill() {
String str;
diff --git a/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java b/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java
index 2fe815d..2f0a55a 100644
--- a/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java
+++ b/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java
@@ -26,6 +26,7 @@
/**
* Must refer to a valid module that inherits from com.google.gwt.junit.JUnit.
*/
+ @Override
public String getModuleName() {
return "com.google.gwt.i18n.I18NTest_fr";
}
@@ -147,7 +148,7 @@
str = NumberFormat.getFormat("##0.###E0").format(12345);
assertEquals("12,345E3", str);
- str = NumberFormat.getFormat("##0.####E0").format(789.12345e-9);
+ str = NumberFormat.getFormat("##0.####E0").format(789.12346e-9);
assertEquals("789,1235E-9", str);
str = NumberFormat.getFormat("##0.####E0").format(780.e-9);
assertEquals("780E-9", str);
diff --git a/user/test/com/google/gwt/i18n/client/RuntimeLocalesTest.java b/user/test/com/google/gwt/i18n/client/RuntimeLocalesTest.java
new file mode 100644
index 0000000..a3ccad8
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/RuntimeLocalesTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.junit.client.GWTTestCase;
+
+/**
+ * Test the same things as I18NTest but with a different module which
+ * uses different locales.
+ */
+public class RuntimeLocalesTest extends GWTTestCase {
+ // TODO(jat): add tests to verify runtime locales with NumberFormat etc.
+ // Have to figure out how to get runtime locale set within JUnitShell.
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.i18n.RuntimeLocalesTest";
+ }
+
+ public void testAvailable() {
+ String[] locales = LocaleInfo.getAvailableLocaleNames();
+ assertEquals(50, locales.length);
+ }
+}
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_bb_CC.properties
similarity index 100%
rename from user/test/com/google/gwt/i18n/client/TestAnnotatedMessages$Nested_b_C.properties
rename to user/test/com/google/gwt/i18n/client/TestAnnotatedMessages$Nested_bb_CC.properties
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_b.properties b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_bb.properties
similarity index 100%
rename from user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_b.properties
rename to user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_Nested_bb.properties
diff --git a/user/test/com/google/gwt/i18n/client/TestBinding.java b/user/test/com/google/gwt/i18n/client/TestBinding.java
index bd07fc9..be9e550 100644
--- a/user/test/com/google/gwt/i18n/client/TestBinding.java
+++ b/user/test/com/google/gwt/i18n/client/TestBinding.java
@@ -27,19 +27,19 @@
class Wrapper {
- static class TestBinding_a extends TestBinding_ {
+ static class TestBinding_aa extends TestBinding_ {
public String a() {
return "a";
}
}
- static class TestBinding_b_C_d extends TestBinding_ {
+ static class TestBinding_bb_CC_DDDDD extends TestBinding_ {
public String a() {
return "b_c_d";
}
}
- static class TestBinding_b implements TestBinding {
+ static class TestBinding_bb implements TestBinding {
public String a() {
return "b";
@@ -69,13 +69,13 @@
abstract String b();
}
- static class TestBindingImpl_a extends TestBindingImpl_b_C_d {
+ static class TestBindingImpl_aa extends TestBindingImpl_bb_CC_DDDDD {
public String a() {
return "a";
}
}
- static class TestBindingImpl_b_C_d extends TestBindingImpl {
+ static class TestBindingImpl_bb_CC_DDDDD extends TestBindingImpl {
public String a() {
return "b_c_d";
}
diff --git a/user/test/com/google/gwt/i18n/client/TestLeafBundle.java b/user/test/com/google/gwt/i18n/client/TestLeafBundle.java
index 4dd101d..35924ab 100644
--- a/user/test/com/google/gwt/i18n/client/TestLeafBundle.java
+++ b/user/test/com/google/gwt/i18n/client/TestLeafBundle.java
@@ -13,7 +13,6 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-
package com.google.gwt.i18n.client;
/**
@@ -25,6 +24,7 @@
class TestLeafBundleImpl extends TestLeafBundle {
+ @Override
public String b() {
return "TestLeafBundleImpl";
}
@@ -35,19 +35,25 @@
}
class TestLeafBundle_piglatin extends TestLeafBundleImpl {
+
+ @Override
public String b() {
return "TestLeafBundle_piglatin";
}
}
class TestLeafBundle_piglatin_UK extends TestLeafBundle_piglatin {
+
+ @Override
public String b() {
return "TestLeafBundle_piglatin_UK";
}
}
-class TestLeafBundle_piglatin_UK_win extends TestLeafBundleImpl {
+class TestLeafBundle_piglatin_UK_WINDOWS extends TestLeafBundleImpl {
+
+ @Override
public String b() {
- return "TestLeafBundle_piglatin_UK_win";
+ return "TestLeafBundle_piglatin_UK_WINDOWS";
}
}
diff --git a/user/test/com/google/gwt/i18n/client/gen/Colors_b.properties b/user/test/com/google/gwt/i18n/client/gen/Colors_bb.properties
similarity index 100%
rename from user/test/com/google/gwt/i18n/client/gen/Colors_b.properties
rename to user/test/com/google/gwt/i18n/client/gen/Colors_bb.properties
diff --git a/user/test/com/google/gwt/i18n/client/gen/Colors_b_C.properties b/user/test/com/google/gwt/i18n/client/gen/Colors_bb_CC.properties
similarity index 100%
rename from user/test/com/google/gwt/i18n/client/gen/Colors_b_C.properties
rename to user/test/com/google/gwt/i18n/client/gen/Colors_bb_CC.properties
diff --git a/user/test/com/google/gwt/i18n/client/gen/Colors_b_C_d.properties b/user/test/com/google/gwt/i18n/client/gen/Colors_bb_CC_DDDDD.properties
similarity index 100%
rename from user/test/com/google/gwt/i18n/client/gen/Colors_b_C_d.properties
rename to user/test/com/google/gwt/i18n/client/gen/Colors_bb_CC_DDDDD.properties
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_bb_CC_DDDDD.properties
similarity index 100%
rename from user/test/com/google/gwt/i18n/client/gen/TestBadKeys_b_C_d.properties
rename to user/test/com/google/gwt/i18n/client/gen/TestBadKeys_bb_CC_DDDDD.properties
diff --git a/user/test/com/google/gwt/i18n/rebind/AbstractResourceTest.java b/user/test/com/google/gwt/i18n/rebind/AbstractResourceTest.java
index 4645e10..f3fea7e 100644
--- a/user/test/com/google/gwt/i18n/rebind/AbstractResourceTest.java
+++ b/user/test/com/google/gwt/i18n/rebind/AbstractResourceTest.java
@@ -19,6 +19,7 @@
import com.google.gwt.i18n.client.ColorsAndShapesAndConcepts;
import com.google.gwt.i18n.client.gen.Colors;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
+import com.google.gwt.i18n.shared.GwtLocale;
import junit.framework.TestCase;
@@ -33,13 +34,14 @@
*/
public class AbstractResourceTest extends TestCase {
public static final String UNICODE = "Îñţérñåţîöñåļîžåţîöñ";
- private static final String LOCALE_NAME_PIGLATIN = "piglatin";
- private static final String LOCALE_NAME_PIGLATIN_UK = "piglatin_UK";
+ private static final GwtLocale LOCALE_NAME_PIGLATIN = LocaleUtils.getLocaleFactory().fromString("piglatin");
+ private static final GwtLocale LOCALE_NAME_PIGLATIN_UK = LocaleUtils.getLocaleFactory().fromString("piglatin_UK");
+ private static final GwtLocale LOCALE_DEFAULT = LocaleUtils.getLocaleFactory().getDefault();
public void testBundle() {
// simple test
String s = Colors.class.getName();
- ResourceList resourceList = ResourceFactory.getBundle(s, null, true);
+ ResourceList resourceList = ResourceFactory.getBundle(s, LOCALE_DEFAULT, true);
assertNotNull(resourceList);
ResourceList pigLatinResourceList =
ResourceFactory.getBundle(s, LOCALE_NAME_PIGLATIN, true);
diff --git a/user/test/com/google/gwt/i18n/server/GwtLocaleTest.java b/user/test/com/google/gwt/i18n/server/GwtLocaleTest.java
new file mode 100644
index 0000000..3bf1298
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/server/GwtLocaleTest.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2009 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.server;
+
+import com.google.gwt.i18n.shared.GwtLocale;
+import com.google.gwt.i18n.shared.GwtLocaleFactory;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test GwtLocale.
+ */
+public class GwtLocaleTest extends TestCase {
+
+ private GwtLocaleFactory factory = new GwtLocaleFactoryImpl();
+
+ public void testAliases() {
+ GwtLocale zhCN = factory.fromString("zh_CN");
+ List<GwtLocale> aliases = zhCN.getAliases();
+ assertEquals(2, aliases.size());
+ assertEquals(aliases.get(0), zhCN);
+ assertContainsAndGetPosition(aliases, factory.fromString("zh_Hans_CN"));
+ GwtLocale zhHant = factory.fromString("zh_Hant");
+ aliases = zhHant.getAliases();
+ assertEquals(aliases.get(0), zhHant);
+ assertContainsAndGetPosition(aliases, factory.fromString("zh_Hant_TW"));
+ GwtLocale zhHans = factory.fromString("zh_Hans");
+ aliases = zhHans.getAliases();
+ assertEquals(aliases.get(0), zhHans);
+ assertContainsAndGetPosition(aliases, factory.fromString("zh_Hans_CN"));
+ GwtLocale en = factory.fromString("en");
+ aliases = en.getAliases();
+ assertEquals(aliases.get(0), en);
+ GwtLocale enLatn = factory.fromString("en_Latn");
+ assertContainsAndGetPosition(aliases, enLatn);
+ assertTrue(en.usesSameScript(enLatn));
+ assertTrue(enLatn.inheritsFrom(en));
+ assertFalse(en.inheritsFrom(enLatn));
+ assertFalse(en.inheritsFrom(en));
+ GwtLocale pt = factory.fromString("pt");
+ aliases = pt.getAliases();
+ assertContainsAndGetPosition(aliases, factory.fromString("pt_BR"));
+ GwtLocale he = factory.fromString("he");
+ aliases = he.getAliases();
+ assertContainsAndGetPosition(aliases, factory.fromString("iw_Hebr"));
+ GwtLocale id = factory.fromString("id");
+ aliases = id.getAliases();
+ assertContainsAndGetPosition(aliases, factory.fromString("in"));
+ GwtLocale mo = factory.fromString("mo");
+ aliases = mo.getAliases();
+ assertContainsAndGetPosition(aliases, factory.fromString("ro"));
+ GwtLocale jv = factory.fromString("jv");
+ aliases = jv.getAliases();
+ assertContainsAndGetPosition(aliases, factory.fromString("jw"));
+ GwtLocale ji = factory.fromString("ji");
+ aliases = ji.getAliases();
+ assertContainsAndGetPosition(aliases, factory.fromString("yi"));
+ }
+
+ public void testCompare() {
+ GwtLocale[] locales = new GwtLocale[] {
+ factory.fromString("en_US_POSIX"),
+ factory.fromString("en"),
+ factory.fromString("es-419"),
+ factory.fromString("en-gb"),
+ factory.fromString("en-AU-OUTBACK"),
+ factory.fromString("es_AR"),
+ factory.fromString("en_US"),
+ factory.fromString("en_Latn"),
+ factory.fromString("es-ES"),
+ };
+ Arrays.sort(locales);
+ assertEquals("en", locales[0].getAsString());
+ assertEquals("en_AU_OUTBACK", locales[1].getAsString());
+ assertEquals("en_GB", locales[2].getAsString());
+ assertEquals("en_US", locales[3].getAsString());
+ assertEquals("en_US_POSIX", locales[4].getAsString());
+ assertEquals("en_Latn", locales[5].getAsString());
+ assertEquals("es_419", locales[6].getAsString());
+ assertEquals("es_AR", locales[7].getAsString());
+ assertEquals("es_ES", locales[8].getAsString());
+ // Test equals against some non-GwtLocale class
+ assertFalse(locales[0].equals(factory));
+ }
+
+ public void testDefault() {
+ GwtLocale def1 = factory.getDefault();
+ GwtLocale def2 = factory.fromString("default");
+ assertSame(def1, def2);
+ assertTrue(def1.isDefault());
+ assertEquals("", def1.getLanguageNotNull());
+ assertEquals("", def1.getScriptNotNull());
+ assertEquals("", def1.getRegionNotNull());
+ assertEquals("", def1.getVariantNotNull());
+ GwtLocale def3 = factory.fromString(null);
+ assertSame(def1, def3);
+ GwtLocale def4 = factory.fromComponents("", "", "", "");
+ assertSame(def1, def4);
+ }
+
+ public void testFromComponents() {
+ GwtLocale test = factory.fromComponents("a", "b", "c", "d");
+ assertEquals("a", test.getLanguage());
+ assertEquals("B", test.getScript());
+ assertEquals("C", test.getRegion());
+ assertEquals("D", test.getVariant());
+ }
+
+ public void testFromString() {
+ GwtLocale ha = factory.fromString("ha_Arab_NG");
+ assertEquals("ha", ha.getLanguage());
+ assertEquals("Arab", ha.getScript());
+ assertEquals("NG", ha.getRegion());
+ assertNull(ha.getVariant());
+ GwtLocale us1 = factory.fromString("en-us");
+ GwtLocale us2 = factory.fromString("en_US");
+ assertSame(us1, us2);
+ GwtLocale us3 = factory.fromString("EN_uS");
+ assertSame(us1, us3);
+ assertEquals("en", us3.getLanguageNotNull());
+ assertNull(us3.getScript());
+ assertEquals("US", us3.getRegionNotNull());
+ assertNull(us3.getVariant());
+ GwtLocale en = factory.fromString("en-VARIANT");
+ assertEquals("en", en.getLanguage());
+ assertNull(en.getScript());
+ assertNull(en.getRegion());
+ assertEquals("VARIANT", en.getVariantNotNull());
+ en = factory.fromString("en_variant");
+ assertEquals("en", en.getLanguage());
+ assertNull(en.getScript());
+ assertNull(en.getRegion());
+ assertEquals("VARIANT", en.getVariant());
+ GwtLocale zh = factory.fromString("zh-min-nan-Hant-CN");
+ assertEquals("zh-min-nan", zh.getLanguage());
+ assertEquals("Hant", zh.getScriptNotNull());
+ assertEquals("CN", zh.getRegion());
+ assertNull(zh.getVariant());
+ assertFalse(ha.usesSameScript(zh));
+ zh = factory.fromString("zh_min_nan_Hant_CN");
+ assertEquals("zh-min-nan", zh.getLanguage());
+ GwtLocale variant4 = factory.fromString("en-1234");
+ assertNull(variant4.getScript());
+ assertEquals("1234", variant4.getVariant());
+ GwtLocale extLang = factory.fromString("en-ext");
+ assertEquals("en-ext", extLang.getLanguage());
+ try {
+ factory.fromString("english_USA");
+ fail("Should have thrown IllegalArgumentException on english_USA");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testInheritance() {
+ GwtLocale en = factory.fromString("en_Latn_US_VARIANT");
+ List<GwtLocale> chain = en.getInheritanceChain();
+ assertEquals(12, chain.size());
+ assertEquals(en, chain.get(0));
+ assertEquals(factory.fromString("en_Latn_US"), chain.get(1));
+ assertEquals(factory.fromString("en_Latn_021"), chain.get(2));
+ assertEquals(factory.fromString("en_Latn_019"), chain.get(3));
+ assertEquals(factory.fromString("en_Latn_001"), chain.get(4));
+ assertEquals(factory.fromString("en_Latn"), chain.get(5));
+ assertEquals(factory.fromString("en_US"), chain.get(6));
+ assertEquals(factory.fromString("en_021"), chain.get(7));
+ assertEquals(factory.fromString("en_019"), chain.get(8));
+ assertEquals(factory.fromString("en_001"), chain.get(9));
+ assertEquals(factory.fromString("en"), chain.get(10));
+ assertEquals(factory.getDefault(), chain.get(11));
+ }
+
+ public void testInstanceCache() {
+ GwtLocale a = factory.fromString("en_US");
+ GwtLocale b = factory.fromString("en_US");
+ assertFalse(a.isDefault());
+ assertSame(a, b);
+ assertEquals(a, b);
+ assertEquals(a.hashCode(), b.hashCode());
+ }
+
+ public void testPrivate() {
+ GwtLocale priv = factory.fromString("x-mylang");
+ assertEquals("x-mylang", priv.getLanguage());
+ assertNull(priv.getScript());
+ assertNull(priv.getRegion());
+ assertNull(priv.getVariant());
+ assertFalse(priv.isDefault());
+ }
+
+ public void testSearchList() {
+ GwtLocale nbNO = factory.fromString("nb_NO");
+ List<GwtLocale> searchList = nbNO.getCompleteSearchList();
+ int idx_nb_154 = assertContainsAndGetPosition(searchList,
+ factory.fromString("nb_154"));
+ assertContainsAndGetPosition(searchList,
+ factory.fromString("no_154_BOKMAL"));
+ int idx_no = assertContainsAndGetPosition(searchList,
+ factory.fromString("no_BOKMAL"));
+ assertTrue("nb_154 should come before no_BOKMAL", idx_nb_154 < idx_no);
+ int idx_default = assertContainsAndGetPosition(searchList,
+ factory.getDefault());
+ assertEquals(searchList.size() - 1, idx_default);
+ GwtLocale esMX = factory.fromString("es_MX");
+ searchList = esMX.getCompleteSearchList();
+ assertContainsAndGetPosition(searchList, factory.fromString("es_013"));
+ assertContainsAndGetPosition(searchList, factory.fromString("es_419"));
+ GwtLocale srCyrlBA = factory.fromString("sr_Cyrl_BA");
+ searchList = srCyrlBA.getCompleteSearchList();
+ assertContainsAndGetPosition(searchList, factory.fromString("sr_Cyrl"));
+ assertContainsAndGetPosition(searchList, factory.fromString("sr_BA"));
+ assertContainsAndGetPosition(searchList, factory.fromString("sr"));
+ assertContainsAndGetPosition(searchList, factory.getDefault());
+ GwtLocale noNynorsk = factory.fromString("no_NYNORSK");
+ searchList = noNynorsk.getCompleteSearchList();
+ assertContainsAndGetPosition(searchList, factory.fromString("nn"));
+ assertContainsAndGetPosition(searchList, factory.fromString("no"));
+ GwtLocale zhTW = factory.fromString("zh_TW");
+ searchList = zhTW.getCompleteSearchList();
+ assertContainsAndGetPosition(searchList, factory.fromString("zh_Hant"));
+ assertNotContains(searchList, factory.fromString("zh_Hans"));
+ // TODO: explicitly verify search list for zh_TW
+ idx_default = assertContainsAndGetPosition(searchList,
+ factory.getDefault());
+ assertEquals(searchList.size() - 1, idx_default);
+ }
+
+ private <T> int assertContainsAndGetPosition(List<T> list, T value) {
+ int idx = list.indexOf(value);
+ assertTrue("List " + list + " should have contained " + value,
+ idx >= 0);
+ return idx;
+ }
+
+ private <T> void assertNotContains(List<T> list, T value) {
+ assertFalse("List " + list + " should not have contained " + value,
+ list.contains(value));
+ }
+}
diff --git a/user/test/com/google/gwt/i18n/server/RegionInheritanceTest.java b/user/test/com/google/gwt/i18n/server/RegionInheritanceTest.java
new file mode 100644
index 0000000..19e3530
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/server/RegionInheritanceTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2009 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.server;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Test of RegionInheritance.
+ */
+public class RegionInheritanceTest extends TestCase {
+
+ /**
+ * Test method for {@link com.google.gwt.i18n.server.RegionInheritance#findCommonParent(java.lang.String, java.lang.String)}.
+ */
+ public void testFindCommonParent() {
+ assertEquals("001", RegionInheritance.findCommonParent("US", "KZ"));
+ assertEquals("019", RegionInheritance.findCommonParent("US", "MX"));
+ assertEquals("021", RegionInheritance.findCommonParent("US", "CA"));
+ assertEquals("419", RegionInheritance.findCommonParent("BR", "MX"));
+ assertEquals("005", RegionInheritance.findCommonParent("BR", "AR"));
+ assertNull(RegionInheritance.findCommonParent("BR", null));
+ assertNull(RegionInheritance.findCommonParent(null, "BR"));
+ assertNull(RegionInheritance.findCommonParent(null, null));
+ assertNull(RegionInheritance.findCommonParent("US", "XQZ"));
+ }
+
+ /**
+ * Test method for {@link com.google.gwt.i18n.server.RegionInheritance#getAllAncestors(java.lang.String)}.
+ */
+ public void testGetAllAncestors() {
+ List<String> ancestors = RegionInheritance.getAllAncestors("US");
+ assertEquals(3, ancestors.size());
+ assertTrue("Should have contained 001", ancestors.contains("001"));
+ assertTrue("Should have contained 021", ancestors.contains("021"));
+ assertTrue("Should have contained 019", ancestors.contains("019"));
+ }
+
+ /**
+ * Test method for {@link com.google.gwt.i18n.server.RegionInheritance#getImmediateParents(java.lang.String)}.
+ */
+ public void testGetImmediateParents() {
+ // TODO(jat): adjust if the inheritance data is modified to allow multiple
+ // parents.
+ Set<String> parents = RegionInheritance.getImmediateParents("US");
+ assertEquals(1, parents.size());
+ assertEquals("021", parents.iterator().next());
+ parents = RegionInheritance.getImmediateParents("BO");
+ assertEquals(1, parents.size());
+ assertEquals("005", parents.iterator().next());
+ parents = RegionInheritance.getImmediateParents("005");
+ assertEquals(1, parents.size());
+ assertEquals("419", parents.iterator().next());
+ }
+
+ /**
+ * Test method for {@link com.google.gwt.i18n.server.RegionInheritance#isParentOf(java.lang.String, java.lang.String)}.
+ */
+ public void testIsParentOf() {
+ assertTrue(RegionInheritance.isParentOf(null, null));
+ assertFalse(RegionInheritance.isParentOf(null, "US"));
+ assertFalse(RegionInheritance.isParentOf("US", null));
+ assertTrue(RegionInheritance.isParentOf("US", "US"));
+ assertTrue(RegionInheritance.isParentOf("019", "US"));
+ assertFalse(RegionInheritance.isParentOf("419", "US"));
+ assertTrue(RegionInheritance.isParentOf("419", "MX"));
+ assertTrue(RegionInheritance.isParentOf("001", "US"));
+ assertFalse(RegionInheritance.isParentOf("US", "001"));
+ }
+
+ /**
+ * Verifies some basic assumptions about the map.
+ */
+ public void testMap() {
+ Map<String, String> map = RegionInheritance.getInheritanceMap();
+ Set<String> regions = map.keySet();
+ for (String region : regions) {
+ if (region.length() == 2) {
+ if (!Character.isLetter(region.charAt(0))
+ || !Character.isLetter(region.charAt(1))) {
+ fail("2-character region names should be letters");
+ }
+ } else if (region.length() == 3) {
+ if (!Character.isDigit(region.charAt(0))
+ || !Character.isDigit(region.charAt(1))
+ || !Character.isDigit(region.charAt(2))) {
+ fail("3-character region names should be numeric");
+ }
+ } else {
+ fail("Regions in parent map should be 2 letters or 3 digits");
+ }
+ checkUltimateParent(map, region, "001");
+ }
+ }
+
+ private void checkUltimateParent(Map<String, String> map, String region,
+ String match) {
+ String origRegion = region;
+ while (region != null) {
+ if (region.equals(match)) {
+ return;
+ }
+ region = map.get(region);
+ }
+ fail("Ultimate parent of " + origRegion + " not " + match);
+ }
+}
diff --git a/user/test/com/google/gwt/json/client/JSONTest.java b/user/test/com/google/gwt/json/client/JSONTest.java
index c10751f..ba639cd 100644
--- a/user/test/com/google/gwt/json/client/JSONTest.java
+++ b/user/test/com/google/gwt/json/client/JSONTest.java
@@ -205,7 +205,7 @@
// Null characters do not work in hosted mode
public void testEscaping() {
JSONObject o = new JSONObject();
- char[] charsToEscape = new char[40];
+ char[] charsToEscape = new char[42];
for (char i = 1; i < 32; i++) {
charsToEscape[i] = i;
}
@@ -217,7 +217,9 @@
charsToEscape[37] = '\r';
charsToEscape[38] = '\t';
charsToEscape[39] = '/';
- for (int i = 1; i < 40; i++) {
+ charsToEscape[40] = '\u2028';
+ charsToEscape[41] = '\u2029';
+ for (int i = 1; i < charsToEscape.length; i++) {
o.put("c" + i, new JSONString(new Character(charsToEscape[i]).toString()));
}
assertEquals("{\"c1\":\"\\u0001\", \"c2\":\"\\u0002\", "
@@ -233,7 +235,7 @@
+ "\"c30\":\"\\u001E\", \"c31\":\"\\u001F\", \"c32\":\"\\\"\", "
+ "\"c33\":\"\\\\\", \"c34\":\"\\b\", \"c35\":\"\\f\", "
+ "\"c36\":\"\\n\", \"c37\":\"\\r\", \"c38\":\"\\t\", "
- + "\"c39\":\"/\"}", o.toString());
+ + "\"c39\":\"/\", \"c40\":\"\\u2028\", \"c41\":\"\\u2029\"}", o.toString());
}
public void testLargeArrays() {
diff --git a/user/test/com/google/gwt/user/RPCSuite.java b/user/test/com/google/gwt/user/RPCSuite.java
index 499446a..b32b50f 100644
--- a/user/test/com/google/gwt/user/RPCSuite.java
+++ b/user/test/com/google/gwt/user/RPCSuite.java
@@ -18,12 +18,19 @@
import com.google.gwt.dev.BootStrapPlatform;
import com.google.gwt.junit.tools.GWTTestSuite;
import com.google.gwt.user.client.rpc.CollectionsTest;
+import com.google.gwt.user.client.rpc.CollectionsTestWithTypeObfuscation;
import com.google.gwt.user.client.rpc.CustomFieldSerializerTest;
+import com.google.gwt.user.client.rpc.CustomFieldSerializerTestWithTypeObfuscation;
import com.google.gwt.user.client.rpc.EnumsTest;
+import com.google.gwt.user.client.rpc.EnumsTestWithTypeObfuscation;
import com.google.gwt.user.client.rpc.InheritanceTest;
+import com.google.gwt.user.client.rpc.InheritanceTestWithTypeObfuscation;
import com.google.gwt.user.client.rpc.ObjectGraphTest;
+import com.google.gwt.user.client.rpc.ObjectGraphTestWithTypeObfuscation;
import com.google.gwt.user.client.rpc.UnicodeEscapingTest;
+import com.google.gwt.user.client.rpc.UnicodeEscapingTestWithTypeObfuscation;
import com.google.gwt.user.client.rpc.ValueTypesTest;
+import com.google.gwt.user.client.rpc.ValueTypesTestWithTypeObfuscation;
import com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilderTest;
import com.google.gwt.user.rebind.rpc.TypeHierarchyUtilsTest;
import com.google.gwt.user.server.rpc.RPCRequestTest;
@@ -53,9 +60,18 @@
GWTTestSuite suite = new GWTTestSuite(
"Test for com.google.gwt.user.client.rpc");
+ // Non GWTTestCases
suite.addTestSuite(SerializableTypeOracleBuilderTest.class);
suite.addTestSuite(TypeHierarchyUtilsTest.class);
suite.addTestSuite(RPCTest.class);
+ suite.addTestSuite(com.google.gwt.user.server.rpc.RemoteServiceServletTest.class);
+ suite.addTestSuite(LegacySerializationPolicyTest.class);
+ suite.addTestSuite(StandardSerializationPolicyTest.class);
+ suite.addTestSuite(SerializationPolicyLoaderTest.class);
+ suite.addTestSuite(RPCServletUtilsTest.class);
+ suite.addTestSuite(RPCRequestTest.class);
+
+ // GWTTestCases
suite.addTestSuite(ValueTypesTest.class);
suite.addTestSuite(EnumsTest.class);
suite.addTestSuite(InheritanceTest.class);
@@ -63,13 +79,17 @@
suite.addTestSuite(CustomFieldSerializerTest.class);
suite.addTestSuite(ObjectGraphTest.class);
suite.addTestSuite(com.google.gwt.user.client.rpc.RemoteServiceServletTest.class);
- suite.addTestSuite(com.google.gwt.user.server.rpc.RemoteServiceServletTest.class);
suite.addTestSuite(UnicodeEscapingTest.class);
- suite.addTestSuite(LegacySerializationPolicyTest.class);
- suite.addTestSuite(StandardSerializationPolicyTest.class);
- suite.addTestSuite(SerializationPolicyLoaderTest.class);
- suite.addTestSuite(RPCServletUtilsTest.class);
- suite.addTestSuite(RPCRequestTest.class);
+
+ // This test turns on the type-elision feature of RPC
+ suite.addTestSuite(ValueTypesTestWithTypeObfuscation.class);
+ suite.addTestSuite(EnumsTestWithTypeObfuscation.class);
+ suite.addTestSuite(InheritanceTestWithTypeObfuscation.class);
+ suite.addTestSuite(CollectionsTestWithTypeObfuscation.class);
+ suite.addTestSuite(CustomFieldSerializerTestWithTypeObfuscation.class);
+ suite.addTestSuite(ObjectGraphTestWithTypeObfuscation.class);
+ suite.addTestSuite(com.google.gwt.user.client.rpc.RemoteServiceServletTestWithTypeObfuscation.class);
+ suite.addTestSuite(UnicodeEscapingTestWithTypeObfuscation.class);
return suite;
}
}
diff --git a/user/test/com/google/gwt/user/RPCSuiteWithObfuscation.gwt.xml b/user/test/com/google/gwt/user/RPCSuiteWithObfuscation.gwt.xml
new file mode 100644
index 0000000..4f427b3
--- /dev/null
+++ b/user/test/com/google/gwt/user/RPCSuiteWithObfuscation.gwt.xml
@@ -0,0 +1,18 @@
+<!-- -->
+<!-- Copyright 2009 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <inherits name="com.google.gwt.user.RPCSuite" />
+ <inherits name="com.google.gwt.user.RemoteServiceObfuscateTypeNames" />
+</module>
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index f5b3da7..c5bac76 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -16,6 +16,7 @@
package com.google.gwt.user;
import com.google.gwt.junit.tools.GWTTestSuite;
+import com.google.gwt.user.client.AsyncProxyTest;
import com.google.gwt.user.client.CommandExecutorTest;
import com.google.gwt.user.client.CookieTest;
import com.google.gwt.user.client.EventTest;
@@ -97,6 +98,7 @@
suite.addTestSuite(AbsolutePanelTest.class);
suite.addTestSuite(AnchorTest.class);
+ suite.addTestSuite(AsyncProxyTest.class);
suite.addTestSuite(ButtonTest.class);
suite.addTestSuite(CaptionPanelTest.class);
suite.addTestSuite(CheckBoxTest.class);
diff --git a/user/test/com/google/gwt/user/client/AsyncProxyTest.java b/user/test/com/google/gwt/user/client/AsyncProxyTest.java
new file mode 100644
index 0000000..94f7474
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/AsyncProxyTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.AsyncProxy.AllowNonVoid;
+import com.google.gwt.user.client.AsyncProxy.ConcreteType;
+import com.google.gwt.user.client.AsyncProxy.DefaultValue;
+import com.google.gwt.user.client.AsyncProxy.ProxyCallback;
+import com.google.gwt.user.client.impl.AsyncProxyBase;
+
+/**
+ * Tests the AsyncProxy type.
+ */
+public class AsyncProxyTest extends GWTTestCase {
+ interface Test {
+ boolean defaultBool();
+
+ byte defaultByte();
+
+ char defaultChar();
+
+ double defaultDouble();
+
+ float defaultFloat();
+
+ int defaultInt();
+
+ long defaultLong();
+
+ Object defaultObject();
+
+ short defaultShort();
+
+ String defaultString();
+
+ void one();
+
+ void three();
+
+ void two();
+ }
+
+ static class TestImpl implements Test {
+ @AllowNonVoid
+ @ConcreteType(TestImpl.class)
+ @DefaultValue(intValue = 42, longValue = 42)
+ interface Proxy extends AsyncProxy<Test>, Test {
+ }
+
+ private int value = 0;
+
+ public boolean defaultBool() {
+ return true;
+ }
+
+ public byte defaultByte() {
+ return 1;
+ }
+
+ public char defaultChar() {
+ return 1;
+ }
+
+ public double defaultDouble() {
+ return 1;
+ }
+
+ public float defaultFloat() {
+ return 1;
+ }
+
+ public int defaultInt() {
+ return 1;
+ }
+
+ public long defaultLong() {
+ return 1;
+ }
+
+ public Object defaultObject() {
+ return this;
+ }
+
+ public short defaultShort() {
+ return 1;
+ }
+
+ public String defaultString() {
+ return "";
+ }
+
+ public void one() {
+ GWTTestCase.assertEquals(0, value);
+ value = 1;
+ }
+
+ public void three() {
+ GWTTestCase.assertEquals(2, value);
+ testInstance.finishTest();
+ }
+
+ public void two() {
+ GWTTestCase.assertEquals(1, value);
+ value = 2;
+ }
+ }
+
+ private static final int TEST_FINISH_DELAY_MILLIS = 10000;
+
+ private static AsyncProxyTest testInstance;
+
+ public String getModuleName() {
+ return "com.google.gwt.user.User";
+ }
+
+ public void testProxy() {
+ // Disable in web mode for now
+ // TODO Make sure runAsync and JUnit play nicely together
+ if (GWT.isScript()) {
+ return;
+ }
+
+ testInstance = this;
+ final Test proxy = GWT.create(TestImpl.Proxy.class);
+ assertTrue(proxy instanceof AsyncProxy);
+
+ final TestImpl.Proxy asHidden = (TestImpl.Proxy) proxy;
+ assertNull(asHidden.getProxiedInstance());
+
+ asHidden.setProxyCallback(new ProxyCallback<Test>() {
+
+ @Override
+ public void onComplete(Test instance) {
+ // Check that the proxy is returning the correct values now
+ assertEquals(true, proxy.defaultBool());
+ assertEquals(1, proxy.defaultByte());
+ assertEquals(1, proxy.defaultChar());
+ assertEquals(1D, proxy.defaultDouble());
+ assertEquals(1F, proxy.defaultFloat());
+ assertEquals(1, proxy.defaultInt());
+ assertEquals(1L, proxy.defaultLong());
+ assertEquals(1, proxy.defaultShort());
+ assertEquals("", proxy.defaultString());
+ assertSame(instance, proxy.defaultObject());
+
+ instance.three();
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ t.printStackTrace();
+ fail(t.getMessage());
+ }
+
+ @Override
+ public void onInit(Test instance) {
+ assertTrue(instance instanceof TestImpl);
+ assertSame(asHidden.getProxiedInstance(), instance);
+ instance.one();
+ }
+ });
+
+ // Cast to AsyncProxyBase to fiddle with internals
+ AsyncProxyBase<?> asBase = (AsyncProxyBase<?>) proxy;
+ asBase.suppressLoadForTest0();
+ assertEquals(false, proxy.defaultBool());
+ assertEquals(0, proxy.defaultByte());
+ assertEquals(0, proxy.defaultChar());
+ assertEquals(0D, proxy.defaultDouble());
+ assertEquals(0F, proxy.defaultFloat());
+ assertEquals(42, proxy.defaultInt());
+ assertEquals(42L, proxy.defaultLong());
+ assertEquals(0, proxy.defaultShort());
+ assertNull(proxy.defaultString());
+ assertNull(proxy.defaultObject());
+ asBase.enableLoadForTest0();
+
+ delayTestFinish(TEST_FINISH_DELAY_MILLIS);
+ proxy.two();
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestWithTypeObfuscation.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestWithTypeObfuscation.java
new file mode 100644
index 0000000..54d74c2
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestWithTypeObfuscation.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ *
+ */
+public class CollectionsTestWithTypeObfuscation extends CollectionsTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.RPCSuiteWithObfuscation";
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestWithTypeObfuscation.java b/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestWithTypeObfuscation.java
new file mode 100644
index 0000000..8b22287
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestWithTypeObfuscation.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ *
+ */
+public class CustomFieldSerializerTestWithTypeObfuscation extends CustomFieldSerializerTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.RPCSuiteWithObfuscation";
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/EnumsTestWithTypeObfuscation.java b/user/test/com/google/gwt/user/client/rpc/EnumsTestWithTypeObfuscation.java
new file mode 100644
index 0000000..476ac40
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/EnumsTestWithTypeObfuscation.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ *
+ */
+public class EnumsTestWithTypeObfuscation extends EnumsTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.RPCSuiteWithObfuscation";
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/InheritanceTestWithTypeObfuscation.java b/user/test/com/google/gwt/user/client/rpc/InheritanceTestWithTypeObfuscation.java
new file mode 100644
index 0000000..9761152
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/InheritanceTestWithTypeObfuscation.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ *
+ */
+public class InheritanceTestWithTypeObfuscation extends InheritanceTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.RPCSuiteWithObfuscation";
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/ObjectGraphTest.java b/user/test/com/google/gwt/user/client/rpc/ObjectGraphTest.java
index 1819e85..ce6b964 100644
--- a/user/test/com/google/gwt/user/client/rpc/ObjectGraphTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/ObjectGraphTest.java
@@ -20,6 +20,7 @@
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;
+import com.google.gwt.user.client.rpc.impl.AbstractSerializationStream;
/**
* TODO: document me.
@@ -84,7 +85,7 @@
}
});
}
-
+
public void testDoublyReferencedArray() {
delayTestFinish(TEST_DELAY);
@@ -102,7 +103,24 @@
}
});
}
-
+
+ public void testElision() throws SerializationException {
+ ObjectGraphTestServiceAsync async = getServiceAsync();
+
+ SerializationStreamWriter writer = ((SerializationStreamFactory) async).createStreamWriter();
+ AbstractSerializationStream stream = (AbstractSerializationStream) writer;
+ assertEquals("Missing flag", expectedObfuscationState(),
+ stream.hasFlags(AbstractSerializationStream.FLAG_ELIDE_TYPE_NAMES));
+
+ SerializableDoublyLinkedNode node = new SerializableDoublyLinkedNode();
+ writer.writeObject(node);
+ String s = writer.toString();
+
+ // Don't use class.getName() due to conflict with removal of type names
+ assertEquals("Checking for SerializableDoublyLinkedNode",
+ expectedObfuscationState(), !s.contains("SerializableDoublyLinkedNode"));
+ }
+
public void testPrivateNoArg() {
delayTestFinish(TEST_DELAY);
@@ -139,6 +157,10 @@
});
}
+ protected boolean expectedObfuscationState() {
+ return false;
+ }
+
private ObjectGraphTestServiceAsync getServiceAsync() {
if (objectGraphTestService == null) {
objectGraphTestService = (ObjectGraphTestServiceAsync) GWT.create(ObjectGraphTestService.class);
diff --git a/user/test/com/google/gwt/user/client/rpc/ObjectGraphTestWithTypeObfuscation.java b/user/test/com/google/gwt/user/client/rpc/ObjectGraphTestWithTypeObfuscation.java
new file mode 100644
index 0000000..53a149c
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/ObjectGraphTestWithTypeObfuscation.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ *
+ */
+public class ObjectGraphTestWithTypeObfuscation extends ObjectGraphTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.RPCSuiteWithObfuscation";
+ }
+
+ @Override
+ protected boolean expectedObfuscationState() {
+ return true;
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTest.java b/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTest.java
index 52251c8..4145b16 100644
--- a/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTest.java
@@ -27,9 +27,9 @@
* hierarchy looking for the service interface. Prior to this test the servlet
* would only look into the concrete class but not in any of its super classes.
*
- * See <a
- * href="http://code.google.com/p/google-web-toolkit/issues/detail?id=50&can=3&q=">Bug
- * 50</a> for more details.
+ * See <a href=
+ * "http://code.google.com/p/google-web-toolkit/issues/detail?id=50&can=3&q="
+ * >Bug 50</a> for more details.
* <p>
* This test works in conjunction with
* {@link com.google.gwt.user.server.rpc.RemoteServiceServletTestServiceImpl}.
@@ -38,7 +38,7 @@
public class RemoteServiceServletTest extends GWTTestCase {
private static final int TEST_DELAY = 10000;
- private static RemoteServiceServletTestServiceAsync getAsyncService() {
+ protected static RemoteServiceServletTestServiceAsync getAsyncService() {
RemoteServiceServletTestServiceAsync service = (RemoteServiceServletTestServiceAsync) GWT.create(RemoteServiceServletTestService.class);
((ServiceDefTarget) service).setServiceEntryPoint(GWT.getModuleBaseURL()
diff --git a/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTestWithTypeObfuscation.java b/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTestWithTypeObfuscation.java
new file mode 100644
index 0000000..82ad29f
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTestWithTypeObfuscation.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ *
+ */
+public class RemoteServiceServletTestWithTypeObfuscation extends
+ RemoteServiceServletTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.RPCSuiteWithObfuscation";
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTestWithTypeObfuscation.java b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTestWithTypeObfuscation.java
new file mode 100644
index 0000000..2a9a23a
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTestWithTypeObfuscation.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ *
+ */
+public class UnicodeEscapingTestWithTypeObfuscation extends UnicodeEscapingTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.RPCSuiteWithObfuscation";
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java b/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java
index 7f82ce2..ff8eee4 100644
--- a/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java
@@ -22,6 +22,7 @@
* TODO: document me.
*/
public class ValueTypesTest extends GWTTestCase {
+
private static final int TEST_DELAY = 5000;
private ValueTypesTestServiceAsync primitiveTypeTestService;
diff --git a/user/test/com/google/gwt/user/client/rpc/ValueTypesTestWithTypeObfuscation.java b/user/test/com/google/gwt/user/client/rpc/ValueTypesTestWithTypeObfuscation.java
new file mode 100644
index 0000000..aa30cff
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/ValueTypesTestWithTypeObfuscation.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2009 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;
+
+/**
+ * This is a top-level type because our test-runner doesn't like running static
+ * nested classes.
+ */
+public class ValueTypesTestWithTypeObfuscation extends ValueTypesTest {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.RPCSuiteWithObfuscation";
+ }
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java b/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
index 9f75759..566c50e 100644
--- a/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
+++ b/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
@@ -110,4 +110,22 @@
assertFalse(r2.getValue());
assertTrue(r3.getValue());
}
+
+ /**
+ * Ensures that the element order doesn't get reversed when the radio's
+ * name is changed.
+ */
+ public void testOrderAfterSetName() {
+ RadioButton radio = new RadioButton("oldName");
+ assertEquals("oldName", radio.getName());
+
+ radio.setName("newName");
+ assertEquals("newName", radio.getName());
+
+ Element parent = radio.getElement();
+ Element firstChild = parent.getFirstChildElement().cast();
+ Element secondChild = firstChild.getNextSiblingElement().cast();
+ assertEquals("input", firstChild.getTagName().toLowerCase());
+ assertEquals("label", secondChild.getTagName().toLowerCase());
+ }
}
diff --git a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
index a3d9d13..e7b1258 100644
--- a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
+++ b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
@@ -105,6 +105,14 @@
private static final int EXPOSURE_NONE = TypeParameterExposureComputer.EXPOSURE_NONE;
+ private static void addGwtTransient(Set<CompilationUnit> units) {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.user.client.rpc;\n");
+ code.append("public @interface GwtTransient { }\n");
+ units.add(createMockCompilationUnit(
+ "com.google.gwt.user.client.rpc.GwtTransient", code));
+ }
+
private static void addICRSE(Set<CompilationUnit> units) {
StringBuffer code = new StringBuffer();
code.append("package com.google.gwt.user.client.rpc;\n");
@@ -167,6 +175,7 @@
}
private static void addStandardClasses(Set<CompilationUnit> units) {
+ addGwtTransient(units);
addJavaIoSerializable(units);
addJavaLangObject(units);
addJavaLangString(units);
@@ -2022,6 +2031,59 @@
}
/**
+ * Tests that STOB skips transient fields.
+ */
+ public void testTransient() throws UnableToCompleteException,
+ NotFoundException {
+ Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+ addStandardClasses(units);
+
+ {
+ StringBuilder code = new StringBuilder();
+ code.append("import com.google.gwt.user.client.rpc.GwtTransient;\n");
+ code.append("import java.io.Serializable;\n");
+ code.append("public class A implements Serializable {\n");
+ code.append(" transient ServerOnly1 serverOnly1;\n");
+ code.append(" @GwtTransient ServerOnly2 serverOnly2;\n");
+ code.append("}\n");
+ units.add(createMockCompilationUnit("A", code));
+ }
+
+ {
+ StringBuilder code = new StringBuilder();
+ code.append("import java.io.Serializable;\n");
+ code.append("class ServerOnly1 implements Serializable {\n");
+ code.append("}\n");
+ units.add(createMockCompilationUnit("ServerOnly1", code));
+ }
+
+ {
+ StringBuilder code = new StringBuilder();
+ code.append("import java.io.Serializable;\n");
+ code.append("class ServerOnly2 implements Serializable {\n");
+ code.append("}\n");
+ units.add(createMockCompilationUnit("ServerOnly2", code));
+ }
+
+ TreeLogger logger = createLogger();
+ TypeOracle to = TypeOracleTestingUtils.buildTypeOracle(logger, units);
+
+ JClassType a = to.getType("A");
+ JClassType serverOnly1 = to.getType("ServerOnly1");
+ JClassType serverOnly2 = to.getType("ServerOnly2");
+
+ SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
+ logger, to);
+ sob.addRootType(logger, a);
+ SerializableTypeOracle so = sob.build(logger);
+
+ assertSerializableTypes(so, a);
+ assertInstantiable(so, a);
+ assertNotFieldSerializable(so, serverOnly1);
+ assertNotFieldSerializable(so, serverOnly2);
+ }
+
+ /**
* Miscellaneous direct tests of {@link TypeConstrainer}.
*
* @throws UnableToCompleteException
diff --git a/user/test/com/google/gwt/user/server/rpc/RPCRequestTest.java b/user/test/com/google/gwt/user/server/rpc/RPCRequestTest.java
index a8d4bfa..73bd3fe 100644
--- a/user/test/com/google/gwt/user/server/rpc/RPCRequestTest.java
+++ b/user/test/com/google/gwt/user/server/rpc/RPCRequestTest.java
@@ -43,7 +43,7 @@
// Test simple case
Object params[] = new Object[] {"abcdefg", 1234};
- RPCRequest request = new RPCRequest(method, params, null);
+ RPCRequest request = new RPCRequest(method, params, null, 0);
String strRequest = request.toString();
assertEquals("com.google.gwt.user.server.rpc.RPCRequestTest$"
+ "MockRequestImplementation.doSomething(\"abcdefg\", 1234)",
@@ -51,7 +51,7 @@
// Test case with a string that needs escaping
Object params2[] = new Object[] {"ab\"cde\"fg", 1234};
- RPCRequest request2 = new RPCRequest(method, params2, null);
+ RPCRequest request2 = new RPCRequest(method, params2, null, 0);
String strRequest2 = request2.toString();
System.out.println(strRequest2);
assertEquals("com.google.gwt.user.server.rpc.RPCRequestTest$"
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 20dd1b9..404c8f4 100644
--- a/user/test/com/google/gwt/user/server/rpc/RPCTest.java
+++ b/user/test/com/google/gwt/user/server/rpc/RPCTest.java
@@ -23,9 +23,11 @@
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 com.google.gwt.user.server.rpc.impl.TypeNameObfuscator;
import junit.framework.TestCase;
+import java.io.Serializable;
import java.lang.reflect.Method;
/**
@@ -34,6 +36,24 @@
@SuppressWarnings("deprecation")
public class RPCTest extends TestCase {
+ /**
+ * Test serialization class.
+ *
+ * @see RPCTest#testElision()
+ */
+ public static class C implements Serializable {
+ int i = 0;
+ }
+
+ /**
+ * Test serialization class.
+ *
+ * @see RPCTest#testElision()
+ */
+ private static interface CC {
+ C c();
+ }
+
private static interface A extends RemoteService {
void method1() throws SerializableException;
@@ -46,9 +66,9 @@
void method1();
}
- private static final String VALID_ENCODED_REQUEST = "" +
- AbstractSerializationStream.SERIALIZATION_STREAM_VERSION +
- RPC_SEPARATOR_CHAR + // version
+ 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
@@ -61,9 +81,9 @@
"2" + RPC_SEPARATOR_CHAR + // method name
"0" + RPC_SEPARATOR_CHAR; // param count
- private static final String INVALID_METHOD_REQUEST = "" +
- AbstractSerializationStream.SERIALIZATION_STREAM_VERSION +
- RPC_SEPARATOR_CHAR + // version
+ 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
@@ -76,9 +96,9 @@
"2" + RPC_SEPARATOR_CHAR + // method name
"0" + RPC_SEPARATOR_CHAR; // param count
- private static final String INVALID_INTERFACE_REQUEST = "" +
- AbstractSerializationStream.SERIALIZATION_STREAM_VERSION +
- RPC_SEPARATOR_CHAR + // version
+ 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
@@ -91,9 +111,9 @@
"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
+ 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
@@ -106,8 +126,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;
+ "6" + RPC_SEPARATOR_CHAR + "7" + RPC_SEPARATOR_CHAR;
private static final String VALID_V2_ENCODED_REQUEST = "2\uffff" + // version
"0\uffff" + // flags
@@ -174,7 +193,8 @@
/**
* Tests for method {@link RPC#decodeRequest(String)}
*
- * <p/> Cases:
+ * <p/>
+ * Cases:
* <ol>
* <li>String == null</li>
* <li>String == ""</li>
@@ -205,7 +225,8 @@
/**
* Tests for method {@link RPC#decodeRequest(String, Class)}
*
- * <p/> Cases:
+ * <p/>
+ * Cases:
* <ol>
* <li>String == null</li>
* <li>String == ""</li>
@@ -265,6 +286,83 @@
}
}
+ public void testElision() throws SecurityException, SerializationException,
+ NoSuchMethodException {
+ class TestPolicy extends SerializationPolicy implements TypeNameObfuscator {
+ private static final String C_NAME = "__c__";
+
+ public String getClassNameForTypeId(String id)
+ throws SerializationException {
+ assertEquals(C_NAME, id);
+ return C.class.getName();
+ }
+
+ public String getTypeIdForClass(Class<?> clazz)
+ throws SerializationException {
+ assertEquals(C.class, clazz);
+ return C_NAME;
+ }
+
+ @Override
+ public boolean shouldDeserializeFields(Class<?> clazz) {
+ return C.class.equals(clazz);
+ }
+
+ @Override
+ public boolean shouldSerializeFields(Class<?> clazz) {
+ return C.class.equals(clazz);
+ }
+
+ @Override
+ public void validateDeserialize(Class<?> clazz)
+ throws SerializationException {
+ }
+
+ @Override
+ public void validateSerialize(Class<?> clazz)
+ throws SerializationException {
+ }
+ }
+
+ String rpc = RPC.encodeResponseForSuccess(CC.class.getMethod("c"), new C(),
+ new TestPolicy(), AbstractSerializationStream.FLAG_ELIDE_TYPE_NAMES);
+ assertTrue(rpc.contains(TestPolicy.C_NAME));
+ assertFalse(rpc.contains(C.class.getName()));
+ }
+
+ public void testElisionWithNoObfuscator() throws SecurityException,
+ NoSuchMethodException {
+ class TestPolicy extends SerializationPolicy {
+ @Override
+ public boolean shouldDeserializeFields(Class<?> clazz) {
+ return C.class.equals(clazz);
+ }
+
+ @Override
+ public boolean shouldSerializeFields(Class<?> clazz) {
+ return C.class.equals(clazz);
+ }
+
+ @Override
+ public void validateDeserialize(Class<?> clazz)
+ throws SerializationException {
+ }
+
+ @Override
+ public void validateSerialize(Class<?> clazz)
+ throws SerializationException {
+ }
+ }
+
+ try {
+ RPC.encodeResponseForSuccess(CC.class.getMethod("c"), new C(),
+ new TestPolicy(), AbstractSerializationStream.FLAG_ELIDE_TYPE_NAMES);
+ fail("Should have thrown a SerializationException");
+ } catch (SerializationException e) {
+ // OK
+ }
+ }
+
/**
* Tests for method {@link RPC#encodeResponseForFailure(Method, Throwable)}.
*
@@ -307,8 +405,8 @@
}
// Case 4
- String str = RPC.encodeResponseForFailure(
- A.class.getMethod("method1"), new SerializableException());
+ String str = RPC.encodeResponseForFailure(A.class.getMethod("method1"),
+ new SerializableException());
assertTrue(str.indexOf("SerializableException") != -1);
}
@@ -451,9 +549,10 @@
}
}, A_method1, null);
}
-
+
public void testSerializationStreamDequote() throws SerializationException {
- ServerSerializationStreamReader reader = new ServerSerializationStreamReader(null, null);
+ ServerSerializationStreamReader reader = new ServerSerializationStreamReader(
+ null, null);
reader.prepareToRead(STRING_QUOTE_REQUEST);
assertEquals("Raw backslash \\", reader.readString());
assertEquals("Quoted separator " + RPC_SEPARATOR_CHAR, reader.readString());
diff --git a/user/test/com/google/gwt/user/server/rpc/SerializationPolicyLoaderTest.java b/user/test/com/google/gwt/user/server/rpc/SerializationPolicyLoaderTest.java
index 5ced7cf..f3ac42a 100644
--- a/user/test/com/google/gwt/user/server/rpc/SerializationPolicyLoaderTest.java
+++ b/user/test/com/google/gwt/user/server/rpc/SerializationPolicyLoaderTest.java
@@ -16,6 +16,7 @@
package com.google.gwt.user.server.rpc;
import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.server.rpc.impl.TypeNameObfuscator;
import junit.framework.TestCase;
@@ -39,20 +40,94 @@
static class B {
}
- // missing the instantiable attribute
- private static String POLICY_FILE_MISSING_FIELD = A.class.getName();
+ static class I {
+ }
- private static String POLICY_FILE_TRIGGERS_CLASSNOTFOUND = "C,false";
-
- private static String VALID_POLICY_FILE_CONTENTS = A.class.getName()
+ private static final String OLD_VALID_POLICY_FILE_CONTENTS = A.class.getName()
+ ", true";
+ // missing the instantiable attribute
+ private static final String POLICY_FILE_MISSING_FIELD = A.class.getName();
+
+ private static final String POLICY_FILE_TRIGGERS_CLASSNOTFOUND = "C,false";
+
+ private static final String VALID_POLICY_FILE_CONTENTS = A.class.getName()
+ + ", true, true, false, false, a, 1234\n" + B.class.getName()
+ + ", false, false, true, false, b, 5678\n" + I.class.getName()
+ + ", false, false, false, false, "
+ + TypeNameObfuscator.SERVICE_INTERFACE_ID + ", 999\n";
+
public static InputStream getInputStreamFromString(String content)
throws UnsupportedEncodingException {
return new ByteArrayInputStream(
content.getBytes(SerializationPolicyLoader.SERIALIZATION_POLICY_FILE_ENCODING));
}
+ /**
+ * Test that a valid policy file will allow the types in the policy to be used
+ * and reject those that are not.
+ *
+ * @throws ClassNotFoundException
+ * @throws ParseException
+ */
+ public void testLoading() throws IOException, SerializationException,
+ ParseException, ClassNotFoundException {
+
+ InputStream is = getInputStreamFromString(VALID_POLICY_FILE_CONTENTS);
+ List<ClassNotFoundException> notFounds = new ArrayList<ClassNotFoundException>();
+ SerializationPolicy sp = SerializationPolicyLoader.loadFromStream(is,
+ notFounds);
+ assertTrue(notFounds.isEmpty());
+
+ assertTrue(sp.shouldSerializeFields(A.class));
+ sp.validateSerialize(A.class);
+ assertFalse(sp.shouldDeserializeFields(A.class));
+ assertCannotDeserialize(sp, A.class);
+
+ assertFalse(sp.shouldSerializeFields(B.class));
+ assertCannotDeserialize(sp, B.class);
+ assertTrue(sp.shouldDeserializeFields(B.class));
+ assertCannotDeserialize(sp, B.class);
+
+ assertTrue(sp instanceof TypeNameObfuscator);
+ TypeNameObfuscator ob = (TypeNameObfuscator) sp;
+ assertEquals("a", ob.getTypeIdForClass(A.class));
+ assertEquals(A.class.getName(), ob.getClassNameForTypeId("a"));
+ assertEquals("b", ob.getTypeIdForClass(B.class));
+ assertEquals(B.class.getName(), ob.getClassNameForTypeId("b"));
+ assertEquals(TypeNameObfuscator.SERVICE_INTERFACE_ID,
+ ob.getTypeIdForClass(I.class));
+ assertEquals(I.class.getName(),
+ ob.getClassNameForTypeId(TypeNameObfuscator.SERVICE_INTERFACE_ID));
+ }
+
+ /**
+ * Test that a valid policy file will allow the types in the policy to be used
+ * and reject those that are not. Uses the old policy file format, which is no
+ * longer generated as of November 2008.
+ *
+ * @throws ClassNotFoundException
+ * @throws ParseException
+ */
+ public void testLoadingOldFileFormat() throws IOException,
+ SerializationException, ParseException, ClassNotFoundException {
+
+ InputStream is = getInputStreamFromString(OLD_VALID_POLICY_FILE_CONTENTS);
+ SerializationPolicy sp = SerializationPolicyLoader.loadFromStream(is);
+
+ assertTrue(sp.shouldDeserializeFields(A.class));
+ assertTrue(sp.shouldSerializeFields(A.class));
+
+ assertFalse(sp.shouldDeserializeFields(B.class));
+ assertFalse(sp.shouldSerializeFields(B.class));
+
+ sp.validateDeserialize(A.class);
+ sp.validateSerialize(A.class);
+
+ assertCannotDeserialize(sp, B.class);
+ assertCannotSerialize(sp, B.class);
+ }
+
public void testPolicyFileMissingField() throws IOException,
ClassNotFoundException {
InputStream is = getInputStreamFromString(POLICY_FILE_MISSING_FIELD);
@@ -73,7 +148,7 @@
} catch (ClassNotFoundException e) {
// expected to get here
}
-
+
// Test loading without collecting ClassNotFoundExceptions.
is.reset();
SerializationPolicyLoader.loadFromStream(is, null);
@@ -86,36 +161,18 @@
assertNotNull(classNotFoundExceptions.get(0));
}
- /**
- * Test that a valid policy file will allow the types in the policy to be used
- * and reject those that are not.
- *
- * @throws ClassNotFoundException
- * @throws ParseException
- */
- public void testValidSerializationPolicy() throws IOException,
- SerializationException, ParseException, ClassNotFoundException {
-
- InputStream is = getInputStreamFromString(VALID_POLICY_FILE_CONTENTS);
- SerializationPolicy sp = SerializationPolicyLoader.loadFromStream(is);
- assertTrue(sp.shouldDeserializeFields(A.class));
- assertTrue(sp.shouldSerializeFields(A.class));
-
- assertFalse(sp.shouldDeserializeFields(B.class));
- assertFalse(sp.shouldSerializeFields(B.class));
-
- sp.validateDeserialize(A.class);
- sp.validateSerialize(A.class);
-
+ private void assertCannotDeserialize(SerializationPolicy sp, Class<?> cls) {
try {
- sp.validateDeserialize(B.class);
+ sp.validateDeserialize(cls);
fail("Expected SerializationException");
} catch (SerializationException ex) {
// should get here
}
+ }
+ private void assertCannotSerialize(SerializationPolicy sp, Class<?> cls) {
try {
- sp.validateSerialize(B.class);
+ sp.validateSerialize(cls);
fail("Expected SerializationException");
} catch (SerializationException ex) {
// should get here
diff --git a/user/test/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicyTest.java b/user/test/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicyTest.java
index bae526f..9d28e6a 100644
--- a/user/test/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicyTest.java
+++ b/user/test/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicyTest.java
@@ -20,6 +20,7 @@
import junit.framework.TestCase;
import java.util.HashMap;
+import java.util.Map;
/**
* Tests for the {@link StandardSerializationPolicy} class.
@@ -116,9 +117,14 @@
}
StandardSerializationPolicy getStandardSerializationPolicy() {
- java.util.Map map = new HashMap();
+ Map map = new HashMap();
map.put(A.class, Boolean.TRUE);
map.put(C.class, Boolean.FALSE);
- return new StandardSerializationPolicy(map);
+
+ Map typeIds = new HashMap();
+ typeIds.put(A.class, "A");
+ typeIds.put(B.class, "B");
+
+ return new StandardSerializationPolicy(map, map, typeIds);
}
}