river-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From peter_firmst...@apache.org
Subject svn commit: r1590000 [4/4] - in /river/jtsk/skunk/qa_refactor/trunk: qa/src/com/sun/jini/qa/harness/ qa/src/com/sun/jini/test/impl/start/ qa/src/com/sun/jini/test/share/ qa/src/com/sun/jini/test/spec/io/marshalinputstream/ qa/src/com/sun/jini/test/spec...
Date Fri, 25 Apr 2014 11:34:03 GMT
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);
 	}



Mime
View raw message