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