You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by mg...@apache.org on 2012/03/08 14:29:00 UTC

[1/2] git commit: WICKET-4443 AbstractClassResolver recreates URL incorrectly

Updated Branches:
  refs/heads/master 5b954da73 -> 38a500a45


WICKET-4443 AbstractClassResolver recreates URL incorrectly

Use a custom comparator when using Set<URL>.
Add a comment explaining how to deal with URLs with custom schemes in UrlResourceStreamReference.


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/38a500a4
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/38a500a4
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/38a500a4

Branch: refs/heads/master
Commit: 38a500a458bf2c42b896fa2ff6dc0ae5824ba73c
Parents: c7ff501
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Thu Mar 8 15:12:17 2012 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Thu Mar 8 15:28:22 2012 +0200

----------------------------------------------------------------------
 .../wicket/application/AbstractClassResolver.java  |   27 ++++-------
 .../wicket/application/CompoundClassResolver.java  |   16 ++-----
 .../wicket/application/ReloadingClassLoader.java   |    5 +-
 .../caching/UrlResourceStreamReference.java        |   15 +++++-
 .../collections/UrlExternalFormComparator.java     |   38 +++++++++++++++
 5 files changed, 66 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/38a500a4/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java b/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java
index 108029e..dbd4fe2 100644
--- a/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java
+++ b/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java
@@ -18,17 +18,16 @@ package org.apache.wicket.application;
 
 import java.lang.ref.WeakReference;
 import java.net.URL;
-import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.HashSet;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Set;
+import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 import org.apache.wicket.Application;
 import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.util.collections.UrlExternalFormComparator;
 
 /**
  * An abstract implementation of a {@link IClassResolver} which uses a {@link ClassLoader} for
@@ -128,35 +127,28 @@ public abstract class AbstractClassResolver implements IClassResolver
 	@Override
 	public Iterator<URL> getResources(final String name)
 	{
-		List<URL> resultList = new ArrayList<URL>();
+		Set<URL> resultSet = new TreeSet<URL>(new UrlExternalFormComparator());
 
-		// URL's externalForm should be used instead of URLs as Set keys. See WICKET-3867/4203.
-		Set<String> loadedResources = new HashSet<String>();
 		try
 		{
 			// Try the classloader for the wicket jar/bundle
 			Enumeration<URL> resources = Application.class.getClassLoader().getResources(name);
-			loadResources(resources, loadedResources);
+			loadResources(resources, resultSet);
 
 			// Try the classloader for the user's application jar/bundle
 			resources = Application.get().getClass().getClassLoader().getResources(name);
-			loadResources(resources, loadedResources);
+			loadResources(resources, resultSet);
 
 			// Try the context class loader
 			resources = getClassLoader().getResources(name);
-			loadResources(resources, loadedResources);
-
-			for (String urlExternalForm : loadedResources)
-			{
-				resultList.add(new URL(urlExternalForm));
-			}
+			loadResources(resources, resultSet);
 		}
 		catch (Exception e)
 		{
 			throw new WicketRuntimeException(e);
 		}
 
-		return resultList.iterator();
+		return resultSet.iterator();
 	}
 
 	/**
@@ -164,15 +156,14 @@ public abstract class AbstractClassResolver implements IClassResolver
 	 * @param resources
 	 * @param loadedResources
 	 */
-	private void loadResources(Enumeration<URL> resources, Set<String> loadedResources)
+	private void loadResources(Enumeration<URL> resources, Set<URL> loadedResources)
 	{
 		if (resources != null)
 		{
 			while (resources.hasMoreElements())
 			{
 				final URL url = resources.nextElement();
-				String externalForm = url.toExternalForm();
-				loadedResources.add(externalForm);
+				loadedResources.add(url);
 			}
 		}
 	}

http://git-wip-us.apache.org/repos/asf/wicket/blob/38a500a4/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java b/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java
index 05aff82..8a39a9c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java
+++ b/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java
@@ -17,13 +17,13 @@
 package org.apache.wicket.application;
 
 import java.net.URL;
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.CopyOnWriteArrayList;
 
