Author: mgrigorov
Date: Thu Jul 14 11:01:25 2011
New Revision: 1146646

URL: http://svn.apache.org/viewvc?rev=1146646&view=rev
Log:
WICKET-3898 Add CompoundClassResolver


Added:
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java
Modified:
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/DefaultClassResolver.java

Added: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java?rev=1146646&view=auto
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java
 (added)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/AbstractClassResolver.java
 Thu Jul 14 11:01:25 2011
@@ -0,0 +1,185 @@
+/*
+ * 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.application;
+
+import java.lang.ref.WeakReference;
+import java.net.URI;
+import java.net.URISyntaxException;
+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.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.WicketRuntimeException;
+
+/**
+ * An abstract implementation of a {@link IClassResolver} which uses a {@link 
ClassLoader} for
+ * resolving classes.
+ * 
+ * @see org.apache.wicket.settings.IApplicationSettings#getClassResolver()
+ * 
+ * @author Juergen Donnerstag
+ * @author Jonathan Locke
+ */
+public abstract class AbstractClassResolver implements IClassResolver
+{
+       /**
+        * Usually class loaders implement more efficient caching strategies 
than we could possibly do,
+        * but we experienced synchronization issue resulting in stack traces 
like:
+        * java.lang.LinkageError: duplicate class definition:
+        * 
+        * <pre>
+        *    wicket/examples/repeater/RepeatingPage at 
java.lang.ClassLoader.defineClass1(Native Method)
+        * </pre>
+        * 
+        * This problem has gone since we synchronize the access.
+        */
+       private final ConcurrentMap<String, WeakReference<Class<?>>> classes = 
new ConcurrentHashMap<String, WeakReference<Class<?>>>();
+
+       public final Class<?> resolveClass(final String className) throws 
ClassNotFoundException
+       {
+               Class<?> clazz = null;
+               WeakReference<Class<?>> ref = classes.get(className);
+
+               // Might be garbage-collected between getting the WeakRef and 
retrieving
+               // the Class from it.
+               if (ref != null)
+               {
+                       clazz = ref.get();
+               }
+               if (clazz == null)
+               {
+                       if (className.equals("byte"))
+                       {
+                               clazz = byte.class;
+                       }
+                       else if (className.equals("short"))
+                       {
+                               clazz = short.class;
+                       }
+                       else if (className.equals("int"))
+                       {
+                               clazz = int.class;
+                       }
+                       else if (className.equals("long"))
+                       {
+                               clazz = long.class;
+                       }
+                       else if (className.equals("float"))
+                       {
+                               clazz = float.class;
+                       }
+                       else if (className.equals("double"))
+                       {
+                               clazz = double.class;
+                       }
+                       else if (className.equals("boolean"))
+                       {
+                               clazz = boolean.class;
+                       }
+                       else if (className.equals("char"))
+                       {
+                               clazz = char.class;
+                       }
+                       else
+                       {
+                               // synchronize on the only class member to load 
only one class at a time and
+                               // prevent LinkageError. See above for more info
+                               synchronized (classes)
+                               {
+                                       clazz = Class.forName(className, false, 
getClassLoader());
+                                       if (clazz == null)
+                                       {
+                                               throw new 
ClassNotFoundException(className);
+                                       }
+                               }
+                               classes.put(className, new 
WeakReference<Class<?>>(clazz));
+                       }
+               }
+               return clazz;
+       }
+
+       /**
+        * Returns the {@link ClassLoader} to be used for resolving classes
+        * 
+        * @return the {@link ClassLoader} to be used for resolving classes
+        */
+       protected abstract ClassLoader getClassLoader();
+
+       public Iterator<URL> getResources(final String name)
+       {
+               List<URL> resultList = new ArrayList<URL>();
+
+               // URIs should be used instead of URLs as Set keys. See 
WICKET-3867.
+               HashSet<URI> loadedFiles = new HashSet<URI>();
+               try
+               {
+                       // Try the classloader for the wicket jar/bundle
+                       Enumeration<URL> resources = 
Application.class.getClassLoader().getResources(name);
+                       loadResources(resources, loadedFiles);
+
+                       // Try the classloader for the user's application 
jar/bundle
+                       resources = 
Application.get().getClass().getClassLoader().getResources(name);
+                       loadResources(resources, loadedFiles);
+
+                       // Try the context class loader
+                       resources = getClassLoader().getResources(name);
+                       loadResources(resources, loadedFiles);
+
+                       for (URI uri : loadedFiles)
+                       {
+                               resultList.add(uri.toURL());
+                       }
+               }
+               catch (Exception e)
+               {
+                       throw new WicketRuntimeException(e);
+               }
+
+               return resultList.iterator();
+       }
+
+       /**
+        * 
+        * @param resources
+        * @param loadedFiles
+        * @throws URISyntaxException
+        *             if URL.toURI() throws
+        */
+       private void loadResources(Enumeration<URL> resources, Set<URI> 
loadedFiles)
+               throws URISyntaxException
+       {
+               if (resources != null)
+               {
+                       while (resources.hasMoreElements())
+                       {
+                               final URL url = resources.nextElement();
+                               URI uri = url.toURI();
+                               if (!loadedFiles.contains(uri))
+                               {
+                                       loadedFiles.add(uri);
+                               }
+                       }
+               }
+       }
+}
\ No newline at end of file

