Author: peter_firmstone Date: Mon May 19 10:54:16 2014 New Revision: 1595826
URL: http://svn.apache.org/r1595826 Log: Move forName method out of ClassLoading, to avoid causing early loading of ClassLoading class, in case RMIClassLoaderSpi providers aren't ready. Added: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/LoadClass.java Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/resource/Service.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/ActivateWrapper.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/NonActivatableServiceDescriptor.java river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationFile.java river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationProvider.java river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/ClassLoading.java river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/pref/PreferredClassProvider.java Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/resource/Service.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/resource/Service.java?rev=1595826&r1=1595825&r2=1595826&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/resource/Service.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/resource/Service.java Mon May 19 10:54:16 2014 @@ -32,6 +32,7 @@ import java.util.Set; import java.util.LinkedHashSet; import java.util.logging.Logger; import net.jini.loader.ClassLoading; +import net.jini.loader.LoadClass; /** @@ -274,7 +275,7 @@ public final class Service { String cn = nextName; nextName = null; try { - Class c = ClassLoading.forName(cn, true, loader); + Class c = LoadClass.forName(cn, true, loader); if (!service.isAssignableFrom(c)) { log.severe("service classloader is " + service.getClass().getClassLoader() Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/ActivateWrapper.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/ActivateWrapper.java?rev=1595826&r1=1595825&r2=1595826&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/ActivateWrapper.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/ActivateWrapper.java Mon May 19 10:54:16 2014 @@ -55,6 +55,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import net.jini.io.MarshalledInstance; import net.jini.loader.ClassLoading; +import net.jini.loader.LoadClass; /** * A wrapper for activatable objects, providing separation of the import @@ -465,7 +466,7 @@ public class ActivateWrapper implements } boolean initialize = false; - Class ac = ClassLoading.forName(desc.className, initialize, cl); + Class ac = LoadClass.forName(desc.className, initialize, cl); logger.log(Level.FINEST, "Obtained implementation class: {0}", ac); t.setContextClassLoader(cl); Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/NonActivatableServiceDescriptor.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/NonActivatableServiceDescriptor.java?rev=1595826&r1=1595825&r2=1595826&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/NonActivatableServiceDescriptor.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/NonActivatableServiceDescriptor.java Mon May 19 10:54:16 2014 @@ -45,6 +45,7 @@ import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; import net.jini.loader.ClassLoading; +import net.jini.loader.LoadClass; /** * Class used to launch shared, non-activatable, in-process @@ -653,7 +654,7 @@ public class NonActivatableServiceDescri logger.finest("Attempting to get implementation class"); Class implClass = null; implClass = - ClassLoading.forName(getImplClassName(), false, newClassLoader); + LoadClass.forName(getImplClassName(), false, newClassLoader); logger.finest("Setting context class loader"); curThread.setContextClassLoader(newClassLoader); Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationFile.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationFile.java?rev=1595826&r1=1595825&r2=1595826&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationFile.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationFile.java Mon May 19 10:54:16 2014 @@ -57,6 +57,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import net.jini.export.Exporter; import net.jini.loader.ClassLoading; +import net.jini.loader.LoadClass; import net.jini.security.ProxyPreparer; import net.jini.security.Security; @@ -2334,7 +2335,7 @@ public class ConfigurationFile extends A throws ConfigurationException { try { - Class result = ClassLoading.forName(name, false, cl); + Class result = LoadClass.forName(name, false, cl); Class c = result; do { if (!Modifier.isPublic(c.getModifiers())) { Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationProvider.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationProvider.java?rev=1595826&r1=1595825&r2=1595826&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationProvider.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/config/ConfigurationProvider.java Mon May 19 10:54:16 2014 @@ -33,6 +33,7 @@ import java.util.Enumeration; import java.util.logging.Level; import java.util.logging.Logger; import net.jini.loader.ClassLoading; +import net.jini.loader.LoadClass; import net.jini.security.Security; /** @@ -241,7 +242,7 @@ public class ConfigurationProvider { return new ConfigurationFile(options, cl); } try { - Class cls = ClassLoading.forName(cname, true, resourceLoader); + Class cls = LoadClass.forName(cname, true, resourceLoader); if (!Configuration.class.isAssignableFrom(cls)) { configEx = new ConfigurationException( "provider class " + cname + Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/ClassLoading.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/ClassLoading.java?rev=1595826&r1=1595825&r2=1595826&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/ClassLoading.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/ClassLoading.java Mon May 19 10:54:16 2014 @@ -18,9 +18,6 @@ package net.jini.loader; -import au.net.zeus.collection.RC; -import au.net.zeus.collection.Ref; -import au.net.zeus.collection.Referrer; import java.lang.ref.SoftReference; import java.net.MalformedURLException; import java.rmi.server.RMIClassLoader; @@ -32,19 +29,9 @@ import java.util.Iterator; import java.util.Map; import java.util.ServiceLoader; import java.util.WeakHashMap; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.FutureTask; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import net.jini.security.Security; -import org.apache.river.impl.thread.NamedThreadFactory; /** * Provides static methods for loading classes using {@link @@ -202,22 +189,6 @@ public final class ClassLoading { return provider(providerName, providerLoader); } } - - /** - * loaderMap contains a list of single threaded ExecutorService's for - * each ClassLoader, used for loading classes and proxies to avoid - * ClassLoader lock contention. An Entry is removed if the ClassLoader - * becomes weakly reachable, or the ExecutorService hasn't been used - * recently. - */ - private static final ConcurrentMap<ClassLoader,ExecutorService> loaderMap - = RC.concurrentMap( - new ConcurrentHashMap<Referrer<ClassLoader>,Referrer<ExecutorService>>(), - Ref.WEAK_IDENTITY, - Ref.TIME, - 10000L, - 10000L - ); /** * per-thread cache (weakly) mapping verifierLoader values to @@ -543,95 +514,6 @@ public final class ClassLoading { verifiedCodebases.put(codebase, new SoftReference(codebase)); return; } - - /** - * Returns the {@code Class} object associated with the class or - * interface with the given string name, using the given class loader. - * - * This method calls {@link Class#forName(String,boolean,ClassLoader)}, - * from a Thread dedicated for each - * ClassLoader, avoiding contention for ClassLoader locks by thread - * confinement. This provides a significant scalability benefit for - * JERI, without needing to resort to parallel ClassLoader locks, which - * isn't part of the Java specification. - * - * If loader is null, thread confinement is not used. - * - * @param name fully qualified name of the desired class - * @param initialize whether the class must be initialized - * @param loader class loader from which the class must be loaded - * @return class object representing the desired class - * - * @exception LinkageError if the linkage fails - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails - * @exception ClassNotFoundException if the class cannot be located by - * the specified class loader - * @see Class - * @since 3.0 - */ - public static Class<?> forName(String name, boolean initialize, - ClassLoader loader) - throws ClassNotFoundException - { - if (loader == null) return Class.forName(name, initialize, loader); - // Don't thread confine profiler ClassLoaders. - if (loader.toString().startsWith("javax.management.remote.rmi.RMIConnectionImpl") ) - return Class.forName(name, initialize, loader); - - ExecutorService exec = loaderMap.get(loader); - if (exec == null){ - exec = new ThreadPoolExecutor( - 1, - 1, - 0, - TimeUnit.SECONDS, - new LinkedBlockingQueue(), - new NamedThreadFactory(loader.toString(),false), - new ThreadPoolExecutor.CallerRunsPolicy() - ); - ExecutorService existed = loaderMap.putIfAbsent(loader, exec); - if (existed != null){ - exec = existed; - } - } - FutureTask<Class> future = new FutureTask(new GetClassTask(name, initialize, loader)); - exec.submit(future); - try { - return future.get(); - } catch (InterruptedException e){ - e.fillInStackTrace(); - throw new ClassNotFoundException("Interrupted, Unable to find Class: " + name, e); - } catch (ExecutionException e){ - Throwable t = e.getCause(); - if (t instanceof LinkageError) throw (LinkageError) t; - if (t instanceof ExceptionInInitializerError) - throw (ExceptionInInitializerError) t; - if (t instanceof SecurityException) throw (SecurityException) t; - if (t instanceof ClassNotFoundException ) - throw (ClassNotFoundException) t; - if (t instanceof NullPointerException) throw (NullPointerException) t; - throw new ClassNotFoundException("Unable to find Class:" + name, t); - } - } - - private static class GetClassTask implements Callable<Class> { - private final String name; - private final boolean initialize; - private final ClassLoader loader; - - private GetClassTask(String name, boolean initialize, ClassLoader loader){ - this.name = name; - this.initialize = initialize; - this.loader = loader; - } - - @Override - public Class call() throws ClassNotFoundException { - return Class.forName(name, initialize, loader); - } - - } private ClassLoading() { throw new AssertionError(); } } Added: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/LoadClass.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/LoadClass.java?rev=1595826&view=auto ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/LoadClass.java (added) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/LoadClass.java Mon May 19 10:54:16 2014 @@ -0,0 +1,162 @@ +/* + * 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 net.jini.loader; + +import au.net.zeus.collection.RC; +import au.net.zeus.collection.Ref; +import au.net.zeus.collection.Referrer; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.FutureTask; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.river.impl.thread.NamedThreadFactory; + +/** + * LoadClass delegates to @link {Class#forName(String, boolean, ClassLoader)}, + * calls to each ClassLoader are thread confined. + * + * @author peter + */ +public class LoadClass { + + private LoadClass() {throw new AssertionError();} + /** + * loaderMap contains a list of single threaded ExecutorService's for + * each ClassLoader, used for loading classes and proxies to avoid + * ClassLoader lock contention. An Entry is removed if the ClassLoader + * becomes weakly reachable, or the ExecutorService hasn't been used + * recently. + */ + private static final ConcurrentMap<ClassLoader, ExecutorService> loaderMap + = RC.concurrentMap( + new ConcurrentHashMap<Referrer<ClassLoader>, + Referrer<ExecutorService>>(), + Ref.WEAK_IDENTITY, + Ref.TIME, + 10000L, + 10000L + ); + + /** + * Returns the {@code Class} object associated with the class or + * interface with the given string name, using the given class loader. + * + * This method calls {@link Class#forName(String,boolean,ClassLoader)}, + * from a Thread dedicated for each + * ClassLoader, avoiding contention for ClassLoader locks by thread + * confinement. This provides a significant scalability benefit for + * JERI, without needing to resort to parallel ClassLoader locks, which + * isn't part of the Java specification. + * + * If loader is null, thread confinement is not used. + * + * @param name fully qualified name of the desired class + * @param initialize whether the class must be initialized + * @param loader class loader from which the class must be loaded + * @return class object representing the desired class + * + * @exception LinkageError if the linkage fails + * @exception ExceptionInInitializerError if the initialization provoked + * by this method fails + * @exception ClassNotFoundException if the class cannot be located by + * the specified class loader + * @see Class + * @since 3.0 + */ + public static Class forName(String name, boolean initialize, ClassLoader loader) + throws ClassNotFoundException + { + if (loader == null) return Class.forName(name, initialize, loader); + if (loader.toString().startsWith( + "javax.management.remote.rmi.RMIConnectionImpl")) + { + return Class.forName(name, initialize, loader); + } + ExecutorService exec = loaderMap.get(loader); + if (exec == null) { + exec = new ThreadPoolExecutor( + 1, + 1, + 0, + TimeUnit.SECONDS, + new LinkedBlockingQueue(), + new NamedThreadFactory(loader.toString(), false), + new ThreadPoolExecutor.CallerRunsPolicy() + ); + ExecutorService existed = loaderMap.putIfAbsent(loader, exec); + if (existed != null) { + exec = existed; + } + } + FutureTask<Class> future = + new FutureTask(new GetClassTask(name, initialize, loader)); + exec.submit(future); + try { + return future.get(); + } catch (InterruptedException e) { + e.fillInStackTrace(); + throw new ClassNotFoundException( + "Interrupted, Unable to find Class: " + name, e); + } catch (ExecutionException e) { + Throwable t = e.getCause(); + if (t instanceof LinkageError) { + throw (LinkageError) t; + } + if (t instanceof ExceptionInInitializerError) { + throw (ExceptionInInitializerError) t; + } + if (t instanceof SecurityException) { + throw (SecurityException) t; + } + if (t instanceof ClassNotFoundException) { + throw (ClassNotFoundException) t; + } + if (t instanceof NullPointerException) { + throw (NullPointerException) t; + } + throw new ClassNotFoundException( + "Unable to find Class:" + name, t); + } + } + + private static class GetClassTask implements Callable<Class> { + + private final String name; + private final boolean initialize; + private final ClassLoader loader; + + private GetClassTask(String name, boolean initialize, ClassLoader loader) { + this.name = name; + this.initialize = initialize; + this.loader = loader; + } + + @Override + public Class call() throws ClassNotFoundException { + return Class.forName(name, initialize, loader); + } + + } + +} Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/pref/PreferredClassProvider.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/pref/PreferredClassProvider.java?rev=1595826&r1=1595825&r2=1595826&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/pref/PreferredClassProvider.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/loader/pref/PreferredClassProvider.java Mon May 19 10:54:16 2014 @@ -56,6 +56,7 @@ import java.util.logging.Level; import net.jini.loader.ClassAnnotation; import net.jini.loader.ClassLoading; import net.jini.loader.DownloadPermission; +import net.jini.loader.LoadClass; import org.apache.river.api.net.Uri; /** @@ -577,7 +578,7 @@ public class PreferredClassProvider exte urlsMatchLoaderAnnotation(codebaseURIs, defaultLoader))) { try { - Class c = ClassLoading.forName(name, false, defaultLoader); + Class c = LoadClass.forName(name, false, defaultLoader); if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "class \"{0}\" found " + "via defaultLoader, defined by {1}", @@ -609,7 +610,7 @@ public class PreferredClassProvider exte !(codebaseLoader instanceof PreferredClassLoader)) { try { - Class c = ClassLoading.forName(name, false, defaultLoader); + Class c = LoadClass.forName(name, false, defaultLoader); if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "class \"{0}\" found " + "via defaultLoader, defined by {1}", @@ -660,7 +661,7 @@ public class PreferredClassProvider exte } if (tryDL) { try { - Class c = ClassLoading.forName(name, false, defaultLoader); + Class c = LoadClass.forName(name, false, defaultLoader); if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "class \"{0}\" found " + "via defaultLoader, defined by {1}", @@ -677,7 +678,7 @@ public class PreferredClassProvider exte * context class loader as appropriate. */ try { - Class c = ClassLoading.forName(name, false, + Class c = LoadClass.forName(name, false, (sm != null && secEx == null ? codebaseLoader : contextLoader)); if (logger.isLoggable(Level.FINEST)) { @@ -1428,7 +1429,7 @@ public class PreferredClassProvider exte for (int i = 0; i < interfaces.length; i++) { Class cl = - (classObjs[i] = ClassLoading.forName(interfaces[i], false, loader)); + (classObjs[i] = LoadClass.forName(interfaces[i], false, loader)); if (!Modifier.isPublic(cl.getModifiers())) { ClassLoader current = getClassLoader(cl);