+import org.apache.wicket.util.collections.UrlExternalFormComparator;
 import org.apache.wicket.util.lang.Args;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -93,23 +93,15 @@ public class CompoundClassResolver implements IClassResolver
 	{
 		Args.notNull(name, "name");
 
-		Set<String> externalForms = new TreeSet<String>();
-		List<URL> urls = new ArrayList<URL>();
+		Set<URL> urls = new TreeSet<URL>(new UrlExternalFormComparator());
+
 		for (IClassResolver resolver : resolvers)
 		{
 			Iterator<URL> it = resolver.getResources(name);
 			while (it.hasNext())
 			{
 				URL url = it.next();
-
-				// use URL's external form to make the check for equality/containment
-				// because URL makes domain name resolution and is slow
-				String externalForm = url.toExternalForm();
-				if (externalForms.contains(externalForm) == false)
-				{
-					externalForms.add(externalForm);
-					urls.add(url);
-				}
+				urls.add(url);
 			}
 		}
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/38a500a4/wicket-core/src/main/java/org/apache/wicket/application/ReloadingClassLoader.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/application/ReloadingClassLoader.java b/wicket-core/src/main/java/org/apache/wicket/application/ReloadingClassLoader.java
index 6c170ff..e31c915 100644
--- a/wicket-core/src/main/java/org/apache/wicket/application/ReloadingClassLoader.java
+++ b/wicket-core/src/main/java/org/apache/wicket/application/ReloadingClassLoader.java
@@ -21,11 +21,12 @@ import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.TreeSet;
 
+import org.apache.wicket.util.collections.UrlExternalFormComparator;
 import org.apache.wicket.util.file.File;
 import org.apache.wicket.util.listener.IChangeListener;
 import org.apache.wicket.util.time.Duration;
@@ -45,7 +46,7 @@ public class ReloadingClassLoader extends URLClassLoader
 {
 	private static final Logger log = LoggerFactory.getLogger(ReloadingClassLoader.class);
 
-	private static final Set<URL> urls = new HashSet<URL>();
+	private static final Set<URL> urls = new TreeSet<URL>(new UrlExternalFormComparator());
 
 	private static final List<String> patterns = new ArrayList<String>();
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/38a500a4/wicket-core/src/main/java/org/apache/wicket/util/resource/locator/caching/UrlResourceStreamReference.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/util/resource/locator/caching/UrlResourceStreamReference.java b/wicket-core/src/main/java/org/apache/wicket/util/resource/locator/caching/UrlResourceStreamReference.java
index d1f36ab..a627cca 100644
--- a/wicket-core/src/main/java/org/apache/wicket/util/resource/locator/caching/UrlResourceStreamReference.java
+++ b/wicket-core/src/main/java/org/apache/wicket/util/resource/locator/caching/UrlResourceStreamReference.java
@@ -23,7 +23,13 @@ import org.apache.wicket.WicketRuntimeException;
 import org.apache.wicket.util.resource.UrlResourceStream;
 
 /**
- * A reference which may be used to recreate {@link UrlResourceStream}
+ * A reference which may be used to recreate {@link UrlResourceStream}.
+ * <p>
+ * If the UrlResourceStream deals with URLs with custom {@link java.net.URLStreamHandler}
+ * then you will need to export <em>java.protocol.handler.pkgs</em> system property
+ * so that the JVM can automatically use them to re-create the URL from its cached
+ * external form.
+ * </p>
  */
 class UrlResourceStreamReference extends AbstractResourceStreamReference
 {
@@ -46,8 +52,11 @@ class UrlResourceStreamReference extends AbstractResourceStreamReference
 		}
 		catch (MalformedURLException e)
 		{
-			// should not ever happen. The cached url is created by previously existing URL
-			// instance
+			// It can happen when the previously existing URL had a non-standard protocol, and
+			// had a custom URLStreamHandler associated with it, which knew how to deal with
+			// said protocol. When the URL is recreated from the external form, the
+			// URLStreamHandler is no longer associated, and, if the URL has a non-standard
+			// protocol for which Java has no handler, a MalformedURLException will be thrown.
 			throw new WicketRuntimeException(e);
 		}
 	}

http://git-wip-us.apache.org/repos/asf/wicket/blob/38a500a4/wicket-util/src/main/java/org/apache/wicket/util/collections/UrlExternalFormComparator.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/collections/UrlExternalFormComparator.java b/wicket-util/src/main/java/org/apache/wicket/util/collections/UrlExternalFormComparator.java
new file mode 100644
index 0000000..d79e2d8
--- /dev/null
+++ b/wicket-util/src/main/java/org/apache/wicket/util/collections/UrlExternalFormComparator.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache 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 org.apache.wicket.util.collections;
+
+import java.net.URL;
+import java.util.Comparator;
+
+/**
+ * A comparator of URL instances.
+ *
+ * Comparing URLs with their implementation of #equals() is
+ * bad because it may cause problems like DNS resolving, or other
+ * slow checks. This comparator uses the external form of an URL
+ * to make a simple comparison of two Strings.
+ *
+ * @since 1.5.6
+ */
+public class UrlExternalFormComparator implements Comparator<URL>
+{
+	public int compare(URL url1, URL url2)
+	{
+		return url1.toExternalForm().compareTo(url2.toExternalForm());
+	}
+}