Added: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java?rev=1146646&view=auto
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java
 (added)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/CompoundClassResolver.java
 Thu Jul 14 11:01:25 2011
@@ -0,0 +1,136 @@
+/*
+ * 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.application;
+
+import java.net.URL;
+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.lang.Args;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A thread safe compound {@link IClassResolver}. Class resolving is done by 
iterating through all
+ * {@link IClassResolver}s until the class is found. Resource resolving is 
done by combining the
+ * results of all {@link IClassResolver}s.
+ * 
+ * @author Jesse Long
+ */
+public class CompoundClassResolver implements IClassResolver
+{
+       private static final Logger logger = 
LoggerFactory.getLogger(CompoundClassResolver.class);
+
+       private final List<IClassResolver> resolvers = new 
CopyOnWriteArrayList<IClassResolver>();
+
+       /**
+        * {@inheritDoc}
+        * <p>
+        * This implementation iterates through all the {@link IClassResolver} 
trying to load the class
+        * until the class is found.
+        * 
+        * @param className
+        *            The name of the class to resolve.
+        * @return The {@link Class}, if it is found.
+        * @throws ClassNotFoundException
+        *             If the class was not found
+        */
+       public Class<?> resolveClass(final String className) throws 
ClassNotFoundException
+       {
+               boolean debugEnabled = logger.isDebugEnabled();
+
+               for (IClassResolver resolver : resolvers)
+               {
+                       try
+                       {
+                               return resolver.resolveClass(className);
+                       }
+                       catch (ClassNotFoundException cnfx)
+                       {
+                               if (debugEnabled)
+                               {
+                                       logger.debug("ClassResolver '{}' cannot 
find class: '{}'", resolver.getClass()
+                                               .getName(), className);
+                               }
+                       }
+               }
+
+               throw new ClassNotFoundException(className);
+       }
+
+       /**
+        * {@inheritDoc}
+        * <p>
+        * This implementation iterates through all {@link IClassResolver}s 
added, and combines the
+        * results into one {@link Set} of {@link URL}s, and returns an {@link 
Iterator} for the set.
+        * {@link URL}s are unique in the set.
+        * 
+        * @param name
+        *            The name of the resource to find.
+        * @return An {@link Iterator} of all the {@link URL}s matching the 
resource name.
+        */
+       public Iterator<URL> getResources(final String name)
+       {
+               Args.notNull(name, "name");
+
+               Set<URL> urls = new TreeSet<URL>();
+               for (IClassResolver resolver : resolvers)
+               {
+                       Iterator<URL> it = resolver.getResources(name);
+                       while (it.hasNext())
+                       {
+                               URL url = it.next();
+                               if (urls.contains(url) == false)
+                               {
+                                       urls.add(url);
+                               }
+                       }
+               }
+
+               return urls.iterator();
+       }
+
+       /**
+        * Adds a resolver
+        * 
+        * @param resolver
+        *            The resolver to add
+        * @return {@code this} for chaining
+        */
+       public CompoundClassResolver add(final IClassResolver resolver)
+       {
+               Args.notNull(resolver, "resolver");
+               resolvers.add(resolver);
+               return this;
+       }
+
+       /**
+        * Removes a resolver
+        * 
+        * @param resolver
+        *            The resolver to remove
+        * @return {@code this} for chaining
+        */
+       public CompoundClassResolver remove(final IClassResolver resolver)
+       {
+               resolvers.remove(resolver);
+               return this;
+       }
+}
\ No newline at end of file

Modified: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/DefaultClassResolver.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/DefaultClassResolver.java?rev=1146646&r1=1146645&r2=1146646&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/DefaultClassResolver.java
 (original)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/application/DefaultClassResolver.java
 Thu Jul 14 11:01:25 2011
@@ -16,21 +16,6 @@
  */
 package org.apache.wicket.application;
 
-import java.lang.ref.WeakReference;
-import java.net.URI;
-import java.net.URISyntaxException;
-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.concurrent.ConcurrentHashMap;
-
-import org.apache.wicket.Application;
-import org.apache.wicket.WicketRuntimeException;
-
 /**
  * Resolves a class by using the classloader that loaded this class.
  * 
@@ -39,152 +24,23 @@ import org.apache.wicket.WicketRuntimeEx
  * @author Juergen Donnerstag
  * @author Jonathan Locke
  */
