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=1590000&r1=1589999&r2=1590000&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 Fri Apr 25 11:34:00 2014 @@ -32,6 +32,7 @@ import java.security.PrivilegedException import java.util.Enumeration; import java.util.logging.Level; import java.util.logging.Logger; +import net.jini.loader.ClassLoading; import net.jini.security.Security; /** @@ -240,7 +241,7 @@ public class ConfigurationProvider { return new ConfigurationFile(options, cl); } try { - Class cls = Class.forName(cname, true, resourceLoader); + Class cls = ClassLoading.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/core/discovery/LookupLocator.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/discovery/LookupLocator.java?rev=1590000&r1=1589999&r2=1590000&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/discovery/LookupLocator.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/discovery/LookupLocator.java Fri Apr 25 11:34:00 2014 @@ -35,6 +35,7 @@ import java.security.PrivilegedAction; import net.jini.core.lookup.ServiceRegistrar; import net.jini.discovery.ConstrainableLookupLocator; import net.jini.discovery.LookupLocatorDiscovery; +import net.jini.io.MarshalledInstance; import org.apache.river.api.net.Uri; /** @@ -362,7 +363,8 @@ public class LookupLocator implements Se ObjectInputStream istr = new ObjectInputStream(sock.getInputStream()); ServiceRegistrar registrar = - (ServiceRegistrar)((MarshalledObject)istr.readObject()).get(); + (ServiceRegistrar) new MarshalledInstance( + (MarshalledObject)istr.readObject()).get(false); for (int grpCount = istr.readInt(); --grpCount >= 0; ) { istr.readUTF(); // ensure proper format, then discard } Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/IncomingUnicastResponse.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/IncomingUnicastResponse.java?rev=1590000&r1=1589999&r2=1590000&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/IncomingUnicastResponse.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/IncomingUnicastResponse.java Fri Apr 25 11:34:00 2014 @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.rmi.MarshalledObject; import net.jini.core.lookup.ServiceRegistrar; +import net.jini.io.MarshalledInstance; /** * This class encapsulates the details of unmarshaling an incoming @@ -57,7 +58,8 @@ public class IncomingUnicastResponse { { ObjectInputStream istr = new ObjectInputStream(str); registrar = - (ServiceRegistrar)((MarshalledObject)istr.readObject()).get(); + (ServiceRegistrar) new MarshalledInstance( + (MarshalledObject)istr.readObject()).get(false); int grpCount = istr.readInt(); groups = new String[grpCount]; for (int i = 0; i < groups.length; i++) { Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/OutgoingUnicastResponse.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/OutgoingUnicastResponse.java?rev=1590000&r1=1589999&r2=1590000&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/OutgoingUnicastResponse.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/OutgoingUnicastResponse.java Fri Apr 25 11:34:00 2014 @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.OutputStream; import java.rmi.MarshalledObject; import net.jini.core.lookup.ServiceRegistrar; +import net.jini.io.MarshalledInstance; /** * Encapsulate the details of marshaling a unicast response. @@ -52,7 +53,7 @@ public class OutgoingUnicastResponse { throws IOException { ObjectOutputStream ostr = new ObjectOutputStream(str); - ostr.writeObject(new MarshalledObject(reg)); + ostr.writeObject(new MarshalledInstance(reg).convertToMarshalledObject()); ostr.writeInt(groups.length); for (int i = 0; i < groups.length; i++) { ostr.writeUTF(groups[i]); Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/RemoteDiscoveryEvent.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/RemoteDiscoveryEvent.java?rev=1590000&r1=1589999&r2=1590000&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/RemoteDiscoveryEvent.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/RemoteDiscoveryEvent.java Fri Apr 25 11:34:00 2014 @@ -23,7 +23,6 @@ import java.io.ObjectInputStream; import java.rmi.MarshalledObject; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import net.jini.core.event.RemoteEvent; @@ -31,6 +30,8 @@ import net.jini.core.lookup.ServiceRegis import net.jini.io.MarshalledInstance; import com.sun.jini.proxy.MarshalledWrapper; +import java.util.List; +import net.jini.core.lookup.ServiceID; /** * Whenever the lookup discovery service discovers or discards a lookup @@ -109,7 +110,7 @@ public class RemoteDiscoveryEvent extend * * @serial */ - protected boolean discarded; + protected final boolean discarded; /** * List consisting of marshalled proxy objects where each proxy implements @@ -137,7 +138,7 @@ public class RemoteDiscoveryEvent extend * * @serial */ - protected ArrayList marshalledRegs; + private final List<MarshalledObject> marshalledRegs; /** * Array containing a subset of the set of proxies to the lookup @@ -152,7 +153,7 @@ public class RemoteDiscoveryEvent extend * * @serial */ - protected ServiceRegistrar[] regs; + private final ServiceRegistrar[] regs; /** * <code>Map</code> from the service IDs of the registrars of this event @@ -160,7 +161,7 @@ public class RemoteDiscoveryEvent extend * * @serial */ - protected Map groups; + private final Map<ServiceID,String> groups; /** * Flag related to the verification of codebase integrity. A value of @@ -202,7 +203,7 @@ public class RemoteDiscoveryEvent extend long seqNum, MarshalledObject handback, boolean discarded, - Map groups) throws IOException + Map<ServiceRegistrar,String> groups) throws IOException { super(source, eventID, seqNum, handback); this.discarded = discarded; @@ -229,11 +230,12 @@ public class RemoteDiscoveryEvent extend * * Drop any element that can't be serialized. */ - this.groups = new HashMap(groups.size()); + this.groups = new HashMap<ServiceID,String>(groups.size()); this.marshalledRegs = new ArrayList(groups.size()); - for(int i=0;i<registrars.length;i++) { + int l = registrars.length; + for(int i=0;i<l;i++) { try { - marshalledRegs.add(new MarshalledObject(registrars[i])); + marshalledRegs.add(new MarshalledInstance(registrars[i]).convertToMarshalledObject()); (this.groups).put((registrars[i]).getServiceID(), groups.get(registrars[i]) ); } catch(IOException e) { /* drop if can't serialize */ } @@ -324,8 +326,8 @@ public class RemoteDiscoveryEvent extend public ServiceRegistrar[] getRegistrars() throws LookupUnmarshalException { synchronized (marshalledRegs) { if( marshalledRegs.size() > 0 ) { - ArrayList unmarshalledRegs = new ArrayList(); - ArrayList exceptions = unmarshalRegistrars(marshalledRegs, + List unmarshalledRegs = new ArrayList(); + List exceptions = unmarshalRegistrars(marshalledRegs, unmarshalledRegs); /* Add the un-marshalled elements to the end of regs */ insertRegistrars(regs,unmarshalledRegs); @@ -363,8 +365,8 @@ public class RemoteDiscoveryEvent extend * the names of the groups in which the lookup service having * the corresponding service ID is a member. */ - public Map getGroups() { - return groups; + public Map<ServiceID,String> getGroups() { + return new HashMap<ServiceID,String>(groups); }//end getGroups /** @@ -396,8 +398,8 @@ public class RemoteDiscoveryEvent extend * result of attempts to unmarshal each element of the first * argument to this method. */ - private ArrayList unmarshalRegistrars(ArrayList marshalledRegs, - ArrayList unmarshalledRegs) + private List unmarshalRegistrars(List marshalledRegs, + List unmarshalledRegs) { ArrayList exceptions = new ArrayList(); /* Try to un-marshal each element in marshalledRegs; verify codebase @@ -450,11 +452,11 @@ public class RemoteDiscoveryEvent extend * * @param regsArray array that will receive the new references. * - * @param regsList ArrayList containing the ServiceRegistrar references + * @param regsList List containing the ServiceRegistrar references * to place in regsArray input argument. */ private static void insertRegistrars(ServiceRegistrar[] regsArray, - ArrayList regsList) + List regsList) { if((regsArray != null) && (regsList != null)) { int lenA = regsArray.length; Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/MarshalInputStream.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/MarshalInputStream.java?rev=1590000&r1=1589999&r2=1590000&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/MarshalInputStream.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/MarshalInputStream.java Fri Apr 25 11:34:00 2014 @@ -23,8 +23,7 @@ import java.io.InputStream; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; -import java.net.MalformedURLException; -import java.rmi.server.RMIClassLoader; +import java.rmi.server.RMIClassLoaderSpi; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; @@ -38,7 +37,7 @@ import org.apache.river.api.io.Distribut * An extension of <code>ObjectInputStream</code> that implements the * dynamic class loading semantics of Java(TM) Remote Method * Invocation (Java RMI) argument and result - * unmarshalling (using {@link RMIClassLoader}). A + * unmarshalling (using {@link ClassLoading}). A * <code>MarshalInputStream</code> is intended to read data written by * a corresponding {@link MarshalOutputStream}. * @@ -49,10 +48,10 @@ import org.apache.river.api.io.Distribut * class descriptors in the stream using {@link ClassLoading#loadClass * ClassLoading.loadClass} and {@link ClassLoading#loadProxyClass * ClassLoading.loadProxyClass} (which, in turn, use {@link - * RMIClassLoader#loadClass(String,String,ClassLoader) - * RMIClassLoader.loadClass} and {@link - * RMIClassLoader#loadProxyClass(String,String[],ClassLoader) - * RMIClassLoader.loadProxyClass}), optionally with codebase + * RMIClassLoaderSpi#loadClass(String,String,ClassLoader) + * RMIClassLoaderSpi.loadClass} and {@link + * RMIClassLoaderSpi#loadProxyClass(String,String[],ClassLoader) + * RMIClassLoaderSpi.loadProxyClass}), optionally with codebase * annotation strings written by a <code>MarshalOutputStream</code>. * * <p>By default, a <code>MarshalInputStream</code> ignores all Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/MarshalOutputStream.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/MarshalOutputStream.java?rev=1590000&r1=1589999&r2=1590000&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/MarshalOutputStream.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/MarshalOutputStream.java Fri Apr 25 11:34:00 2014 @@ -21,17 +21,18 @@ package net.jini.io; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.OutputStream; -import java.rmi.server.RMIClassLoader; +import java.rmi.server.RMIClassLoaderSpi; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; +import net.jini.loader.ClassLoading; import org.apache.river.api.io.DistributedObjectOutputStream; /** * An extension of <code>ObjectOutputStream</code> that implements the * dynamic class loading semantics of Java(TM) Remote Method Invocation * (Java RMI) argument and result - * marshalling (using {@link RMIClassLoader}). A + * marshalling (using {@link ClassLoading}). A * <code>MarshalOutputStream</code> writes data that is intended to be * written by a corresponding {@link MarshalInputStream}. * @@ -40,8 +41,8 @@ import org.apache.river.api.io.Distribut * ObjectOutputStream#annotateClass annotateClass} and {@link * ObjectOutputStream#annotateProxyClass annotateProxyClass} to * annotate class descriptors in the stream with codebase strings - * obtained using {@link RMIClassLoader#getClassAnnotation - * RMIClassLoader.getClassAnnotation}. + * obtained using {@link RMIClassLoaderSpi#getClassAnnotation + * RMIClassLoaderSpi.getClassAnnotation}. * * <p><code>MarshalOutputStream</code> writes class annotations to its * own stream; a subclass may override the {@link #writeAnnotation @@ -124,8 +125,8 @@ public class MarshalOutputStream * <p><code>MarshalOutputStream</code> implements this method as * follows: * - * <p>This method invokes {@link RMIClassLoader#getClassAnnotation - * RMIClassLoader.getClassAnnotation} with <code>cl</code> to get + * <p>This method invokes {@link RMIClassLoaderSpi#getClassAnnotation + * RMIClassLoaderSpi.getClassAnnotation} with <code>cl</code> to get * the appropriate class annotation string value (possibly * <code>null</code>), and then it invokes this stream's {@link * #writeAnnotation writeAnnotation} method with that string to @@ -140,7 +141,7 @@ public class MarshalOutputStream * <code>null</code> **/ protected void annotateClass(Class cl) throws IOException { - writeAnnotation(RMIClassLoader.getClassAnnotation(cl)); + writeAnnotation(ClassLoading.getClassAnnotation(cl)); } /** @@ -150,8 +151,8 @@ public class MarshalOutputStream * <p><code>MarshalOutputStream</code> implements this method as * follows: * - * <p>This method invokes {@link RMIClassLoader#getClassAnnotation - * RMIClassLoader.getClassAnnotation} with <code>cl</code> to get + * <p>This method invokes {@link RMIClassLoaderSpi#getClassAnnotation + * RMIClassLoaderSpi.getClassAnnotation} with <code>cl</code> to get * the appropriate class annotation string value (possibly * <code>null</code>), and then it invokes this stream's {@link * #writeAnnotation writeAnnotation} method with that string to @@ -166,7 +167,7 @@ public class MarshalOutputStream * <code>null</code> **/ protected void annotateProxyClass(Class cl) throws IOException { - writeAnnotation(RMIClassLoader.getClassAnnotation(cl)); + writeAnnotation(ClassLoading.getClassAnnotation(cl)); } /** 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=1590000&r1=1589999&r2=1590000&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 Fri Apr 25 11:34:00 2014 @@ -18,26 +18,145 @@ 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; +import java.rmi.server.RMIClassLoaderSpi; import java.security.AccessController; import java.security.PrivilegedAction; +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.Executors; +import java.util.concurrent.FutureTask; +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 - * RMIClassLoader} with optional verification that the codebase URLs + * RMIClassLoaderSpi} with optional verification that the codebase URIs * used to load classes provide content integrity (see {@link * Security#verifyCodebaseIntegrity * Security.verifyCodebaseIntegrity}). - * + * <p> + * Traditionally a class extending {@link RMIClassLoaderSpi} is determined by setting + * the system property "java.rmi.server.RMIClassLoaderSpi", or alternatively, + * {@link RMIClassLoaderSpi} may also be defined by {@link RMIClassLoader} + * using a provider visible to the {@link ClassLoader} returned by + * {@link ClassLoader#getSystemClassLoader} with {@link ServiceLoader}. + * </p><p> + * As explained in River-336 this isn't always practical for IDE's or other + * frameworks. To solve River-336, ClassLoading now uses {@link ServiceLoader} + * to determine a {@link RMIClassLoaderSpi} provider, however unlike + * {@link RMIClassLoader}, it uses ClassLoading's {@link ClassLoader#getResources} + * instance to find providers. So if ClassLoading is loaded by a framework + * {@link ClassLoader}, resources will be selected from ClassLoaders reachable + * from ClassLoading's own ClassLoader. + * </p><p> + * To define a new RMIClassLoaderSpi for River to utilize, create a file in + * your application jar file called: + * </p><p> + * META-INF/services/java.rmi.server.RMIClassLoaderSpi + * </p><p> + * This file should contain a single line with the fully qualified name of + * your RMIClassLoaderSpi implementation. + * </p><p> + * ClassLoading will iterate through all RMIClassLoaderSpi implementations found + * until it finds one defined by the system property: + * </p><p> + * System.getProperty("net.jini.loader.ClassLoading.provider"); + * </p><p> + * If this System property is not defined, ClassLoading will load the first + * provider found. + * </p><p> + * <h1>History</h1> + * <p>Gregg Wonderly originally reported River-336 and provided a patch + * containing a new CodebaseAccessClassLoader to replace {@link RMIClassLoader}, + * later Sim Isjkes created RiverClassLoader that utilised ServiceLoader. + * Both implementations contained methods identical to {@link RMIClassLoaderSpi}, + * however new implementations were required to extend new provider + * implementations, creating a compatibility issue with existing implementations + * extending {@link RMIClassLoaderSpi}. For backward compatibility with existing + * implementations, {@link RMIClassLoaderSpi} has been retained as the provider, + * avoiding the need to recompile client code. + * </p><p> + * Instead, all that is required for utilization of existing service provider + * {@link RMIClassLoaderSpi} implementations is to set the system property + * "net.jini.loader.ClassLoading.provider". + * </p> * @author Sun Microsystems, Inc. * @since 2.0 **/ public final class ClassLoading { + private final static Logger logger = Logger.getLogger(ClassLoading.class.getName()); + private static final RMIClassLoaderSpi provider; + + static { + provider = AccessController.doPrivileged( + new PrivilegedAction<RMIClassLoaderSpi>(){ + @Override + public RMIClassLoaderSpi run() { + String providerClassName = + System.getProperty("net.jini.loader.ClassLoading.provider"); + ServiceLoader<RMIClassLoaderSpi> loader + = ServiceLoader.load(RMIClassLoaderSpi.class, + ClassLoading.class.getClassLoader()); + Iterator<RMIClassLoaderSpi> iter = loader.iterator(); + RMIClassLoaderSpi firstSpi; + while ( iter.hasNext() ) { + try { + firstSpi = iter.next(); + if (firstSpi != null) { + if (providerClassName == null) { + logger.log(Level.CONFIG, "loaded: {0}", firstSpi.getClass().getName()); + return firstSpi; + } + if (!providerClassName.equals(firstSpi.getClass().getName())) + continue; + logger.log(Level.CONFIG, "loaded: {0}", providerClassName); + return firstSpi; + } + } catch (Exception e) { + logger.log( + Level.CONFIG, + "error loading RMIClassLoaderSpi: {0}", + new Object[]{e} + ); + } + } + if (providerClassName != null) logger.log(Level.CONFIG, + "uable to find {0}" , providerClassName); + return null; + } + }); + } + + /** + * 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 @@ -47,12 +166,75 @@ public final class ClassLoading { private static final ThreadLocal perThreadCache = new ThreadLocal() { protected Object initialValue() { return new WeakHashMap(); } }; + + /** + * Returns a class loader that loads classes from the given codebase + * RFC3986 compliant URI path. + * + * <p>This method delegates to the + * {@link RMIClassLoaderSpi#getClassLoader(String)} method + * of the provider instance, passing <code>codebase</code> as the argument. + * + * <p>If there is a security manger, its <code>checkPermission</code> + * method will be invoked with a + * <code>RuntimePermission("getClassLoader")</code> permission; + * this could result in a <code>SecurityException</code>. + * The provider implementation of this method may also perform further + * security checks to verify that the calling context has permission to + * connect to all of the URIs in the codebase URI path. + * + * @param codebase the list of URIs (space-separated) from which + * the returned class loader will load classes from, or <code>null</code> + * + * @return a class loader that loads classes from the given codebase URI + * path + * + * @throws MalformedURLException if <code>codebase</code> is + * non-<code>null</code> and contains an non RFC3986 compliant URI, or + * if <code>codebase</code> is <code>null</code> and a provider-specific + * URL used to identify the class loader is invalid + * + * @throws SecurityException if there is a security manager and the + * invocation of its <code>checkPermission</code> method fails, or + * if the caller does not have permission to connect to all of the + * URIs in the codebase URI path + * @since 3.0 + */ + public static ClassLoader getClassLoader(String codebase) + throws MalformedURLException, SecurityException + { + if (provider != null) return provider.getClassLoader(codebase); + return RMIClassLoader.getClassLoader(codebase); + } + + /** + * Returns the annotation string (representing a location for + * the class definition as a single or space delimited list of + * RFC3986 compliant URI) that JERI will use to annotate the class + * descriptor when marshalling objects of the given class. + * + * <p>This method delegates to the + * {@link RMIClassLoaderSpi#getClassAnnotation(Class)} method + * of the provider instance, passing <code>cl</code> as the argument. + * + * @param cl the class to obtain the annotation for + * + * @return a string to be used to annotate the given class when + * it gets marshalled, or <code>null</code> + * + * @throws NullPointerException if <code>cl</code> is <code>null</code> + * @since 3.0 + */ + public static String getClassAnnotation(Class<?> cl) { + if (provider != null) return provider.getClassAnnotation(cl); + return RMIClassLoader.getClassAnnotation(cl); + } /** * Loads a class using {@link - * RMIClassLoader#loadClass(String,String,ClassLoader) - * RMIClassLoader.loadClass}, optionally verifying that the - * codebase URLs provide content integrity. + * RMIClassLoaderSpi#loadClass(String,String,ClassLoader)}, + * optionally verifying that the RFC3986 compliant + * codebase URIs provide content integrity. * * <p>If <code>verifyCodebaseIntegrity</code> is <code>true</code> * and <code>codebase</code> is not <code>null</code>, then this @@ -72,19 +254,19 @@ public final class ClassLoading { * other exception, then this method throws that exception. * * <p>This method then invokes {@link - * RMIClassLoader#loadClass(String,String,ClassLoader) - * RMIClassLoader.loadClass} with <code>codebase</code> as the + * RMIClassLoaderSpi#loadClass(String,String,ClassLoader) + * RMIClassLoaderSpi.loadClass} with <code>codebase</code> as the * first argument (or <code>null</code> if in the previous step * <code>Security.verifyCodebaseIntegrity</code> was invoked and * it threw a <code>SecurityException</code>), <code>name</code> * as the second argument, and <code>defaultLoader</code> as the - * third argument. If <code>RMIClassLoader.loadClass</code> + * third argument. If <code>RMIClassLoaderSpi.loadClass</code> * throws a <code>ClassNotFoundException</code>, then this method * throws a <code>ClassNotFoundException</code>; if - * <code>RMIClassLoader.loadClass</code> throws any other + * <code>RMIClassLoaderSpi.loadClass</code> throws any other * exception, then this method throws that exception; otherwise, * this method returns the <code>Class</code> returned by - * <code>RMIClassLoader.loadClass</code>. + * <code>RMIClassLoaderSpi.loadClass</code>. * * @param codebase the list of URLs (separated by spaces) to load * the class from, or <code>null</code> @@ -93,10 +275,10 @@ public final class ClassLoading { * * @param defaultLoader the class loader value (possibly * <code>null</code>) to pass as the <code>defaultLoader</code> - * argument to <code>RMIClassLoader.loadClass</code> + * argument to <code>RMIClassLoaderSpi.loadClass</code> * * @param verifyCodebaseIntegrity if <code>true</code>, verify - * that the codebase URLs provide content integrity + * that the RFC3986 compliant codebase URIs provide content integrity * * @param verifierLoader the class loader value (possibly * <code>null</code>) to pass to @@ -108,17 +290,17 @@ public final class ClassLoading { * * @throws MalformedURLException if * <code>Security.verifyCodebaseIntegrity</code> or - * <code>RMIClassLoader.loadClass</code> throws a + * <code>RMIClassLoaderSpi.loadClass</code> throws a * <code>MalformedURLException</code> * * @throws ClassNotFoundException if - * <code>RMIClassLoader.loadClass</code> throws a + * <code>RMIClassLoaderSpi.loadClass</code> throws a * <code>ClassNotFoundException</code> * * @throws NullPointerException if <code>name</code> is * <code>null</code> **/ - public static Class loadClass(String codebase, + public static Class<?> loadClass(String codebase, String name, ClassLoader defaultLoader, boolean verifyCodebaseIntegrity, @@ -135,6 +317,8 @@ public final class ClassLoading { } } try { + if (provider != null) + return provider.loadClass(codebase, name, defaultLoader); return RMIClassLoader.loadClass(codebase, name, defaultLoader); } catch (ClassNotFoundException e) { if (verifyException != null) { @@ -142,6 +326,7 @@ public final class ClassLoading { throw new ClassNotFoundException(e.getMessage(), verifyException); } else { + e.fillInStackTrace(); throw e; } } @@ -149,9 +334,9 @@ public final class ClassLoading { /** * Loads a dynamic proxy class using {@link - * RMIClassLoader#loadProxyClass(String,String[],ClassLoader) - * RMIClassLoader.loadProxyClass}, optionally verifying that the - * codebase URLs provide content integrity. + * RMIClassLoaderSpi#loadProxyClass(String,String[],ClassLoader)}, + * optionally verifying that the RFC3986 compliant + * codebase URIs provide content integrity. * * <p>If <code>verifyCodebaseIntegrity</code> is <code>true</code> * and <code>codebase</code> is not <code>null</code>, then this @@ -171,20 +356,20 @@ public final class ClassLoading { * exception, then this method throws that exception. * * <p>This method invokes {@link - * RMIClassLoader#loadProxyClass(String,String[],ClassLoader) - * RMIClassLoader.loadProxyClass} with <code>codebase</code> as + * RMIClassLoaderSpi#loadProxyClass(String,String[],ClassLoader)} + * with <code>codebase</code> as * the first argument (or <code>null</code> if in the previous * step <code>Security.verifyCodebaseIntegrity</code> was invoked * and it threw a <code>SecurityException</code>), * <code>interfaceNames</code> as the second argument, and * <code>defaultLoader</code> as the third argument. If - * <code>RMIClassLoader.loadProxyClass</code> throws a + * <code>RMIClassLoaderSpi.loadProxyClass</code> throws a * <code>ClassNotFoundException</code>, then this method throws a * <code>ClassNotFoundException</code>; if - * <code>RMIClassLoader.loadProxyClass</code> throws any other + * <code>RMIClassLoaderSpi.loadProxyClass</code> throws any other * exception, then this method throws that exception; otherwise, * this method returns the <code>Class</code> returned by - * <code>RMIClassLoader.loadProxyClass</code>. + * <code>RMIClassLoaderSpi.loadProxyClass</code>. * * @param codebase the list of URLs (separated by spaces) to load * classes from, or <code>null</code> @@ -209,18 +394,18 @@ public final class ClassLoading { * * @throws MalformedURLException if * <code>Security.verifyCodebaseIntegrity</code> or - * <code>RMIClassLoader.loadProxyClass</code> throws a + * <code>RMIClassLoaderSpi.loadProxyClass</code> throws a * <code>MalformedURLException</code> * * @throws ClassNotFoundException if - * <code>RMIClassLoader.loadProxyClass</code> throws a + * <code>RMIClassLoaderSpi.loadProxyClass</code> throws a * <code>ClassNotFoundException</code> * * @throws NullPointerException if <code>interfaceNames</code> is * <code>null</code> or if any element of * <code>interfaceNames</code> is <code>null</code> **/ - public static Class loadProxyClass(String codebase, + public static Class<?> loadProxyClass(String codebase, String[] interfaceNames, ClassLoader defaultLoader, boolean verifyCodebaseIntegrity, @@ -237,6 +422,8 @@ public final class ClassLoading { } } try { + if (provider != null) return + provider.loadProxyClass(codebase, interfaceNames, defaultLoader); return RMIClassLoader.loadProxyClass(codebase, interfaceNames, defaultLoader); } catch (ClassNotFoundException e) { @@ -245,6 +432,7 @@ public final class ClassLoading { throw new ClassNotFoundException(e.getMessage(), verifyException); } else { + e.fillInStackTrace(); throw e; } } @@ -294,6 +482,82 @@ 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); + ExecutorService exec = loaderMap.get(loader); + if (exec == null){ + exec = Executors.newSingleThreadExecutor(new NamedThreadFactory(loader.toString(),true)); + 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; + 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(); } } 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=1590000&r1=1589999&r2=1590000&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 Fri Apr 25 11:34:00 2014 @@ -54,6 +54,7 @@ import java.util.concurrent.ConcurrentMa import java.util.logging.Logger; import java.util.logging.Level; import net.jini.loader.ClassAnnotation; +import net.jini.loader.ClassLoading; import net.jini.loader.DownloadPermission; import org.apache.river.api.net.Uri; @@ -576,7 +577,7 @@ public class PreferredClassProvider exte urlsMatchLoaderAnnotation(codebaseURIs, defaultLoader))) { try { - Class c = Class.forName(name, false, defaultLoader); + Class c = ClassLoading.forName(name, false, defaultLoader); if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "class \"{0}\" found " + "via defaultLoader, defined by {1}", @@ -608,7 +609,7 @@ public class PreferredClassProvider exte !(codebaseLoader instanceof PreferredClassLoader)) { try { - Class c = Class.forName(name, false, defaultLoader); + Class c = ClassLoading.forName(name, false, defaultLoader); if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "class \"{0}\" found " + "via defaultLoader, defined by {1}", @@ -659,7 +660,7 @@ public class PreferredClassProvider exte } if (tryDL) { try { - Class c = Class.forName(name, false, defaultLoader); + Class c = ClassLoading.forName(name, false, defaultLoader); if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "class \"{0}\" found " + "via defaultLoader, defined by {1}", @@ -676,7 +677,7 @@ public class PreferredClassProvider exte * context class loader as appropriate. */ try { - Class c = Class.forName(name, false, + Class c = ClassLoading.forName(name, false, (sm != null && secEx == null ? codebaseLoader : contextLoader)); if (logger.isLoggable(Level.FINEST)) { @@ -1427,7 +1428,7 @@ public class PreferredClassProvider exte for (int i = 0; i < interfaces.length; i++) { Class cl = - (classObjs[i] = Class.forName(interfaces[i], false, loader)); + (classObjs[i] = ClassLoading.forName(interfaces[i], false, loader)); if (!Modifier.isPublic(cl.getModifiers())) { ClassLoader current = getClassLoader(cl); Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lookup/entry/UIDescriptor.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lookup/entry/UIDescriptor.java?rev=1590000&r1=1589999&r2=1590000&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lookup/entry/UIDescriptor.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lookup/entry/UIDescriptor.java Fri Apr 25 11:34:00 2014 @@ -24,6 +24,7 @@ import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import com.artima.lookup.util.ConsistentSet; +import net.jini.io.MarshalledInstance; /** * <CODE>Entry</CODE> that enables a UI for a service to be associated @@ -163,7 +164,7 @@ public class UIDescriptor extends Abstra ClassLoader original = currentThread.getContextClassLoader(); try { currentThread.setContextClassLoader(parentLoader); - uiFactory = factory.get(); + uiFactory = new MarshalledInstance(factory).get(false); } finally { currentThread.setContextClassLoader(original); Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/proxytrust/ProxyTrustVerifier.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/proxytrust/ProxyTrustVerifier.java?rev=1590000&r1=1589999&r2=1590000&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/proxytrust/ProxyTrustVerifier.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/proxytrust/ProxyTrustVerifier.java Fri Apr 25 11:34:00 2014 @@ -46,6 +46,7 @@ import net.jini.core.constraint.MethodCo import net.jini.core.constraint.RemoteMethodControl; import net.jini.io.MarshalInputStream; import net.jini.io.ObjectStreamContext; +import net.jini.loader.ClassLoading; import net.jini.security.SecurityContext; import net.jini.security.TrustVerifier; @@ -513,7 +514,7 @@ public class ProxyTrustVerifier implemen return null; } final Class base = obj.getClass(); - final String bcb = RMIClassLoader.getClassAnnotation(base); + final String bcb = ClassLoading.getClassAnnotation(base); if (bcb == null || bcb.length() == 0) { return null; } @@ -530,7 +531,7 @@ public class ProxyTrustVerifier implemen boolean proper = false; try { t.setContextClassLoader(pcl); - proper = (RMIClassLoader.getClassLoader(bcb) == bcl); + proper = (ClassLoading.getClassLoader(bcb) == bcl); } catch (MalformedURLException e) { } finally { t.setContextClassLoader(ccl); @@ -631,7 +632,7 @@ public class ProxyTrustVerifier implemen } private void writeAnnotation(final Class c) throws IOException { - String cb = RMIClassLoader.getClassAnnotation(c); + String cb = ClassLoading.getClassAnnotation(c); writeObject(cb); if (bcb.equals(cb)) { AccessController.doPrivileged(new PrivilegedAction() { Modified: river/jtsk/skunk/qa_refactor/trunk/test/src/net/jini/core/event/RemoteEventTest.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/test/src/net/jini/core/event/RemoteEventTest.java?rev=1590000&r1=1589999&r2=1590000&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/test/src/net/jini/core/event/RemoteEventTest.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/test/src/net/jini/core/event/RemoteEventTest.java Fri Apr 25 11:34:00 2014 @@ -49,7 +49,7 @@ public class RemoteEventTest { @SuppressWarnings("deprecation") public void setUp() { try { - m = new MarshalledObject(s); + m = new MarshalledInstance(s).convertToMarshalledObject(); } catch (IOException ex) { Logger.getLogger(RemoteEventTest.class.getName()).log(Level.SEVERE, null, ex); }
