001    /*****************************************************************************
002     * Copyright (C) PicoContainer Organization. All rights reserved.            *
003     * ------------------------------------------------------------------------- *
004     * The software in this package is published under the terms of the BSD      *
005     * style license a copy of which has been included with this distribution in *
006     * the LICENSE.txt file.                                                     *
007     *                                                                           *
008     *****************************************************************************/
009    
010    package org.picocontainer.security;
011    
012    import java.net.URL;
013    import java.net.URLClassLoader;
014    import java.security.AccessController;
015    import java.security.CodeSource;
016    import java.security.PermissionCollection;
017    import java.security.Permissions;
018    import java.security.PrivilegedAction;
019    import java.util.Map;
020    
021    /**
022     * CustomPermissionsURLClassLoader extends URLClassLoader, adding the abilty to programatically add permissions easily.
023     * To be effective for permission management, it should be run in conjunction with a policy that restricts
024     * some of the classloaders, but not all.
025     * It's not ordinarily used by PicoContainer, but is here because PicoContainer is common
026     * to most classloader trees.
027     * 
028     * @author Paul Hammant
029     */
030    public class CustomPermissionsURLClassLoader extends URLClassLoader {
031        private final Map<URL, Permissions> permissionsMap;
032    
033        public CustomPermissionsURLClassLoader(URL[] urls, Map<URL, Permissions> permissionsMap, ClassLoader parent) {
034            super(urls, parent);
035            this.permissionsMap = permissionsMap;
036        }
037    
038        public Class<?> loadClass(String name) throws ClassNotFoundException {
039            try {
040                return super.loadClass(name);
041            } catch (ClassNotFoundException e) {
042                throw decorateException(name, e);
043            }
044        }
045    
046        protected Class<?> findClass(String name) throws ClassNotFoundException {
047            try {
048                return super.findClass(name);
049            } catch (ClassNotFoundException e) {
050                throw decorateException(name, e);
051            }
052        }
053    
054        private ClassNotFoundException decorateException(String name, ClassNotFoundException e) {
055            if (name.startsWith("class ")) {
056                return new ClassNotFoundException("Class '" + name + "' is not a classInstance.getName(). " +
057                        "It's a classInstance.toString(). The clue is that it starts with 'class ', no classname contains a space.");
058            }
059            ClassLoader classLoader = this;
060            StringBuffer sb = new StringBuffer("'").append(name).append("' classloader stack [");
061            while (classLoader != null) {
062                sb.append(classLoader.toString()).append("\n");
063                final ClassLoader cl = classLoader;
064                classLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
065                    public ClassLoader run() {
066                        return cl.getParent();
067                    }
068                });
069    
070            }
071            return new ClassNotFoundException(sb.append("]").toString(), e);
072        }
073    
074        public String toString() {
075            String result = CustomPermissionsURLClassLoader.class.getName() + " " + System.identityHashCode(this) + ":";
076            URL[] urls = getURLs();
077            for (URL url : urls) {
078                result += "\n\t" + url.toString();
079            }
080    
081            return result;
082        }
083    
084        public PermissionCollection getPermissions(CodeSource codeSource) {
085            return (Permissions) permissionsMap.get(codeSource.getLocation());
086        }
087    
088    }
089