0001: /*
0002: * Copyright 1999,2004 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.apache.catalina.loader;
0018:
0019: import java.io.File;
0020: import java.io.FilePermission;
0021: import java.io.IOException;
0022: import java.io.InputStream;
0023: import java.net.JarURLConnection;
0024: import java.net.MalformedURLException;
0025: import java.net.URL;
0026: import java.net.URLClassLoader;
0027: import java.net.URLConnection;
0028: import java.net.URLStreamHandler;
0029: import java.net.URLStreamHandlerFactory;
0030: import java.security.AccessControlException;
0031: import java.security.CodeSource;
0032: import java.security.Permission;
0033: import java.security.PermissionCollection;
0034: import java.security.Policy;
0035: import java.util.ArrayList;
0036: import java.util.Enumeration;
0037: import java.util.HashMap;
0038: import java.util.Iterator;
0039: import java.util.jar.JarFile;
0040: import java.util.jar.JarInputStream;
0041: import java.util.jar.Manifest;
0042:
0043: import org.apache.naming.JndiPermission;
0044: import org.apache.tomcat.util.compat.JdkCompat;
0045:
0046: /**
0047: * Subclass implementation of <b>java.net.URLClassLoader</b> that knows how
0048: * to load classes from disk directories, as well as local and remote JAR
0049: * files. It also implements the <code>Reloader</code> interface, to provide
0050: * automatic reloading support to the associated loader.
0051: * <p>
0052: * In all cases, URLs must conform to the contract specified by
0053: * <code>URLClassLoader</code> - any URL that ends with a "/" character is
0054: * assumed to represent a directory; all other URLs are assumed to be the
0055: * address of a JAR file.
0056: * <p>
0057: * <strong>IMPLEMENTATION NOTE</strong> - Local repositories are searched in
0058: * the order they are added via the initial constructor and/or any subsequent
0059: * calls to <code>addRepository()</code>.
0060: * <p>
0061: * <strong>IMPLEMENTATION NOTE</strong> - At present, there are no dependencies
0062: * from this class to any other Catalina class, so that it could be used
0063: * independently.
0064: *
0065: * @author Craig R. McClanahan
0066: * @author Remy Maucherat
0067: * @version $Revision: 1.13 $ $Date: 2004/05/26 15:47:34 $
0068: */
0069:
0070: public class StandardClassLoader extends URLClassLoader implements
0071: Reloader, StandardClassLoaderMBean {
0072:
0073: // ----------------------------------------------------------- Constructors
0074:
0075: /**
0076: * Construct a new ClassLoader with no defined repositories and no
0077: * parent ClassLoader.
0078: */
0079: public StandardClassLoader() {
0080:
0081: super (new URL[0]);
0082: this .parent = getParent();
0083: this .system = getSystemClassLoader();
0084: securityManager = System.getSecurityManager();
0085:
0086: }
0087:
0088: /**
0089: * Construct a new ClassLoader with no defined repositories and no
0090: * parent ClassLoader, but with a stream handler factory.
0091: *
0092: * @param factory the URLStreamHandlerFactory to use when creating URLs
0093: */
0094: public StandardClassLoader(URLStreamHandlerFactory factory) {
0095:
0096: super (new URL[0], null, factory);
0097: this .factory = factory;
0098:
0099: }
0100:
0101: /**
0102: * Construct a new ClassLoader with no defined repositories and the
0103: * specified parent ClassLoader.
0104: *
0105: * @param parent The parent ClassLoader
0106: */
0107: public StandardClassLoader(ClassLoader parent) {
0108:
0109: super ((new URL[0]), parent);
0110: this .parent = parent;
0111: this .system = getSystemClassLoader();
0112: securityManager = System.getSecurityManager();
0113:
0114: }
0115:
0116: /**
0117: * Construct a new ClassLoader with no defined repositories and the
0118: * specified parent ClassLoader.
0119: *
0120: * @param parent The parent ClassLoader
0121: * @param factory the URLStreamHandlerFactory to use when creating URLs
0122: */
0123: public StandardClassLoader(ClassLoader parent,
0124: URLStreamHandlerFactory factory) {
0125:
0126: super ((new URL[0]), parent, factory);
0127: this .factory = factory;
0128:
0129: }
0130:
0131: /**
0132: * Construct a new ClassLoader with the specified repositories and
0133: * no parent ClassLoader.
0134: *
0135: * @param repositories The initial set of repositories
0136: */
0137: public StandardClassLoader(String repositories[]) {
0138:
0139: super (convert(repositories));
0140: this .parent = getParent();
0141: this .system = getSystemClassLoader();
0142: securityManager = System.getSecurityManager();
0143: if (repositories != null) {
0144: for (int i = 0; i < repositories.length; i++)
0145: addRepositoryInternal(repositories[i]);
0146: }
0147:
0148: }
0149:
0150: /**
0151: * Construct a new ClassLoader with the specified repositories and
0152: * parent ClassLoader.
0153: *
0154: * @param repositories The initial set of repositories
0155: * @param parent The parent ClassLoader
0156: */
0157: public StandardClassLoader(String repositories[], ClassLoader parent) {
0158:
0159: super (convert(repositories), parent);
0160: this .parent = parent;
0161: this .system = getSystemClassLoader();
0162: securityManager = System.getSecurityManager();
0163: if (repositories != null) {
0164: for (int i = 0; i < repositories.length; i++)
0165: addRepositoryInternal(repositories[i]);
0166: }
0167:
0168: }
0169:
0170: /**
0171: * Construct a new ClassLoader with the specified repositories and
0172: * parent ClassLoader.
0173: *
0174: * @param repositories The initial set of repositories
0175: * @param parent The parent ClassLoader
0176: */
0177: public StandardClassLoader(URL repositories[], ClassLoader parent) {
0178:
0179: super (repositories, parent);
0180: this .parent = parent;
0181: this .system = getSystemClassLoader();
0182: securityManager = System.getSecurityManager();
0183: if (repositories != null) {
0184: for (int i = 0; i < repositories.length; i++)
0185: addRepositoryInternal(repositories[i].toString());
0186: }
0187:
0188: }
0189:
0190: // ----------------------------------------------------- Class Variables
0191:
0192: /**
0193: * JDK compatibility support
0194: */
0195: private static final JdkCompat jdkCompat = JdkCompat.getJdkCompat();
0196:
0197: // ----------------------------------------------------- Instance Variables
0198:
0199: /**
0200: * The debugging detail level of this component.
0201: */
0202: protected int debug = 0;
0203:
0204: /**
0205: * Should this class loader delegate to the parent class loader
0206: * <strong>before</strong> searching its own repositories (i.e. the
0207: * usual Java2 delegation model)? If set to <code>false</code>,
0208: * this class loader will search its own repositories first, and
0209: * delegate to the parent only if the class or resource is not
0210: * found locally.
0211: */
0212: protected boolean delegate = false;
0213:
0214: /**
0215: * The list of local repositories, in the order they should be searched
0216: * for locally loaded classes or resources.
0217: */
0218: protected String repositories[] = new String[0];
0219:
0220: /**
0221: * A list of read File and Jndi Permission's required if this loader
0222: * is for a web application context.
0223: */
0224: private ArrayList permissionList = new ArrayList();
0225:
0226: /**
0227: * The PermissionCollection for each CodeSource for a web
0228: * application context.
0229: */
0230: private HashMap loaderPC = new HashMap();
0231:
0232: /**
0233: * Instance of the SecurityManager installed.
0234: */
0235: private SecurityManager securityManager = null;
0236:
0237: /**
0238: * Flag that the security policy has been refreshed from file.
0239: */
0240: private boolean policy_refresh = false;
0241:
0242: /**
0243: * The parent class loader.
0244: */
0245: private ClassLoader parent = null;
0246:
0247: /**
0248: * The system class loader.
0249: */
0250: private ClassLoader system = null;
0251:
0252: /**
0253: * URL stream handler for additional protocols.
0254: */
0255: protected URLStreamHandlerFactory factory = null;
0256:
0257: // ------------------------------------------------------------- Properties
0258:
0259: /**
0260: * Return the debugging detail level for this component.
0261: */
0262: public int getDebug() {
0263:
0264: return (this .debug);
0265:
0266: }
0267:
0268: /**
0269: * Set the debugging detail level for this component.
0270: *
0271: * @param debug The new debugging detail level
0272: */
0273: public void setDebug(int debug) {
0274:
0275: this .debug = debug;
0276:
0277: }
0278:
0279: /**
0280: * Return the "delegate first" flag for this class loader.
0281: */
0282: public boolean getDelegate() {
0283:
0284: return (this .delegate);
0285:
0286: }
0287:
0288: /**
0289: * Set the "delegate first" flag for this class loader.
0290: *
0291: * @param delegate The new "delegate first" flag
0292: */
0293: public void setDelegate(boolean delegate) {
0294:
0295: this .delegate = delegate;
0296:
0297: }
0298:
0299: /**
0300: * If there is a Java SecurityManager create a read FilePermission
0301: * or JndiPermission for the file directory path.
0302: *
0303: * @param path file directory path
0304: */
0305: protected void setPermissions(String path) {
0306: if (securityManager != null) {
0307: if (path.startsWith("jndi:")
0308: || path.startsWith("jar:jndi:")) {
0309: permissionList.add(new JndiPermission(path + "*"));
0310: } else {
0311: permissionList.add(new FilePermission(path + "-",
0312: "read"));
0313: }
0314: }
0315: }
0316:
0317: /**
0318: * If there is a Java SecurityManager add a read FilePermission
0319: * or JndiPermission for URL.
0320: *
0321: * @param url URL for a file or directory on local system
0322: */
0323: protected void setPermissions(URL url) {
0324: setPermissions(url.toString());
0325: }
0326:
0327: // ------------------------------------------------------- Reloader Methods
0328:
0329: /**
0330: * Add a new repository to the set of places this ClassLoader can look for
0331: * classes to be loaded.
0332: *
0333: * @param repository Name of a source of classes to be loaded, such as a
0334: * directory pathname, a JAR file pathname, or a ZIP file pathname
0335: *
0336: * @exception IllegalArgumentException if the specified repository is
0337: * invalid or does not exist
0338: */
0339: public void addRepository(String repository) {
0340:
0341: if (debug >= 1)
0342: log("addRepository(" + repository + ")");
0343:
0344: // Add this repository to our underlying class loader
0345: try {
0346: URLStreamHandler streamHandler = null;
0347: String protocol = parseProtocol(repository);
0348: if (factory != null)
0349: streamHandler = factory
0350: .createURLStreamHandler(protocol);
0351: URL url = new URL(null, repository, streamHandler);
0352: super .addURL(url);
0353: } catch (MalformedURLException e) {
0354: IllegalArgumentException iae = new IllegalArgumentException(
0355: "Invalid repository: " + repository);
0356: jdkCompat.chainException(iae, e);
0357: throw iae;
0358: }
0359:
0360: // Add this repository to our internal list
0361: addRepositoryInternal(repository);
0362:
0363: }
0364:
0365: /**
0366: * Return a String array of the current repositories for this class
0367: * loader. If there are no repositories, a zero-length array is
0368: * returned. For security reason, returns a clone of the Array (since
0369: * String are immutable).
0370: */
0371: public String[] findRepositories() {
0372:
0373: return ((String[]) repositories.clone());
0374:
0375: }
0376:
0377: /**
0378: * This class loader doesn't check for reloading.
0379: */
0380: public boolean modified() {
0381:
0382: return (false);
0383:
0384: }
0385:
0386: /**
0387: * Render a String representation of this object.
0388: */
0389: public String toString() {
0390:
0391: StringBuffer sb = new StringBuffer("StandardClassLoader\r\n");
0392: sb.append(" delegate: ");
0393: sb.append(delegate);
0394: sb.append("\r\n");
0395: sb.append(" repositories:\r\n");
0396: for (int i = 0; i < repositories.length; i++) {
0397: sb.append(" ");
0398: sb.append(repositories[i]);
0399: sb.append("\r\n");
0400: }
0401: if (this .parent != null) {
0402: sb.append("----------> Parent Classloader:\r\n");
0403: sb.append(this .parent.toString());
0404: sb.append("\r\n");
0405: }
0406: return (sb.toString());
0407:
0408: }
0409:
0410: // ---------------------------------------------------- ClassLoader Methods
0411:
0412: /**
0413: * Find the specified class in our local repositories, if possible. If
0414: * not found, throw <code>ClassNotFoundException</code>.
0415: *
0416: * @param name Name of the class to be loaded
0417: *
0418: * @exception ClassNotFoundException if the class was not found
0419: */
0420: public Class findClass(String name) throws ClassNotFoundException {
0421:
0422: if (debug >= 3)
0423: log(" findClass(" + name + ")");
0424:
0425: // (1) Permission to define this class when using a SecurityManager
0426: if (securityManager != null) {
0427: int i = name.lastIndexOf('.');
0428: if (i >= 0) {
0429: try {
0430: if (debug >= 4)
0431: log(" securityManager.checkPackageDefinition");
0432: securityManager.checkPackageDefinition(name
0433: .substring(0, i));
0434: } catch (Exception se) {
0435: if (debug >= 4)
0436: log(
0437: " -->Exception-->ClassNotFoundException",
0438: se);
0439: throw new ClassNotFoundException(name, se);
0440: }
0441: }
0442: }
0443:
0444: // Ask our superclass to locate this class, if possible
0445: // (throws ClassNotFoundException if it is not found)
0446: Class clazz = null;
0447: try {
0448: if (debug >= 4)
0449: log(" super.findClass(" + name + ")");
0450: try {
0451: synchronized (this ) {
0452: clazz = findLoadedClass(name);
0453: if (clazz != null)
0454: return clazz;
0455: clazz = super .findClass(name);
0456: }
0457: } catch (AccessControlException ace) {
0458: throw new ClassNotFoundException(name, ace);
0459: } catch (RuntimeException e) {
0460: if (debug >= 4)
0461: log(" -->RuntimeException Rethrown", e);
0462: throw e;
0463: }
0464: if (clazz == null) {
0465: if (debug >= 3)
0466: log(" --> Returning ClassNotFoundException");
0467: throw new ClassNotFoundException(name);
0468: }
0469: } catch (ClassNotFoundException e) {
0470: if (debug >= 3)
0471: log(" --> Passing on ClassNotFoundException", e);
0472: throw e;
0473: }
0474:
0475: // Return the class we have located
0476: if (debug >= 4)
0477: log(" Returning class " + clazz);
0478: if ((debug >= 4) && (clazz != null))
0479: log(" Loaded by " + clazz.getClassLoader());
0480: return (clazz);
0481:
0482: }
0483:
0484: /**
0485: * Find the specified resource in our local repository, and return a
0486: * <code>URL</code> refering to it, or <code>null</code> if this resource
0487: * cannot be found.
0488: *
0489: * @param name Name of the resource to be found
0490: */
0491: public URL findResource(String name) {
0492:
0493: if (debug >= 3)
0494: log(" findResource(" + name + ")");
0495:
0496: URL url = super .findResource(name);
0497: if (debug >= 3) {
0498: if (url != null)
0499: log(" --> Returning '" + url.toString() + "'");
0500: else
0501: log(" --> Resource not found, returning null");
0502: }
0503: return (url);
0504:
0505: }
0506:
0507: /**
0508: * Return an enumeration of <code>URLs</code> representing all of the
0509: * resources with the given name. If no resources with this name are
0510: * found, return an empty enumeration.
0511: *
0512: * @param name Name of the resources to be found
0513: *
0514: * @exception IOException if an input/output error occurs
0515: */
0516: public Enumeration findResources(String name) throws IOException {
0517:
0518: if (debug >= 3)
0519: log(" findResources(" + name + ")");
0520: return (super .findResources(name));
0521:
0522: }
0523:
0524: /**
0525: * Find the resource with the given name. A resource is some data
0526: * (images, audio, text, etc.) that can be accessed by class code in a
0527: * way that is independent of the location of the code. The name of a
0528: * resource is a "/"-separated path name that identifies the resource.
0529: * If the resource cannot be found, return <code>null</code>.
0530: * <p>
0531: * This method searches according to the following algorithm, returning
0532: * as soon as it finds the appropriate URL. If the resource cannot be
0533: * found, returns <code>null</code>.
0534: * <ul>
0535: * <li>If the <code>delegate</code> property is set to <code>true</code>,
0536: * call the <code>getResource()</code> method of the parent class
0537: * loader, if any.</li>
0538: * <li>Call <code>findResource()</code> to find this resource in our
0539: * locally defined repositories.</li>
0540: * <li>Call the <code>getResource()</code> method of the parent class
0541: * loader, if any.</li>
0542: * </ul>
0543: *
0544: * @param name Name of the resource to return a URL for
0545: */
0546: public URL getResource(String name) {
0547:
0548: if (debug >= 2)
0549: log("getResource(" + name + ")");
0550: URL url = null;
0551:
0552: // (1) Delegate to parent if requested
0553: if (delegate) {
0554: if (debug >= 3)
0555: log(" Delegating to parent classloader");
0556: ClassLoader loader = parent;
0557: if (loader == null)
0558: loader = system;
0559: url = loader.getResource(name);
0560: if (url != null) {
0561: if (debug >= 2)
0562: log(" --> Returning '" + url.toString() + "'");
0563: return (url);
0564: }
0565: }
0566:
0567: // (2) Search local repositories
0568: if (debug >= 3)
0569: log(" Searching local repositories");
0570: url = findResource(name);
0571: if (url != null) {
0572: if (debug >= 2)
0573: log(" --> Returning '" + url.toString() + "'");
0574: return (url);
0575: }
0576:
0577: // (3) Delegate to parent unconditionally if not already attempted
0578: if (!delegate) {
0579: ClassLoader loader = parent;
0580: if (loader == null)
0581: loader = system;
0582: url = loader.getResource(name);
0583: if (url != null) {
0584: if (debug >= 2)
0585: log(" --> Returning '" + url.toString() + "'");
0586: return (url);
0587: }
0588: }
0589:
0590: // (4) Resource was not found
0591: if (debug >= 2)
0592: log(" --> Resource not found, returning null");
0593: return (null);
0594:
0595: }
0596:
0597: /**
0598: * Find the resource with the given name, and return an input stream
0599: * that can be used for reading it. The search order is as described
0600: * for <code>getResource()</code>, after checking to see if the resource
0601: * data has been previously cached. If the resource cannot be found,
0602: * return <code>null</code>.
0603: *
0604: * @param name Name of the resource to return an input stream for
0605: */
0606: public InputStream getResourceAsStream(String name) {
0607:
0608: if (debug >= 2)
0609: log("getResourceAsStream(" + name + ")");
0610: InputStream stream = null;
0611:
0612: // (0) Check for a cached copy of this resource
0613: stream = findLoadedResource(name);
0614: if (stream != null) {
0615: if (debug >= 2)
0616: log(" --> Returning stream from cache");
0617: return (stream);
0618: }
0619:
0620: // (1) Delegate to parent if requested
0621: if (delegate) {
0622: if (debug >= 3)
0623: log(" Delegating to parent classloader");
0624: ClassLoader loader = parent;
0625: if (loader == null)
0626: loader = system;
0627: stream = loader.getResourceAsStream(name);
0628: if (stream != null) {
0629: // FIXME - cache???
0630: if (debug >= 2)
0631: log(" --> Returning stream from parent");
0632: return (stream);
0633: }
0634: }
0635:
0636: // (2) Search local repositories
0637: if (debug >= 3)
0638: log(" Searching local repositories");
0639: URL url = findResource(name);
0640: if (url != null) {
0641: // FIXME - cache???
0642: if (debug >= 2)
0643: log(" --> Returning stream from local");
0644: try {
0645: return (url.openStream());
0646: } catch (IOException e) {
0647: log("url.openStream(" + url.toString() + ")", e);
0648: return (null);
0649: }
0650: }
0651:
0652: // (3) Delegate to parent unconditionally
0653: if (!delegate) {
0654: if (debug >= 3)
0655: log(" Delegating to parent classloader");
0656: ClassLoader loader = parent;
0657: if (loader == null)
0658: loader = system;
0659: stream = loader.getResourceAsStream(name);
0660: if (stream != null) {
0661: // FIXME - cache???
0662: if (debug >= 2)
0663: log(" --> Returning stream from parent");
0664: return (stream);
0665: }
0666: }
0667:
0668: // (4) Resource was not found
0669: if (debug >= 2)
0670: log(" --> Resource not found, returning null");
0671: return (null);
0672:
0673: }
0674:
0675: /**
0676: * Load the class with the specified name. This method searches for
0677: * classes in the same manner as <code>loadClass(String, boolean)</code>
0678: * with <code>false</code> as the second argument.
0679: *
0680: * @param name Name of the class to be loaded
0681: *
0682: * @exception ClassNotFoundException if the class was not found
0683: */
0684: public Class loadClass(String name) throws ClassNotFoundException {
0685:
0686: return (loadClass(name, false));
0687:
0688: }
0689:
0690: /**
0691: * Load the class with the specified name, searching using the following
0692: * algorithm until it finds and returns the class. If the class cannot
0693: * be found, returns <code>ClassNotFoundException</code>.
0694: * <ul>
0695: * <li>Call <code>findLoadedClass(String)</code> to check if the
0696: * class has already been loaded. If it has, the same
0697: * <code>Class</code> object is returned.</li>
0698: * <li>If the <code>delegate</code> property is set to <code>true</code>,
0699: * call the <code>loadClass()</code> method of the parent class
0700: * loader, if any.</li>
0701: * <li>Call <code>findClass()</code> to find this class in our locally
0702: * defined repositories.</li>
0703: * <li>Call the <code>loadClass()</code> method of our parent
0704: * class loader, if any.</li>
0705: * </ul>
0706: * If the class was found using the above steps, and the
0707: * <code>resolve</code> flag is <code>true</code>, this method will then
0708: * call <code>resolveClass(Class)</code> on the resulting Class object.
0709: *
0710: * @param name Name of the class to be loaded
0711: * @param resolve If <code>true</code> then resolve the class
0712: *
0713: * @exception ClassNotFoundException if the class was not found
0714: */
0715: public Class loadClass(String name, boolean resolve)
0716: throws ClassNotFoundException {
0717:
0718: if (debug >= 2)
0719: log("loadClass(" + name + ", " + resolve + ")");
0720: Class clazz = null;
0721:
0722: // (0) Check our previously loaded class cache
0723: clazz = findLoadedClass(name);
0724: if (clazz != null) {
0725: if (debug >= 3)
0726: log(" Returning class from cache");
0727: if (resolve)
0728: resolveClass(clazz);
0729: return (clazz);
0730: }
0731:
0732: // If a system class, use system class loader
0733: if (name.startsWith("java.")) {
0734: ClassLoader loader = system;
0735: clazz = loader.loadClass(name);
0736: if (clazz != null) {
0737: if (resolve)
0738: resolveClass(clazz);
0739: return (clazz);
0740: }
0741: throw new ClassNotFoundException(name);
0742: }
0743:
0744: // (.5) Permission to access this class when using a SecurityManager
0745: if (securityManager != null) {
0746: int i = name.lastIndexOf('.');
0747: if (i >= 0) {
0748: try {
0749: securityManager.checkPackageAccess(name.substring(
0750: 0, i));
0751: } catch (SecurityException se) {
0752: String error = "Security Violation, attempt to use "
0753: + "Restricted Class: " + name;
0754: log(error);
0755: throw new ClassNotFoundException(error, se);
0756: }
0757: }
0758: }
0759:
0760: // (1) Delegate to our parent if requested
0761: if (delegate) {
0762: if (debug >= 3)
0763: log(" Delegating to parent classloader");
0764: ClassLoader loader = parent;
0765: if (loader == null)
0766: loader = system;
0767: try {
0768: clazz = loader.loadClass(name);
0769: if (clazz != null) {
0770: if (debug >= 3)
0771: log(" Loading class from parent");
0772: if (resolve)
0773: resolveClass(clazz);
0774: return (clazz);
0775: }
0776: } catch (ClassNotFoundException e) {
0777: ;
0778: }
0779: }
0780:
0781: // (2) Search local repositories
0782: if (debug >= 3)
0783: log(" Searching local repositories");
0784: try {
0785: clazz = findClass(name);
0786: if (clazz != null) {
0787: if (debug >= 3)
0788: log(" Loading class from local repository");
0789: if (resolve)
0790: resolveClass(clazz);
0791: return (clazz);
0792: }
0793: } catch (ClassNotFoundException e) {
0794: ;
0795: }
0796:
0797: // (3) Delegate to parent unconditionally
0798: if (!delegate) {
0799: if (debug >= 3)
0800: log(" Delegating to parent classloader");
0801: ClassLoader loader = parent;
0802: if (loader == null)
0803: loader = system;
0804: try {
0805: clazz = loader.loadClass(name);
0806: if (clazz != null) {
0807: if (debug >= 3)
0808: log(" Loading class from parent");
0809: if (resolve)
0810: resolveClass(clazz);
0811: return (clazz);
0812: }
0813: } catch (ClassNotFoundException e) {
0814: ;
0815: }
0816: }
0817:
0818: // This class was not found
0819: throw new ClassNotFoundException(name);
0820:
0821: }
0822:
0823: /**
0824: * Get the Permissions for a CodeSource. If this instance
0825: * of StandardClassLoader is for a web application context,
0826: * add read FilePermissions for the base directory (if unpacked),
0827: * the context URL, and jar file resources.
0828: *
0829: * @param codeSource where the code was loaded from
0830: * @return PermissionCollection for CodeSource
0831: */
0832: protected final PermissionCollection getPermissions(
0833: CodeSource codeSource) {
0834: if (!policy_refresh) {
0835: // Refresh the security policies
0836: Policy policy = Policy.getPolicy();
0837: policy.refresh();
0838: policy_refresh = true;
0839: }
0840: String codeUrl = codeSource.getLocation().toString();
0841: PermissionCollection pc;
0842: if ((pc = (PermissionCollection) loaderPC.get(codeUrl)) == null) {
0843: pc = super .getPermissions(codeSource);
0844: if (pc != null) {
0845: Iterator perms = permissionList.iterator();
0846: while (perms.hasNext()) {
0847: Permission p = (Permission) perms.next();
0848: pc.add(p);
0849: }
0850: loaderPC.put(codeUrl, pc);
0851: }
0852: }
0853: return (pc);
0854:
0855: }
0856:
0857: // ------------------------------------------------------ Protected Methods
0858:
0859: /**
0860: * Parse URL protocol.
0861: *
0862: * @return String protocol
0863: */
0864: protected static String parseProtocol(String spec) {
0865: if (spec == null)
0866: return "";
0867: int pos = spec.indexOf(':');
0868: if (pos <= 0)
0869: return "";
0870: return spec.substring(0, pos).trim();
0871: }
0872:
0873: /**
0874: * Add a repository to our internal array only.
0875: *
0876: * @param repository The new repository
0877: *
0878: * @exception IllegalArgumentException if the manifest of a JAR file
0879: * cannot be processed correctly
0880: */
0881: protected void addRepositoryInternal(String repository) {
0882:
0883: URLStreamHandler streamHandler = null;
0884: String protocol = parseProtocol(repository);
0885: if (factory != null)
0886: streamHandler = factory.createURLStreamHandler(protocol);
0887:
0888: // Validate the manifest of a JAR file repository
0889: if (!repository.endsWith(File.separator)
0890: && !repository.endsWith("/")) {
0891: JarFile jarFile = null;
0892: try {
0893: Manifest manifest = null;
0894: if (repository.startsWith("jar:")) {
0895: URL url = new URL(null, repository, streamHandler);
0896: JarURLConnection conn = (JarURLConnection) url
0897: .openConnection();
0898: conn.setAllowUserInteraction(false);
0899: conn.setDoInput(true);
0900: conn.setDoOutput(false);
0901: conn.connect();
0902: jarFile = conn.getJarFile();
0903: } else if (repository.startsWith("file://")) {
0904: jarFile = new JarFile(repository.substring(7));
0905: } else if (repository.startsWith("file:")) {
0906: jarFile = new JarFile(repository.substring(5));
0907: } else if (repository.endsWith(".jar")) {
0908: URL url = new URL(null, repository, streamHandler);
0909: URLConnection conn = url.openConnection();
0910: JarInputStream jis = new JarInputStream(conn
0911: .getInputStream());
0912: manifest = jis.getManifest();
0913: } else {
0914: throw new IllegalArgumentException(
0915: "addRepositoryInternal: Invalid URL '"
0916: + repository + "'");
0917: }
0918: } catch (Throwable t) {
0919: IllegalArgumentException iae = new IllegalArgumentException(
0920: "addRepositoryInternal");
0921: jdkCompat.chainException(iae, t);
0922: throw iae;
0923: } finally {
0924: if (jarFile != null) {
0925: try {
0926: jarFile.close();
0927: } catch (Throwable t) {
0928: }
0929: }
0930: }
0931: }
0932:
0933: // Add this repository to our internal list
0934: synchronized (repositories) {
0935: String results[] = new String[repositories.length + 1];
0936: System.arraycopy(repositories, 0, results, 0,
0937: repositories.length);
0938: results[repositories.length] = repository;
0939: repositories = results;
0940: }
0941:
0942: }
0943:
0944: /**
0945: * Convert an array of String to an array of URL and return it.
0946: *
0947: * @param input The array of String to be converted
0948: */
0949: protected static URL[] convert(String input[]) {
0950: return convert(input, null);
0951: }
0952:
0953: /**
0954: * Convert an array of String to an array of URL and return it.
0955: *
0956: * @param input The array of String to be converted
0957: * @param factory Handler factory to use to generate the URLs
0958: */
0959: protected static URL[] convert(String input[],
0960: URLStreamHandlerFactory factory) {
0961:
0962: URLStreamHandler streamHandler = null;
0963:
0964: URL url[] = new URL[input.length];
0965: for (int i = 0; i < url.length; i++) {
0966: try {
0967: String protocol = parseProtocol(input[i]);
0968: if (factory != null)
0969: streamHandler = factory
0970: .createURLStreamHandler(protocol);
0971: else
0972: streamHandler = null;
0973: url[i] = new URL(null, input[i], streamHandler);
0974: } catch (MalformedURLException e) {
0975: url[i] = null;
0976: }
0977: }
0978: return (url);
0979:
0980: }
0981:
0982: /**
0983: * Finds the resource with the given name if it has previously been
0984: * loaded and cached by this class loader, and return an input stream
0985: * to the resource data. If this resource has not been cached, return
0986: * <code>null</code>.
0987: *
0988: * @param name Name of the resource to return
0989: */
0990: protected InputStream findLoadedResource(String name) {
0991:
0992: return (null); // FIXME - findLoadedResource()
0993:
0994: }
0995:
0996: /**
0997: * Log a debugging output message.
0998: *
0999: * @param message Message to be logged
1000: */
1001: private void log(String message) {
1002:
1003: System.out.println("StandardClassLoader: " + message);
1004:
1005: }
1006:
1007: /**
1008: * Log a debugging output message with an exception.
1009: *
1010: * @param message Message to be logged
1011: * @param throwable Exception to be logged
1012: */
1013: private void log(String message, Throwable throwable) {
1014:
1015: System.out.println("StandardClassLoader: " + message);
1016: throwable.printStackTrace(System.out);
1017:
1018: }
1019:
1020: }
|