svn merge -r4490:4497 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
svn merge -r4498:4511 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
Note that we skip 4498 which was previously cherry picked (tmp dir fix), and
4499 (the merge of the cherry pick, not strictly necessary, but hey)
Review by jgw
ant test passed on linux
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4512 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/Compiler.java b/dev/core/src/com/google/gwt/dev/Compiler.java
index c044d22..7acdcfb 100644
--- a/dev/core/src/com/google/gwt/dev/Compiler.java
+++ b/dev/core/src/com/google/gwt/dev/Compiler.java
@@ -142,7 +142,8 @@
}
for (String moduleName : options.getModuleNames()) {
- ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, moduleName);
+ ModuleDef module = ModuleDefLoader.loadFromClassPath(logger,
+ moduleName, true);
File compilerWorkDir = options.getCompilerWorkDir(moduleName);
if (options.isValidateOnly()) {
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index ad1854f..0c1097b 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -136,7 +136,7 @@
ModuleDef[] modules = new ModuleDef[options.getModuleNames().size()];
int i = 0;
for (String moduleName : options.getModuleNames()) {
- modules[i++] = ModuleDefLoader.loadFromClassPath(logger, moduleName);
+ modules[i++] = ModuleDefLoader.loadFromClassPath(logger, moduleName, true);
}
return run(logger, modules);
}
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 1fc2d9b..0bccea5 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
@@ -203,6 +203,7 @@
catEngine = catEmbedded.createEngine();
catEngine.setName("gwt");
catEngine.setDefaultHost("localhost");
+ catEngine.setParentClassLoader(this.getClass().getClassLoader());
// It answers localhost requests.
//
@@ -363,7 +364,7 @@
*/
private Map<String, Resource> getResourcesFor(TreeLogger logger,
String tomcatEtcDir) throws URISyntaxException, IOException {
- ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ ClassLoader contextClassLoader = this.getClass().getClassLoader();
URL url = contextClassLoader.getResource(tomcatEtcDir);
if (url == null) {
return null;
diff --git a/dev/core/src/org/apache/catalina/loader/WebappClassLoader.java b/dev/core/src/org/apache/catalina/loader/WebappClassLoader.java
new file mode 100644
index 0000000..f9c5ee0
--- /dev/null
+++ b/dev/core/src/org/apache/catalina/loader/WebappClassLoader.java
@@ -0,0 +1,2167 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache 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.
+ */
+// Modified by Google.
+
+package org.apache.catalina.loader;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes.Name;
+
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.util.StringManager;
+import org.apache.naming.JndiPermission;
+import org.apache.naming.resources.Resource;
+import org.apache.naming.resources.ResourceAttributes;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * Specialized web application class loader.
+ * <p>
+ * This class loader is a full reimplementation of the
+ * <code>URLClassLoader</code> from the JDK. It is desinged to be fully
+ * compatible with a normal <code>URLClassLoader</code>, although its internal
+ * behavior may be completely different.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - This class loader faithfully follows
+ * the delegation model recommended in the specification. The system class
+ * loader will be queried first, then the local repositories, and only then
+ * delegation to the parent class loader will occur. This allows the web
+ * application to override any shared class except the classes from J2SE.
+ * Special handling is provided from the JAXP XML parser interfaces, the JNDI
+ * interfaces, and the classes from the servlet API, which are never loaded
+ * from the webapp repository.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - Due to limitations in Jasper
+ * compilation technology, any repository which contains classes from
+ * the servlet API will be ignored by the class loader.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - The class loader generates source
+ * URLs which include the full JAR URL when a class is loaded from a JAR file,
+ * which allows setting security permission at the class level, even when a
+ * class is contained inside a JAR.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - Local repositories are searched in
+ * the order they are added via the initial constructor and/or any subsequent
+ * calls to <code>addRepository()</code> or <code>addJar()</code>.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - No check for sealing violations or
+ * security is made unless a security manager is present.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.34 $ $Date: 2004/05/26 15:47:40 $
+ */
+public class WebappClassLoader
+ extends URLClassLoader
+ implements Reloader, Lifecycle
+ {
+
+ private static org.apache.commons.logging.Log log=
+ org.apache.commons.logging.LogFactory.getLog( WebappClassLoader.class );
+
+ protected class PrivilegedFindResource
+ implements PrivilegedAction {
+
+ private File file;
+ private String path;
+
+ PrivilegedFindResource(File file, String path) {
+ this.file = file;
+ this.path = path;
+ }
+
+ public Object run() {
+ return findResourceInternal(file, path);
+ }
+
+ }
+
+
+ // ------------------------------------------------------- Static Variables
+
+
+ /**
+ * The set of trigger classes that will cause a proposed repository not
+ * to be added if this class is visible to the class loader that loaded
+ * this factory class. Typically, trigger classes will be listed for
+ * components that have been integrated into the JDK for later versions,
+ * but where the corresponding JAR files are required to run on
+ * earlier versions.
+ */
+ private static final String[] triggers = {
+ "javax.servlet.Servlet" // Servlet API
+ };
+
+ /**
+ * Jdk Compatibility Support.
+ */
+ private static JdkCompat jdkCompat = JdkCompat.getJdkCompat();
+
+ /**
+ * Set of package names which are not allowed to be loaded from a webapp
+ * class loader without delegating first.
+ */
+ private static final String[] packageTriggers = {
+ "javax", // Java extensions
+ "org.xml.sax", // SAX 1 & 2
+ "org.w3c.dom", // DOM 1 & 2
+ "org.apache.xerces", // Xerces 1 & 2
+ "org.apache.xalan" // Xalan
+ };
+
+
+ /**
+ * The string manager for this package.
+ */
+ protected static final StringManager sm =
+ StringManager.getManager(Constants.Package);
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Construct a new ClassLoader with no defined repositories and no
+ * parent ClassLoader.
+ */
+ public WebappClassLoader() {
+
+ super(new URL[0]);
+ this.parent = getParent();
+ system = getSystemClassLoader();
+ securityManager = System.getSecurityManager();
+
+ if (securityManager != null) {
+ refreshPolicy();
+ }
+
+ }
+
+
+ /**
+ * Construct a new ClassLoader with no defined repositories and no
+ * parent ClassLoader.
+ */
+ public WebappClassLoader(ClassLoader parent) {
+
+ super(new URL[0], parent);
+
+ this.parent = getParent();
+
+ system = getSystemClassLoader();
+ securityManager = System.getSecurityManager();
+
+ if (securityManager != null) {
+ refreshPolicy();
+ }
+ }
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * Associated directory context giving access to the resources in this
+ * webapp.
+ */
+ protected DirContext resources = null;
+
+
+ /**
+ * The cache of ResourceEntry for classes and resources we have loaded,
+ * keyed by resource name.
+ */
+ protected HashMap resourceEntries = new HashMap();
+
+
+ /**
+ * The list of not found resources.
+ */
+ protected HashMap notFoundResources = new HashMap();
+
+
+ /**
+ * The debugging detail level of this component.
+ */
+ protected int debug = 0;
+
+
+ /**
+ * Should this class loader delegate to the parent class loader
+ * <strong>before</strong> searching its own repositories (i.e. the
+ * usual Java2 delegation model)? If set to <code>false</code>,
+ * this class loader will search its own repositories first, and
+ * delegate to the parent only if the class or resource is not
+ * found locally.
+ */
+ protected boolean delegate = false;
+
+
+ /**
+ * Last time a JAR was accessed.
+ */
+ protected long lastJarAccessed = 0L;
+
+
+ /**
+ * The list of local repositories, in the order they should be searched
+ * for locally loaded classes or resources.
+ */
+ protected String[] repositories = new String[0];
+
+
+ /**
+ * Repositories URLs, used to cache the result of getURLs.
+ */
+ protected URL[] repositoryURLs = null;
+
+
+ /**
+ * Repositories translated as path in the work directory (for Jasper
+ * originally), but which is used to generate fake URLs should getURLs be
+ * called.
+ */
+ protected File[] files = new File[0];
+
+
+ /**
+ * The list of JARs, in the order they should be searched
+ * for locally loaded classes or resources.
+ */
+ protected JarFile[] jarFiles = new JarFile[0];
+
+
+ /**
+ * The list of JARs, in the order they should be searched
+ * for locally loaded classes or resources.
+ */
+ protected File[] jarRealFiles = new File[0];
+
+
+ /**
+ * The path which will be monitored for added Jar files.
+ */
+ protected String jarPath = null;
+
+
+ /**
+ * The list of JARs, in the order they should be searched
+ * for locally loaded classes or resources.
+ */
+ protected String[] jarNames = new String[0];
+
+
+ /**
+ * The list of JARs last modified dates, in the order they should be
+ * searched for locally loaded classes or resources.
+ */
+ protected long[] lastModifiedDates = new long[0];
+
+
+ /**
+ * The list of resources which should be checked when checking for
+ * modifications.
+ */
+ protected String[] paths = new String[0];
+
+
+ /**
+ * A list of read File and Jndi Permission's required if this loader
+ * is for a web application context.
+ */
+ private ArrayList permissionList = new ArrayList();
+
+
+ /**
+ * Path where resources loaded from JARs will be extracted.
+ */
+ private File loaderDir = null;
+
+
+ /**
+ * The PermissionCollection for each CodeSource for a web
+ * application context.
+ */
+ private HashMap loaderPC = new HashMap();
+
+
+ /**
+ * Instance of the SecurityManager installed.
+ */
+ private SecurityManager securityManager = null;
+
+
+ /**
+ * The parent class loader.
+ */
+ private ClassLoader parent = null;
+
+
+ /**
+ * The system class loader.
+ */
+ private ClassLoader system = null;
+
+
+ /**
+ * Has this component been started?
+ */
+ protected boolean started = false;
+
+
+ /**
+ * Has external repositories.
+ */
+ protected boolean hasExternalRepositories = false;
+
+
+ /**
+ * All permission.
+ */
+ private Permission allPermission = new java.security.AllPermission();
+
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Get associated resources.
+ */
+ public DirContext getResources() {
+
+ return this.resources;
+
+ }
+
+
+ /**
+ * Set associated resources.
+ */
+ public void setResources(DirContext resources) {
+
+ this.resources = resources;
+
+ }
+
+
+ /**
+ * Return the debugging detail level for this component.
+ */
+ public int getDebug() {
+
+ return (this.debug);
+
+ }
+
+
+ /**
+ * Set the debugging detail level for this component.
+ *
+ * @param debug The new debugging detail level
+ */
+ public void setDebug(int debug) {
+
+ this.debug = debug;
+
+ }
+
+
+ /**
+ * Return the "delegate first" flag for this class loader.
+ */
+ public boolean getDelegate() {
+
+ return (this.delegate);
+
+ }
+
+
+ /**
+ * Set the "delegate first" flag for this class loader.
+ *
+ * @param delegate The new "delegate first" flag
+ */
+ public void setDelegate(boolean delegate) {
+
+ this.delegate = delegate;
+
+ }
+
+
+ /**
+ * If there is a Java SecurityManager create a read FilePermission
+ * or JndiPermission for the file directory path.
+ *
+ * @param path file directory path
+ */
+ public void addPermission(String path) {
+ if (path == null) {
+ return;
+ }
+
+ if (securityManager != null) {
+ Permission permission = null;
+ if( path.startsWith("jndi:") || path.startsWith("jar:jndi:") ) {
+ if (!path.endsWith("/")) {
+ path = path + "/";
+ }
+ permission = new JndiPermission(path + "*");
+ addPermission(permission);
+ } else {
+ if (!path.endsWith(File.separator)) {
+ permission = new FilePermission(path, "read");
+ addPermission(permission);
+ path = path + File.separator;
+ }
+ permission = new FilePermission(path + "-", "read");
+ addPermission(permission);
+ }
+ }
+ }
+
+
+ /**
+ * If there is a Java SecurityManager create a read FilePermission
+ * or JndiPermission for URL.
+ *
+ * @param url URL for a file or directory on local system
+ */
+ public void addPermission(URL url) {
+ if (url != null) {
+ addPermission(url.toString());
+ }
+ }
+
+
+ /**
+ * If there is a Java SecurityManager create a Permission.
+ *
+ * @param url URL for a file or directory on local system
+ */
+ public void addPermission(Permission permission) {
+ if ((securityManager != null) && (permission != null)) {
+ permissionList.add(permission);
+ }
+ }
+
+
+ /**
+ * Return the JAR path.
+ */
+ public String getJarPath() {
+
+ return this.jarPath;
+
+ }
+
+
+ /**
+ * Change the Jar path.
+ */
+ public void setJarPath(String jarPath) {
+
+ this.jarPath = jarPath;
+
+ }
+
+
+ /**
+ * Change the work directory.
+ */
+ public void setWorkDir(File workDir) {
+ this.loaderDir = new File(workDir, "loader");
+ }
+
+
+ // ------------------------------------------------------- Reloader Methods
+
+
+ /**
+ * Add a new repository to the set of places this ClassLoader can look for
+ * classes to be loaded.
+ *
+ * @param repository Name of a source of classes to be loaded, such as a
+ * directory pathname, a JAR file pathname, or a ZIP file pathname
+ *
+ * @exception IllegalArgumentException if the specified repository is
+ * invalid or does not exist
+ */
+ public void addRepository(String repository) {
+
+ // Ignore any of the standard repositories, as they are set up using
+ // either addJar or addRepository
+ if (repository.startsWith("/WEB-INF/lib")
+ || repository.startsWith("/WEB-INF/classes"))
+ return;
+
+ // Add this repository to our underlying class loader
+ try {
+ URL url = new URL(repository);
+ super.addURL(url);
+ hasExternalRepositories = true;
+ repositoryURLs = null;
+ } catch (MalformedURLException e) {
+ IllegalArgumentException iae = new IllegalArgumentException
+ ("Invalid repository: " + repository);
+ jdkCompat.chainException(iae, e);
+ throw iae;
+ }
+
+ }
+
+
+ /**
+ * Add a new repository to the set of places this ClassLoader can look for
+ * classes to be loaded.
+ *
+ * @param repository Name of a source of classes to be loaded, such as a
+ * directory pathname, a JAR file pathname, or a ZIP file pathname
+ *
+ * @exception IllegalArgumentException if the specified repository is
+ * invalid or does not exist
+ */
+ synchronized void addRepository(String repository, File file) {
+
+ // Note : There should be only one (of course), but I think we should
+ // keep this a bit generic
+
+ if (repository == null)
+ return;
+
+ if (log.isDebugEnabled())
+ log.debug("addRepository(" + repository + ")");
+
+ int i;
+
+ // Add this repository to our internal list
+ String[] result = new String[repositories.length + 1];
+ for (i = 0; i < repositories.length; i++) {
+ result[i] = repositories[i];
+ }
+ result[repositories.length] = repository;
+ repositories = result;
+
+ // Add the file to the list
+ File[] result2 = new File[files.length + 1];
+ for (i = 0; i < files.length; i++) {
+ result2[i] = files[i];
+ }
+ result2[files.length] = file;
+ files = result2;
+
+ }
+
+
+ synchronized void addJar(String jar, JarFile jarFile, File file)
+ throws IOException {
+
+ if (jar == null)
+ return;
+ if (jarFile == null)
+ return;
+ if (file == null)
+ return;
+
+ if (log.isDebugEnabled())
+ log.debug("addJar(" + jar + ")");
+
+ int i;
+
+ if ((jarPath != null) && (jar.startsWith(jarPath))) {
+
+ String jarName = jar.substring(jarPath.length());
+ while (jarName.startsWith("/"))
+ jarName = jarName.substring(1);
+
+ String[] result = new String[jarNames.length + 1];
+ for (i = 0; i < jarNames.length; i++) {
+ result[i] = jarNames[i];
+ }
+ result[jarNames.length] = jarName;
+ jarNames = result;
+
+ }
+
+ try {
+
+ // Register the JAR for tracking
+
+ long lastModified =
+ ((ResourceAttributes) resources.getAttributes(jar))
+ .getLastModified();
+
+ String[] result = new String[paths.length + 1];
+ for (i = 0; i < paths.length; i++) {
+ result[i] = paths[i];
+ }
+ result[paths.length] = jar;
+ paths = result;
+
+ long[] result3 = new long[lastModifiedDates.length + 1];
+ for (i = 0; i < lastModifiedDates.length; i++) {
+ result3[i] = lastModifiedDates[i];
+ }
+ result3[lastModifiedDates.length] = lastModified;
+ lastModifiedDates = result3;
+
+ } catch (NamingException e) {
+ // Ignore
+ }
+
+ // If the JAR currently contains invalid classes, don't actually use it
+ // for classloading
+ if (!validateJarFile(file))
+ return;
+
+ JarFile[] result2 = new JarFile[jarFiles.length + 1];
+ for (i = 0; i < jarFiles.length; i++) {
+ result2[i] = jarFiles[i];
+ }
+ result2[jarFiles.length] = jarFile;
+ jarFiles = result2;
+
+ // Add the file to the list
+ File[] result4 = new File[jarRealFiles.length + 1];
+ for (i = 0; i < jarRealFiles.length; i++) {
+ result4[i] = jarRealFiles[i];
+ }
+ result4[jarRealFiles.length] = file;
+ jarRealFiles = result4;
+ }
+
+
+ /**
+ * Return a String array of the current repositories for this class
+ * loader. If there are no repositories, a zero-length array is
+ * returned.For security reason, returns a clone of the Array (since
+ * String are immutable).
+ */
+ public String[] findRepositories() {
+
+ return ((String[])repositories.clone());
+
+ }
+
+
+ /**
+ * Have one or more classes or resources been modified so that a reload
+ * is appropriate?
+ */
+ public boolean modified() {
+
+ if (log.isDebugEnabled())
+ log.debug("modified()");
+
+ // Checking for modified loaded resources
+ int length = paths.length;
+
+ // A rare race condition can occur in the updates of the two arrays
+ // It's totally ok if the latest class added is not checked (it will
+ // be checked the next time
+ int length2 = lastModifiedDates.length;
+ if (length > length2)
+ length = length2;
+
+ for (int i = 0; i < length; i++) {
+ try {
+ long lastModified =
+ ((ResourceAttributes) resources.getAttributes(paths[i]))
+ .getLastModified();
+ if (lastModified != lastModifiedDates[i]) {
+ if( log.isDebugEnabled() )
+ log.debug(" Resource '" + paths[i]
+ + "' was modified; Date is now: "
+ + new java.util.Date(lastModified) + " Was: "
+ + new java.util.Date(lastModifiedDates[i]));
+ return (true);
+ }
+ } catch (NamingException e) {
+ log.error(" Resource '" + paths[i] + "' is missing");
+ return (true);
+ }
+ }
+
+ length = jarNames.length;
+
+ // Check if JARs have been added or removed
+ if (getJarPath() != null) {
+
+ try {
+ NamingEnumeration enum_ = resources.listBindings(getJarPath());
+ int i = 0;
+ while (enum_.hasMoreElements() && (i < length)) {
+ NameClassPair ncPair = (NameClassPair) enum_.nextElement();
+ String name = ncPair.getName();
+ // Ignore non JARs present in the lib folder
+ if (!name.endsWith(".jar"))
+ continue;
+ if (!name.equals(jarNames[i])) {
+ // Missing JAR
+ log.info(" Additional JARs have been added : '"
+ + name + "'");
+ return (true);
+ }
+ i++;
+ }
+ if (enum_.hasMoreElements()) {
+ while (enum_.hasMoreElements()) {
+ NameClassPair ncPair =
+ (NameClassPair) enum_.nextElement();
+ String name = ncPair.getName();
+ // Additional non-JAR files are allowed
+ if (name.endsWith(".jar")) {
+ // There was more JARs
+ log.info(" Additional JARs have been added");
+ return (true);
+ }
+ }
+ } else if (i < jarNames.length) {
+ // There was less JARs
+ log.info(" Additional JARs have been added");
+ return (true);
+ }
+ } catch (NamingException e) {
+ if (log.isDebugEnabled())
+ log.debug(" Failed tracking modifications of '"
+ + getJarPath() + "'");
+ } catch (ClassCastException e) {
+ log.error(" Failed tracking modifications of '"
+ + getJarPath() + "' : " + e.getMessage());
+ }
+
+ }
+
+ // No classes have been modified
+ return (false);
+
+ }
+
+
+ /**
+ * Render a String representation of this object.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("WebappClassLoader\r\n");
+ sb.append(" delegate: ");
+ sb.append(delegate);
+ sb.append("\r\n");
+ sb.append(" repositories:\r\n");
+ if (repositories != null) {
+ for (int i = 0; i < repositories.length; i++) {
+ sb.append(" ");
+ sb.append(repositories[i]);
+ sb.append("\r\n");
+ }
+ }
+ if (this.parent != null) {
+ sb.append("----------> Parent Classloader:\r\n");
+ sb.append(this.parent.toString());
+ sb.append("\r\n");
+ }
+ return (sb.toString());
+
+ }
+
+
+ // ---------------------------------------------------- ClassLoader Methods
+
+
+ /**
+ * Add the specified URL to the classloader.
+ */
+ protected void addURL(URL url) {
+ super.addURL(url);
+ hasExternalRepositories = true;
+ repositoryURLs = null;
+ }
+
+
+ /**
+ * Find the specified class in our local repositories, if possible. If
+ * not found, throw <code>ClassNotFoundException</code>.
+ *
+ * @param name Name of the class to be loaded
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class findClass(String name) throws ClassNotFoundException {
+
+ if (log.isDebugEnabled())
+ log.debug(" findClass(" + name + ")");
+
+ // (1) Permission to define this class when using a SecurityManager
+ if (securityManager != null) {
+ int i = name.lastIndexOf('.');
+ if (i >= 0) {
+ try {
+ if (log.isTraceEnabled())
+ log.trace(" securityManager.checkPackageDefinition");
+ securityManager.checkPackageDefinition(name.substring(0,i));
+ } catch (Exception se) {
+ if (log.isTraceEnabled())
+ log.trace(" -->Exception-->ClassNotFoundException", se);
+ throw new ClassNotFoundException(name, se);
+ }
+ }
+ }
+
+ // Ask our superclass to locate this class, if possible
+ // (throws ClassNotFoundException if it is not found)
+ Class clazz = null;
+ try {
+ if (log.isTraceEnabled())
+ log.trace(" findClassInternal(" + name + ")");
+ try {
+ clazz = findClassInternal(name);
+ } catch(ClassNotFoundException cnfe) {
+ if (!hasExternalRepositories) {
+ throw cnfe;
+ }
+ } catch(AccessControlException ace) {
+ throw new ClassNotFoundException(name, ace);
+ } catch (RuntimeException e) {
+ if (log.isTraceEnabled())
+ log.trace(" -->RuntimeException Rethrown", e);
+ throw e;
+ }
+ if ((clazz == null) && hasExternalRepositories) {
+ try {
+ clazz = super.findClass(name);
+ } catch(AccessControlException ace) {
+ throw new ClassNotFoundException(name, ace);
+ } catch (RuntimeException e) {
+ if (log.isTraceEnabled())
+ log.trace(" -->RuntimeException Rethrown", e);
+ throw e;
+ }
+ }
+ if (clazz == null) {
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning ClassNotFoundException");
+ throw new ClassNotFoundException(name);
+ }
+ } catch (ClassNotFoundException e) {
+ if (log.isTraceEnabled())
+ log.trace(" --> Passing on ClassNotFoundException");
+ throw e;
+ }
+
+ // Return the class we have located
+ if (log.isTraceEnabled())
+ log.debug(" Returning class " + clazz);
+ if ((log.isTraceEnabled()) && (clazz != null))
+ log.debug(" Loaded by " + clazz.getClassLoader());
+ return (clazz);
+
+ }
+
+
+ /**
+ * Find the specified resource in our local repository, and return a
+ * <code>URL</code> refering to it, or <code>null</code> if this resource
+ * cannot be found.
+ *
+ * @param name Name of the resource to be found
+ */
+ public URL findResource(final String name) {
+
+ if (log.isDebugEnabled())
+ log.debug(" findResource(" + name + ")");
+
+ URL url = null;
+
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ if (entry == null) {
+ entry = findResourceInternal(name, name);
+ }
+ if (entry != null) {
+ url = entry.source;
+ }
+
+ if ((url == null) && hasExternalRepositories)
+ url = super.findResource(name);
+
+ if (log.isDebugEnabled()) {
+ if (url != null)
+ log.debug(" --> Returning '" + url.toString() + "'");
+ else
+ log.debug(" --> Resource not found, returning null");
+ }
+ return (url);
+
+ }
+
+
+ /**
+ * Return an enumeration of <code>URLs</code> representing all of the
+ * resources with the given name. If no resources with this name are
+ * found, return an empty enumeration.
+ *
+ * @param name Name of the resources to be found
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public Enumeration findResources(String name) throws IOException {
+
+ if (log.isDebugEnabled())
+ log.debug(" findResources(" + name + ")");
+
+ Vector result = new Vector();
+
+ int jarFilesLength = jarFiles.length;
+ int repositoriesLength = repositories.length;
+
+ int i;
+
+ // Looking at the repositories
+ for (i = 0; i < repositoriesLength; i++) {
+ try {
+ String fullPath = repositories[i] + name;
+ resources.lookup(fullPath);
+ // Note : Not getting an exception here means the resource was
+ // found
+ try {
+ result.addElement(getURI(new File(files[i], name)));
+ } catch (MalformedURLException e) {
+ // Ignore
+ }
+ } catch (NamingException e) {
+ }
+ }
+
+ // Looking at the JAR files
+ synchronized (jarFiles) {
+ openJARs();
+ for (i = 0; i < jarFilesLength; i++) {
+ JarEntry jarEntry = jarFiles[i].getJarEntry(name);
+ if (jarEntry != null) {
+ try {
+ String jarFakeUrl = getURI(jarRealFiles[i]).toString();
+ jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
+ result.addElement(new URL(jarFakeUrl));
+ } catch (MalformedURLException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+ // Adding the results of a call to the superclass
+ if (hasExternalRepositories) {
+
+ Enumeration otherResourcePaths = super.findResources(name);
+
+ while (otherResourcePaths.hasMoreElements()) {
+ result.addElement(otherResourcePaths.nextElement());
+ }
+
+ }
+
+ return result.elements();
+
+ }
+
+
+ /**
+ * Find the resource with the given name. A resource is some data
+ * (images, audio, text, etc.) that can be accessed by class code in a
+ * way that is independent of the location of the code. The name of a
+ * resource is a "/"-separated path name that identifies the resource.
+ * If the resource cannot be found, return <code>null</code>.
+ * <p>
+ * This method searches according to the following algorithm, returning
+ * as soon as it finds the appropriate URL. If the resource cannot be
+ * found, returns <code>null</code>.
+ * <ul>
+ * <li>If the <code>delegate</code> property is set to <code>true</code>,
+ * call the <code>getResource()</code> method of the parent class
+ * loader, if any.</li>
+ * <li>Call <code>findResource()</code> to find this resource in our
+ * locally defined repositories.</li>
+ * <li>Call the <code>getResource()</code> method of the parent class
+ * loader, if any.</li>
+ * </ul>
+ *
+ * @param name Name of the resource to return a URL for
+ */
+ public URL getResource(String name) {
+
+ if (log.isDebugEnabled())
+ log.debug("getResource(" + name + ")");
+ URL url = null;
+
+ // (1) Delegate to parent if requested
+ if (delegate) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ url = loader.getResource(name);
+ if (url != null) {
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning '" + url.toString() + "'");
+ return (url);
+ }
+ }
+
+ // (2) Search local repositories
+ url = findResource(name);
+ if (url != null) {
+ // Locating the repository for special handling in the case
+ // of a JAR
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ try {
+ String repository = entry.codeBase.toString();
+ if ((repository.endsWith(".jar"))
+ && (!(name.endsWith(".class")))) {
+ // Copy binary content to the work directory if not present
+ File resourceFile = new File(loaderDir, name);
+ url = resourceFile.toURL();
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning '" + url.toString() + "'");
+ return (url);
+ }
+
+ // (3) Delegate to parent unconditionally if not already attempted
+ if( !delegate ) {
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ url = loader.getResource(name);
+ if (url != null) {
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning '" + url.toString() + "'");
+ return (url);
+ }
+ }
+
+ // (4) Resource was not found
+ if (log.isDebugEnabled())
+ log.debug(" --> Resource not found, returning null");
+ return (null);
+
+ }
+
+
+ /**
+ * Find the resource with the given name, and return an input stream
+ * that can be used for reading it. The search order is as described
+ * for <code>getResource()</code>, after checking to see if the resource
+ * data has been previously cached. If the resource cannot be found,
+ * return <code>null</code>.
+ *
+ * @param name Name of the resource to return an input stream for
+ */
+ public InputStream getResourceAsStream(String name) {
+
+ if (log.isDebugEnabled())
+ log.debug("getResourceAsStream(" + name + ")");
+ InputStream stream = null;
+
+ // (0) Check for a cached copy of this resource
+ stream = findLoadedResource(name);
+ if (stream != null) {
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning stream from cache");
+ return (stream);
+ }
+
+ // (1) Delegate to parent if requested
+ if (delegate) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ stream = loader.getResourceAsStream(name);
+ if (stream != null) {
+ // FIXME - cache???
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning stream from parent");
+ return (stream);
+ }
+ }
+
+ // (2) Search local repositories
+ if (log.isDebugEnabled())
+ log.debug(" Searching local repositories");
+ URL url = findResource(name);
+ if (url != null) {
+ // FIXME - cache???
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning stream from local");
+ stream = findLoadedResource(name);
+ try {
+ if (hasExternalRepositories && (stream == null))
+ stream = url.openStream();
+ } catch (IOException e) {
+ ; // Ignore
+ }
+ if (stream != null)
+ return (stream);
+ }
+
+ // (3) Delegate to parent unconditionally
+ if (!delegate) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader unconditionally " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ stream = loader.getResourceAsStream(name);
+ if (stream != null) {
+ // FIXME - cache???
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning stream from parent");
+ return (stream);
+ }
+ }
+
+ // (4) Resource was not found
+ if (log.isDebugEnabled())
+ log.debug(" --> Resource not found, returning null");
+ return (null);
+
+ }
+
+
+ /**
+ * Load the class with the specified name. This method searches for
+ * classes in the same manner as <code>loadClass(String, boolean)</code>
+ * with <code>false</code> as the second argument.
+ *
+ * @param name Name of the class to be loaded
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class loadClass(String name) throws ClassNotFoundException {
+
+ return (loadClass(name, false));
+
+ }
+
+
+ /**
+ * Load the class with the specified name, searching using the following
+ * algorithm until it finds and returns the class. If the class cannot
+ * be found, returns <code>ClassNotFoundException</code>.
+ * <ul>
+ * <li>Call <code>findLoadedClass(String)</code> to check if the
+ * class has already been loaded. If it has, the same
+ * <code>Class</code> object is returned.</li>
+ * <li>If the <code>delegate</code> property is set to <code>true</code>,
+ * call the <code>loadClass()</code> method of the parent class
+ * loader, if any.</li>
+ * <li>Call <code>findClass()</code> to find this class in our locally
+ * defined repositories.</li>
+ * <li>Call the <code>loadClass()</code> method of our parent
+ * class loader, if any.</li>
+ * </ul>
+ * If the class was found using the above steps, and the
+ * <code>resolve</code> flag is <code>true</code>, this method will then
+ * call <code>resolveClass(Class)</code> on the resulting Class object.
+ *
+ * @param name Name of the class to be loaded
+ * @param resolve If <code>true</code> then resolve the class
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class loadClass(String name, boolean resolve)
+ throws ClassNotFoundException {
+
+ if (log.isDebugEnabled())
+ log.debug("loadClass(" + name + ", " + resolve + ")");
+ Class clazz = null;
+
+ // Don't load classes if class loader is stopped
+ if (!started) {
+ log.info(sm.getString("webappClassLoader.stopped"));
+ throw new ThreadDeath();
+ }
+
+ // (0) Check our previously loaded local class cache
+ clazz = findLoadedClass0(name);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Returning class from cache");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+
+ // (0.1) Check our previously loaded class cache
+ clazz = findLoadedClass(name);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Returning class from cache");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+
+ // (0.2) Try loading the class with the system class loader, to prevent
+ // the webapp from overriding J2SE classes
+ // GOOGLE: use the bootstrap loader, not the system loader; it breaks
+ // embedding.
+ try {
+ // clazz = system.loadClass(name);
+ clazz = Class.forName(name, false, null);
+ if (clazz != null) {
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ // Ignore
+ }
+
+ // (0.5) Permission to access this class when using a SecurityManager
+ if (securityManager != null) {
+ int i = name.lastIndexOf('.');
+ if (i >= 0) {
+ try {
+ securityManager.checkPackageAccess(name.substring(0,i));
+ } catch (SecurityException se) {
+ String error = "Security Violation, attempt to use " +
+ "Restricted Class: " + name;
+ log.info(error, se);
+ throw new ClassNotFoundException(error, se);
+ }
+ }
+ }
+
+ boolean delegateLoad = delegate || filter(name);
+
+ // (1) Delegate to our parent if requested
+ if (delegateLoad) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader1 " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ try {
+ clazz = loader.loadClass(name);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Loading class from parent");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ ;
+ }
+ }
+
+ // (2) Search local repositories
+ if (log.isDebugEnabled())
+ log.debug(" Searching local repositories");
+ try {
+ clazz = findClass(name);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Loading class from local repository");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ ;
+ }
+
+ // (3) Delegate to parent unconditionally
+ if (!delegateLoad) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader at end: " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ try {
+ clazz = loader.loadClass(name);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Loading class from parent");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ ;
+ }
+ }
+
+ throw new ClassNotFoundException(name);
+ }
+
+
+ /**
+ * Get the Permissions for a CodeSource. If this instance
+ * of WebappClassLoader is for a web application context,
+ * add read FilePermission or JndiPermissions for the base
+ * directory (if unpacked),
+ * the context URL, and jar file resources.
+ *
+ * @param codeSource where the code was loaded from
+ * @return PermissionCollection for CodeSource
+ */
+ protected PermissionCollection getPermissions(CodeSource codeSource) {
+
+ String codeUrl = codeSource.getLocation().toString();
+ PermissionCollection pc;
+ if ((pc = (PermissionCollection)loaderPC.get(codeUrl)) == null) {
+ pc = super.getPermissions(codeSource);
+ if (pc != null) {
+ Iterator perms = permissionList.iterator();
+ while (perms.hasNext()) {
+ Permission p = (Permission)perms.next();
+ pc.add(p);
+ }
+ loaderPC.put(codeUrl,pc);
+ }
+ }
+ return (pc);
+
+ }
+
+
+ /**
+ * Returns the search path of URLs for loading classes and resources.
+ * This includes the original list of URLs specified to the constructor,
+ * along with any URLs subsequently appended by the addURL() method.
+ * @return the search path of URLs for loading classes and resources.
+ */
+ public URL[] getURLs() {
+
+ if (repositoryURLs != null) {
+ return repositoryURLs;
+ }
+
+ URL[] external = super.getURLs();
+
+ int filesLength = files.length;
+ int jarFilesLength = jarRealFiles.length;
+ int length = filesLength + jarFilesLength + external.length;
+ int i;
+
+ try {
+
+ URL[] urls = new URL[length];
+ for (i = 0; i < length; i++) {
+ if (i < filesLength) {
+ urls[i] = getURL(files[i]);
+ } else if (i < filesLength + jarFilesLength) {
+ urls[i] = getURL(jarRealFiles[i - filesLength]);
+ } else {
+ urls[i] = external[i - filesLength - jarFilesLength];
+ }
+ }
+
+ repositoryURLs = urls;
+
+ } catch (MalformedURLException e) {
+ repositoryURLs = new URL[0];
+ }
+
+ return repositoryURLs;
+
+ }
+
+
+ // ------------------------------------------------------ Lifecycle Methods
+
+
+ /**
+ * Add a lifecycle event listener to this component.
+ *
+ * @param listener The listener to add
+ */
+ public void addLifecycleListener(LifecycleListener listener) {
+ }
+
+
+ /**
+ * Get the lifecycle listeners associated with this lifecycle. If this
+ * Lifecycle has no listeners registered, a zero-length array is returned.
+ */
+ public LifecycleListener[] findLifecycleListeners() {
+ return new LifecycleListener[0];
+ }
+
+
+ /**
+ * Remove a lifecycle event listener from this component.
+ *
+ * @param listener The listener to remove
+ */
+ public void removeLifecycleListener(LifecycleListener listener) {
+ }
+
+
+ /**
+ * Start the class loader.
+ *
+ * @exception LifecycleException if a lifecycle error occurs
+ */
+ public void start() throws LifecycleException {
+
+ started = true;
+
+ }
+
+
+ /**
+ * Stop the class loader.
+ *
+ * @exception LifecycleException if a lifecycle error occurs
+ */
+ public void stop() throws LifecycleException {
+
+ started = false;
+
+ int length = files.length;
+ for (int i = 0; i < length; i++) {
+ files[i] = null;
+ }
+
+ length = jarFiles.length;
+ for (int i = 0; i < length; i++) {
+ try {
+ if (jarFiles[i] != null) {
+ jarFiles[i].close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+ jarFiles[i] = null;
+ }
+
+ notFoundResources.clear();
+ resourceEntries.clear();
+ resources = null;
+ repositories = null;
+ repositoryURLs = null;
+ files = null;
+ jarFiles = null;
+ jarRealFiles = null;
+ jarPath = null;
+ jarNames = null;
+ lastModifiedDates = null;
+ paths = null;
+ hasExternalRepositories = false;
+ parent = null;
+
+ permissionList.clear();
+ loaderPC.clear();
+
+ if (loaderDir != null) {
+ deleteDir(loaderDir);
+ }
+
+ org.apache.commons.logging.LogFactory.release(this);
+
+ }
+
+
+ /**
+ * Used to periodically signal to the classloader to release
+ * JAR resources.
+ */
+ public void closeJARs(boolean force) {
+ if (jarFiles.length > 0) {
+ try {
+ synchronized (jarFiles) {
+ if (force || (System.currentTimeMillis()
+ > (lastJarAccessed + 90000))) {
+ for (int i = 0; i < jarFiles.length; i++) {
+ if (jarFiles[i] != null) {
+ jarFiles[i].close();
+ jarFiles[i] = null;
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ log("Failed to close JAR", e);
+ }
+ }
+ }
+
+
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * Used to periodically signal to the classloader to release JAR resources.
+ */
+ protected void openJARs() {
+ if (started && (jarFiles.length > 0)) {
+ lastJarAccessed = System.currentTimeMillis();
+ if (jarFiles[0] == null) {
+ try {
+ for (int i = 0; i < jarFiles.length; i++) {
+ jarFiles[i] = new JarFile(jarRealFiles[i]);
+ }
+ } catch (IOException e) {
+ log("Failed to open JAR", e);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Find specified class in local repositories.
+ *
+ * @return the loaded class, or null if the class isn't found
+ */
+ protected Class findClassInternal(String name)
+ throws ClassNotFoundException {
+
+ if (!validate(name))
+ throw new ClassNotFoundException(name);
+
+ String tempPath = name.replace('.', '/');
+ String classPath = tempPath + ".class";
+
+ ResourceEntry entry = null;
+
+ entry = findResourceInternal(name, classPath);
+
+ if ((entry == null) || (entry.binaryContent == null))
+ throw new ClassNotFoundException(name);
+
+ Class clazz = entry.loadedClass;
+ if (clazz != null)
+ return clazz;
+
+ // Looking up the package
+ String packageName = null;
+ int pos = name.lastIndexOf('.');
+ if (pos != -1)
+ packageName = name.substring(0, pos);
+
+ Package pkg = null;
+
+ if (packageName != null) {
+
+ pkg = getPackage(packageName);
+
+ // Define the package (if null)
+ if (pkg == null) {
+ if (entry.manifest == null) {
+ definePackage(packageName, null, null, null, null, null,
+ null, null);
+ } else {
+ definePackage(packageName, entry.manifest, entry.codeBase);
+ }
+ }
+
+ }
+
+ // Create the code source object
+ CodeSource codeSource =
+ new CodeSource(entry.codeBase, entry.certificates);
+
+ if (securityManager != null) {
+
+ // Checking sealing
+ if (pkg != null) {
+ boolean sealCheck = true;
+ if (pkg.isSealed()) {
+ sealCheck = pkg.isSealed(entry.codeBase);
+ } else {
+ sealCheck = (entry.manifest == null)
+ || !isPackageSealed(packageName, entry.manifest);
+ }
+ if (!sealCheck)
+ throw new SecurityException
+ ("Sealing violation loading " + name + " : Package "
+ + packageName + " is sealed.");
+ }
+
+ }
+
+ if (entry.loadedClass == null) {
+ synchronized (this) {
+ if (entry.loadedClass == null) {
+ clazz = defineClass(name, entry.binaryContent, 0,
+ entry.binaryContent.length,
+ codeSource);
+ entry.loadedClass = clazz;
+ entry.binaryContent = null;
+ entry.source = null;
+ entry.codeBase = null;
+ entry.manifest = null;
+ entry.certificates = null;
+ } else {
+ clazz = entry.loadedClass;
+ }
+ }
+ } else {
+ clazz = entry.loadedClass;
+ }
+
+ return clazz;
+
+ }
+
+ /**
+ * Find specified resource in local repositories. This block
+ * will execute under an AccessControl.doPrivilege block.
+ *
+ * @return the loaded resource, or null if the resource isn't found
+ */
+ private ResourceEntry findResourceInternal(File file, String path){
+ ResourceEntry entry = new ResourceEntry();
+ try {
+ entry.source = getURI(new File(file, path));
+ entry.codeBase = getURL(new File(file, path));
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ return entry;
+ }
+
+
+ /**
+ * Find specified resource in local repositories.
+ *
+ * @return the loaded resource, or null if the resource isn't found
+ */
+ protected ResourceEntry findResourceInternal(String name, String path) {
+
+ if (!started) {
+ log.info(sm.getString("webappClassLoader.stopped"));
+ return null;
+ }
+
+ if ((name == null) || (path == null))
+ return null;
+
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ if (entry != null)
+ return entry;
+
+ int contentLength = -1;
+ InputStream binaryStream = null;
+
+ int jarFilesLength = jarFiles.length;
+ int repositoriesLength = repositories.length;
+
+ int i;
+
+ Resource resource = null;
+
+ for (i = 0; (entry == null) && (i < repositoriesLength); i++) {
+ try {
+
+ String fullPath = repositories[i] + path;
+
+ Object lookupResult = resources.lookup(fullPath);
+ if (lookupResult instanceof Resource) {
+ resource = (Resource) lookupResult;
+ }
+
+ // Note : Not getting an exception here means the resource was
+ // found
+ if (securityManager != null) {
+ PrivilegedAction dp =
+ new PrivilegedFindResource(files[i], path);
+ entry = (ResourceEntry)AccessController.doPrivileged(dp);
+ } else {
+ entry = findResourceInternal(files[i], path);
+ }
+
+ ResourceAttributes attributes =
+ (ResourceAttributes) resources.getAttributes(fullPath);
+ contentLength = (int) attributes.getContentLength();
+ entry.lastModified = attributes.getLastModified();
+
+ if (resource != null) {
+
+ try {
+ binaryStream = resource.streamContent();
+ } catch (IOException e) {
+ return null;
+ }
+
+ // Register the full path for modification checking
+ // Note: Only syncing on a 'constant' object is needed
+ synchronized (allPermission) {
+
+ int j;
+
+ long[] result2 =
+ new long[lastModifiedDates.length + 1];
+ for (j = 0; j < lastModifiedDates.length; j++) {
+ result2[j] = lastModifiedDates[j];
+ }
+ result2[lastModifiedDates.length] = entry.lastModified;
+ lastModifiedDates = result2;
+
+ String[] result = new String[paths.length + 1];
+ for (j = 0; j < paths.length; j++) {
+ result[j] = paths[j];
+ }
+ result[paths.length] = fullPath;
+ paths = result;
+
+ }
+
+ }
+
+ } catch (NamingException e) {
+ }
+ }
+
+ if ((entry == null) && (notFoundResources.containsKey(name)))
+ return null;
+
+ JarEntry jarEntry = null;
+
+ synchronized (jarFiles) {
+
+ openJARs();
+ for (i = 0; (entry == null) && (i < jarFilesLength); i++) {
+
+ jarEntry = jarFiles[i].getJarEntry(path);
+
+ if (jarEntry != null) {
+
+ entry = new ResourceEntry();
+ try {
+ entry.codeBase = getURL(jarRealFiles[i]);
+ String jarFakeUrl = getURI(jarRealFiles[i]).toString();
+ jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
+ entry.source = new URL(jarFakeUrl);
+ entry.lastModified = jarRealFiles[i].lastModified();
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ contentLength = (int) jarEntry.getSize();
+ try {
+ entry.manifest = jarFiles[i].getManifest();
+ binaryStream = jarFiles[i].getInputStream(jarEntry);
+ } catch (IOException e) {
+ return null;
+ }
+
+ // Extract resources contained in JAR to the workdir
+ if (!(path.endsWith(".class"))) {
+ byte[] buf = new byte[1024];
+ File resourceFile = new File
+ (loaderDir, jarEntry.getName());
+ if (!resourceFile.exists()) {
+ Enumeration entries = jarFiles[i].entries();
+ while (entries.hasMoreElements()) {
+ JarEntry jarEntry2 =
+ (JarEntry) entries.nextElement();
+ if (!(jarEntry2.isDirectory())
+ && (!jarEntry2.getName().endsWith
+ (".class"))) {
+ resourceFile = new File
+ (loaderDir, jarEntry2.getName());
+ resourceFile.getParentFile().mkdirs();
+ FileOutputStream os = null;
+ InputStream is = null;
+ try {
+ is = jarFiles[i].getInputStream
+ (jarEntry2);
+ os = new FileOutputStream
+ (resourceFile);
+ while (true) {
+ int n = is.read(buf);
+ if (n <= 0) {
+ break;
+ }
+ os.write(buf, 0, n);
+ }
+ } catch (IOException e) {
+ // Ignore
+ } finally {
+ try {
+ if (is != null) {
+ is.close();
+ }
+ } catch (IOException e) {
+ }
+ try {
+ if (os != null) {
+ os.close();
+ }
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ }
+
+ if (entry == null) {
+ synchronized (notFoundResources) {
+ notFoundResources.put(name, name);
+ }
+ return null;
+ }
+
+ if (binaryStream != null) {
+
+ byte[] binaryContent = new byte[contentLength];
+
+ try {
+ int pos = 0;
+
+ while (true) {
+ int n = binaryStream.read(binaryContent, pos,
+ binaryContent.length - pos);
+ if (n <= 0)
+ break;
+ pos += n;
+ }
+ binaryStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ entry.binaryContent = binaryContent;
+
+ // The certificates are only available after the JarEntry
+ // associated input stream has been fully read
+ if (jarEntry != null) {
+ entry.certificates = jarEntry.getCertificates();
+ }
+
+ }
+
+ }
+
+ // Add the entry in the local resource repository
+ synchronized (resourceEntries) {
+ // Ensures that all the threads which may be in a race to load
+ // a particular class all end up with the same ResourceEntry
+ // instance
+ ResourceEntry entry2 = (ResourceEntry) resourceEntries.get(name);
+ if (entry2 == null) {
+ resourceEntries.put(name, entry);
+ } else {
+ entry = entry2;
+ }
+ }
+
+ return entry;
+
+ }
+
+
+ /**
+ * Returns true if the specified package name is sealed according to the
+ * given manifest.
+ */
+ protected boolean isPackageSealed(String name, Manifest man) {
+
+ String path = name + "/";
+ Attributes attr = man.getAttributes(path);
+ String sealed = null;
+ if (attr != null) {
+ sealed = attr.getValue(Name.SEALED);
+ }
+ if (sealed == null) {
+ if ((attr = man.getMainAttributes()) != null) {
+ sealed = attr.getValue(Name.SEALED);
+ }
+ }
+ return "true".equalsIgnoreCase(sealed);
+
+ }
+
+
+ /**
+ * Finds the resource with the given name if it has previously been
+ * loaded and cached by this class loader, and return an input stream
+ * to the resource data. If this resource has not been cached, return
+ * <code>null</code>.
+ *
+ * @param name Name of the resource to return
+ */
+ protected InputStream findLoadedResource(String name) {
+
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ if (entry != null) {
+ if (entry.binaryContent != null)
+ return new ByteArrayInputStream(entry.binaryContent);
+ }
+ return (null);
+
+ }
+
+
+ /**
+ * Finds the class with the given name if it has previously been
+ * loaded and cached by this class loader, and return the Class object.
+ * If this class has not been cached, return <code>null</code>.
+ *
+ * @param name Name of the resource to return
+ */
+ protected Class findLoadedClass0(String name) {
+
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ if (entry != null) {
+ return entry.loadedClass;
+ }
+ return (null); // FIXME - findLoadedResource()
+
+ }
+
+
+ /**
+ * Refresh the system policy file, to pick up eventual changes.
+ */
+ protected void refreshPolicy() {
+
+ try {
+ // The policy file may have been modified to adjust
+ // permissions, so we're reloading it when loading or
+ // reloading a Context
+ Policy policy = Policy.getPolicy();
+ policy.refresh();
+ } catch (AccessControlException e) {
+ // Some policy files may restrict this, even for the core,
+ // so this exception is ignored
+ }
+
+ }
+
+
+ /**
+ * Filter classes.
+ *
+ * @param name class name
+ * @return true if the class should be filtered
+ */
+ protected boolean filter(String name) {
+
+ if (name == null)
+ return false;
+
+ // Looking up the package
+ String packageName = null;
+ int pos = name.lastIndexOf('.');
+ if (pos != -1)
+ packageName = name.substring(0, pos);
+ else
+ return false;
+
+ for (int i = 0; i < packageTriggers.length; i++) {
+ if (packageName.startsWith(packageTriggers[i]))
+ return true;
+ }
+
+ return false;
+
+ }
+
+
+ /**
+ * Validate a classname. As per SRV.9.7.2, we must restict loading of
+ * classes from J2SE (java.*) and classes of the servlet API
+ * (javax.servlet.*). That should enhance robustness and prevent a number
+ * of user error (where an older version of servlet.jar would be present
+ * in /WEB-INF/lib).
+ *
+ * @param name class name
+ * @return true if the name is valid
+ */
+ protected boolean validate(String name) {
+
+ if (name == null)
+ return false;
+ if (name.startsWith("java."))
+ return false;
+
+ return true;
+
+ }
+
+
+ /**
+ * Check the specified JAR file, and return <code>true</code> if it does
+ * not contain any of the trigger classes.
+ *
+ * @param jarfile The JAR file to be checked
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ private boolean validateJarFile(File jarfile)
+ throws IOException {
+
+ if (triggers == null)
+ return (true);
+ JarFile jarFile = new JarFile(jarfile);
+ for (int i = 0; i < triggers.length; i++) {
+ Class clazz = null;
+ try {
+ if (parent != null) {
+ clazz = parent.loadClass(triggers[i]);
+ } else {
+ clazz = Class.forName(triggers[i]);
+ }
+ } catch (Throwable t) {
+ clazz = null;
+ }
+ if (clazz == null)
+ continue;
+ String name = triggers[i].replace('.', '/') + ".class";
+ if (log.isDebugEnabled())
+ log.debug(" Checking for " + name);
+ JarEntry jarEntry = jarFile.getJarEntry(name);
+ if (jarEntry != null) {
+ log.info("validateJarFile(" + jarfile +
+ ") - jar not loaded. See Servlet Spec 2.3, "
+ + "section 9.7.2. Offending class: " + name);
+ jarFile.close();
+ return (false);
+ }
+ }
+ jarFile.close();
+ return (true);
+
+ }
+
+
+ /**
+ * Get URL.
+ */
+ protected URL getURL(File file)
+ throws MalformedURLException {
+
+ File realFile = file;
+ try {
+ realFile = realFile.getCanonicalFile();
+ } catch (IOException e) {
+ // Ignore
+ }
+ return realFile.toURL();
+
+ }
+
+
+ /**
+ * Get URL.
+ */
+ protected URL getURI(File file)
+ throws MalformedURLException {
+
+ return jdkCompat.getURI(file);
+
+ }
+
+
+ /**
+ * Delete the specified directory, including all of its contents and
+ * subdirectories recursively.
+ *
+ * @param dir File object representing the directory to be deleted
+ */
+ protected static void deleteDir(File dir) {
+
+ String files[] = dir.list();
+ if (files == null) {
+ files = new String[0];
+ }
+ for (int i = 0; i < files.length; i++) {
+ File file = new File(dir, files[i]);
+ if (file.isDirectory()) {
+ deleteDir(file);
+ } else {
+ file.delete();
+ }
+ }
+ dir.delete();
+
+ }
+
+
+ /**
+ * Log a debugging output message.
+ *
+ * @param message Message to be logged
+ */
+ private void log(String message) {
+
+ System.out.println("WebappClassLoader: " + message);
+
+ }
+
+
+ /**
+ * Log a debugging output message with an exception.
+ *
+ * @param message Message to be logged
+ * @param throwable Exception to be logged
+ */
+ private void log(String message, Throwable throwable) {
+
+ System.out.println("WebappClassLoader: " + message);
+ throwable.printStackTrace(System.out);
+
+ }
+
+}
diff --git a/dev/core/src/org/apache/catalina/loader/WebappLoader.java b/dev/core/src/org/apache/catalina/loader/WebappLoader.java
deleted file mode 100644
index a38aeba..0000000
--- a/dev/core/src/org/apache/catalina/loader/WebappLoader.java
+++ /dev/null
@@ -1,1238 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache 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.
- */
-// Modified by Google
-package org.apache.catalina.loader;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.beans.PropertyChangeSupport;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FilePermission;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.net.URLStreamHandlerFactory;
-import java.util.ArrayList;
-import java.util.jar.JarFile;
-
-import javax.management.MBeanRegistration;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-import javax.naming.Binding;
-import javax.naming.NameClassPair;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.DirContext;
-import javax.servlet.ServletContext;
-
-import org.apache.catalina.Container;
-import org.apache.catalina.Context;
-import org.apache.catalina.DefaultContext;
-import org.apache.catalina.Engine;
-import org.apache.catalina.Globals;
-import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleException;
-import org.apache.catalina.LifecycleListener;
-import org.apache.catalina.Loader;
-import org.apache.catalina.Logger;
-import org.apache.catalina.core.StandardContext;
-import org.apache.catalina.util.LifecycleSupport;
-import org.apache.catalina.util.StringManager;
-import org.apache.commons.modeler.Registry;
-import org.apache.naming.resources.DirContextURLStreamHandler;
-import org.apache.naming.resources.DirContextURLStreamHandlerFactory;
-import org.apache.naming.resources.Resource;
-
-/**
- * Classloader implementation which is specialized for handling web applications
- * in the most efficient way, while being Catalina aware (all accesses to
- * resources are made through the DirContext interface). This class loader
- * supports detection of modified Java classes, which can be used to implement
- * auto-reload support.
- * <p>
- * This class loader is configured by adding the pathnames of directories, JAR
- * files, and ZIP files with the <code>addRepository()</code> method, prior to
- * calling <code>start()</code>. When a new class is required, these
- * repositories will be consulted first to locate the class. If it is not
- * present, the system class loader will be used instead.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
- * @version $Revision: 1.27 $ $Date: 2004/03/02 12:31:57 $
- */
-
-public class WebappLoader implements Lifecycle, Loader, PropertyChangeListener,
- MBeanRegistration {
-
- // ----------------------------------------------------------- Constructors
-
- /**
- * Construct a new WebappLoader with no defined parent class loader (so that
- * the actual parent will be the system class loader).
- */
- public WebappLoader() {
-
- this(null);
-
- }
-
- /**
- * Construct a new WebappLoader with the specified class loader to be defined
- * as the parent of the ClassLoader we ultimately create.
- *
- * @param parent The parent class loader
- */
- public WebappLoader(ClassLoader parent) {
- super();
- this.parentClassLoader = parent;
- }
-
- // ----------------------------------------------------- Instance Variables
-
- /**
- * First load of the class.
- */
- private static boolean first = true;
-
- /**
- * The class loader being managed by this Loader component.
- */
- private WebappClassLoader classLoader = null;
-
- /**
- * The Container with which this Loader has been associated.
- */
- private Container container = null;
-
- /**
- * The debugging detail level for this component.
- */
- private int debug = 0;
-
- /**
- * The DefaultContext with which this Loader is associated.
- */
- protected DefaultContext defaultContext = null;
-
- /**
- * The "follow standard delegation model" flag that will be used to configure
- * our ClassLoader.
- */
- private boolean delegate = false;
-
- /**
- * The descriptive information about this Loader implementation.
- */
- private static final String info = "org.apache.catalina.loader.WebappLoader/1.0";
-
- /**
- * The lifecycle event support for this component.
- */
- protected LifecycleSupport lifecycle = new LifecycleSupport(this);
-
- /**
- * The Java class name of the ClassLoader implementation to be used. This
- * class should extend WebappClassLoader, otherwise, a different loader
- * implementation must be used.
- */
- private String loaderClass = "org.apache.catalina.loader.WebappClassLoader";
-
- /**
- * The parent class loader of the class loader we will create.
- */
- private ClassLoader parentClassLoader = null;
-
- /**
- * The reloadable flag for this Loader.
- */
- private boolean reloadable = false;
-
- /**
- * The set of repositories associated with this class loader.
- */
- private String repositories[] = new String[0];
-
- /**
- * The string manager for this package.
- */
- protected static final StringManager sm = StringManager.getManager(Constants.Package);
-
- /**
- * Has this component been started?
- */
- private boolean started = false;
-
- /**
- * The property change support for this component.
- */
- protected PropertyChangeSupport support = new PropertyChangeSupport(this);
-
- /**
- * Classpath set in the loader.
- */
- private String classpath = null;
-
- /**
- * Repositories that are set in the loader, for JMX. GOOGLE: Added type
- * information.
- */
- private ArrayList<String> loaderRepositories = null;
-
- // ------------------------------------------------------------- Properties
-
- /**
- * Return the Java class loader to be used by this Container.
- */
- public ClassLoader getClassLoader() {
-
- /*
- * GOOGLE: When tomcat is embedded (as we are doing), classLoader is always
- * null. Returning the parentClassLoader seems to do the right thing.
- */
- if (classLoader != null) {
- return classLoader;
- } else {
- return parentClassLoader;
- }
-
- }
-
- /**
- * Return the Container with which this Logger has been associated.
- */
- public Container getContainer() {
-
- return (container);
-
- }
-
- /**
- * Set the Container with which this Logger has been associated.
- *
- * @param container The associated Container
- */
- public void setContainer(Container container) {
-
- // Deregister from the old Container (if any)
- if ((this.container != null) && (this.container instanceof Context))
- ((Context) this.container).removePropertyChangeListener(this);
-
- // Process this property change
- Container oldContainer = this.container;
- this.container = container;
- support.firePropertyChange("container", oldContainer, this.container);
-
- // Register with the new Container (if any)
- if ((this.container != null) && (this.container instanceof Context)) {
- setReloadable(((Context) this.container).getReloadable());
- ((Context) this.container).addPropertyChangeListener(this);
- }
-
- }
-
- /**
- * Return the DefaultContext with which this Loader is associated. XXX What is
- * that ???
- */
- public DefaultContext getDefaultContext() {
-
- return (this.defaultContext);
-
- }
-
- /**
- * Set the DefaultContext with which this Loader is associated.
- *
- * @param defaultContext The newly associated DefaultContext
- */
- public void setDefaultContext(DefaultContext defaultContext) {
-
- DefaultContext oldDefaultContext = this.defaultContext;
- this.defaultContext = defaultContext;
- support.firePropertyChange("defaultContext", oldDefaultContext,
- this.defaultContext);
-
- }
-
- /**
- * Return the debugging detail level for this component.
- */
- public int getDebug() {
-
- return (this.debug);
-
- }
-
- /**
- * Set the debugging detail level for this component.
- *
- * @param debug The new debugging detail level
- */
- public void setDebug(int debug) {
-
- int oldDebug = this.debug;
- this.debug = debug;
- support.firePropertyChange("debug", new Integer(oldDebug), new Integer(
- this.debug));
-
- }
-
- /**
- * Return the "follow standard delegation model" flag used to configure our
- * ClassLoader.
- */
- public boolean getDelegate() {
-
- return (this.delegate);
-
- }
-
- /**
- * Set the "follow standard delegation model" flag used to configure our
- * ClassLoader.
- *
- * @param delegate The new flag
- */
- public void setDelegate(boolean delegate) {
-
- boolean oldDelegate = this.delegate;
- this.delegate = delegate;
- support.firePropertyChange("delegate", new Boolean(oldDelegate),
- new Boolean(this.delegate));
-
- }
-
- /**
- * Return descriptive information about this Loader implementation and the
- * corresponding version number, in the format
- * <code><description>/<version></code>.
- */
- public String getInfo() {
-
- return (info);
-
- }
-
- /**
- * Return the ClassLoader class name.
- */
- public String getLoaderClass() {
-
- return (this.loaderClass);
-
- }
-
- /**
- * Set the ClassLoader class name.
- *
- * @param loaderClass The new ClassLoader class name
- */
- public void setLoaderClass(String loaderClass) {
-
- this.loaderClass = loaderClass;
-
- }
-
- /**
- * Return the reloadable flag for this Loader.
- */
- public boolean getReloadable() {
-
- return (this.reloadable);
-
- }
-
- /**
- * Set the reloadable flag for this Loader.
- *
- * @param reloadable The new reloadable flag
- */
- public void setReloadable(boolean reloadable) {
-
- // Process this property change
- boolean oldReloadable = this.reloadable;
- this.reloadable = reloadable;
- support.firePropertyChange("reloadable", new Boolean(oldReloadable),
- new Boolean(this.reloadable));
-
- }
-
- // --------------------------------------------------------- Public Methods
-
- /**
- * Add a property change listener to this component.
- *
- * @param listener The listener to add
- */
- public void addPropertyChangeListener(PropertyChangeListener listener) {
-
- support.addPropertyChangeListener(listener);
-
- }
-
- /**
- * Add a new repository to the set of repositories for this class loader.
- *
- * @param repository Repository to be added
- */
- public void addRepository(String repository) {
-
- if (log.isDebugEnabled())
- log.debug(sm.getString("webappLoader.addRepository", repository));
-
- for (int i = 0; i < repositories.length; i++) {
- if (repository.equals(repositories[i]))
- return;
- }
- String results[] = new String[repositories.length + 1];
- for (int i = 0; i < repositories.length; i++)
- results[i] = repositories[i];
- results[repositories.length] = repository;
- repositories = results;
-
- if (started && (classLoader != null)) {
- classLoader.addRepository(repository);
- if (loaderRepositories != null)
- loaderRepositories.add(repository);
- setClassPath();
- }
-
- }
-
- /**
- * Return the set of repositories defined for this class loader. If none are
- * defined, a zero-length array is returned. For security reason, returns a
- * clone of the Array (since String are immutable).
- */
- public String[] findRepositories() {
-
- return ((String[]) repositories.clone());
-
- }
-
- public String[] getRepositories() {
- return ((String[]) repositories.clone());
- }
-
- /**
- * Extra repositories for this loader
- */
- public String getRepositoriesString() {
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < repositories.length; i++) {
- sb.append(repositories[i]).append(":");
- }
- return sb.toString();
- }
-
- public String[] getLoaderRepositories() {
- if (loaderRepositories == null)
- return null;
- String res[] = new String[loaderRepositories.size()];
- loaderRepositories.toArray(res);
- return res;
- }
-
- public String getLoaderRepositoriesString() {
- String repositories[] = getLoaderRepositories();
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < repositories.length; i++) {
- sb.append(repositories[i]).append(":");
- }
- return sb.toString();
- }
-
- /**
- * Classpath, as set in org.apache.catalina.jsp_classpath context property
- *
- * @return The classpath
- */
- public String getClasspath() {
- return classpath;
- }
-
- /**
- * Has the internal repository associated with this Loader been modified, such
- * that the loaded classes should be reloaded?
- */
- public boolean modified() {
-
- return (classLoader.modified());
-
- }
-
- /**
- * Used to periodically signal to the classloader to release JAR resources.
- */
- public void closeJARs(boolean force) {
- if (classLoader != null) {
- classLoader.closeJARs(force);
- }
- }
-
- /**
- * Remove a property change listener from this component.
- *
- * @param listener The listener to remove
- */
- public void removePropertyChangeListener(PropertyChangeListener listener) {
-
- support.removePropertyChangeListener(listener);
-
- }
-
- /**
- * Return a String representation of this component.
- */
- public String toString() {
-
- StringBuffer sb = new StringBuffer("WebappLoader[");
- if (container != null)
- sb.append(container.getName());
- sb.append("]");
- return (sb.toString());
-
- }
-
- // ------------------------------------------------------ Lifecycle Methods
-
- /**
- * Add a lifecycle event listener to this component.
- *
- * @param listener The listener to add
- */
- public void addLifecycleListener(LifecycleListener listener) {
-
- lifecycle.addLifecycleListener(listener);
-
- }
-
- /**
- * Get the lifecycle listeners associated with this lifecycle. If this
- * Lifecycle has no listeners registered, a zero-length array is returned.
- */
- public LifecycleListener[] findLifecycleListeners() {
-
- return lifecycle.findLifecycleListeners();
-
- }
-
- /**
- * Remove a lifecycle event listener from this component.
- *
- * @param listener The listener to remove
- */
- public void removeLifecycleListener(LifecycleListener listener) {
-
- lifecycle.removeLifecycleListener(listener);
-
- }
-
- private boolean initialized = false;
-
- public void init() {
- initialized = true;
-
- if (oname == null) {
- // not registered yet - standalone or API
- if (container instanceof StandardContext) {
- // Register ourself. The container must be a webapp
- try {
- StandardContext ctx = (StandardContext) container;
- Engine eng = (Engine) ctx.getParent().getParent();
- String path = ctx.getPath();
- if (path.equals("")) {
- path = "/";
- }
- oname = new ObjectName(ctx.getEngineName() + ":type=Loader,path="
- + path + ",host=" + ctx.getParent().getName());
- Registry.getRegistry(null, null).registerComponent(this, oname, null);
- controller = oname;
- } catch (Exception e) {
- log.error("Error registering loader", e);
- }
- }
- }
-
- if (container == null) {
- // JMX created the loader
- // TODO
-
- }
- }
-
- public void destroy() {
- if (controller == oname) {
- // Self-registration, undo it
- Registry.getRegistry(null, null).unregisterComponent(oname);
- oname = null;
- }
- initialized = false;
-
- }
-
- /**
- * Start this component, initializing our associated class loader.
- *
- * @exception LifecycleException if a lifecycle error occurs
- */
- public void start() throws LifecycleException {
- // Validate and update our current component state
- if (!initialized)
- init();
- if (started)
- throw new LifecycleException(sm.getString("webappLoader.alreadyStarted"));
- if (log.isDebugEnabled())
- log.debug(sm.getString("webappLoader.starting"));
- lifecycle.fireLifecycleEvent(START_EVENT, null);
- started = true;
-
- if (container.getResources() == null) {
- log.info("No resources for " + container);
- return;
- }
- // Register a stream handler factory for the JNDI protocol
- URLStreamHandlerFactory streamHandlerFactory = new DirContextURLStreamHandlerFactory();
- if (first) {
- first = false;
- try {
- URL.setURLStreamHandlerFactory(streamHandlerFactory);
- } catch (Exception e) {
- // Log and continue anyway, this is not critical
- log.error("Error registering jndi stream handler", e);
- } catch (Throwable t) {
- // This is likely a dual registration
- log.info("Dual registration of jndi stream handler: " + t.getMessage());
- }
- }
-
- // Construct a class loader based on our current repositories list
- try {
-
- classLoader = createClassLoader();
- classLoader.setResources(container.getResources());
- classLoader.setDebug(this.debug);
- classLoader.setDelegate(this.delegate);
-
- for (int i = 0; i < repositories.length; i++) {
- classLoader.addRepository(repositories[i]);
- }
-
- // Configure our repositories
- setRepositories();
- setClassPath();
-
- setPermissions();
-
- if (classLoader instanceof Lifecycle)
- ((Lifecycle) classLoader).start();
-
- // Binding the Webapp class loader to the directory context
- DirContextURLStreamHandler.bind((ClassLoader) classLoader,
- this.container.getResources());
-
- StandardContext ctx = (StandardContext) container;
- Engine eng = (Engine) ctx.getParent().getParent();
- String path = ctx.getPath();
- if (path.equals("")) {
- path = "/";
- }
- ObjectName cloname = new ObjectName(ctx.getEngineName()
- + ":type=WebappClassLoader,path=" + path + ",host="
- + ctx.getParent().getName());
- Registry.getRegistry(null, null).registerComponent(classLoader, cloname,
- null);
-
- } catch (Throwable t) {
- log.error("LifecycleException ", t);
- throw new LifecycleException("start: ", t);
- }
-
- }
-
- /**
- * Stop this component, finalizing our associated class loader.
- *
- * @exception LifecycleException if a lifecycle error occurs
- */
- public void stop() throws LifecycleException {
-
- // Validate and update our current component state
- if (!started)
- throw new LifecycleException(sm.getString("webappLoader.notStarted"));
- if (log.isDebugEnabled())
- log.debug(sm.getString("webappLoader.stopping"));
- lifecycle.fireLifecycleEvent(STOP_EVENT, null);
- started = false;
-
- // Remove context attributes as appropriate
- if (container instanceof Context) {
- ServletContext servletContext = ((Context) container).getServletContext();
- servletContext.removeAttribute(Globals.CLASS_PATH_ATTR);
- }
-
- // Throw away our current class loader
- if (classLoader instanceof Lifecycle)
- ((Lifecycle) classLoader).stop();
- DirContextURLStreamHandler.unbind((ClassLoader) classLoader);
-
- try {
- StandardContext ctx = (StandardContext) container;
- Engine eng = (Engine) ctx.getParent().getParent();
- String path = ctx.getPath();
- if (path.equals("")) {
- path = "/";
- }
- ObjectName cloname = new ObjectName(ctx.getEngineName()
- + ":type=WebappClassLoader,path=" + path + ",host="
- + ctx.getParent().getName());
- Registry.getRegistry(null, null).unregisterComponent(cloname);
- } catch (Throwable t) {
- log.error("LifecycleException ", t);
- }
-
- classLoader = null;
-
- destroy();
-
- }
-
- // ----------------------------------------- PropertyChangeListener Methods
-
- /**
- * Process property change events from our associated Context.
- *
- * @param event The property change event that has occurred
- */
- public void propertyChange(PropertyChangeEvent event) {
-
- // Validate the source of this event
- if (!(event.getSource() instanceof Context))
- return;
- Context context = (Context) event.getSource();
-
- // Process a relevant property change
- if (event.getPropertyName().equals("reloadable")) {
- try {
- setReloadable(((Boolean) event.getNewValue()).booleanValue());
- } catch (NumberFormatException e) {
- log.error(sm.getString("webappLoader.reloadable",
- event.getNewValue().toString()));
- }
- }
-
- }
-
- // ------------------------------------------------------- Private Methods
-
- /**
- * Create associated classLoader. GOOGLE: Added type information.
- */
- private WebappClassLoader createClassLoader() throws Exception {
-
- Class<?> clazz = Class.forName(loaderClass);
- WebappClassLoader classLoader = null;
-
- if (parentClassLoader == null) {
- parentClassLoader = Thread.currentThread().getContextClassLoader();
- }
- Class<?>[] argTypes = {ClassLoader.class};
- Object[] args = {parentClassLoader};
- Constructor<?> constr = clazz.getConstructor(argTypes);
- classLoader = (WebappClassLoader) constr.newInstance(args);
-
- return classLoader;
-
- }
-
- /**
- * Log a message on the Logger associated with our Container (if any)
- *
- * @param message Message to be logged
- */
- private void log(String message) {
-
- Logger logger = null;
- if (container != null)
- logger = container.getLogger();
- if (logger != null)
- logger.log("WebappLoader[" + container.getName() + "]: " + message);
- else {
- String containerName = null;
- if (container != null)
- containerName = container.getName();
- System.out.println("WebappLoader[" + containerName + "]: " + message);
- }
-
- }
-
- /**
- * Log a message on the Logger associated with our Container (if any)
- *
- * @param message Message to be logged
- * @param throwable Associated exception
- */
- private void log(String message, Throwable throwable) {
-
- Logger logger = null;
- if (container != null)
- logger = container.getLogger();
- if (logger != null) {
- logger.log("WebappLoader[" + container.getName() + "] " + message,
- throwable);
- } else {
- String containerName = null;
- if (container != null)
- containerName = container.getName();
- System.out.println("WebappLoader[" + containerName + "]: " + message);
- System.out.println("" + throwable);
- throwable.printStackTrace(System.out);
- }
-
- }
-
- /**
- * Configure associated class loader permissions.
- */
- private void setPermissions() {
-
- if (System.getSecurityManager() == null)
- return;
- if (!(container instanceof Context))
- return;
-
- // Tell the class loader the root of the context
- ServletContext servletContext = ((Context) container).getServletContext();
-
- // Assigning permissions for the work directory
- File workDir = (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
- if (workDir != null) {
- try {
- String workDirPath = workDir.getCanonicalPath();
- classLoader.addPermission(new FilePermission(workDirPath, "read,write"));
- classLoader.addPermission(new FilePermission(workDirPath
- + File.separator + "-", "read,write,delete"));
- } catch (IOException e) {
- // Ignore
- }
- }
-
- try {
-
- URL rootURL = servletContext.getResource("/");
- classLoader.addPermission(rootURL);
-
- String contextRoot = servletContext.getRealPath("/");
- if (contextRoot != null) {
- try {
- contextRoot = (new File(contextRoot)).getCanonicalPath();
- classLoader.addPermission(contextRoot);
- } catch (IOException e) {
- // Ignore
- }
- }
-
- URL classesURL = servletContext.getResource("/WEB-INF/classes/");
- classLoader.addPermission(classesURL);
- URL libURL = servletContext.getResource("/WEB-INF/lib/");
- classLoader.addPermission(libURL);
-
- if (contextRoot != null) {
-
- if (libURL != null) {
- File rootDir = new File(contextRoot);
- File libDir = new File(rootDir, "WEB-INF/lib/");
- try {
- String path = libDir.getCanonicalPath();
- classLoader.addPermission(path);
- } catch (IOException e) {
- }
- }
-
- } else {
-
- if (workDir != null) {
- if (libURL != null) {
- File libDir = new File(workDir, "WEB-INF/lib/");
- try {
- String path = libDir.getCanonicalPath();
- classLoader.addPermission(path);
- } catch (IOException e) {
- }
- }
- if (classesURL != null) {
- File classesDir = new File(workDir, "WEB-INF/classes/");
- try {
- String path = classesDir.getCanonicalPath();
- classLoader.addPermission(path);
- } catch (IOException e) {
- }
- }
- }
-
- }
-
- } catch (MalformedURLException e) {
- }
-
- }
-
- /**
- * Configure the repositories for our class loader, based on the associated
- * Context. GOOGLE: Added type information.
- */
- private void setRepositories() {
-
- if (!(container instanceof Context))
- return;
- ServletContext servletContext = ((Context) container).getServletContext();
- if (servletContext == null)
- return;
-
- loaderRepositories = new ArrayList<String>();
- // Loading the work directory
- File workDir = (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
- if (workDir == null) {
- log.info("No work dir for " + servletContext);
- }
-
- if (log.isDebugEnabled())
- log.debug(sm.getString("webappLoader.deploy", workDir.getAbsolutePath()));
-
- classLoader.setWorkDir(workDir);
-
- DirContext resources = container.getResources();
-
- // Setting up the class repository (/WEB-INF/classes), if it exists
-
- String classesPath = "/WEB-INF/classes";
- DirContext classes = null;
-
- try {
- Object object = resources.lookup(classesPath);
- if (object instanceof DirContext) {
- classes = (DirContext) object;
- }
- } catch (NamingException e) {
- // Silent catch: it's valid that no /WEB-INF/classes collection
- // exists
- }
-
- if (classes != null) {
-
- File classRepository = null;
-
- String absoluteClassesPath = servletContext.getRealPath(classesPath);
-
- if (absoluteClassesPath != null) {
-
- classRepository = new File(absoluteClassesPath);
-
- } else {
-
- classRepository = new File(workDir, classesPath);
- classRepository.mkdirs();
- copyDir(classes, classRepository);
-
- }
-
- if (log.isDebugEnabled())
- log.debug(sm.getString("webappLoader.classDeploy", classesPath,
- classRepository.getAbsolutePath()));
-
- // Adding the repository to the class loader
- classLoader.addRepository(classesPath + "/", classRepository);
- loaderRepositories.add(classesPath + "/");
-
- }
-
- // Setting up the JAR repository (/WEB-INF/lib), if it exists
-
- String libPath = "/WEB-INF/lib";
-
- classLoader.setJarPath(libPath);
-
- DirContext libDir = null;
- // Looking up directory /WEB-INF/lib in the context
- try {
- Object object = resources.lookup(libPath);
- if (object instanceof DirContext)
- libDir = (DirContext) object;
- } catch (NamingException e) {
- // Silent catch: it's valid that no /WEB-INF/lib collection
- // exists
- }
-
- if (libDir != null) {
-
- boolean copyJars = false;
- String absoluteLibPath = servletContext.getRealPath(libPath);
-
- File destDir = null;
-
- if (absoluteLibPath != null) {
- destDir = new File(absoluteLibPath);
- } else {
- copyJars = true;
- destDir = new File(workDir, libPath);
- destDir.mkdirs();
- }
-
- // Looking up directory /WEB-INF/lib in the context
- try {
- // GOOGLE: "enum" is a reserved word in JDK 1.5
- NamingEnumeration<Binding> enum_ = resources.listBindings(libPath);
- while (enum_.hasMoreElements()) {
-
- Binding binding = enum_.nextElement();
- String filename = libPath + "/" + binding.getName();
- if (!filename.endsWith(".jar"))
- continue;
-
- // Copy JAR in the work directory, always (the JAR file
- // would get locked otherwise, which would make it
- // impossible to update it or remove it at runtime)
- File destFile = new File(destDir, binding.getName());
-
- if (log.isDebugEnabled())
- log.debug(sm.getString("webappLoader.jarDeploy", filename,
- destFile.getAbsolutePath()));
-
- Resource jarResource = (Resource) binding.getObject();
- if (copyJars) {
- if (!copy(jarResource.streamContent(), new FileOutputStream(
- destFile)))
- continue;
- }
-
- try {
- JarFile jarFile = new JarFile(destFile);
- classLoader.addJar(filename, jarFile, destFile);
- } catch (Exception ex) {
- // Catch the exception if there is an empty jar file
- // Should ignore and continute loading other jar files
- // in the dir
- }
-
- loaderRepositories.add(filename);
-
- }
- } catch (NamingException e) {
- // Silent catch: it's valid that no /WEB-INF/lib directory
- // exists
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- }
-
- /**
- * Set the appropriate context attribute for our class path. This is required
- * only because Jasper depends on it.
- */
- private void setClassPath() {
-
- // Validate our current state information
- if (!(container instanceof Context))
- return;
- ServletContext servletContext = ((Context) container).getServletContext();
- if (servletContext == null)
- return;
-
- if (container instanceof StandardContext) {
- String baseClasspath = ((StandardContext) container).getCompilerClasspath();
- if (baseClasspath != null) {
- servletContext.setAttribute(Globals.CLASS_PATH_ATTR, baseClasspath);
- return;
- }
- }
-
- StringBuffer classpath = new StringBuffer();
-
- // Assemble the class path information from our class loader chain
- ClassLoader loader = getClassLoader();
- int layers = 0;
- int n = 0;
- while (loader != null) {
- if (!(loader instanceof URLClassLoader)) {
- String cp = getClasspath(loader);
- if (cp == null) {
- log.info("Unknown loader " + loader + " " + loader.getClass());
- break;
- } else {
- if (n > 0)
- classpath.append(File.pathSeparator);
- classpath.append(cp);
- n++;
- }
- break;
- // continue;
- }
- URL repositories[] = ((URLClassLoader) loader).getURLs();
- for (int i = 0; i < repositories.length; i++) {
- String repository = repositories[i].toString();
- if (repository.startsWith("file://"))
- repository = repository.substring(7);
- else if (repository.startsWith("file:"))
- repository = repository.substring(5);
- else if (repository.startsWith("jndi:"))
- repository = servletContext.getRealPath(repository.substring(5));
- else
- continue;
- if (repository == null)
- continue;
- if (n > 0)
- classpath.append(File.pathSeparator);
- classpath.append(repository);
- n++;
- }
- loader = loader.getParent();
- layers++;
- }
-
- this.classpath = classpath.toString();
-
- // Store the assembled class path as a servlet context attribute
- servletContext.setAttribute(Globals.CLASS_PATH_ATTR, classpath.toString());
-
- }
-
- // try to extract the classpath from a loader that is not URLClassLoader
- private String getClasspath(ClassLoader loader) {
- try {
- Method m = loader.getClass().getMethod("getClasspath", new Class[] {});
- if (log.isTraceEnabled())
- log.trace("getClasspath " + m);
- if (m == null)
- return null;
- Object o = m.invoke(loader, new Object[] {});
- if (log.isDebugEnabled())
- log.debug("gotClasspath " + o);
- if (o instanceof String)
- return (String) o;
- return null;
- } catch (Exception ex) {
- if (log.isDebugEnabled())
- log.debug("getClasspath ", ex);
- }
- return null;
- }
-
- /**
- * Copy directory.
- */
- private boolean copyDir(DirContext srcDir, File destDir) {
-
- try {
-
- // GOOGLE: "enum" is a reserved word in JDK 1.5
- NamingEnumeration<NameClassPair> enum_ = srcDir.list("");
- while (enum_.hasMoreElements()) {
- NameClassPair ncPair = enum_.nextElement();
- String name = ncPair.getName();
- Object object = srcDir.lookup(name);
- File currentFile = new File(destDir, name);
- if (object instanceof Resource) {
- InputStream is = ((Resource) object).streamContent();
- OutputStream os = new FileOutputStream(currentFile);
- if (!copy(is, os))
- return false;
- } else if (object instanceof InputStream) {
- OutputStream os = new FileOutputStream(currentFile);
- if (!copy((InputStream) object, os))
- return false;
- } else if (object instanceof DirContext) {
- currentFile.mkdir();
- copyDir((DirContext) object, currentFile);
- }
- }
-
- } catch (NamingException e) {
- return false;
- } catch (IOException e) {
- return false;
- }
-
- return true;
-
- }
-
- /**
- * Copy a file to the specified temp directory. This is required only because
- * Jasper depends on it.
- */
- private boolean copy(InputStream is, OutputStream os) {
-
- try {
- byte[] buf = new byte[4096];
- while (true) {
- int len = is.read(buf);
- if (len < 0)
- break;
- os.write(buf, 0, len);
- }
- is.close();
- os.close();
- } catch (IOException e) {
- return false;
- }
-
- return true;
-
- }
-
- private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(WebappLoader.class);
-
- private ObjectName oname;
- private MBeanServer mserver;
- private String domain;
- private ObjectName controller;
-
- public ObjectName preRegister(MBeanServer server, ObjectName name)
- throws Exception {
- oname = name;
- mserver = server;
- domain = name.getDomain();
-
- return name;
- }
-
- public void postRegister(Boolean registrationDone) {
- }
-
- public void preDeregister() throws Exception {
- }
-
- public void postDeregister() {
- }
-
- public ObjectName getController() {
- return controller;
- }
-
- public void setController(ObjectName controller) {
- this.controller = controller;
- }
-
-}
diff --git a/eclipse/README.txt b/eclipse/README.txt
index 54955ca..f85c7ed 100644
--- a/eclipse/README.txt
+++ b/eclipse/README.txt
@@ -106,6 +106,23 @@
Set the Name to "GWT Checks for Tests" (important)
Set the location to "settings/code-style/gwt-checkstyle-tests.xml".
+------------ GWT dev-jar path ------------
+To run applications against the Eclipse projects for GWT rather than an
+extracted jar file, you need to tell GWT where to find its native libraries
+since they won't be in the jar file. Using this approach requires building
+GWT from the command line with ant once to get the files in the proper
+location, but it doesn't need to be redone unless you change any of the native
+libraries.
+
+Window->Preferences->Run/Debug->String Substitution->New...
+Set the Name to "gwt_devjar".
+Set the Value to the approprate path for your install -- for example:
+ <path-to-trunk>\trunk\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar
+ <path-to-trunk>/trunk/build/staging/gwt-linux-0.0.0/gwt-dev-linux.jar
+ <path-to-trunk>/trunk/build/staging/gwt-mac-0.0.0/gwt-dev-mac.jar
+Description can be left blank.
+
+
== Importing the GWT core projects ==
1) Import the 'gwt-dev-<platform>' and 'gwt-user' projects
@@ -189,17 +206,9 @@
You could also just edit Hello.launch and search/replace "windows" with
"linux" or "mac".
-3) Modify the the gwt.devjar VM argument
+3) Repeat step 2 for the 'Hello compile' project.
- Run->Open Run Dialog...->Java Application->Hello
- Select the 'Arguments' tab
- Modify the 'gwt.devjar' setting in the VM arguments window
-
- -Dgwt.devjar=<path to trunk>\trunk\build\staging\gwt-<platform>-0.0.0\gwt-dev-<platform>.jar
-
-4) Repeat steps 2 and 3 for the 'Hello compile' project.
-
-5) Now you should be able to run the 'Hello' project from the
+4) Now you should be able to run the 'Hello' project from the
Run dialog!
@@ -252,12 +261,12 @@
In the 'VM arguments' text area, add the following:
- -Dgwt.devjar="<path to trunk>/build/staging/gwt-<platform>-0.0.0/gwt-dev-<platform>.jar"
+ -Dgwt.devjar=${gwt_devjar}
This is a very obscure way of telling GWT where to find the C++ libraries
- located in that directory. The name of the .jar file is not important,
- but the path is. If you do not have this set, you'll see the
- following exception at startup:
+ located in that directory, and the gwt_devjar variable should be set as
+ described above. If you do not have this set, or if you have not build GWT
+ at least once using ant, you will see an exception like this at startup:
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: Installation problem detected,
diff --git a/user/src/com/google/gwt/event/Event.gwt.xml b/user/src/com/google/gwt/event/Event.gwt.xml
index 44c8ff4..8c5c4e8 100644
--- a/user/src/com/google/gwt/event/Event.gwt.xml
+++ b/user/src/com/google/gwt/event/Event.gwt.xml
@@ -1,6 +1,5 @@
<module>
- <!-- This module could be broken down into much finer detail -->
- <source path="shared"/>
- <source path="logical/shared"/>
- <source path="dom/client"/>
-</module>
\ No newline at end of file
+ <inherits name="com.google.gwt.event.EventBase" />
+ <inherits name="com.google.gwt.event.dom.DomEvent" />
+ <inherits name="com.google.gwt.event.logical.LogicalEvent" />
+</module>
diff --git a/user/src/com/google/gwt/event/EventBase.gwt.xml b/user/src/com/google/gwt/event/EventBase.gwt.xml
new file mode 100644
index 0000000..9f0de72
--- /dev/null
+++ b/user/src/com/google/gwt/event/EventBase.gwt.xml
@@ -0,0 +1,5 @@
+<module>
+ <inherits name="com.google.gwt.core.Core" />
+
+ <source path="shared" />
+</module>
diff --git a/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml b/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
new file mode 100644
index 0000000..c5434ae
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
@@ -0,0 +1,6 @@
+<module>
+ <inherits name="com.google.gwt.event.EventBase" />
+ <inherits name="com.google.gwt.user.DOM" />
+
+ <source path="client"/>
+</module>
diff --git a/user/src/com/google/gwt/event/dom/client/DomEvent.java b/user/src/com/google/gwt/event/dom/client/DomEvent.java
index b8b7135..c4ff6f4 100644
--- a/user/src/com/google/gwt/event/dom/client/DomEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DomEvent.java
@@ -17,7 +17,7 @@
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerManager;
+import com.google.gwt.event.shared.HasHandlers;
import com.google.gwt.user.client.Event;
/**
@@ -31,6 +31,7 @@
*/
public abstract class DomEvent<H extends EventHandler> extends GwtEvent<H>
implements HasNativeEvent {
+
/**
* Type class used by dom event subclasses. Type is specialized for dom in
* order to carry information about the native event.
@@ -53,7 +54,7 @@
/**
* This constructor allows dom event types to be triggered by the
- * {@link DomEvent#fireNativeEvent(Event, HandlerManager)} method. It should
+ * {@link DomEvent#fireNativeEvent(Event, HasHandlers)} method. It should
* only be used by implementors supporting new dom events.
* <p>
* Any such dom event type must act as a flyweight around a native event
@@ -109,7 +110,7 @@
* @param handlers the event manager containing the handlers to fire (may be
* null)
*/
- public static void fireNativeEvent(Event nativeEvent, HandlerManager handlers) {
+ public static void fireNativeEvent(Event nativeEvent, HasHandlers handlers) {
assert nativeEvent != null : "nativeEvent must not be null";
if (registered != null && handlers != null) {
final DomEvent.Type<?> typeKey = registered.unsafeGet(nativeEvent.getType());
diff --git a/user/src/com/google/gwt/event/logical/LogicalEvent.gwt.xml b/user/src/com/google/gwt/event/logical/LogicalEvent.gwt.xml
new file mode 100644
index 0000000..00485a7
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/LogicalEvent.gwt.xml
@@ -0,0 +1,5 @@
+<module>
+ <inherits name="com.google.gwt.event.EventBase" />
+
+ <source path="shared" />
+</module>
diff --git a/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java b/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
index 62066a2..3fe1144 100644
--- a/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.logical.shared;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerManager;
/**
* Represents a before selection event.
@@ -45,13 +44,10 @@
HasBeforeSelectionHandlers<I> source, I item) {
// If no handlers exist, then type can be null.
if (TYPE != null) {
- HandlerManager handlers = source.getHandlers();
- if (handlers != null) {
- BeforeSelectionEvent<I> event = new BeforeSelectionEvent<I>();
- event.setItem(item);
- handlers.fireEvent(event);
- return event;
- }
+ BeforeSelectionEvent<I> event = new BeforeSelectionEvent<I>();
+ event.setItem(item);
+ source.fireEvent(event);
+ return event;
}
return null;
}
diff --git a/user/src/com/google/gwt/event/logical/shared/CloseEvent.java b/user/src/com/google/gwt/event/logical/shared/CloseEvent.java
index 85006a7..aa71fd1 100644
--- a/user/src/com/google/gwt/event/logical/shared/CloseEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/CloseEvent.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.logical.shared;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerManager;
/**
* Represents a close event.
@@ -53,11 +52,8 @@
public static <T> void fire(HasCloseHandlers<T> source, T target,
boolean autoClosed) {
if (TYPE != null) {
- HandlerManager handlers = source.getHandlers();
- if (handlers != null) {
- CloseEvent<T> event = new CloseEvent<T>(target, autoClosed);
- handlers.fireEvent(event);
- }
+ CloseEvent<T> event = new CloseEvent<T>(target, autoClosed);
+ source.fireEvent(event);
}
}
diff --git a/user/src/com/google/gwt/event/logical/shared/HighlightEvent.java b/user/src/com/google/gwt/event/logical/shared/HighlightEvent.java
index 38f785f..ab8ed2e 100644
--- a/user/src/com/google/gwt/event/logical/shared/HighlightEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/HighlightEvent.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.logical.shared;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HasHandlers;
/**
@@ -42,11 +41,8 @@
public static <V, S extends HasHighlightHandlers<V> & HasHandlers> void fire(
S source, V highlighted) {
if (TYPE != null) {
- HandlerManager handlers = source.getHandlers();
- if (handlers != null) {
- HighlightEvent<V> event = new HighlightEvent<V>(highlighted);
- handlers.fireEvent(event);
- }
+ HighlightEvent<V> event = new HighlightEvent<V>(highlighted);
+ source.fireEvent(event);
}
}
diff --git a/user/src/com/google/gwt/event/logical/shared/OpenEvent.java b/user/src/com/google/gwt/event/logical/shared/OpenEvent.java
index a6a11c2..1e6c20e 100644
--- a/user/src/com/google/gwt/event/logical/shared/OpenEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/OpenEvent.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.logical.shared;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerManager;
/**
* Represents a open event.
@@ -40,11 +39,8 @@
*/
public static <T> void fire(HasOpenHandlers<T> source, T target) {
if (TYPE != null) {
- HandlerManager handlers = source.getHandlers();
- if (handlers != null) {
- OpenEvent<T> event = new OpenEvent<T>(target);
- handlers.fireEvent(event);
- }
+ OpenEvent<T> event = new OpenEvent<T>(target);
+ source.fireEvent(event);
}
}
diff --git a/user/src/com/google/gwt/event/logical/shared/ResizeEvent.java b/user/src/com/google/gwt/event/logical/shared/ResizeEvent.java
index a931456..6ca64e6 100644
--- a/user/src/com/google/gwt/event/logical/shared/ResizeEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/ResizeEvent.java
@@ -17,7 +17,6 @@
package com.google.gwt.event.logical.shared;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HasHandlers;
/**
@@ -41,11 +40,8 @@
public static <S extends HasResizeHandlers & HasHandlers> void fire(S source,
int width, int height) {
if (TYPE != null) {
- HandlerManager handlers = source.getHandlers();
- if (handlers != null) {
- ResizeEvent event = new ResizeEvent(width, height);
- handlers.fireEvent(event);
- }
+ ResizeEvent event = new ResizeEvent(width, height);
+ source.fireEvent(event);
}
}
diff --git a/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java b/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
index 967b557..a482ae6 100644
--- a/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.logical.shared;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerManager;
/**
* Represents a selection event.
@@ -41,11 +40,8 @@
*/
public static <I> void fire(HasSelectionHandlers<I> source, I selectedItem) {
if (TYPE != null) {
- HandlerManager handlers = source.getHandlers();
- if (handlers != null) {
- SelectionEvent<I> event = new SelectionEvent<I>(selectedItem);
- handlers.fireEvent(event);
- }
+ SelectionEvent<I> event = new SelectionEvent<I>(selectedItem);
+ source.fireEvent(event);
}
}
diff --git a/user/src/com/google/gwt/event/logical/shared/ShowRangeEvent.java b/user/src/com/google/gwt/event/logical/shared/ShowRangeEvent.java
index 5733bff..81337d9 100644
--- a/user/src/com/google/gwt/event/logical/shared/ShowRangeEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/ShowRangeEvent.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.logical.shared;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HasHandlers;
/**
@@ -44,11 +43,8 @@
public static <V, S extends HasShowRangeHandlers<V> & HasHandlers> void fire(
S source, V start, V end) {
if (TYPE != null) {
- HandlerManager handlers = source.getHandlers();
- if (handlers != null) {
- ShowRangeEvent<V> event = new ShowRangeEvent<V>(start, end);
- handlers.fireEvent(event);
- }
+ ShowRangeEvent<V> event = new ShowRangeEvent<V>(start, end);
+ source.fireEvent(event);
}
}
diff --git a/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java b/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java
index ab32e66..e5d8368 100644
--- a/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.logical.shared;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerManager;
/**
* Represents a value change event.
@@ -40,11 +39,8 @@
*/
public static <I> void fire(HasValueChangeHandlers<I> source, I value) {
if (TYPE != null) {
- HandlerManager handlers = source.getHandlers();
- if (handlers != null && handlers.isEventHandled(TYPE)) {
- ValueChangeEvent<I> event = new ValueChangeEvent<I>(value);
- handlers.fireEvent(event);
- }
+ ValueChangeEvent<I> event = new ValueChangeEvent<I>(value);
+ source.fireEvent(event);
}
}
@@ -62,7 +58,7 @@
I oldValue, I newValue) {
if (shouldFire(source, oldValue, newValue)) {
ValueChangeEvent<I> event = new ValueChangeEvent<I>(newValue);
- source.getHandlers().fireEvent(event);
+ source.fireEvent(event);
}
}
@@ -90,7 +86,7 @@
*/
protected static <I> boolean shouldFire(HasValueChangeHandlers<I> source,
I oldValue, I newValue) {
- return TYPE != null && source.getHandlers() != null && oldValue != newValue
+ return TYPE != null && oldValue != newValue
&& (oldValue == null || !oldValue.equals(newValue));
}
diff --git a/user/src/com/google/gwt/event/shared/HandlerManager.java b/user/src/com/google/gwt/event/shared/HandlerManager.java
index fc1a0a3..4123dab 100644
--- a/user/src/com/google/gwt/event/shared/HandlerManager.java
+++ b/user/src/com/google/gwt/event/shared/HandlerManager.java
@@ -17,7 +17,6 @@
import com.google.gwt.event.shared.GwtEvent.Type;
import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.ui.RootPanel;
import java.util.ArrayList;
import java.util.HashMap;
@@ -139,6 +138,7 @@
} else {
doAdd(type, handler);
}
+
return new DefaultHandlerRegistration(this, type, handler);
}
@@ -151,7 +151,6 @@
*
* @param event the event
*/
-
public void fireEvent(GwtEvent<?> event) {
// If it not live we should revive it.
if (!event.isLive()) {
@@ -205,16 +204,6 @@
}
/**
- * Are there handlers in this manager listening to the given event type?
- *
- * @param type the event type
- * @return are handlers listening on the given event type
- */
- public boolean isEventHandled(Type<?> type) {
- return getHandlerCount(type) > 0;
- }
-
- /**
* Removes the given handler from the specified event type. Normally,
* applications should call {@link HandlerRegistration#removeHandler()}
* instead.
@@ -244,8 +233,7 @@
* @return a map of all handlers in this handler manager
*/
Map<GwtEvent.Type<?>, ArrayList<?>> createHandlerInfo() {
- HandlerManager manager = RootPanel.get().getHandlers();
- return manager.registry.map;
+ return registry.map;
}
private void defer(Command command) {
diff --git a/user/src/com/google/gwt/event/shared/HasHandlers.java b/user/src/com/google/gwt/event/shared/HasHandlers.java
index b57a40d..a87cf94 100644
--- a/user/src/com/google/gwt/event/shared/HasHandlers.java
+++ b/user/src/com/google/gwt/event/shared/HasHandlers.java
@@ -13,20 +13,18 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-
package com.google.gwt.event.shared;
/**
- * An object that implements this interface has a collection of handlers stored
- * in a {@link HandlerManager}.
+ * An object that implements this interface has a collection of event handlers
+ * associated with it.
*/
-
public interface HasHandlers {
/**
- * Gets this object's handlers. May return null if there are no handlers.
+ * Fires the given event to all the appropriate handlers.
*
- * @return the handlers
+ * @param event the event to be fired
*/
- HandlerManager getHandlers();
+ void fireEvent(GwtEvent<?> event);
}
diff --git a/user/src/com/google/gwt/user/User.gwt.xml b/user/src/com/google/gwt/user/User.gwt.xml
index 53931c4..af4102c 100644
--- a/user/src/com/google/gwt/user/User.gwt.xml
+++ b/user/src/com/google/gwt/user/User.gwt.xml
@@ -42,7 +42,7 @@
<inherits name="com.google.gwt.user.Tree"/>
<inherits name="com.google.gwt.user.Hyperlink"/>
<inherits name="com.google.gwt.user.datepicker.DatePicker"/>
- <super-source path="translatable"/>
- <source path="client"/>
-
+
+ <super-source path="translatable"/>
+ <source path="client"/>
</module>
diff --git a/user/src/com/google/gwt/user/client/BaseListenerWrapper.java b/user/src/com/google/gwt/user/client/BaseListenerWrapper.java
new file mode 100644
index 0000000..686cf20
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/BaseListenerWrapper.java
@@ -0,0 +1,243 @@
+/*
+ * 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.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.event.logical.shared.ResizeEvent;
+import com.google.gwt.event.logical.shared.ResizeHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.GwtEvent;
+import com.google.gwt.event.shared.HandlerManager;
+import com.google.gwt.event.shared.GwtEvent.Type;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Legacy listener support hierarchy root.
+ *
+ * Note, this class and its subtypes all assume that the handlers are stored in
+ * handler managers.
+ *
+ * This class, and its children are used to gather the bulk of the legacy glue
+ * code in one place, for easy deletion when Listener methods are deleted.
+ *
+ * @param <T> listener type to be wrapped
+ * @deprecated will be removed in GWT 2.0 with the handler listeners themselves
+ */
+@Deprecated
+public abstract class BaseListenerWrapper<T> implements EventHandler {
+
+ static class NativePreview extends BaseListenerWrapper<EventPreview>
+ implements Event.NativePreviewHandler {
+ @Deprecated
+ public static void add(EventPreview listener) {
+ Event.addNativePreviewHandler(new NativePreview(listener));
+ }
+
+ public static void remove(EventPreview listener) {
+ baseRemove(Event.handlers, listener, NativePreviewEvent.getType());
+ }
+
+ private NativePreview(EventPreview listener) {
+ super(listener);
+ }
+
+ public void onPreviewNativeEvent(NativePreviewEvent event) {
+ // The legacy EventHandler should only fire if it is on the top of the
+ // stack (ie. the last one added).
+ if (event.isFirstHandler()) {
+ if (!listener.onEventPreview(event.getNativeEvent())) {
+ event.cancel();
+ }
+ }
+ }
+ }
+
+ static class WrapHistory extends BaseListenerWrapper<HistoryListener>
+ implements ValueChangeHandler<String> {
+ @Deprecated
+ public static void add(HistoryListener listener) {
+ History.addValueChangeHandler(new WrapHistory(listener));
+ }
+
+ public static void remove(HandlerManager manager, HistoryListener listener) {
+ baseRemove(manager, listener, ValueChangeEvent.getType());
+ }
+
+ private WrapHistory(HistoryListener listener) {
+ super(listener);
+ }
+
+ public void onValueChange(ValueChangeEvent<String> event) {
+ listener.onHistoryChanged(event.getValue());
+ }
+ }
+
+ static class WrapWindowClose extends BaseListenerWrapper<WindowCloseListener>
+ implements Window.ClosingHandler, CloseHandler<Window> {
+ @Deprecated
+ public static void add(WindowCloseListener listener) {
+ WrapWindowClose handler = new WrapWindowClose(listener);
+ Window.addWindowClosingHandler(handler);
+ Window.addCloseHandler(handler);
+ }
+
+ public static void remove(HandlerManager manager,
+ WindowCloseListener listener) {
+ baseRemove(manager, listener, Window.ClosingEvent.getType(),
+ CloseEvent.getType());
+ }
+
+ private WrapWindowClose(WindowCloseListener listener) {
+ super(listener);
+ }
+
+ public void onClose(CloseEvent<Window> event) {
+ listener.onWindowClosed();
+ }
+
+ public void onWindowClosing(Window.ClosingEvent event) {
+ String message = listener.onWindowClosing();
+ if (event.getMessage() == null) {
+ event.setMessage(message);
+ }
+ }
+ }
+
+ static class WrapWindowResize extends
+ BaseListenerWrapper<WindowResizeListener> implements ResizeHandler {
+ @Deprecated
+ public static void add(WindowResizeListener listener) {
+ Window.addResizeHandler(new WrapWindowResize(listener));
+ }
+
+ public static void remove(HandlerManager manager,
+ WindowResizeListener listener) {
+ baseRemove(manager, listener, ResizeEvent.getType());
+ }
+
+ private WrapWindowResize(WindowResizeListener listener) {
+ super(listener);
+ }
+
+ public void onResize(ResizeEvent event) {
+ listener.onWindowResized(event.getWidth(), event.getHeight());
+ }
+ }
+
+ static class WrapWindowScroll extends
+ BaseListenerWrapper<WindowScrollListener> implements Window.ScrollHandler {
+ @Deprecated
+ public static void add(WindowScrollListener listener) {
+ Window.addWindowScrollHandler(new WrapWindowScroll(listener));
+ }
+
+ public static void remove(HandlerManager manager,
+ WindowScrollListener listener) {
+ baseRemove(manager, listener, Window.ScrollEvent.getType());
+ }
+
+ private WrapWindowScroll(WindowScrollListener listener) {
+ super(listener);
+ }
+
+ public void onWindowScroll(Window.ScrollEvent event) {
+ listener.onWindowScrolled(event.getScrollLeft(), event.getScrollTop());
+ }
+ }
+
+ /**
+ * Helper method to remove all wrapped listeners from the given event types.
+ *
+ * @param manager the manager to remove the listener from
+ * @param listener the listener
+ * @param types the event types to remove the listener from
+ * @param <H>
+ */
+ // This is an internal helper method with the current formulation, we have
+ // lost the info needed to make it safe by this point.
+ @SuppressWarnings("unchecked")
+ protected static <H extends EventHandler> void baseRemove(
+ HandlerManager manager, Object listener, Type... types) {
+ if (manager != null) {
+ for (Type<H> key : types) {
+ int handlerCount = manager.getHandlerCount(key);
+ // We are removing things as we traverse, have to go backward
+ for (int i = handlerCount - 1; i >= 0; i--) {
+ H handler = manager.getHandler(key, i);
+ if (handler instanceof BaseListenerWrapper
+ && ((BaseListenerWrapper) handler).listener.equals(listener)) {
+ manager.removeHandler(key, handler);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Listener being wrapped.
+ */
+ final T listener;
+
+ private Widget source;
+
+ /**
+ * Creates a new listener wrapper.
+ *
+ * @param listener the listener to wrap
+ */
+ protected BaseListenerWrapper(T listener) {
+ this.listener = listener;
+ }
+
+ /**
+ * Sets the widget source to pass to the listeners. Source defaults to
+ * event.getSource() if this method is not used.
+ *
+ * @param source the source to provide as the listener's source
+ */
+ public void setSource(Widget source) {
+ this.source = source;
+ }
+
+ /**
+ * Gets the listener being wrapped.
+ *
+ * @return the wrapped listener
+ */
+ protected T getListener() {
+ return listener;
+ }
+
+ /**
+ * Gets the widget source to pass to the listeners. Source defaults to
+ * event.getSource() if not specified by {@link #setSource(Widget)}.
+ *
+ * @param event the event
+ * @return source the source to provide as the listener's source
+ */
+ protected Widget getSource(GwtEvent<?> event) {
+ if (source == null) {
+ return (Widget) event.getSource();
+ } else {
+ return source;
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/DOM.java b/user/src/com/google/gwt/user/client/DOM.java
index a51597c..7840ff3 100644
--- a/user/src/com/google/gwt/user/client/DOM.java
+++ b/user/src/com/google/gwt/user/client/DOM.java
@@ -48,7 +48,7 @@
*/
@Deprecated
public static void addEventPreview(EventPreview preview) {
- ListenerWrapper.NativePreview.add(preview);
+ BaseListenerWrapper.NativePreview.add(preview);
}
/**
@@ -998,7 +998,7 @@
*/
@Deprecated
public static void removeEventPreview(EventPreview preview) {
- ListenerWrapper.NativePreview.remove(preview);
+ BaseListenerWrapper.NativePreview.remove(preview);
}
/**
diff --git a/user/src/com/google/gwt/user/client/History.java b/user/src/com/google/gwt/user/client/History.java
index 795ed67..e62bf8c 100644
--- a/user/src/com/google/gwt/user/client/History.java
+++ b/user/src/com/google/gwt/user/client/History.java
@@ -81,7 +81,7 @@
*/
@Deprecated
public static void addHistoryListener(HistoryListener listener) {
- ListenerWrapper.HistoryChange.add(listener);
+ BaseListenerWrapper.WrapHistory.add(listener);
}
/**
@@ -193,6 +193,6 @@
*/
@Deprecated
public static void removeHistoryListener(HistoryListener listener) {
- ListenerWrapper.HistoryChange.remove(impl.getHandlers(), listener);
+ BaseListenerWrapper.WrapHistory.remove(impl.getHandlers(), listener);
}
}
diff --git a/user/src/com/google/gwt/user/client/ListenerWrapper.java b/user/src/com/google/gwt/user/client/ListenerWrapper.java
deleted file mode 100644
index 77f51ad..0000000
--- a/user/src/com/google/gwt/user/client/ListenerWrapper.java
+++ /dev/null
@@ -1,188 +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.user.client;
-
-import com.google.gwt.event.logical.shared.CloseEvent;
-import com.google.gwt.event.logical.shared.CloseHandler;
-import com.google.gwt.event.logical.shared.ResizeEvent;
-import com.google.gwt.event.logical.shared.ResizeHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerManager;
-import com.google.gwt.event.shared.GwtEvent.Type;
-import com.google.gwt.user.client.Event.NativePreviewEvent;
-
-/**
- * Legacy listener support for <code>com.google.gwt.user.client</code>. Gathers
- * the bulk of the legacy glue code in one place, for easy deletion when
- * Listener methods are deleted.
- *
- * @param <T> listener type
- */
-@Deprecated
-abstract class ListenerWrapper<T> implements EventHandler {
- public static class HistoryChange extends ListenerWrapper<HistoryListener>
- implements ValueChangeHandler<String> {
- @Deprecated
- public static void add(HistoryListener listener) {
- History.addValueChangeHandler(new HistoryChange(listener));
- }
-
- public static void remove(HandlerManager manager, HistoryListener listener) {
- baseRemove(manager, listener, ValueChangeEvent.getType());
- }
-
- private HistoryChange(HistoryListener listener) {
- super(listener);
- }
-
- public void onValueChange(ValueChangeEvent<String> event) {
- listener.onHistoryChanged(event.getValue());
- }
- }
-
- public static class NativePreview extends ListenerWrapper<EventPreview>
- implements Event.NativePreviewHandler {
- @Deprecated
- public static void add(EventPreview listener) {
- Event.addNativePreviewHandler(new NativePreview(listener));
- }
-
- public static void remove(EventPreview listener) {
- baseRemove(Event.handlers, listener, NativePreviewEvent.getType());
- }
-
- private NativePreview(EventPreview listener) {
- super(listener);
- }
-
- public void onPreviewNativeEvent(NativePreviewEvent event) {
- // The legacy EventHandler should only fire if it is on the top of the
- // stack (ie. the last one added).
- if (event.isFirstHandler()) {
- if (!listener.onEventPreview(event.getNativeEvent())) {
- event.cancel();
- }
- }
- }
- }
-
- public static class WindowClose extends ListenerWrapper<WindowCloseListener>
- implements Window.ClosingHandler, CloseHandler<Window> {
- @Deprecated
- public static void add(WindowCloseListener listener) {
- WindowClose handler = new WindowClose(listener);
- Window.addWindowClosingHandler(handler);
- Window.addCloseHandler(handler);
- }
-
- public static void remove(HandlerManager manager,
- WindowCloseListener listener) {
- baseRemove(manager, listener, Window.ClosingEvent.getType(),
- CloseEvent.getType());
- }
-
- private WindowClose(WindowCloseListener listener) {
- super(listener);
- }
-
- public void onClose(CloseEvent<Window> event) {
- listener.onWindowClosed();
- }
-
- public void onWindowClosing(Window.ClosingEvent event) {
- String message = listener.onWindowClosing();
- if (event.getMessage() == null) {
- event.setMessage(message);
- }
- }
- }
-
- public static class WindowResize extends
- ListenerWrapper<WindowResizeListener> implements ResizeHandler {
- @Deprecated
- public static void add(WindowResizeListener listener) {
- Window.addResizeHandler(new WindowResize(listener));
- }
-
- public static void remove(HandlerManager manager,
- WindowResizeListener listener) {
- baseRemove(manager, listener, ResizeEvent.getType());
- }
-
- private WindowResize(WindowResizeListener listener) {
- super(listener);
- }
-
- public void onResize(ResizeEvent event) {
- listener.onWindowResized(event.getWidth(), event.getHeight());
- }
- }
-
- public static class WindowScroll extends
- ListenerWrapper<WindowScrollListener> implements Window.ScrollHandler {
- @Deprecated
- public static void add(WindowScrollListener listener) {
- Window.addWindowScrollHandler(new WindowScroll(listener));
- }
-
- public static void remove(HandlerManager manager,
- WindowScrollListener listener) {
- baseRemove(manager, listener, Window.ScrollEvent.getType());
- }
-
- private WindowScroll(WindowScrollListener listener) {
- super(listener);
- }
-
- public void onWindowScroll(Window.ScrollEvent event) {
- listener.onWindowScrolled(event.getScrollLeft(), event.getScrollTop());
- }
- }
-
- // This is an internal helper method with the current formulation, we have
- // lost the info needed to make it safe by this point.
- @SuppressWarnings("unchecked")
- // This is a direct copy of the baseRemove from
- // com.google.gwt.user.client.ui.ListenerWrapper. Change in parallel.
- static <H extends EventHandler> void baseRemove(HandlerManager manager,
- Object listener, Type... keys) {
- if (manager != null) {
- for (Type<H> key : keys) {
- int handlerCount = manager.getHandlerCount(key);
- // We are removing things as we traverse, have to go backward
- for (int i = handlerCount - 1; i >= 0; i--) {
- H handler = manager.getHandler(key, i);
- if (handler instanceof ListenerWrapper
- && ((ListenerWrapper) handler).listener.equals(listener)) {
- manager.removeHandler(key, handler);
- }
- }
- }
- }
- }
-
- /**
- * Listener being wrapped.
- */
- protected final T listener;
-
- protected ListenerWrapper(T listener) {
- this.listener = listener;
- }
-}
diff --git a/user/src/com/google/gwt/user/client/Window.java b/user/src/com/google/gwt/user/client/Window.java
index 8f966f5..d90ed9b 100644
--- a/user/src/com/google/gwt/user/client/Window.java
+++ b/user/src/com/google/gwt/user/client/Window.java
@@ -431,7 +431,7 @@
*/
@Deprecated
public static void addWindowCloseListener(WindowCloseListener listener) {
- ListenerWrapper.WindowClose.add(listener);
+ BaseListenerWrapper.WrapWindowClose.add(listener);
}
/**
@@ -454,7 +454,7 @@
*/
@Deprecated
public static void addWindowResizeListener(WindowResizeListener listener) {
- ListenerWrapper.WindowResize.add(listener);
+ BaseListenerWrapper.WrapWindowResize.add(listener);
}
/**
@@ -478,7 +478,7 @@
*/
@Deprecated
public static void addWindowScrollListener(WindowScrollListener listener) {
- ListenerWrapper.WindowScroll.add(listener);
+ BaseListenerWrapper.WrapWindowScroll.add(listener);
}
/**
@@ -601,7 +601,7 @@
*/
@Deprecated
public static void removeWindowCloseListener(WindowCloseListener listener) {
- ListenerWrapper.WindowClose.remove(handlers, listener);
+ BaseListenerWrapper.WrapWindowClose.remove(handlers, listener);
}
/**
@@ -611,7 +611,7 @@
*/
@Deprecated
public static void removeWindowResizeListener(WindowResizeListener listener) {
- ListenerWrapper.WindowResize.remove(handlers, listener);
+ BaseListenerWrapper.WrapWindowResize.remove(handlers, listener);
}
/**
@@ -621,7 +621,7 @@
*/
@Deprecated
public static void removeWindowScrollListener(WindowScrollListener listener) {
- ListenerWrapper.WindowScroll.remove(handlers, listener);
+ BaseListenerWrapper.WrapWindowScroll.remove(handlers, listener);
}
/**
diff --git a/user/src/com/google/gwt/user/client/impl/ElementMapperImpl.java b/user/src/com/google/gwt/user/client/impl/ElementMapperImpl.java
index f595008..e5dba7c 100644
--- a/user/src/com/google/gwt/user/client/impl/ElementMapperImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/ElementMapperImpl.java
@@ -70,12 +70,17 @@
return uiObjectList.get(index);
}
+ /**
+ * Gets the list of ui objects contained in this element mapper.
+ *
+ * @return the list of ui objects
+ */
public ArrayList<T> getObjectList() {
return uiObjectList;
}
/**
- * Creates an iterator from the ui objects stored within
+ * Creates an iterator from the ui objects stored within.
*
* @return an iterator of the ui objects indexed by this element mapper.
*/
@@ -116,4 +121,4 @@
uiObjectList.set(index, null);
freeList = new FreeNode(index, freeList);
}
-}
\ No newline at end of file
+}
diff --git a/user/src/com/google/gwt/user/client/impl/HistoryImpl.java b/user/src/com/google/gwt/user/client/impl/HistoryImpl.java
index 62e7c75..b4a05d6 100644
--- a/user/src/com/google/gwt/user/client/impl/HistoryImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/HistoryImpl.java
@@ -20,6 +20,7 @@
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.HasHandlers;
@@ -54,6 +55,10 @@
return handlers.addHandler(ValueChangeEvent.getType(), handler);
}
+ public void fireEvent(GwtEvent<?> event) {
+ handlers.fireEvent(event);
+ }
+
/**
* Fires the {@link ValueChangeEvent} to all handlers with the given tokens.
*/
diff --git a/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java b/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java
index 87cbbea..2c1cf74 100644
--- a/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java
@@ -369,7 +369,7 @@
*/
@Deprecated
public void addEventHandler(final DisclosureHandler handler) {
- ListenerWrapper.Disclosure.add(this, handler);
+ ListenerWrapper.WrappedOldDisclosureHandler.add(this, handler);
}
public HandlerRegistration addOpenHandler(OpenHandler<DisclosurePanel> handler) {
@@ -443,7 +443,7 @@
*/
@Deprecated
public void removeEventHandler(DisclosureHandler handler) {
- ListenerWrapper.Disclosure.remove(this, handler);
+ ListenerWrapper.WrappedOldDisclosureHandler.remove(this, handler);
}
public void setAnimationEnabled(boolean enable) {
diff --git a/user/src/com/google/gwt/user/client/ui/FocusPanel.java b/user/src/com/google/gwt/user/client/ui/FocusPanel.java
index a0665f6..37dd2dc 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusPanel.java
@@ -77,7 +77,7 @@
@Deprecated
public void addClickListener(ClickListener listener) {
- ListenerWrapper.Click.add(this, listener);
+ ListenerWrapper.WrappedClickListener.add(this, listener);
}
public HandlerRegistration addFocusHandler(FocusHandler handler) {
@@ -86,12 +86,12 @@
@Deprecated
public void addFocusListener(FocusListener listener) {
- ListenerWrapper.Focus.add(this, listener);
+ ListenerWrapper.WrappedFocusListener.add(this, listener);
}
@Deprecated
public void addKeyboardListener(KeyboardListener listener) {
- ListenerWrapper.Keyboard.add(this, listener);
+ ListenerWrapper.WrappedKeyboardListener.add(this, listener);
}
public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
@@ -112,7 +112,7 @@
@Deprecated
public void addMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.add(this, listener);
+ ListenerWrapper.WrappedMouseListener.add(this, listener);
}
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
@@ -137,7 +137,7 @@
@Deprecated
public void addMouseWheelListener(MouseWheelListener listener) {
- ListenerWrapper.MouseWheel.add(this, listener);
+ ListenerWrapper.WrappedMouseWheelListener.add(this, listener);
}
public int getTabIndex() {
@@ -146,27 +146,27 @@
@Deprecated
public void removeClickListener(ClickListener listener) {
- ListenerWrapper.Click.remove(this, listener);
+ ListenerWrapper.WrappedClickListener.remove(this, listener);
}
@Deprecated
public void removeFocusListener(FocusListener listener) {
- ListenerWrapper.Focus.remove(this, listener);
+ ListenerWrapper.WrappedFocusListener.remove(this, listener);
}
@Deprecated
public void removeKeyboardListener(KeyboardListener listener) {
- ListenerWrapper.Keyboard.remove(this, listener);
+ ListenerWrapper.WrappedKeyboardListener.remove(this, listener);
}
@Deprecated
public void removeMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.remove(this, listener);
+ ListenerWrapper.WrappedMouseListener.remove(this, listener);
}
@Deprecated
public void removeMouseWheelListener(MouseWheelListener listener) {
- ListenerWrapper.MouseWheel.remove(this, listener);
+ ListenerWrapper.WrappedMouseWheelListener.remove(this, listener);
}
public void setAccessKey(char key) {
diff --git a/user/src/com/google/gwt/user/client/ui/FocusWidget.java b/user/src/com/google/gwt/user/client/ui/FocusWidget.java
index 7cdcb13..9ed6c6c 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusWidget.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusWidget.java
@@ -93,7 +93,7 @@
@Deprecated
public void addClickListener(ClickListener listener) {
- ListenerWrapper.Click.add(this, listener);
+ ListenerWrapper.WrappedClickListener.add(this, listener);
}
public HandlerRegistration addFocusHandler(FocusHandler handler) {
@@ -102,12 +102,12 @@
@Deprecated
public void addFocusListener(FocusListener listener) {
- ListenerWrapper.Focus.add(this, listener);
+ ListenerWrapper.WrappedFocusListener.add(this, listener);
}
@Deprecated
public void addKeyboardListener(KeyboardListener listener) {
- ListenerWrapper.Keyboard.add(this, listener);
+ ListenerWrapper.WrappedKeyboardListener.add(this, listener);
}
public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
@@ -128,7 +128,7 @@
@Deprecated
public void addMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.add(this, listener);
+ ListenerWrapper.WrappedMouseListener.add(this, listener);
}
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
@@ -153,7 +153,7 @@
@Deprecated
public void addMouseWheelListener(MouseWheelListener listener) {
- ListenerWrapper.MouseWheel.add(this, listener);
+ ListenerWrapper.WrappedMouseWheelListener.add(this, listener);
}
/**
@@ -176,27 +176,27 @@
@Deprecated
public void removeClickListener(ClickListener listener) {
- ListenerWrapper.Click.remove(this, listener);
+ ListenerWrapper.WrappedClickListener.remove(this, listener);
}
@Deprecated
public void removeFocusListener(FocusListener listener) {
- ListenerWrapper.Focus.remove(this, listener);
+ ListenerWrapper.WrappedFocusListener.remove(this, listener);
}
@Deprecated
public void removeKeyboardListener(KeyboardListener listener) {
- ListenerWrapper.Keyboard.remove(this, listener);
+ ListenerWrapper.WrappedKeyboardListener.remove(this, listener);
}
@Deprecated
public void removeMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.remove(this, listener);
+ ListenerWrapper.WrappedMouseListener.remove(this, listener);
}
@Deprecated
public void removeMouseWheelListener(MouseWheelListener listener) {
- ListenerWrapper.MouseWheel.remove(this, listener);
+ ListenerWrapper.WrappedMouseWheelListener.remove(this, listener);
}
public void setAccessKey(char key) {
diff --git a/user/src/com/google/gwt/user/client/ui/FormPanel.java b/user/src/com/google/gwt/user/client/ui/FormPanel.java
index d810ef8..c1353c8 100644
--- a/user/src/com/google/gwt/user/client/ui/FormPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/FormPanel.java
@@ -404,7 +404,7 @@
@Deprecated
public void addFormHandler(FormHandler handler) {
- ListenerWrapper.Form.add(this, handler);
+ ListenerWrapper.WrappedOldFormHandler.add(this, handler);
}
/**
@@ -494,7 +494,7 @@
@Deprecated
public void removeFormHandler(FormHandler handler) {
- ListenerWrapper.Form.remove(this, handler);
+ ListenerWrapper.WrappedOldFormHandler.remove(this, handler);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/HTMLTable.java b/user/src/com/google/gwt/user/client/ui/HTMLTable.java
index be27082..51eb0a3 100644
--- a/user/src/com/google/gwt/user/client/ui/HTMLTable.java
+++ b/user/src/com/google/gwt/user/client/ui/HTMLTable.java
@@ -704,7 +704,7 @@
*/
@Deprecated
public void addTableListener(TableListener listener) {
- ListenerWrapper.Table.add(this, listener);
+ ListenerWrapper.WrappedTableListener.add(this, listener);
}
/**
@@ -958,7 +958,7 @@
*/
@Deprecated
public void removeTableListener(TableListener listener) {
- ListenerWrapper.Table.remove(this, listener);
+ ListenerWrapper.WrappedTableListener.remove(this, listener);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/Hyperlink.java b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
index 7bb6109..ca070a3 100644
--- a/user/src/com/google/gwt/user/client/ui/Hyperlink.java
+++ b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
@@ -115,7 +115,7 @@
@Deprecated
public void addClickListener(ClickListener listener) {
- ListenerWrapper.Click.add(this, listener);
+ ListenerWrapper.WrappedClickListener.add(this, listener);
}
public String getHTML() {
@@ -147,7 +147,7 @@
@Deprecated
public void removeClickListener(ClickListener listener) {
- ListenerWrapper.Click.remove(this, listener);
+ ListenerWrapper.WrappedClickListener.remove(this, listener);
}
public void setHTML(String html) {
diff --git a/user/src/com/google/gwt/user/client/ui/Image.java b/user/src/com/google/gwt/user/client/ui/Image.java
index 7ddfeff..ee62223 100644
--- a/user/src/com/google/gwt/user/client/ui/Image.java
+++ b/user/src/com/google/gwt/user/client/ui/Image.java
@@ -422,7 +422,7 @@
@Deprecated
public void addClickListener(ClickListener listener) {
- ListenerWrapper.Click.add(this, listener);
+ ListenerWrapper.WrappedClickListener.add(this, listener);
}
public HandlerRegistration addErrorHandler(ErrorHandler handler) {
@@ -435,7 +435,7 @@
@Deprecated
public void addLoadListener(LoadListener listener) {
- ListenerWrapper.Load.add(this, listener);
+ ListenerWrapper.WrappedLoadListener.add(this, listener);
}
public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
@@ -444,7 +444,7 @@
@Deprecated
public void addMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.add(this, listener);
+ ListenerWrapper.WrappedMouseListener.add(this, listener);
}
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
@@ -469,7 +469,7 @@
@Deprecated
public void addMouseWheelListener(MouseWheelListener listener) {
- ListenerWrapper.MouseWheel.add(this, listener);
+ ListenerWrapper.WrappedMouseWheelListener.add(this, listener);
}
/**
@@ -533,22 +533,22 @@
@Deprecated
public void removeClickListener(ClickListener listener) {
- ListenerWrapper.Click.remove(this, listener);
+ ListenerWrapper.WrappedClickListener.remove(this, listener);
}
@Deprecated
public void removeLoadListener(LoadListener listener) {
- ListenerWrapper.Load.remove(this, listener);
+ ListenerWrapper.WrappedLoadListener.remove(this, listener);
}
@Deprecated
public void removeMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.remove(this, listener);
+ ListenerWrapper.WrappedMouseListener.remove(this, listener);
}
@Deprecated
public void removeMouseWheelListener(MouseWheelListener listener) {
- ListenerWrapper.MouseWheel.remove(this, listener);
+ ListenerWrapper.WrappedMouseWheelListener.remove(this, listener);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/Label.java b/user/src/com/google/gwt/user/client/ui/Label.java
index 89a7ef9..9166b7b 100644
--- a/user/src/com/google/gwt/user/client/ui/Label.java
+++ b/user/src/com/google/gwt/user/client/ui/Label.java
@@ -130,7 +130,7 @@
@Deprecated
public void addClickListener(ClickListener listener) {
- ListenerWrapper.Click.add(this, listener);
+ ListenerWrapper.WrappedClickListener.add(this, listener);
}
public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
@@ -139,7 +139,7 @@
@Deprecated
public void addMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.add(this, listener);
+ ListenerWrapper.WrappedMouseListener.add(this, listener);
}
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
@@ -164,7 +164,7 @@
@Deprecated
public void addMouseWheelListener(MouseWheelListener listener) {
- ListenerWrapper.MouseWheel.add(this, listener);
+ ListenerWrapper.WrappedMouseWheelListener.add(this, listener);
}
public Direction getDirection() {
@@ -185,17 +185,17 @@
@Deprecated
public void removeClickListener(ClickListener listener) {
- ListenerWrapper.Click.remove(this, listener);
+ ListenerWrapper.WrappedClickListener.remove(this, listener);
}
@Deprecated
public void removeMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.remove(this, listener);
+ ListenerWrapper.WrappedMouseListener.remove(this, listener);
}
@Deprecated
public void removeMouseWheelListener(MouseWheelListener listener) {
- ListenerWrapper.MouseWheel.remove(this, listener);
+ ListenerWrapper.WrappedMouseWheelListener.remove(this, listener);
}
public void setDirection(Direction direction) {
diff --git a/user/src/com/google/gwt/user/client/ui/ListBox.java b/user/src/com/google/gwt/user/client/ui/ListBox.java
index d94c1f3..cd40ef3 100644
--- a/user/src/com/google/gwt/user/client/ui/ListBox.java
+++ b/user/src/com/google/gwt/user/client/ui/ListBox.java
@@ -106,8 +106,8 @@
@Deprecated
public void addChangeListener(ChangeListener listener) {
- addChangeHandler(new ListenerWrapper.Change(listener));
- }
+ ListenerWrapper.WrappedChangeListener.add(this, listener);
+ }
/**
* Adds an item to the list box. This method has the same effect as
@@ -259,7 +259,7 @@
@Deprecated
public void removeChangeListener(ChangeListener listener) {
- ListenerWrapper.Change.remove(this, listener);
+ ListenerWrapper.WrappedChangeListener.remove(this, listener);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java b/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
index 321815d..ed2aff7 100644
--- a/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
+++ b/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
@@ -69,15 +69,17 @@
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.HasCloseHandlers;
+import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.GwtEvent.Type;
+import com.google.gwt.user.client.BaseListenerWrapper;
import java.util.EventListener;
@@ -86,59 +88,506 @@
* <code>com.google.gwt.user.client.ui</code>. Gathers the bulk of the legacy
* glue code in one place, for easy deletion when Listener methods are deleted.
*
- * @see com.google.gwt.user.client.L
+ *
* @param <T> listener type
+ * @deprecated will be removed in GWT 2.0 with the handler listeners themselves
*/
@Deprecated
-abstract class ListenerWrapper<T> implements EventHandler {
+public abstract class ListenerWrapper<T> extends BaseListenerWrapper<T> {
- public static class Change extends ListenerWrapper<ChangeListener> implements
- ChangeHandler {
+ /**
+ * Wrapper for a {@link LoadListener}.
+ */
+ public static class WrappedLoadListener extends ListenerWrapper<LoadListener> implements
+ LoadHandler, ErrorHandler {
+
+ /**
+ * Adds the wrapped listener.
+ *
+ * @param <S> the source of the events
+ *
+ * @param source the event source
+ * @param listener the listener
+ * @return the wrapped listener
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
@Deprecated
- public static void add(HasChangeHandlers source, ChangeListener listener) {
- source.addChangeHandler(new Change(listener));
+ public static <S extends HasLoadHandlers & HasErrorHandlers> WrappedLoadListener add(
+ S source, LoadListener listener) {
+ WrappedLoadListener l = new WrappedLoadListener(listener);
+ source.addLoadHandler(l);
+ source.addErrorHandler(l);
+ return l;
}
+ /**
+ * Removes the wrapped listener.
+ *
+ * @param eventSource the event source from which to remove the wrapped
+ * listener
+ * @param listener the listener to remove
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static void remove(Widget eventSource, LoadListener listener) {
+ baseRemove(eventSource, listener, LoadEvent.getType(),
+ ErrorEvent.getType());
+ }
+
+ private WrappedLoadListener(LoadListener listener) {
+ super(listener);
+ }
+
+ public void onError(ErrorEvent event) {
+ getListener().onError(getSource(event));
+ }
+
+ public void onLoad(LoadEvent event) {
+ getListener().onLoad(getSource(event));
+ }
+ }
+ /**
+ * Wrapper for a {@link ChangeListener}.
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listeners being
+ * wrapped
+ */
+ @Deprecated
+ public static class WrappedChangeListener extends
+ ListenerWrapper<ChangeListener> implements ChangeHandler {
+
+ /**
+ * Adds the wrapped listener.
+ *
+ * @param source the event source
+ * @param listener the listener
+ * @return the wrapped listener
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static WrappedChangeListener add(HasChangeHandlers source,
+ ChangeListener listener) {
+ WrappedChangeListener rtn = new WrappedChangeListener(listener);
+ source.addChangeHandler(rtn);
+ return rtn;
+ }
+
+ /**
+ * Removes the wrapped listener.
+ *
+ * @param eventSource the event source from which to remove the wrapped
+ * listener
+ * @param listener the listener to remove
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
public static void remove(Widget eventSource, ChangeListener listener) {
baseRemove(eventSource, listener, ChangeEvent.getType());
}
- protected Change(ChangeListener listener) {
+ WrappedChangeListener(ChangeListener listener) {
super(listener);
}
public void onChange(ChangeEvent event) {
- listener.onChange(source(event));
+ getListener().onChange(getSource(event));
}
}
- public static class Click extends ListenerWrapper<ClickListener> implements
- ClickHandler {
+ /**
+ * Wrapper for a {@link ClickListener}.
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listeners being
+ * wrapped
+ */
+ @Deprecated
+ public static class WrappedClickListener extends
+ ListenerWrapper<ClickListener> implements ClickHandler {
+
+ /**
+ * Adds the wrapped listener.
+ *
+ * @param source the event source
+ * @param listener the listener
+ * @return the wrapped listener
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
@Deprecated
- public static Click add(HasClickHandlers source, ClickListener listener) {
- Click rtn = new Click(listener);
+ public static WrappedClickListener add(HasClickHandlers source,
+ ClickListener listener) {
+ WrappedClickListener rtn = new WrappedClickListener(listener);
source.addClickHandler(rtn);
return rtn;
}
+ /**
+ * Removes the wrapped listener.
+ *
+ * @param eventSource the event source from which to remove the wrapped
+ * listener
+ * @param listener the listener to remove
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
public static void remove(Widget eventSource, ClickListener listener) {
baseRemove(eventSource, listener, ClickEvent.getType());
}
- private Click(ClickListener listener) {
+ private WrappedClickListener(ClickListener listener) {
super(listener);
}
public void onClick(ClickEvent event) {
- listener.onClick(source(event));
+ getListener().onClick(getSource(event));
+ }
+ }
+ /**
+ * Wrapper for a {@link FocusListener}.
+ */
+ public static class WrappedFocusListener extends
+ ListenerWrapper<FocusListener> implements FocusHandler, BlurHandler {
+
+ /**
+ * Adds the wrapped listener.
+ *
+ * @param eventSource the event source
+ * @param listener the listener
+ *
+ * @return the wrapped listener
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static WrappedFocusListener add(HasAllFocusHandlers eventSource,
+ FocusListener listener) {
+ WrappedFocusListener rtn = new WrappedFocusListener(listener);
+ HandlesAllFocusEvents.handle(eventSource, rtn);
+ return rtn;
+ }
+
+ /**
+ * Removes the wrapped listener.
+ *
+ * @param eventSource the event source from which to remove the wrapped
+ * listener
+ * @param listener the listener to remove
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static void remove(Widget eventSource, FocusListener listener) {
+ baseRemove(eventSource, listener, LoadEvent.getType(),
+ ErrorEvent.getType());
+ }
+
+ private WrappedFocusListener(FocusListener listener) {
+ super(listener);
+ }
+
+ public void onBlur(BlurEvent event) {
+ getListener().onLostFocus(getSource(event));
+ }
+
+ public void onFocus(FocusEvent event) {
+ getListener().onFocus(getSource(event));
}
}
- public static class Disclosure extends ListenerWrapper<DisclosureHandler>
- implements CloseHandler<DisclosurePanel>, OpenHandler<DisclosurePanel> {
+ /**
+ * Wrapper for a {@link KeyboardListener}.
+ */
+ public static class WrappedKeyboardListener extends
+ ListenerWrapper<KeyboardListener> implements KeyDownHandler,
+ KeyUpHandler, KeyPressHandler {
+
+ /**
+ * Adds the wrapped listener.
+ *
+ * @param source the event source
+ * @param listener the listener
+ * @return the wrapped listener
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static WrappedKeyboardListener add(HasAllKeyHandlers source,
+ KeyboardListener listener) {
+ WrappedKeyboardListener b = new WrappedKeyboardListener(listener);
+ HandlesAllKeyEvents.addHandlers(source, b);
+ return b;
+ }
+
+ /**
+ * Removes the wrapped listener.
+ *
+ * @param eventSource the event source from which to remove the wrapped
+ * listener
+ * @param listener the listener to remove
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static void remove(Widget eventSource, KeyboardListener listener) {
+ ListenerWrapper.baseRemove(eventSource, listener, KeyDownEvent.getType(),
+ KeyUpEvent.getType(), KeyPressEvent.getType());
+ }
+
+ private WrappedKeyboardListener(KeyboardListener listener) {
+ super(listener);
+ }
+
+ public void onKeyDown(KeyDownEvent event) {
+ getListener().onKeyDown(
+ getSource(event),
+ (char) event.getNativeKeyCode(),
+ KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));
+ }
+
+ public void onKeyPress(KeyPressEvent event) {
+ getListener().onKeyPress(
+ getSource(event),
+ (char) event.getNativeEvent().getKeyCode(),
+ KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));
+ }
+
+ public void onKeyUp(KeyUpEvent event) {
+ getSource(event);
+ getListener().onKeyUp(
+ getSource(event),
+ (char) event.getNativeKeyCode(),
+ KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));
+ }
+ }
+
+ /**
+ * Wrapper for a {@link ChangeListener} being converted to a logical
+ * {@link ValueChangeHandler}.
+ *
+ * @param <V> the type of the value changed
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listeners being
+ * wrapped
+ */
+ @Deprecated
+ public static class WrappedLogicalChangeListener<V> extends
+ ListenerWrapper<ChangeListener> implements ValueChangeHandler<V> {
+
+ /**
+ * Adds the wrapped listener.
+ *
+ * @param <V> the type of value changed
+ *
+ * @param source the event source
+ * @param listener the listener
+ * @return the wrapped listener
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static <V> WrappedLogicalChangeListener<V> add(
+ HasValueChangeHandlers<V> source, ChangeListener listener) {
+ WrappedLogicalChangeListener<V> rtn = new WrappedLogicalChangeListener<V>(
+ listener);
+ source.addValueChangeHandler(rtn);
+ return rtn;
+ }
+
+ /**
+ * Removes the wrapped listener.
+ *
+ * @param eventSource the event source from which to remove the wrapped
+ * listener
+ * @param listener the listener to remove
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static void remove(Widget eventSource, ChangeListener listener) {
+ baseRemove(eventSource, listener, ValueChangeEvent.getType());
+ }
+
+ private WrappedLogicalChangeListener(ChangeListener listener) {
+ super(listener);
+ }
+
+ public void onValueChange(ValueChangeEvent<V> event) {
+ getListener().onChange(getSource(event));
+ }
+ }
+ /**
+ * Wrapper for a {@link MouseListener}.
+ */
+ public static class WrappedMouseListener extends
+ ListenerWrapper<MouseListener> implements MouseDownHandler,
+ MouseUpHandler, MouseOutHandler, MouseOverHandler, MouseMoveHandler {
+ /**
+ * Adds the wrapped listener.
+ *
+ * @param source the event source
+ * @param listener the listener
+ * @return the wrapped listener
+ * @param <E> source of the handlers
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static <E extends HasMouseDownHandlers & HasMouseUpHandlers & HasMouseOutHandlers & HasMouseOverHandlers & HasMouseMoveHandlers> WrappedMouseListener add(
+ E source, MouseListener listener) {
+ WrappedMouseListener handlers = new WrappedMouseListener(listener);
+ source.addMouseDownHandler(handlers);
+ source.addMouseUpHandler(handlers);
+ source.addMouseOutHandler(handlers);
+ source.addMouseOverHandler(handlers);
+ source.addMouseMoveHandler(handlers);
+ return handlers;
+ }
+
+ /**
+ * Removes the wrapped listener.
+ *
+ * @param eventSource the event source from which to remove the wrapped
+ * listener
+ * @param listener the listener to remove
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static void remove(Widget eventSource, MouseListener listener) {
+ baseRemove(eventSource, listener, MouseDownEvent.getType(),
+ MouseUpEvent.getType(), MouseOverEvent.getType(),
+ MouseOutEvent.getType());
+ }
+
+ private WrappedMouseListener(MouseListener listener) {
+ super(listener);
+ }
+
+ public void onMouseDown(MouseDownEvent event) {
+ Widget source = getSource(event);
+ Element elem = source.getElement();
+ getListener().onMouseDown(source, event.getRelativeX(elem),
+ event.getRelativeY(elem));
+ }
+
+ public void onMouseMove(MouseMoveEvent event) {
+ Widget source = getSource(event);
+ Element elem = source.getElement();
+ getListener().onMouseMove(source, event.getRelativeX(elem),
+ event.getRelativeY(elem));
+ }
+
+ public void onMouseOut(MouseOutEvent event) {
+ getListener().onMouseLeave(getSource(event));
+ }
+
+ public void onMouseOver(MouseOverEvent event) {
+ getListener().onMouseEnter(getSource(event));
+ }
+
+ public void onMouseUp(MouseUpEvent event) {
+ Widget source = getSource(event);
+ Element elem = source.getElement();
+ getListener().onMouseUp(source, event.getRelativeX(elem),
+ event.getRelativeY(elem));
+ }
+ }
+ /**
+ * Wrapper for a {@link MouseWheelListener}.
+ */
+ public static class WrappedMouseWheelListener extends
+ ListenerWrapper<MouseWheelListener> implements MouseWheelHandler {
+ /**
+ * Adds the wrapped listener.
+ *
+ * @param source the event source
+ * @param listener the listener
+ * @return the wrapped listener
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static WrappedMouseWheelListener add(HasMouseWheelHandlers source,
+ MouseWheelListener listener) {
+ WrappedMouseWheelListener wrap = new WrappedMouseWheelListener(listener);
+ source.addMouseWheelHandler(new WrappedMouseWheelListener(listener));
+ return wrap;
+ }
+
+ /**
+ * Removes the wrapped listener.
+ *
+ * @param eventSource the event source from which to remove the wrapped
+ * listener
+ * @param listener the listener to remove
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static void remove(Widget eventSource, MouseWheelListener listener) {
+ baseRemove(eventSource, listener, MouseWheelEvent.getType());
+ }
+
+ private WrappedMouseWheelListener(MouseWheelListener listener) {
+ super(listener);
+ }
+
+ public void onMouseWheel(MouseWheelEvent event) {
+ getListener().onMouseWheel(getSource(event),
+ new MouseWheelVelocity(event.getNativeEvent()));
+ }
+ }
+ /**
+ * Wrapper for a {@link ScrollListener}.
+ */
+ public static class WrappedScrollListener extends
+ ListenerWrapper<ScrollListener> implements ScrollHandler {
+
+ /**
+ * Adds the wrapped listener.
+ *
+ * @param source the event source
+ * @param listener the listener
+ * @return the wrapped listener
+ *
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static WrappedScrollListener add(HasScrollHandlers source,
+ ScrollListener listener) {
+ WrappedScrollListener s = new WrappedScrollListener(listener);
+ source.addScrollHandler(s);
+ return s;
+ }
+
+ /**
+ * Removes the wrapped listener.
+ *
+ * @param eventSource the event source from which to remove the wrapped
+ * listener
+ * @param listener the listener to remove
+ * @deprecated will be removed in GWT 2.0 along with the listener classes
+ */
+ @Deprecated
+ public static void remove(Widget eventSource, ScrollListener listener) {
+ baseRemove(eventSource, listener, ScrollEvent.getType(),
+ ErrorEvent.getType());
+ }
+
+ private WrappedScrollListener(ScrollListener listener) {
+ super(listener);
+ }
+
+ public void onScroll(ScrollEvent event) {
+ Widget source = getSource(event);
+ Element elem = source.getElement();
+ getListener().onScroll(getSource(event), elem.getScrollLeft(),
+ elem.getScrollTop());
+ }
+ }
+ static class WrappedOldDisclosureHandler extends
+ ListenerWrapper<DisclosureHandler> implements
+ CloseHandler<DisclosurePanel>, OpenHandler<DisclosurePanel> {
public static void add(DisclosurePanel source, DisclosureHandler listener) {
- Disclosure handlers = new Disclosure(listener);
+ WrappedOldDisclosureHandler handlers = new WrappedOldDisclosureHandler(
+ listener);
source.addOpenHandler(handlers);
source.addCloseHandler(handlers);
}
@@ -148,55 +597,26 @@
OpenEvent.getType());
}
- private Disclosure(DisclosureHandler listener) {
+ private WrappedOldDisclosureHandler(DisclosureHandler listener) {
super(listener);
}
public void onClose(CloseEvent<DisclosurePanel> event) {
- listener.onClose(new DisclosureEvent((DisclosurePanel) event.getSource()));
+ getListener().onClose(
+ new DisclosureEvent((DisclosurePanel) event.getSource()));
}
public void onOpen(OpenEvent<DisclosurePanel> event) {
- listener.onOpen(new DisclosureEvent((DisclosurePanel) event.getSource()));
+ getListener().onOpen(
+ new DisclosureEvent((DisclosurePanel) event.getSource()));
}
}
- /*
- * Handler wrapper for {@link FocusListener}.
- */
- public static class Focus extends ListenerWrapper<FocusListener> implements
- FocusHandler, BlurHandler {
-
- public static <EventSourceType extends Widget & HasAllFocusHandlers> Focus add(
- EventSourceType source, FocusListener listener) {
- Focus rtn = new Focus(listener);
- HandlesAllFocusEvents.handle(source, rtn);
- return rtn;
- }
-
- public static void remove(Widget eventSource, FocusListener listener) {
- baseRemove(eventSource, listener, LoadEvent.getType(),
- ErrorEvent.getType());
- }
-
- private Focus(FocusListener listener) {
- super(listener);
- }
-
- public void onBlur(BlurEvent event) {
- listener.onLostFocus(source(event));
- }
-
- public void onFocus(FocusEvent event) {
- listener.onFocus(source(event));
- }
- }
-
- public static class Form extends ListenerWrapper<FormHandler> implements
- FormPanel.SubmitHandler, FormPanel.SubmitCompleteHandler {
+ static class WrappedOldFormHandler extends ListenerWrapper<FormHandler>
+ implements FormPanel.SubmitHandler, FormPanel.SubmitCompleteHandler {
public static void add(FormPanel source, FormHandler listener) {
- Form handlers = new Form(listener);
+ WrappedOldFormHandler handlers = new WrappedOldFormHandler(listener);
source.addSubmitHandler(handlers);
source.addSubmitCompleteHandler(handlers);
}
@@ -206,203 +626,104 @@
FormPanel.SubmitCompleteEvent.getType());
}
- private Form(FormHandler listener) {
+ private WrappedOldFormHandler(FormHandler listener) {
super(listener);
}
public void onSubmit(FormPanel.SubmitEvent event) {
FormSubmitEvent fse = new FormSubmitEvent((FormPanel) event.getSource());
- listener.onSubmit(fse);
+ getListener().onSubmit(fse);
if (fse.isSetCancelledCalled()) {
event.setCanceled(fse.isCancelled());
}
}
public void onSubmitComplete(FormPanel.SubmitCompleteEvent event) {
- listener.onSubmitComplete(new FormSubmitCompleteEvent(
- (FormPanel) event.getSource(), event.getResults()));
+ getListener().onSubmitComplete(
+ new FormSubmitCompleteEvent((FormPanel) event.getSource(),
+ event.getResults()));
}
}
- public static class Load extends ListenerWrapper<LoadListener> implements
- LoadHandler, ErrorHandler {
-
- public static <S extends HasLoadHandlers & HasErrorHandlers>void add(S source, LoadListener listener) {
- Load l = new Load(listener);
- source.addLoadHandler(l);
- source.addErrorHandler(l);
- }
-
- public static void remove(Widget eventSource, LoadListener listener) {
- baseRemove(eventSource, listener, LoadEvent.getType(),
- ErrorEvent.getType());
- }
-
- private Load(LoadListener listener) {
- super(listener);
- }
-
- public void onError(ErrorEvent event) {
- listener.onError(source(event));
- }
-
- public void onLoad(LoadEvent event) {
- listener.onLoad(source(event));
- }
- }
-
- public static class Mouse extends ListenerWrapper<MouseListener> implements
- MouseDownHandler, MouseUpHandler, MouseOutHandler, MouseOverHandler,
- MouseMoveHandler {
-
- public static <EventSourceType extends Widget & HasMouseDownHandlers & HasMouseUpHandlers & HasMouseOutHandlers & HasMouseOverHandlers & HasMouseMoveHandlers> void add(
- EventSourceType source, MouseListener listener) {
- Mouse handlers = new Mouse(listener);
- source.addMouseDownHandler(handlers);
- source.addMouseUpHandler(handlers);
- source.addMouseOutHandler(handlers);
- source.addMouseOverHandler(handlers);
- source.addMouseMoveHandler(handlers);
- }
-
- public static void remove(Widget eventSource, MouseListener listener) {
- baseRemove(eventSource, listener, MouseDownEvent.getType(),
- MouseUpEvent.getType(), MouseOverEvent.getType(),
- MouseOutEvent.getType());
- }
-
- private Mouse(MouseListener listener) {
- super(listener);
- }
-
- public void onMouseDown(MouseDownEvent event) {
- Widget source = source(event);
- Element elem = source.getElement();
- listener.onMouseDown(source, event.getRelativeX(elem),
- event.getRelativeY(elem));
- }
-
- public void onMouseMove(MouseMoveEvent event) {
- Widget source = source(event);
- Element elem = source.getElement();
- listener.onMouseMove(source, event.getRelativeX(elem),
- event.getRelativeY(elem));
- }
-
- public void onMouseOut(MouseOutEvent event) {
- listener.onMouseLeave(source(event));
- }
-
- public void onMouseOver(MouseOverEvent event) {
- listener.onMouseEnter(source(event));
- }
-
- public void onMouseUp(MouseUpEvent event) {
- Widget source = source(event);
- Element elem = source.getElement();
- listener.onMouseUp(source, event.getRelativeX(elem),
- event.getRelativeY(elem));
- }
- }
- public static class MouseWheel extends ListenerWrapper<MouseWheelListener>
- implements MouseWheelHandler {
- public static void add(HasMouseWheelHandlers source,
- MouseWheelListener listener) {
- source.addMouseWheelHandler(new MouseWheel(listener));
- }
-
- public static void remove(Widget eventSource, MouseWheelListener listener) {
- baseRemove(eventSource, listener, MouseWheelEvent.getType());
- }
-
- private MouseWheel(MouseWheelListener listener) {
- super(listener);
- }
-
- public void onMouseWheel(MouseWheelEvent event) {
- listener.onMouseWheel(source(event), new MouseWheelVelocity(
- event.getNativeEvent()));
- }
- }
-
- public static class Popup extends ListenerWrapper<PopupListener> implements
- CloseHandler<PopupPanel> {
-
- public static void add(HasCloseHandlers<PopupPanel> source,
- PopupListener listener) {
- source.addCloseHandler(new Popup(listener));
- }
-
- public static void remove(Widget eventSource, PopupListener listener) {
- baseRemove(eventSource, listener, CloseEvent.getType());
- }
-
- private Popup(PopupListener listener) {
- super(listener);
- }
-
- public void onClose(CloseEvent<PopupPanel> event) {
- listener.onPopupClosed((PopupPanel) event.getSource(),
- event.isAutoClosed());
- }
- }
-
- public static class Scroll extends ListenerWrapper<ScrollListener> implements
- ScrollHandler {
-
- public static void add(HasScrollHandlers source, ScrollListener listener) {
- source.addScrollHandler(new Scroll(listener));
- }
-
- public static void remove(Widget eventSource, ScrollListener listener) {
- baseRemove(eventSource, listener, ScrollEvent.getType(),
- ErrorEvent.getType());
- }
-
- private Scroll(ScrollListener listener) {
- super(listener);
- }
-
- public void onScroll(ScrollEvent event) {
- Widget source = source(event);
- Element elem = source.getElement();
- listener.onScroll(source(event), elem.getScrollLeft(),
- elem.getScrollTop());
- }
- }
-
- public static class Suggestion extends ListenerWrapper<SuggestionHandler>
- implements SelectionHandler<SuggestOracle.Suggestion> {
+ static class WrappedOldSuggestionHandler extends
+ ListenerWrapper<SuggestionHandler> implements
+ SelectionHandler<SuggestOracle.Suggestion> {
@Deprecated
public static void add(SuggestBox source, SuggestionHandler listener) {
- source.addSelectionHandler(new Suggestion(listener));
+ source.addSelectionHandler(new WrappedOldSuggestionHandler(listener));
}
public static void remove(Widget eventSource, SuggestionHandler listener) {
baseRemove(eventSource, listener, SelectionEvent.getType());
}
- private Suggestion(SuggestionHandler listener) {
+ private WrappedOldSuggestionHandler(SuggestionHandler listener) {
super(listener);
}
public void onSelection(SelectionEvent<SuggestOracle.Suggestion> event) {
- listener.onSuggestionSelected(new SuggestionEvent(
- (SuggestBox) event.getSource(), event.getSelectedItem()));
+ getListener().onSuggestionSelected(
+ new SuggestionEvent((SuggestBox) event.getSource(),
+ event.getSelectedItem()));
}
}
- public static class Tab extends ListenerWrapper<TabListener> implements
- SelectionHandler<Integer>, BeforeSelectionHandler<Integer> {
+ static class WrappedPopupListener extends ListenerWrapper<PopupListener>
+ implements CloseHandler<PopupPanel> {
+
+ public static void add(HasCloseHandlers<PopupPanel> source,
+ PopupListener listener) {
+ source.addCloseHandler(new WrappedPopupListener(listener));
+ }
+
+ public static void remove(Widget eventSource, PopupListener listener) {
+ baseRemove(eventSource, listener, CloseEvent.getType());
+ }
+
+ private WrappedPopupListener(PopupListener listener) {
+ super(listener);
+ }
+
+ public void onClose(CloseEvent<PopupPanel> event) {
+ getListener().onPopupClosed((PopupPanel) event.getSource(),
+ event.isAutoClosed());
+ }
+ }
+
+ static class WrappedTableListener extends ListenerWrapper<TableListener>
+ implements ClickHandler {
+ @Deprecated
+ public static void add(HasClickHandlers source, TableListener listener) {
+ source.addClickHandler(new WrappedTableListener(listener));
+ }
+
+ public static void remove(Widget eventSource, TableListener listener) {
+ baseRemove(eventSource, listener, ClickEvent.getType());
+ }
+
+ private WrappedTableListener(TableListener listener) {
+ super(listener);
+ }
+
+ public void onClick(ClickEvent event) {
+ HTMLTable table = (HTMLTable) event.getSource();
+ HTMLTable.Cell cell = table.getCellForEvent(event);
+ getListener().onCellClicked(table, cell.getRowIndex(),
+ cell.getCellIndex());
+ }
+ }
+
+ static class WrappedTabListener extends ListenerWrapper<TabListener>
+ implements SelectionHandler<Integer>, BeforeSelectionHandler<Integer> {
@Deprecated
public static void add(TabBar source, TabListener listener) {
- Tab t = new Tab(listener);
+ WrappedTabListener t = new WrappedTabListener(listener);
source.addBeforeSelectionHandler(t);
source.addSelectionHandler(t);
}
public static void add(TabPanel source, TabListener listener) {
- Tab t = new Tab(listener);
+ WrappedTabListener t = new WrappedTabListener(listener);
source.addBeforeSelectionHandler(t);
source.addSelectionHandler(t);
}
@@ -412,51 +733,30 @@
BeforeSelectionEvent.getType());
}
- private Tab(TabListener listener) {
+ private WrappedTabListener(TabListener listener) {
super(listener);
}
public void onBeforeSelection(BeforeSelectionEvent<Integer> event) {
- if (!listener.onBeforeTabSelected((SourcesTabEvents) event.getSource(),
- event.getItem().intValue())) {
+ if (!getListener().onBeforeTabSelected(
+ (SourcesTabEvents) event.getSource(), event.getItem().intValue())) {
event.cancel();
}
}
public void onSelection(SelectionEvent<Integer> event) {
- listener.onTabSelected((SourcesTabEvents) event.getSource(),
+ getListener().onTabSelected((SourcesTabEvents) event.getSource(),
event.getSelectedItem().intValue());
}
}
- public static class Table extends ListenerWrapper<TableListener> implements
- ClickHandler {
- @Deprecated
- public static void add(HasClickHandlers source, TableListener listener) {
- source.addClickHandler(new Table(listener));
- }
-
- public static void remove(Widget eventSource, TableListener listener) {
- baseRemove(eventSource, listener, ClickEvent.getType());
- }
-
- private Table(TableListener listener) {
- super(listener);
- }
-
- public void onClick(ClickEvent event) {
- HTMLTable table = (HTMLTable) event.getSource();
- HTMLTable.Cell cell = table.getCellForEvent(event);
- listener.onCellClicked(table, cell.getRowIndex(), cell.getCellIndex());
- }
- }
-
- public static class Tree extends ListenerWrapper<TreeListener> implements
- SelectionHandler<TreeItem>, CloseHandler<TreeItem>, OpenHandler<TreeItem> {
+ static class WrappedTreeListener extends ListenerWrapper<TreeListener>
+ implements SelectionHandler<TreeItem>, CloseHandler<TreeItem>,
+ OpenHandler<TreeItem> {
@Deprecated
public static void add(com.google.gwt.user.client.ui.Tree tree,
TreeListener listener) {
- Tree t = new Tree(listener);
+ WrappedTreeListener t = new WrappedTreeListener(listener);
tree.addSelectionHandler(t);
tree.addCloseHandler(t);
tree.addOpenHandler(t);
@@ -466,106 +766,44 @@
baseRemove(eventSource, listener, ValueChangeEvent.getType());
}
- private Tree(TreeListener listener) {
+ private WrappedTreeListener(TreeListener listener) {
super(listener);
}
public void onClose(CloseEvent<TreeItem> event) {
- listener.onTreeItemStateChanged(event.getTarget());
+ getListener().onTreeItemStateChanged(event.getTarget());
}
public void onOpen(OpenEvent<TreeItem> event) {
- listener.onTreeItemStateChanged(event.getTarget());
+ getListener().onTreeItemStateChanged(event.getTarget());
}
public void onSelection(SelectionEvent<TreeItem> event) {
- listener.onTreeItemSelected(event.getSelectedItem());
- }
- }
-
- static class Keyboard extends ListenerWrapper<KeyboardListener> implements
- KeyDownHandler, KeyUpHandler, KeyPressHandler {
-
- public static <EventSourceType extends Widget & HasAllKeyHandlers> void add(
- EventSourceType source, KeyboardListener listener) {
- HandlesAllKeyEvents.addHandlers(source, new Keyboard(listener));
- }
-
- public static void remove(Widget eventSource, KeyboardListener listener) {
- ListenerWrapper.baseRemove(eventSource, listener, KeyDownEvent.getType(),
- KeyUpEvent.getType(), KeyPressEvent.getType());
- }
-
- private Keyboard(KeyboardListener listener) {
- super(listener);
- }
-
- public void onKeyDown(KeyDownEvent event) {
- listener.onKeyDown(
- source(event),
- (char) event.getNativeKeyCode(),
- KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));
- }
-
- public void onKeyPress(KeyPressEvent event) {
- listener.onKeyPress(
- source(event),
- (char) event.getNativeEvent().getKeyCode(),
- KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));
- }
-
- public void onKeyUp(KeyUpEvent event) {
- source(event);
- listener.onKeyUp(
- source(event),
- (char) event.getNativeKeyCode(),
- KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));
- }
- }
-
- // This is an internal helper method with the current formulation, we have
- // lost the info needed to make it safe by this point.
- @SuppressWarnings("unchecked")
- static <H extends EventHandler> void baseRemove(Widget eventSource,
- EventListener listener, Type... keys) {
- HandlerManager manager = eventSource.getHandlers();
- if (manager != null) {
- // This is a direct copy of the baseRemove from
- // com.google.gwt.user.client.ListenerWrapper. Change in parallel.
- for (Type<H> key : keys) {
- int handlerCount = manager.getHandlerCount(key);
- // We are removing things as we traverse, have to go backward
- for (int i = handlerCount - 1; i >= 0; i--) {
- H handler = manager.getHandler(key, i);
- if (handler instanceof ListenerWrapper
- && ((ListenerWrapper) handler).listener.equals(listener)) {
- manager.removeHandler(key, handler);
- }
- }
- }
+ getListener().onTreeItemSelected(event.getSelectedItem());
}
}
/**
- * Listener being wrapped.
+ * Convenience method to remove wrapped handlers from a widget.
+ *
+ * @param <H> event handler type
+ * @param eventSource the event source
+ * @param listener the listener to remove
+ * @param types the event types to remove it from
*/
- protected final T listener;
-
- private Widget source;
-
- protected ListenerWrapper(T listener) {
- this.listener = listener;
- }
-
- public void setSource(Widget source) {
- this.source = source;
- }
-
- Widget source(GwtEvent<?> event) {
- if (source == null) {
- return (Widget) event.getSource();
- } else {
- return source;
+ // This is an internal helper method with the current formulation, we have
+ // lost the info needed to make it safe by this point.
+ @SuppressWarnings("unchecked")
+ protected static <H extends EventHandler> void baseRemove(Widget eventSource,
+ EventListener listener, Type... types) {
+ HandlerManager manager = eventSource.getHandlerManager();
+ if (manager != null) {
+ baseRemove(manager, listener, types);
}
}
+
+ protected ListenerWrapper(T listener) {
+ super(listener);
+ }
+
}
diff --git a/user/src/com/google/gwt/user/client/ui/PopupPanel.java b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
index 981d9cb..986f45a 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
@@ -365,7 +365,7 @@
@Deprecated
public void addPopupListener(final PopupListener listener) {
- ListenerWrapper.Popup.add(this, listener);
+ ListenerWrapper.WrappedPopupListener.add(this, listener);
}
/**
@@ -602,7 +602,7 @@
@Deprecated
public void removePopupListener(PopupListener listener) {
- ListenerWrapper.Popup.remove(this, listener);
+ ListenerWrapper.WrappedPopupListener.remove(this, listener);
}
public void setAnimationEnabled(boolean enable) {
diff --git a/user/src/com/google/gwt/user/client/ui/ScrollPanel.java b/user/src/com/google/gwt/user/client/ui/ScrollPanel.java
index 7669844..66a4dd8 100644
--- a/user/src/com/google/gwt/user/client/ui/ScrollPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/ScrollPanel.java
@@ -54,7 +54,7 @@
@Deprecated
public void addScrollListener(ScrollListener listener) {
- ListenerWrapper.Scroll.add(this, listener);
+ ListenerWrapper.WrappedScrollListener.add(this, listener);
}
/**
@@ -89,7 +89,7 @@
@Deprecated
public void removeScrollListener(ScrollListener listener) {
- ListenerWrapper.Scroll.remove(this, listener);
+ ListenerWrapper.WrappedScrollListener.remove(this, listener);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/SuggestBox.java b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
index 90a464e..fcabb5c 100644
--- a/user/src/com/google/gwt/user/client/ui/SuggestBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.user.client.ui;
-import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.HandlesAllKeyEvents;
import com.google.gwt.event.dom.client.HasAllKeyHandlers;
import com.google.gwt.event.dom.client.KeyCodes;
@@ -308,9 +307,7 @@
*/
@Deprecated
public void addChangeListener(final ChangeListener listener) {
- ListenerWrapper.Change legacy = new ListenerWrapper.Change(listener);
- legacy.setSource(this);
- box.addDomHandler(legacy, ChangeEvent.getType());
+ ListenerWrapper.WrappedLogicalChangeListener.add(box, listener).setSource(this);
}
/**
@@ -322,7 +319,8 @@
*/
@Deprecated
public void addClickListener(final ClickListener listener) {
- ListenerWrapper.Click legacy = ListenerWrapper.Click.add(box, listener);
+ ListenerWrapper.WrappedClickListener legacy = ListenerWrapper.WrappedClickListener.add(box,
+ listener);
legacy.setSource(this);
}
@@ -333,7 +331,7 @@
*/
@Deprecated
public void addEventHandler(final SuggestionHandler handler) {
- ListenerWrapper.Suggestion.add(this, handler);
+ ListenerWrapper.WrappedOldSuggestionHandler.add(this, handler);
}
/**
@@ -345,13 +343,14 @@
*/
@Deprecated
public void addFocusListener(final FocusListener listener) {
- ListenerWrapper.Focus focus = ListenerWrapper.Focus.add(box, listener);
+ ListenerWrapper.WrappedFocusListener focus = ListenerWrapper.WrappedFocusListener.add(box,
+ listener);
focus.setSource(this);
}
@Deprecated
public void addKeyboardListener(KeyboardListener listener) {
- ListenerWrapper.Keyboard.add(this, listener);
+ ListenerWrapper.WrappedKeyboardListener.add(this, listener);
}
public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
@@ -447,27 +446,27 @@
@Deprecated
public void removeChangeListener(ChangeListener listener) {
- ListenerWrapper.Change.remove(box, listener);
+ ListenerWrapper.WrappedChangeListener.remove(box, listener);
}
@Deprecated
public void removeClickListener(ClickListener listener) {
- ListenerWrapper.Click.remove(box, listener);
+ ListenerWrapper.WrappedClickListener.remove(box, listener);
}
@Deprecated
public void removeEventHandler(SuggestionHandler handler) {
- ListenerWrapper.Suggestion.remove(this, handler);
+ ListenerWrapper.WrappedOldSuggestionHandler.remove(this, handler);
}
@Deprecated
public void removeFocusListener(FocusListener listener) {
- ListenerWrapper.Focus.remove(this, listener);
+ ListenerWrapper.WrappedFocusListener.remove(this, listener);
}
@Deprecated
public void removeKeyboardListener(KeyboardListener listener) {
- ListenerWrapper.Keyboard.remove(this, listener);
+ ListenerWrapper.WrappedKeyboardListener.remove(this, listener);
}
public void setAccessKey(char key) {
diff --git a/user/src/com/google/gwt/user/client/ui/TabBar.java b/user/src/com/google/gwt/user/client/ui/TabBar.java
index 55baec4..218a148 100644
--- a/user/src/com/google/gwt/user/client/ui/TabBar.java
+++ b/user/src/com/google/gwt/user/client/ui/TabBar.java
@@ -250,7 +250,7 @@
@Deprecated
public void addTabListener(TabListener listener) {
- ListenerWrapper.Tab.add(this, listener);
+ ListenerWrapper.WrappedTabListener.add(this, listener);
}
/**
@@ -422,7 +422,7 @@
@Deprecated
public void removeTabListener(TabListener listener) {
- ListenerWrapper.Tab.remove(this, listener);
+ ListenerWrapper.WrappedTabListener.remove(this, listener);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/TabPanel.java b/user/src/com/google/gwt/user/client/ui/TabPanel.java
index 2a3bf67..5f6b116 100644
--- a/user/src/com/google/gwt/user/client/ui/TabPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/TabPanel.java
@@ -262,7 +262,7 @@
@Deprecated
public void addTabListener(TabListener listener) {
- ListenerWrapper.Tab.add(this, listener);
+ ListenerWrapper.WrappedTabListener.add(this, listener);
}
public void clear() {
@@ -383,7 +383,7 @@
@Deprecated
public void removeTabListener(TabListener listener) {
- ListenerWrapper.Tab.remove(this, listener);
+ ListenerWrapper.WrappedTabListener.remove(this, listener);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
index ca4d3ae..9fbad0c 100644
--- a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
+++ b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
@@ -90,7 +90,7 @@
@Deprecated
public void addChangeListener(ChangeListener listener) {
- addDomHandler(new ListenerWrapper.Change(listener), ChangeEvent.getType());
+ addDomHandler(new ListenerWrapper.WrappedChangeListener(listener), ChangeEvent.getType());
}
public HandlerRegistration addValueChangeHandler(
@@ -192,7 +192,7 @@
@Deprecated
public void removeChangeListener(ChangeListener listener) {
- ListenerWrapper.Change.remove(this, listener);
+ ListenerWrapper.WrappedChangeListener.remove(this, listener);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/Tree.java b/user/src/com/google/gwt/user/client/ui/Tree.java
index f27b247..9dff280 100644
--- a/user/src/com/google/gwt/user/client/ui/Tree.java
+++ b/user/src/com/google/gwt/user/client/ui/Tree.java
@@ -303,7 +303,7 @@
@Deprecated
public void addFocusListener(FocusListener listener) {
- ListenerWrapper.Focus.add(this, listener);
+ ListenerWrapper.WrappedFocusListener.add(this, listener);
}
/**
@@ -340,7 +340,7 @@
@Deprecated
public void addKeyboardListener(KeyboardListener listener) {
- ListenerWrapper.Keyboard.add(this, listener);
+ ListenerWrapper.WrappedKeyboardListener.add(this, listener);
}
public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
@@ -361,7 +361,7 @@
@Deprecated
public void addMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.add(this, listener);
+ ListenerWrapper.WrappedMouseListener.add(this, listener);
}
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
@@ -395,7 +395,7 @@
@Deprecated
public void addTreeListener(TreeListener listener) {
- ListenerWrapper.Tree.add(this, listener);
+ ListenerWrapper.WrappedTreeListener.add(this, listener);
}
/**
@@ -589,7 +589,7 @@
@Deprecated
public void removeFocusListener(FocusListener listener) {
- ListenerWrapper.Focus.remove(this, listener);
+ ListenerWrapper.WrappedFocusListener.remove(this, listener);
}
/**
@@ -612,17 +612,17 @@
@Deprecated
public void removeKeyboardListener(KeyboardListener listener) {
- ListenerWrapper.Keyboard.remove(this, listener);
+ ListenerWrapper.WrappedKeyboardListener.remove(this, listener);
}
@Deprecated
public void removeMouseListener(MouseListener listener) {
- ListenerWrapper.Mouse.remove(this, listener);
+ ListenerWrapper.WrappedMouseListener.remove(this, listener);
}
@Deprecated
public void removeTreeListener(TreeListener listener) {
- ListenerWrapper.Tree.remove(this, listener);
+ ListenerWrapper.WrappedTreeListener.remove(this, listener);
}
public void setAccessKey(char key) {
diff --git a/user/src/com/google/gwt/user/client/ui/TreeItem.java b/user/src/com/google/gwt/user/client/ui/TreeItem.java
index 38c5756..9eb040d 100644
--- a/user/src/com/google/gwt/user/client/ui/TreeItem.java
+++ b/user/src/com/google/gwt/user/client/ui/TreeItem.java
@@ -68,7 +68,7 @@
if (GWT.isClient()) {
// Create the base table element that will be cloned.
BASE_INTERNAL_ELEM = DOM.createTable();
- Element contentElem = DOM.createSpan();
+ Element contentElem = DOM.createDiv();
Element tbody = DOM.createTBody(), tr = DOM.createTR();
Element tdImg = DOM.createTD(), tdContent = DOM.createTD();
DOM.appendChild(BASE_INTERNAL_ELEM, tbody);
@@ -102,19 +102,6 @@
super.convertToFullNode(item);
DOM.setStyleAttribute(item.getElement(), "marginBottom", "0px");
}
-
- @Override
- void initializeClonableElements() {
- super.initializeClonableElements();
- if (GWT.isClient()) {
- // We can't use a 3px padding all around because IE will wrap the
- // childSpan to the next line, so we need to add a 3px margin on the top
- // and bottom instead. However, margins overlap, so we need a 6px bottom
- // margin.
- DOM.setStyleAttribute(BASE_BARE_ELEM, "margin", "3px 0px 6px 0px");
- DOM.setStyleAttribute(BASE_BARE_ELEM, "padding", "0px 3px");
- }
- }
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/Widget.java b/user/src/com/google/gwt/user/client/ui/Widget.java
index e544e6a..2bcf44a 100644
--- a/user/src/com/google/gwt/user/client/ui/Widget.java
+++ b/user/src/com/google/gwt/user/client/ui/Widget.java
@@ -32,6 +32,7 @@
* {@link com.google.gwt.user.client.ui.Panel panels}.
*/
public class Widget extends UIObject implements EventListener, HasHandlers {
+
/**
* A bit-map of the events that should be sunk when the widget is attached to
* the DOM. (We delay the sinking of events to improve startup performance.)
@@ -45,13 +46,10 @@
private Widget parent;
private HandlerManager handlerManager;
- /**
- * Returns this widget's {@link HandlerManager} used for event management.
- *
- * @return the handler manager
- */
- public final HandlerManager getHandlers() {
- return handlerManager;
+ public void fireEvent(GwtEvent<?> event) {
+ if (handlerManager != null) {
+ handlerManager.fireEvent(event);
+ }
}
/**
@@ -74,20 +72,6 @@
return attached;
}
- /**
- * Returns true if the widget has handlers of the given type. Used by some
- * widget implementations to be lazy about initializing dom event handlers
- * (e.g. a click handler on a checkbox) until the first relevant logical event
- * handler is attached (e.g. in the <code>addValueChangeHandler</code>
- * method).
- *
- * @param type the event type
- * @return true if the widget has handlers of the give type
- */
- public boolean isEventHandled(GwtEvent.Type<?> type) {
- return handlerManager != null && handlerManager.isEventHandled(type);
- }
-
public void onBrowserEvent(Event event) {
switch (DOM.eventGetType(event)) {
case Event.ONMOUSEOVER:
@@ -106,7 +90,7 @@
return;
}
}
- DomEvent.fireNativeEvent(event, handlerManager);
+ DomEvent.fireNativeEvent(event, this);
}
/**
@@ -215,18 +199,6 @@
}
/**
- * Fires an event. Usually used when passing an event from one source to
- * another.
- *
- * @param event the event
- */
- protected void fireEvent(GwtEvent<?> event) {
- if (handlerManager != null) {
- handlerManager.fireEvent(event);
- }
- }
-
- /**
* Has this widget ever been attached?
*
* @return true if this widget ever been attached to the DOM, false otherwise
@@ -328,6 +300,10 @@
: handlerManager;
}
+ HandlerManager getHandlerManager() {
+ return handlerManager;
+ }
+
/**
* Gets the panel-defined layout data associated with this widget.
*
diff --git a/user/src/com/google/gwt/user/datepicker/client/DateChangeEvent.java b/user/src/com/google/gwt/user/datepicker/client/DateChangeEvent.java
index 940637a..75586ef 100644
--- a/user/src/com/google/gwt/user/datepicker/client/DateChangeEvent.java
+++ b/user/src/com/google/gwt/user/datepicker/client/DateChangeEvent.java
@@ -41,7 +41,7 @@
public static <S extends HasValueChangeHandlers<Date> & HasHandlers> void fireIfNotEqualDates(
S source, Date oldValue, Date newValue) {
if (ValueChangeEvent.shouldFire(source, oldValue, newValue)) {
- source.getHandlers().fireEvent(new DateChangeEvent(newValue));
+ source.fireEvent(new DateChangeEvent(newValue));
}
}
diff --git a/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java
index 9b592c8..7f166f0 100644
--- a/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java
+++ b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java
@@ -62,6 +62,37 @@
}
/**
+ * UncaughtExceptionHandler used to catch exceptions thrown out of Javascript
+ * event handlers.
+ */
+ private final class TestCaseUncaughtExceptionHandler implements
+ UncaughtExceptionHandler {
+
+ // Holds the first exception that's throws "synchronously", meaning "before
+ // the test method returns".
+ private Throwable synchronousException = null;
+
+ /**
+ * An uncaught exception escaped to the browser; what we should do depends
+ * on what state we're in.
+ */
+ public void onUncaughtException(Throwable ex) {
+ if (mainTestHasRun && timer != null) {
+ // Asynchronous mode; uncaught exceptions cause an immediate failure.
+ assert (!testIsFinished);
+ reportResultsAndRunNextMethod(ex);
+ } else {
+ // Synchronous mode: hang on to it for after the test method returns.
+ // We can't call reportResultsAndRunNextMethod() yet, as it will cause
+ // a race condition that often causes the same test to be run again.
+ if (synchronousException == null) {
+ synchronousException = ex;
+ }
+ }
+ }
+ };
+
+ /**
* The collected checkpoint messages.
*/
private List<String> checkPoints;
@@ -86,21 +117,11 @@
*/
private KillTimer timer;
- private final UncaughtExceptionHandler uncaughtHandler = new UncaughtExceptionHandler() {
- /**
- * An uncaught exception escaped to the browser; what we should do depends
- * on what state we're in.
- */
- public void onUncaughtException(Throwable ex) {
- if (mainTestHasRun && timer != null) {
- // Asynchronous mode; uncaught exceptions cause an immediate failure.
- assert (!testIsFinished);
- reportResultsAndRunNextMethod(ex);
- } else {
- // just ignore it
- }
- }
- };
+ /**
+ * The UncaughtExceptionHandler that will be used to catch exceptions thrown
+ * from event handlers. We will create a new one for each test method.
+ */
+ private TestCaseUncaughtExceptionHandler uncaughtHandler;
// CHECKSTYLE_OFF
/**
@@ -111,7 +132,7 @@
if (shouldCatchExceptions()) {
// Make sure no exceptions escape
- GWT.setUncaughtExceptionHandler(uncaughtHandler);
+ GWT.setUncaughtExceptionHandler(uncaughtHandler = new TestCaseUncaughtExceptionHandler());
try {
runBare();
} catch (Throwable e) {
@@ -127,6 +148,13 @@
// timer != null we are in true asynchronous mode.
mainTestHasRun = true;
+ // See if any synchronous exceptions got picked up by the UncaughtExceptionHandler.
+ if ((uncaughtHandler != null) && (uncaughtHandler.synchronousException != null)) {
+ // If an exception was caught in an event handler, it must have happened
+ // before the exception was thrown from the test method.
+ caught = uncaughtHandler.synchronousException;
+ }
+
if (caught != null) {
// Test failed; finish test no matter what state we're in.
reportResultsAndRunNextMethod(caught);
@@ -262,6 +290,10 @@
// ignore any exceptions thrown from tearDown
}
+ // Remove the UncaughtExceptionHandler we may have installed in __doRunTest.
+ GWT.setUncaughtExceptionHandler(null);
+ uncaughtHandler = null;
+
JUnitResult myResult = __getOrCreateTestResult();
if (ex != null) {
ExceptionWrapper ew = new ExceptionWrapper(ex);
diff --git a/user/test/com/google/gwt/event/shared/HandlerManagerTest.java b/user/test/com/google/gwt/event/shared/HandlerManagerTest.java
index 480db2f..48bc156 100644
--- a/user/test/com/google/gwt/event/shared/HandlerManagerTest.java
+++ b/user/test/com/google/gwt/event/shared/HandlerManagerTest.java
@@ -32,7 +32,6 @@
addHandlers(manager);
}
- @SuppressWarnings("deprecation")
private void addHandlers(HandlerManager manager) {
manager.addHandler(MouseDownEvent.getType(), mouse1);
manager.addHandler(MouseDownEvent.getType(), mouse2);
@@ -281,12 +280,9 @@
add(this);
}
};
- HandlerRegistration reg0 = manager.addHandler(MouseDownEvent.getType(),
- handler0);
- HandlerRegistration reg1 = manager.addHandler(MouseDownEvent.getType(),
- handler1);
- HandlerRegistration reg2 = manager.addHandler(MouseDownEvent.getType(),
- handler2);
+ manager.addHandler(MouseDownEvent.getType(), handler0);
+ manager.addHandler(MouseDownEvent.getType(), handler1);
+ manager.addHandler(MouseDownEvent.getType(), handler2);
// Fire the event
reset();
diff --git a/user/test/com/google/gwt/junit/client/TestManualAsync.java b/user/test/com/google/gwt/junit/client/TestManualAsync.java
index f4d62c5..907d252 100644
--- a/user/test/com/google/gwt/junit/client/TestManualAsync.java
+++ b/user/test/com/google/gwt/junit/client/TestManualAsync.java
@@ -18,6 +18,11 @@
import static com.google.gwt.junit.client.GWTTestCaseTest.SetUpTearDownState.IS_SETUP;
import static com.google.gwt.junit.client.GWTTestCaseTest.SetUpTearDownState.IS_TORNDOWN;
+import com.google.gwt.dom.client.ButtonElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Timer;
/**
@@ -27,6 +32,80 @@
*/
public class TestManualAsync extends GWTTestCaseTest {
+ // The following tests (all prefixed with test_) are intended to test the
+ // interaction of synchronous failures (within event handlers) with various
+ // other types of failures and successes. All of them are expected to fail
+ // with the message "Expected failure".
+ //
+ // Nomenclature for these tests:
+ // DTF => delayTestFinish()
+ // SF => synchronous failure (from event handler)
+ // FT => finishTest()
+ // F => fail()
+ // R => return;
+
+ public void test_dtf_sf() {
+ delayTestFinish();
+ synchronousFailure("test_dtf_sf");
+ }
+
+ public void test_dtf_sf_f() {
+ delayTestFinish();
+ synchronousFailure("test_dtf_sf_f");
+ failNow("test_dtf_sf_f");
+ }
+
+ public void test_dtf_sf_ft() {
+ delayTestFinish();
+ synchronousFailure("test_dtf_sf_ft");
+ finishTest();
+ }
+
+ public void test_dtf_sf_r_f() {
+ delayTestFinish();
+ synchronousFailure("test_dtf_sf_r_f");
+ failLater("test_dtf_sf_r_f");
+ }
+
+ public void test_dtf_sf_r_ft() {
+ delayTestFinish();
+ synchronousFailure("test_dtf_sf_r_ft");
+ finishTestLater();
+ }
+
+ public void test_sf() {
+ synchronousFailure("test_sf");
+ }
+
+ public void test_sf_dtf_f() {
+ synchronousFailure("test_sf_dtf_f");
+ delayTestFinish();
+ failNow("test_sf_dtf_f");
+ }
+
+ public void test_sf_dtf_ft() {
+ synchronousFailure("test_sf_dtf_ft");
+ delayTestFinish();
+ finishTest();
+ }
+
+ public void test_sf_dtf_r_f() {
+ synchronousFailure("test_sf_dtf_r_f");
+ delayTestFinish();
+ failLater("test_sf_dtf_r_f");
+ }
+
+ public void test_sf_dtf_r_ft() {
+ synchronousFailure("test_sf_dtf_r_ft");
+ delayTestFinish(5 * 60 * 1000);
+ finishTestLater();
+ }
+
+ public void test_sf_f() {
+ synchronousFailure("test_sf_f");
+ failNow("test_sf_f");
+ }
+
/**
* Fails normally.
*/
@@ -55,7 +134,7 @@
* Async fails.
*/
public void testFailAsync() {
- delayTestFinish(200);
+ delayTestFinish(1000);
new Timer() {
public void run() {
fail("Expected failure");
@@ -64,6 +143,41 @@
}
/**
+ * Tests the case where a JUnit exception is thrown from an event handler, but
+ * after this test method has completed successfully.
+ *
+ * This test should *not* fail, but the next one should.
+ */
+ public void testLateFailPart1() {
+ // Leave the test in synchronous mode, but crank up a timer to fail in 2.5s.
+ new Timer() {
+ @Override
+ public void run() {
+ // This fail should be called during the next test.
+ fail();
+ }
+ }.schedule(2500);
+
+ // We don't actually assert anything here. This test exists solely to make
+ // the next one fail.
+ }
+
+ /**
+ * Second half of the previous test.
+ */
+ public void testLateFailPart2() {
+ // Go into async mode from 5s, finishing in 4. The timer from the previous
+ // test will go off and call fail() before finishTest() is called.
+ delayTestFinish(5000);
+ new Timer() {
+ @Override
+ public void run() {
+ finishTest();
+ }
+ }.schedule(4000);
+ }
+
+ /**
* Completes normally.
*/
public void testNormal() {
@@ -182,4 +296,52 @@
}.schedule(200);
}
+ // Call delayTestFinish() with enough time so that failLater() will
+ // definitely fail.
+ private void delayTestFinish() {
+ delayTestFinish(2500);
+ }
+
+ // Fail asynchronously after a small amount of time.
+ private void failLater(final String failMsg) {
+ new Timer() {
+ @Override
+ public void run() {
+ failNow(failMsg);
+ }
+ }.schedule(100);
+ }
+
+ // Fail synchronously with an "expected failure" message.
+ private void failNow(String failMsg) {
+ fail("Expected failure (" + failMsg + ")");
+ }
+
+ // Finish the test asynchronously after a small amount of time.
+ private void finishTestLater() {
+ new Timer() {
+ @Override
+ public void run() {
+ finishTest();
+ }
+ }.schedule(1);
+ }
+
+ // Trigger a test failure synchronously, but from within an event handler.
+ // (The exception thrown from fail() will get caught by the GWT
+ // UncaughtExceptionHandler).
+ private void synchronousFailure(final String failMsg) {
+ ButtonElement btn = Document.get().createButtonElement();
+ Document.get().getBody().appendChild(btn);
+ Event.sinkEvents(btn, Event.ONCLICK);
+
+ EventListener listener = new EventListener() {
+ public void onBrowserEvent(Event event) {
+ failNow(failMsg);
+ }
+ };
+
+ DOM.setEventListener(btn.<com.google.gwt.user.client.Element>cast(), listener);
+ btn.click();
+ }
}
diff --git a/user/test/com/google/gwt/user/client/CommandExecutorTest.java b/user/test/com/google/gwt/user/client/CommandExecutorTest.java
index 1b335d9..d96a761 100644
--- a/user/test/com/google/gwt/user/client/CommandExecutorTest.java
+++ b/user/test/com/google/gwt/user/client/CommandExecutorTest.java
@@ -206,7 +206,7 @@
UncaughtExceptionHandler ueh1 = new UncaughtExceptionHandler() {
public void onUncaughtException(Throwable e) {
- if (!(e instanceof CommandCanceledException)) {
+ if (!(e instanceof CommandCanceledException || e instanceof IncrementalCommandCanceledException)) {
originalUEH.onUncaughtException(e);
return;
}
diff --git a/user/test/com/google/gwt/user/client/ui/DisclosurePanelTest.java b/user/test/com/google/gwt/user/client/ui/DisclosurePanelTest.java
index 6039eea..41c8828 100644
--- a/user/test/com/google/gwt/user/client/ui/DisclosurePanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DisclosurePanelTest.java
@@ -81,14 +81,14 @@
public void testEvents() {
final DisclosurePanel panel = createTestPanel();
- assertEquals(1, panel.getHandlers().getHandlerCount(CloseEvent.getType()));
+ assertEquals(1, panel.getHandlerManager().getHandlerCount(CloseEvent.getType()));
panel.addCloseHandler(new CloseHandler<DisclosurePanel>() {
public void onClose(CloseEvent<DisclosurePanel> event) {
// for now nothing.
}
});
- assertEquals(2, panel.getHandlers().getHandlerCount(CloseEvent.getType()));
+ assertEquals(2, panel.getHandlerManager().getHandlerCount(CloseEvent.getType()));
}
/**
@@ -126,8 +126,8 @@
panel.addEventHandler(handleA);
panel.addEventHandler(handleB);
// There is one to begin with.
- assertEquals(3, panel.getHandlers().getHandlerCount(CloseEvent.getType()));
- assertEquals(3, panel.getHandlers().getHandlerCount(OpenEvent.getType()));
+ assertEquals(3, panel.getHandlerManager().getHandlerCount(CloseEvent.getType()));
+ assertEquals(3, panel.getHandlerManager().getHandlerCount(OpenEvent.getType()));
panel.setOpen(true);
// We expect onOpen to fire and onClose to not fire.
@@ -144,8 +144,8 @@
aDidFire[OPEN] = bDidFire[CLOSE] = false;
panel.removeEventHandler(handleB);
- assertEquals(2, panel.getHandlers().getHandlerCount(OpenEvent.getType()));
- assertEquals(2, panel.getHandlers().getHandlerCount(CloseEvent.getType()));
+ assertEquals(2, panel.getHandlerManager().getHandlerCount(OpenEvent.getType()));
+ assertEquals(2, panel.getHandlerManager().getHandlerCount(CloseEvent.getType()));
panel.setOpen(true);
panel.setOpen(false);
diff --git a/user/test/com/google/gwt/user/datepicker/client/DateChangeEventTest.java b/user/test/com/google/gwt/user/datepicker/client/DateChangeEventTest.java
index b8c5361..9c68c69 100644
--- a/user/test/com/google/gwt/user/datepicker/client/DateChangeEventTest.java
+++ b/user/test/com/google/gwt/user/datepicker/client/DateChangeEventTest.java
@@ -18,6 +18,7 @@
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.DateValueChangeTester;
@@ -41,6 +42,10 @@
return handlers.addHandler(ValueChangeEvent.getType(), handler);
}
+ public void fireEvent(GwtEvent<?> event) {
+ handlers.fireEvent(event);
+ }
+
public HandlerManager getHandlers() {
return handlers;
}
@@ -65,5 +70,4 @@
public void testValueChangeViaHasValue() {
new DateValueChangeTester(new MockWidget()).run();
}
-
}