1201 lines · 46.0 KB · Java
RawDownload
         * define the proxy class in the default loader.         *         * If the interface classes can not be loaded from the default         * loader or the default loader is null, try to load them from         * the RMI class loader.  Then try to define the proxy class         * in the RMI class loader.         *         * Additionally, if any of the proxy interface classes are not         * public, all of the non-public interfaces must reside in the         * same class loader or it will be impossible to define the         * proxy class (an IllegalAccessError will be thrown).  An         * attempt to load the interfaces from the default loader is         * made.  If the attempt fails, a second attempt will be made         * to load the interfaces from the RMI loader. If all of the         * non-public interfaces classes do reside in the same class         * loader, then we attempt to define the proxy class in the         * class loader of the non-public interfaces.  No other         * attempt to define the proxy class will be made.         */        ClassLoader parent = getRMIContextClassLoader();        if (loaderLog.isLoggable(Log.VERBOSE)) {            loaderLog.log(Log.VERBOSE,                "(thread context class loader: " + parent + ")");        }         URL[] urls;        if (codebase != null) {            urls = pathToURLs(codebase);        } else {            urls = getDefaultCodebaseURLs();        }         /*         * If no security manager is set, disable access to RMI class         * loaders and use the would-de parent instead.         */        SecurityManager sm = System.getSecurityManager();        if (sm == null) {            try {                Class c = loadProxyClass(interfaces, defaultLoader, parent,                                         false);                if (loaderLog.isLoggable(Log.VERBOSE)) {                    loaderLog.log(Log.VERBOSE,                        "(no security manager: codebase disabled) " +                        "proxy class defined by " + c.getClassLoader());                }                return c;            } catch (ClassNotFoundException e) {                if (loaderLog.isLoggable(Log.BRIEF)) {                    loaderLog.log(Log.BRIEF,                        "(no security manager: codebase disabled) " +                        "proxy class resolution failed", e);                }                throw new ClassNotFoundException(e.getMessage() +                    " (no security manager: RMI class loader disabled)",                    e.getException());            }        }         /*         * Get or create the RMI class loader for this codebase URL path         * and parent class loader pair.         */        Loader loader = lookupLoader(urls, parent);         try {            if (loader != null) {                /*                 * Verify that the caller has permission to access this loader.                 */                loader.checkPermissions();            }        } catch (SecurityException e) {            /*             * If the current access control context does not have permission             * to access all of the URLs in the codebase path, wrap the             * resulting security exception in a ClassNotFoundException, so             * the caller can handle this outcome just like any other class             * loading failure (see bugid 4146529).             */            try {                /*                 * But first, check to see if the proxy class could have been                 * resolved without the security-offending codebase anyway;                 * if so, return successfully (see bugids 4191926 & 4349670).                 */                Class c = loadProxyClass(interfaces, defaultLoader, parent,                                         false);                if (loaderLog.isLoggable(Log.VERBOSE)) {                    loaderLog.log(Log.VERBOSE,                        "(access to codebase denied) " +                        "proxy class defined by " + c.getClassLoader());                }                return c;            } catch (ClassNotFoundException unimportant) {                /*                 * Presumably the security exception is the more important                 * exception to report in this case.                 */                if (loaderLog.isLoggable(Log.BRIEF)) {                    loaderLog.log(Log.BRIEF,                        "(access to codebase denied) " +                        "proxy class resolution failed", e);                }                throw new ClassNotFoundException(                    "access to class loader denied", e);            }        }         try {            Class c = loadProxyClass(interfaces, defaultLoader, loader, true);            if (loaderLog.isLoggable(Log.VERBOSE)) {                loaderLog.log(Log.VERBOSE,                              "proxy class defined by " + c.getClassLoader());            }            return c;        } catch (ClassNotFoundException e) {            if (loaderLog.isLoggable(Log.BRIEF)) {                loaderLog.log(Log.BRIEF,                              "proxy class resolution failed", e);            }            throw e;        }    }     /**     * Define a proxy class in the default loader if appropriate.     * Define the class in an RMI class loader otherwise.  The proxy     * class will implement classes which are named in the supplied     * interfaceNames.     */    private static Class loadProxyClass(String[] interfaceNames,                                        ClassLoader defaultLoader,                                        ClassLoader codebaseLoader,                                        boolean preferCodebase)        throws ClassNotFoundException    {        ClassLoader proxyLoader = null;        Class[] classObjs = new Class[interfaceNames.length];        boolean[] nonpublic = { false };       defaultLoaderCase:        if (defaultLoader != null) {            try {                proxyLoader =                    loadProxyInterfaces(interfaceNames, defaultLoader,                                        classObjs, nonpublic);                if (loaderLog.isLoggable(Log.VERBOSE)) {                    ClassLoader[] definingLoaders =                        new ClassLoader[classObjs.length];                    for (int i = 0; i < definingLoaders.length; i++) {                        definingLoaders[i] = classObjs[i].getClassLoader();                    }                    loaderLog.log(Log.VERBOSE,                        "proxy interfaces found via defaultLoader, " +                        "defined by " + Arrays.asList(definingLoaders));                }            } catch (ClassNotFoundException e) {                break defaultLoaderCase;            }            if (!nonpublic[0]) {                if (preferCodebase) {                    try {                        return Proxy.getProxyClass(codebaseLoader, classObjs);                    } catch (IllegalArgumentException e) {                    }                }                proxyLoader = defaultLoader;            }            return loadProxyClass(proxyLoader, classObjs);        }         nonpublic[0] = false;        proxyLoader = loadProxyInterfaces(interfaceNames, codebaseLoader,                                          classObjs, nonpublic);        if (loaderLog.isLoggable(Log.VERBOSE)) {            ClassLoader[] definingLoaders = new ClassLoader[classObjs.length];            for (int i = 0; i < definingLoaders.length; i++) {                definingLoaders[i] = classObjs[i].getClassLoader();            }            loaderLog.log(Log.VERBOSE,                "proxy interfaces found via codebase, " +                "defined by " + Arrays.asList(definingLoaders));        }        if (!nonpublic[0]) {            proxyLoader = codebaseLoader;        }        return loadProxyClass(proxyLoader, classObjs);    }     /**     * Define a proxy class in the given class loader.  The proxy     * class will implement the given interfaces Classes.     */    private static Class loadProxyClass(ClassLoader loader, Class[] interfaces)        throws ClassNotFoundException    {        try {            return Proxy.getProxyClass(loader, interfaces);        } catch (IllegalArgumentException e) {            throw new ClassNotFoundException(                "error creating dynamic proxy class", e);        }    }     /*     * Load Class objects for the names in the interfaces array fron     * the given class loader.     *     * We pass classObjs and nonpublic arrays to avoid needing a     * multi-element return value.  nonpublic is an array to enable     * the method to take a boolean argument by reference.     *     * nonpublic array is needed to signal when the return value of     * this method should be used as the proxy class loader.  Because     * null represents a valid class loader, that value is     * insufficient to signal that the return value should not be used     * as the proxy class loader.     */    private static ClassLoader loadProxyInterfaces(String[] interfaces,                                                   ClassLoader loader,                                                   Class[] classObjs,                                                   boolean[] nonpublic)        throws ClassNotFoundException    {        /* loader of a non-public interface class */        ClassLoader nonpublicLoader = null;         for (int i = 0; i < interfaces.length; i++) {            Class cl =                (classObjs[i] = Class.forName(interfaces[i], false, loader));             if (!Modifier.isPublic(cl.getModifiers())) {                ClassLoader current = cl.getClassLoader();                if (loaderLog.isLoggable(Log.VERBOSE)) {                    loaderLog.log(Log.VERBOSE,                        "non-public interface \"" + interfaces[i] +                        "\" defined by " + current);                }                if (!nonpublic[0]) {                    nonpublicLoader = current;                    nonpublic[0] = true;                } else if (current != nonpublicLoader) {                    throw new IllegalAccessError(                        "non-public interfaces defined in different " +                        "class loaders");                }            }        }        return nonpublicLoader;    }     /**     * Convert a string containing a space-separated list of URLs into a     * corresponding array of URL objects, throwing a MalformedURLException     * if any of the URLs are invalid.     */    private static URL[] pathToURLs(String path)        throws MalformedURLException    {        synchronized (pathToURLsCache) {            Object[] v = pathToURLsCache.get(path);            if (v != null) {                return ((URL[])v[0]);            }        }        StringTokenizer st = new StringTokenizer(path); // divide by spaces        URL[] urls = new URL[st.countTokens()];        for (int i = 0; st.hasMoreTokens(); i++) {            urls[i] = new URL(st.nextToken());        }        synchronized (pathToURLsCache) {            pathToURLsCache.put(path,                                new Object[] {urls, new SoftReference<String>(path)});        }        return urls;    }     /** map from weak(key=string) to [URL[], soft(key)] */    private static final Map<String, Object[]> pathToURLsCache        = new WeakHashMap<String, Object[]>(5);     /**     * Convert an array of URL objects into a corresponding string     * containing a space-separated list of URLs.     *     * Note that if the array has zero elements, the return value is     * null, not the empty string.     */    private static String urlsToPath(URL[] urls) {        if (urls.length == 0) {            return null;        } else if (urls.length == 1) {            return urls[0].toExternalForm();        } else {            StringBuffer path = new StringBuffer(urls[0].toExternalForm());            for (int i = 1; i < urls.length; i++) {                path.append(' ');                path.append(urls[i].toExternalForm());            }            return path.toString();        }    }     /**     * Return the class loader to be used as the parent for an RMI class     * loader used in the current execution context.     */    private static ClassLoader getRMIContextClassLoader() {        /*         * The current implementation simply uses the current thread's         * context class loader.         */        return Thread.currentThread().getContextClassLoader();    }     /**     * Look up the RMI class loader for the given codebase URL path     * and the given parent class loader.  A new class loader instance     * will be created and returned if no match is found.     */    private static Loader lookupLoader(final URL[] urls,                                       final ClassLoader parent)    {        /*         * If the requested codebase URL path is empty, the supplied         * parent class loader will be sufficient.         *         * REMIND: To be conservative, this optimization is commented out         * for now so that it does not open a security hole in the future         * by providing untrusted code with direct access to the public         * loadClass() method of a class loader instance that it cannot         * get a reference to.  (It's an unlikely optimization anyway.)         *         * if (urls.length == 0) {         *     return parent;         * }         */         LoaderEntry entry;        Loader loader;         synchronized (LoaderHandler.class) {            /*             * Take this opportunity to remove from the table entries             * whose weak references have been cleared.             */            while ((entry = (LoaderEntry) refQueue.poll()) != null) {                if (!entry.removed) {   // ignore entries removed below                    loaderTable.remove(entry.key);                }            }             /*             * Look up the codebase URL path and parent class loader pair             * in the table of RMI class loaders.             */            LoaderKey key = new LoaderKey(urls, parent);            entry = loaderTable.get(key);             if (entry == null || (loader = entry.get()) == null) {                /*                 * If entry was in table but it's weak reference was cleared,                 * remove it from the table and mark it as explicitly cleared,                 * so that new matching entry that we put in the table will                 * not be erroneously removed when this entry is processed                 * from the weak reference queue.                 */                if (entry != null) {                    loaderTable.remove(key);                    entry.removed = true;                }                 /*                 * A matching loader was not found, so create a new class                 * loader instance for the requested codebase URL path and                 * parent class loader.  The instance is created within an                 * access control context retricted to the permissions                 * necessary to load classes from its codebase URL path.                 */                AccessControlContext acc = getLoaderAccessControlContext(urls);                loader = java.security.AccessController.doPrivileged(                    new java.security.PrivilegedAction<Loader>() {                        public Loader run() {                            return new Loader(urls, parent);                        }                    }, acc);                 /*                 * Finally, create an entry to hold the new loader with a                 * weak reference and store it in the table with the key.                 */                entry = new LoaderEntry(key, loader);                loaderTable.put(key, entry);            }        }         return loader;    }     /**     * LoaderKey holds a codebase URL path and parent class loader pair     * used to look up RMI class loader instances in its class loader cache.     */    private static class LoaderKey {         private URL[] urls;         private ClassLoader parent;         private int hashValue;         public LoaderKey(URL[] urls, ClassLoader parent) {            this.urls = urls;            this.parent = parent;             if (parent != null) {                hashValue = parent.hashCode();            }            for (int i = 0; i < urls.length; i++) {                hashValue ^= urls[i].hashCode();            }        }         public int hashCode() {            return hashValue;        }         public boolean equals(Object obj) {            if (obj instanceof LoaderKey) {                LoaderKey other = (LoaderKey) obj;                if (parent != other.parent) {                    return false;                }                if (urls == other.urls) {                    return true;                }                if (urls.length != other.urls.length) {                    return false;                }                for (int i = 0; i < urls.length; i++) {                    if (!urls[i].equals(other.urls[i])) {                        return false;                    }                }                return true;            } else {                return false;            }        }    }     /**     * LoaderEntry contains a weak reference to an RMIClassLoader.  The     * weak reference is registered with the private static "refQueue"     * queue.  The entry contains the codebase URL path and parent class     * loader key for the loader so that the mapping can be removed from     * the table efficiently when the weak reference is cleared.     */    private static class LoaderEntry extends WeakReference<Loader> {         public LoaderKey key;         /**         * set to true if the entry has been removed from the table         * because it has been replaced, so it should not be attempted         * to be removed again         */        public boolean removed = false;         public LoaderEntry(LoaderKey key, Loader loader) {            super(loader, refQueue);            this.key = key;        }    }     /**     * Return the access control context that a loader for the given     * codebase URL path should execute with.     */    private static AccessControlContext getLoaderAccessControlContext(        URL[] urls)    {        /*         * The approach used here is taken from the similar method         * getAccessControlContext() in the sun.applet.AppletPanel class.         */        // begin with permissions granted to all code in current policy        PermissionCollection perms =            java.security.AccessController.doPrivileged(                new java.security.PrivilegedAction<PermissionCollection>() {                public PermissionCollection run() {                    CodeSource codesource = new CodeSource(null,                        (java.security.cert.Certificate[]) null);                    Policy p = java.security.Policy.getPolicy();                    if (p != null) {                        return p.getPermissions(codesource);                    } else {                        return new Permissions();                    }

Lines 501–1000 of 1201. Previous lines