-public final class DefaultClassResolver implements IClassResolver
+public final class DefaultClassResolver extends AbstractClassResolver
 {
-       /**
-        * Usually class loaders implement more efficient caching strategies 
than we could possibly do,
-        * but we experienced synchronization issue resulting in stack traces 
like:
-        * java.lang.LinkageError: duplicate class definition:
-        * 
-        * <pre>
-        *    wicket/examples/repeater/RepeatingPage at 
java.lang.ClassLoader.defineClass1(Native Method)
-        * </pre>
-        * 
-        * This problem has gone since we synchronize the access.
-        */
-       private final ConcurrentHashMap<String, WeakReference<Class<?>>> 
classes = new ConcurrentHashMap<String, WeakReference<Class<?>>>();
-
-       /**
-        * @see 
org.apache.wicket.application.IClassResolver#resolveClass(java.lang.String)
-        */
-       public final Class<?> resolveClass(final String classname) throws 
ClassNotFoundException
-       {
-               Class<?> clazz = null;
-               WeakReference<Class<?>> ref = classes.get(classname);
-
-               // Might be garbage-collected between getting the WeakRef and 
retrieving
-               // the Class from it.
-               if (ref != null)
-               {
-                       clazz = ref.get();
-               }
-               if (clazz == null)
-               {
-                       if (classname.equals("byte"))
-                       {
-                               clazz = byte.class;
-                       }
-                       else if (classname.equals("short"))
-                       {
-                               clazz = short.class;
-                       }
-                       else if (classname.equals("int"))
-                       {
-                               clazz = int.class;
-                       }
-                       else if (classname.equals("long"))
-                       {
-                               clazz = long.class;
-                       }
-                       else if (classname.equals("float"))
-                       {
-                               clazz = float.class;
-                       }
-                       else if (classname.equals("double"))
-                       {
-                               clazz = double.class;
-                       }
-                       else if (classname.equals("boolean"))
-                       {
-                               clazz = boolean.class;
-                       }
-                       else if (classname.equals("char"))
-                       {
-                               clazz = char.class;
-                       }
-                       else
-                       {
-                               // synchronize on the only class member to load 
only one class at a time and
-                               // prevent LinkageError. See above for more info
-                               synchronized (classes)
-                               {
-                                       ClassLoader loader = 
Thread.currentThread().getContextClassLoader();
-                                       if (loader == null)
-                                       {
-                                               loader = 
DefaultClassResolver.class.getClassLoader();
-                                       }
-                                       // see 
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6500212
-                                       // clazz = loader.loadClass(classname);
-                                       clazz = Class.forName(classname, false, 
loader);
-                                       if (clazz == null)
-                                       {
-                                               throw new 
ClassNotFoundException(classname);
-                                       }
-                               }
-                               classes.put(classname, new 
WeakReference<Class<?>>(clazz));
-                       }
-               }
-               return clazz;
-       }
-
-       /**
-        * 
-        * @see 
org.apache.wicket.application.IClassResolver#getResources(java.lang.String)
-        */
-       public Iterator<URL> getResources(String name)
-       {
-               List<URL> resultList = new ArrayList<URL>();
-
-               // URIs should be used instead of URLs as Set keys. See 
WICKET-3867.
-               HashSet<URI> loadedFiles = new HashSet<URI>();
-               try
-               {
-                       // Try the classloader for the wicket jar/bundle
-                       Enumeration<URL> resources = 
Application.class.getClassLoader().getResources(name);
-                       loadResources(resources, loadedFiles);
-
-                       // Try the classloader for the user's application 
jar/bundle
-                       resources = 
Application.get().getClass().getClassLoader().getResources(name);
-                       loadResources(resources, loadedFiles);
-
-                       // Try the context class loader
-                       resources = 
Thread.currentThread().getContextClassLoader().getResources(name);
-                       loadResources(resources, loadedFiles);
-
-                       for (URI uri : loadedFiles)
-                       {
-                               resultList.add(uri.toURL());
-                       }
-               }
-               catch (Exception e)
-               {
-                       throw new WicketRuntimeException(e);
-               }
-
-               return resultList.iterator();
-       }
 
        /**
+        * {@inheritDoc}
         * 
-        * @param resources
-        * @param loadedFiles
-        * @throws URISyntaxException
-        *             if URL.toURI() throws
+        * @return the current {@link Thread}s context {@link ClassLoader} if 
it is set, or the
+        *         {@link ClassLoader} that was used to load this class.
         */
-       private void loadResources(Enumeration<URL> resources, Set<URI> 
loadedFiles)
-               throws URISyntaxException
+       @Override
+       protected ClassLoader getClassLoader()
        {
-               if (resources != null)
+               ClassLoader loader = 
Thread.currentThread().getContextClassLoader();
+               if (loader == null)
                {
-                       while (resources.hasMoreElements())
-                       {
-                               final URL url = resources.nextElement();
-                               URI uri = url.toURI();
-                               if (!loadedFiles.contains(uri))
-                               {
-                                       loadedFiles.add(uri);
-                               }
-                       }
+                       loader = DefaultClassResolver.class.getClassLoader();
                }
+               return loader;
        }
 }


Reply via email to