0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.loader;
0031:
0032: import com.caucho.config.ConfigException;
0033: import com.caucho.lifecycle.Lifecycle;
0034: import com.caucho.loader.enhancer.ByteCodeEnhancer;
0035: import com.caucho.loader.enhancer.EnhancerRuntimeException;
0036: import com.caucho.make.AlwaysModified;
0037: import com.caucho.make.DependencyContainer;
0038: import com.caucho.make.Make;
0039: import com.caucho.make.MakeContainer;
0040: import com.caucho.management.server.*;
0041: import com.caucho.server.util.CauchoSystem;
0042: import com.caucho.util.ByteBuffer;
0043: import com.caucho.util.L10N;
0044: import com.caucho.util.TimedCache;
0045: import com.caucho.vfs.Dependency;
0046: import com.caucho.vfs.JarPath;
0047: import com.caucho.vfs.Path;
0048: import com.caucho.vfs.ReadStream;
0049:
0050: import javax.annotation.PostConstruct;
0051: import java.io.FilePermission;
0052: import java.io.IOException;
0053: import java.io.InputStream;
0054: import java.net.*;
0055: import java.security.*;
0056: import java.lang.instrument.*;
0057: import java.util.ArrayList;
0058: import java.util.Enumeration;
0059: import java.util.Hashtable;
0060: import java.util.Vector;
0061: import java.util.jar.Attributes;
0062: import java.util.jar.Manifest;
0063: import java.util.logging.Level;
0064: import java.util.logging.Logger;
0065: import java.util.regex.Pattern;
0066:
0067: /**
0068: * Class loader which checks for changes in class files and automatically
0069: * picks up new jars.
0070: *
0071: * <p>DynamicClassLoaders can be chained creating one virtual class loader.
0072: * From the perspective of the JDK, it's all one classloader. Internally,
0073: * the class loader chain searches like a classpath.
0074: */
0075: public class DynamicClassLoader extends java.net.URLClassLoader
0076: implements Dependency, Make, DynamicClassLoaderMXBean {
0077: private static L10N _L;
0078: private static Logger _log;
0079:
0080: private final static URL NULL_URL;
0081: private final static URL[] NULL_URL_ARRAY = new URL[0];
0082:
0083: private static long _globalDependencyCheckInterval = 2000L;
0084: private static boolean _isJarCacheEnabled;
0085:
0086: private String _id;
0087:
0088: private final boolean _isVerbose;
0089: private int _verboseDepth;
0090:
0091: // List of resource loaders
0092: private ArrayList<Loader> _loaders = new ArrayList<Loader>();
0093:
0094: private JarLoader _jarLoader;
0095: private PathLoader _pathLoader;
0096:
0097: private ArrayList<Path> _nativePath = new ArrayList<Path>();
0098:
0099: // List of cached classes
0100: private Hashtable<String, ClassEntry> _entryCache;
0101:
0102: private TimedCache<String, URL> _resourceCache;
0103:
0104: // Dependencies
0105: private DependencyContainer _dependencies = new DependencyContainer();
0106: private boolean _isEnableDependencyCheck = false;
0107:
0108: // Makes
0109: private MakeContainer _makeList;
0110:
0111: // If true, use the servlet spec's hack to give the parent priority
0112: // for some classes, but the child priority for other classes.
0113: private boolean _useServletHack;
0114:
0115: // List of packages where the parent has priority.
0116: private String[] _parentPriorityPackages;
0117:
0118: // List of packages where this has priority.
0119: private String[] _priorityPackages;
0120:
0121: // Array of listeners
0122: // XXX: There's still some questions of what kind of reference this
0123: // should be. It either needs to be a WeakReference or
0124: // a normal reference. Anything in between makes no sense.
0125: //
0126: // server/10w3 indicates that it needs to be a regular reference
0127: private ArrayList<ClassLoaderListener> _listeners;
0128:
0129: // The security manager for the loader
0130: private SecurityManager _securityManager;
0131:
0132: // List of permissions allowed in this context
0133: private ArrayList<Permission> _permissions;
0134:
0135: // The security code source for the loader
0136: private CodeSource _codeSource;
0137:
0138: // Any enhancer
0139: private ArrayList<ClassFileTransformer> _classFileTransformerList;
0140:
0141: private URL[] _urls = NULL_URL_ARRAY;
0142:
0143: private WeakCloseListener _closeListener;
0144:
0145: // Lifecycle
0146: protected final Lifecycle _lifecycle = new Lifecycle();
0147:
0148: private boolean _hasNewLoader = true;
0149:
0150: private long _lastNullCheck;
0151:
0152: /**
0153: * Create a new class loader.
0154: *
0155: * @param parent parent class loader
0156: */
0157: public DynamicClassLoader(ClassLoader parent) {
0158: this (parent, true);
0159: }
0160:
0161: /**
0162: * Create a new class loader.
0163: *
0164: * @param parent parent class loader
0165: */
0166: public DynamicClassLoader(ClassLoader parent,
0167: boolean enableDependencyCheck) {
0168: super (NULL_URL_ARRAY, getInitParent(parent));
0169:
0170: parent = getParent();
0171:
0172: _securityManager = System.getSecurityManager();
0173:
0174: _isEnableDependencyCheck = enableDependencyCheck;
0175:
0176: _dependencies.setCheckInterval(_globalDependencyCheckInterval);
0177:
0178: for (; parent != null; parent = parent.getParent()) {
0179: if (parent instanceof DynamicClassLoader) {
0180: DynamicClassLoader loader = (DynamicClassLoader) parent;
0181:
0182: loader.init();
0183:
0184: addPermissions(loader.getPermissions());
0185:
0186: // loader.addListener(this);
0187:
0188: _dependencies.add(loader);
0189: _dependencies.setCheckInterval(loader
0190: .getDependencyCheckInterval());
0191:
0192: _useServletHack = loader._useServletHack;
0193:
0194: break;
0195: }
0196: }
0197:
0198: if (System.getProperty("resin.verbose.classpath") != null) {
0199: _isVerbose = true;
0200:
0201: int depth = 0;
0202:
0203: while (parent != null) {
0204: depth++;
0205: parent = parent.getParent();
0206: }
0207:
0208: _verboseDepth = depth;
0209: } else
0210: _isVerbose = false;
0211: }
0212:
0213: /**
0214: * Returns the initialization parent, i.e. the parent if given
0215: * or the context class loader if not given.
0216: */
0217: private static ClassLoader getInitParent(ClassLoader parent) {
0218: if (parent != null)
0219: return parent;
0220: else
0221: return Thread.currentThread().getContextClassLoader();
0222: }
0223:
0224: /**
0225: * Returns true if jar entries should be cached.
0226: */
0227: public static boolean isJarCacheEnabled() {
0228: return _isJarCacheEnabled;
0229: }
0230:
0231: /**
0232: * Returns true if jar entries should be cached.
0233: */
0234: public static void setJarCacheEnabled(boolean isEnabled) {
0235: _isJarCacheEnabled = isEnabled;
0236: }
0237:
0238: private void verbose(String name, String msg) {
0239: if (_isVerbose) {
0240: for (int i = _verboseDepth; _verboseDepth > 0; _verboseDepth--)
0241: System.err.print(' ');
0242:
0243: System.err.println(toString() + " " + name + " " + msg);
0244: }
0245: }
0246:
0247: /**
0248: * Returns the global dependency check interval.
0249: */
0250: public static long getGlobalDependencyCheckInterval() {
0251: return _globalDependencyCheckInterval;
0252: }
0253:
0254: /**
0255: * Sets the global dependency check interval.
0256: */
0257: public static void setGlobalDependencyCheckInterval(long interval) {
0258: _globalDependencyCheckInterval = interval;
0259: }
0260:
0261: /**
0262: * Sets the name.
0263: */
0264: public void setId(String id) {
0265: _id = id;
0266: }
0267:
0268: /**
0269: * Gets the name.
0270: */
0271: public String getId() {
0272: return _id;
0273: }
0274:
0275: /**
0276: * Returns true if the class loader is closed.
0277: */
0278: public boolean isDestroyed() {
0279: return _lifecycle.isDestroyed();
0280: }
0281:
0282: /**
0283: * Adds a resource loader to the end of the list.
0284: */
0285: public void addLoader(Loader loader) {
0286: int p = _loaders.indexOf(loader);
0287:
0288: // overriding loaders are inserted before the loader they override
0289: // server/10ih
0290: if (p >= 0) {
0291: Loader oldLoader = _loaders.get(p);
0292:
0293: if (oldLoader != loader)
0294: addLoader(loader, p);
0295: } else
0296: addLoader(loader, _loaders.size());
0297:
0298: _hasNewLoader = true;
0299: }
0300:
0301: /**
0302: * Adds a resource loader.
0303: */
0304: public void addLoader(Loader loader, int offset) {
0305: if (_lifecycle.isDestroyed())
0306: throw new IllegalStateException(L().l(
0307: "can't add loaders after initialization"));
0308:
0309: if (log().isLoggable(Level.FINEST))
0310: log().finest(this + " adding loader " + loader);
0311:
0312: _loaders.add(offset, loader);
0313:
0314: if (loader.getLoader() == null)
0315: loader.setLoader(this );
0316:
0317: if (loader instanceof Dependency)
0318: _dependencies.add((Dependency) loader);
0319:
0320: if (loader instanceof Make) {
0321: if (_makeList == null)
0322: _makeList = new MakeContainer();
0323:
0324: _makeList.add((Make) loader);
0325: }
0326:
0327: if (loader instanceof ClassLoaderListener)
0328: addListener(new WeakLoaderListener(
0329: (ClassLoaderListener) loader));
0330:
0331: _hasNewLoader = true;
0332: }
0333:
0334: public ArrayList<Loader> getLoaders() {
0335: return _loaders;
0336: }
0337:
0338: /**
0339: * Adds jars based on a manifest classpath.
0340: */
0341: public void addJarManifestClassPath(Path path) throws IOException {
0342: Path contextPath;
0343: Path manifestPath;
0344:
0345: if (path.isDirectory()) {
0346: manifestPath = path.lookup("META-INF/MANIFEST.MF");
0347: contextPath = path;
0348: } else {
0349: JarPath jar = JarPath.create(path);
0350: manifestPath = jar.lookup("META-INF/MANIFEST.MF");
0351: contextPath = path.getParent();
0352: }
0353:
0354: if (manifestPath.canRead()) {
0355: ReadStream is = manifestPath.openRead();
0356: try {
0357: Manifest manifest = new Manifest(is);
0358:
0359: Attributes main = manifest.getMainAttributes();
0360:
0361: String classPath = main.getValue("Class-Path");
0362:
0363: addManifestClassPath(classPath, contextPath);
0364: } catch (IOException e) {
0365: log().log(Level.WARNING, e.toString(), e);
0366:
0367: return;
0368: } finally {
0369: is.close();
0370: }
0371: }
0372: }
0373:
0374: /**
0375: * Adds jars based on a manifest classpath.
0376: */
0377: public void addManifestClassPath(String classPath, Path pwd) {
0378: if (classPath == null)
0379: return;
0380:
0381: String[] urls = Pattern.compile("[\\s,]+").split(classPath);
0382: if (urls == null)
0383: return;
0384:
0385: for (int i = 0; i < urls.length; i++) {
0386: String url = urls[i];
0387:
0388: if (url.equals(""))
0389: continue;
0390:
0391: addJar(pwd.lookup(url));
0392: }
0393: }
0394:
0395: /**
0396: * Adds a native path.
0397: */
0398: public void addNative(Path path) {
0399: _nativePath.add(path);
0400: }
0401:
0402: /**
0403: * Adds a jar loader.
0404: */
0405: public void addJar(Path jar) {
0406: addRoot(jar);
0407: }
0408:
0409: /**
0410: * Adds a root loader.
0411: */
0412: public void addRoot(Path root) {
0413: if (_lifecycle.isDestroyed())
0414: throw new IllegalStateException(L().l(
0415: "can't add roots after closing"));
0416:
0417: if (root instanceof JarPath || root.getPath().endsWith(".jar")
0418: || root.getPath().endsWith(".zip")) {
0419: if (_jarLoader == null) {
0420: _jarLoader = new JarLoader();
0421: addLoader(_jarLoader);
0422: }
0423:
0424: _jarLoader.addJar(root);
0425: } else {
0426: SimpleLoader loader = new SimpleLoader();
0427: loader.setPath(root);
0428:
0429: if (!_loaders.contains(loader))
0430: addLoader(loader);
0431: }
0432:
0433: addURL(root);
0434: }
0435:
0436: /**
0437: * Adds a jar loader.
0438: */
0439: public void addPathClass(String className, Path path) {
0440: if (_pathLoader == null) {
0441: _pathLoader = new PathLoader();
0442: // ejb/0i00
0443: _loaders.add(0, _pathLoader);
0444: }
0445:
0446: _pathLoader.put(className, path);
0447: }
0448:
0449: /**
0450: * Adds the URL to the URLClassLoader.
0451: */
0452: public void addURL(Path path) {
0453: try {
0454: if (path.getScheme().equals("memory"))
0455: return;
0456:
0457: if (path.getScheme().equals("jar")) {
0458: } else if (path.getFullPath().endsWith(".jar")) {
0459: } else if (!path.getURL().endsWith("/"))
0460: path = path.lookup("./");
0461:
0462: addURL(new URL(path.getURL()));
0463: } catch (MalformedURLException e) {
0464: log().warning(e.toString());
0465: } catch (Exception e) {
0466: log().log(Level.WARNING, e.toString(), e);
0467: }
0468: }
0469:
0470: /**
0471: * Adds the URL to the URLClassLoader.
0472: */
0473: @Override
0474: public void addURL(URL url) {
0475: addURL(_urls.length, url);
0476: }
0477:
0478: /**
0479: * Adds the URL to the URLClassLoader.
0480: */
0481: public void addURL(int index, URL url) {
0482: super .addURL(url);
0483:
0484: for (int i = 0; i < _urls.length; i++) {
0485: if (_urls[i].equals(url))
0486: return;
0487: }
0488:
0489: URL[] newURLs = new URL[_urls.length + 1];
0490:
0491: for (int i = 0; i < index; i++)
0492: newURLs[i] = _urls[i];
0493:
0494: newURLs[index] = url;
0495:
0496: for (int i = index + 1; i < newURLs.length; i++)
0497: newURLs[i] = _urls[i - 1];
0498:
0499: _urls = newURLs;
0500: }
0501:
0502: /**
0503: * Adds a class loader for instrumentation (jdk 1.6).
0504: */
0505: public void appendToClassPathForInstrumentation(String path) {
0506: addRoot(com.caucho.vfs.Vfs.lookup(path));
0507: }
0508:
0509: /**
0510: * Returns the URLs.
0511: */
0512: public URL[] getURLs() {
0513: return _urls;
0514: }
0515:
0516: /**
0517: * Sets the dependency check interval.
0518: */
0519: public void setDependencyCheckInterval(long interval) {
0520: _dependencies.setCheckInterval(interval);
0521: }
0522:
0523: /**
0524: * Gets the dependency check interval.
0525: */
0526: public long getDependencyCheckInterval() {
0527: if (_dependencies != null)
0528: return _dependencies.getCheckInterval();
0529: else
0530: return 0;
0531: }
0532:
0533: /**
0534: * Enables the dependency checking.
0535: */
0536: public void setEnableDependencyCheck(boolean enable) {
0537: _isEnableDependencyCheck = enable;
0538: }
0539:
0540: /**
0541: * Adds a dependency.
0542: */
0543: public void addDependency(Dependency dependency) {
0544: _dependencies.add(dependency);
0545: }
0546:
0547: public void addPermission(String path, String actions) {
0548: addPermission(new FilePermission(path, actions));
0549: }
0550:
0551: /**
0552: * Adds a permission to the loader.
0553: */
0554: public void addPermission(Permission permission) {
0555: if (_permissions == null)
0556: _permissions = new ArrayList<Permission>();
0557:
0558: _permissions.add(permission);
0559: }
0560:
0561: public ArrayList<Permission> getPermissions() {
0562: return _permissions;
0563: }
0564:
0565: public void addPermissions(ArrayList<Permission> perms) {
0566: if (perms == null)
0567: return;
0568:
0569: if (_permissions == null)
0570: _permissions = new ArrayList<Permission>();
0571:
0572: _permissions.addAll(perms);
0573: }
0574:
0575: /**
0576: * Returns the security manager.
0577: */
0578: public SecurityManager getSecurityManager() {
0579: return _securityManager;
0580: }
0581:
0582: /**
0583: * Set true if the loader should use the servlet spec's hack.
0584: */
0585: public void setServletHack(boolean servletHack) {
0586: _useServletHack = servletHack;
0587:
0588: if (_parentPriorityPackages == null)
0589: _parentPriorityPackages = new String[0];
0590: }
0591:
0592: /**
0593: * Adds a listener to detect class loader changes.
0594: */
0595: public final void addListener(ClassLoaderListener listener) {
0596: if (_lifecycle.isDestroyed()) {
0597: IllegalStateException e = new IllegalStateException(
0598: L()
0599: .l(
0600: "attempted to add listener to a closed classloader {0}",
0601: this ));
0602:
0603: log().log(Level.WARNING, e.toString(), e);
0604:
0605: return;
0606: }
0607:
0608: ArrayList<ClassLoaderListener> listeners;
0609: WeakCloseListener closeListener = null;
0610:
0611: synchronized (this ) {
0612: if (_listeners == null) {
0613: _listeners = new ArrayList<ClassLoaderListener>();
0614: closeListener = new WeakCloseListener(this );
0615: //_closeListener = closeListener;
0616: }
0617: listeners = _listeners;
0618: }
0619:
0620: if (closeListener != null) {
0621: for (ClassLoader parent = getParent(); parent != null; parent = parent
0622: .getParent()) {
0623: if (parent instanceof DynamicClassLoader) {
0624: ((DynamicClassLoader) parent)
0625: .addListener(closeListener);
0626: break;
0627: }
0628: }
0629: }
0630:
0631: synchronized (listeners) {
0632: for (int i = listeners.size() - 1; i >= 0; i--) {
0633: ClassLoaderListener oldListener = listeners.get(i);
0634:
0635: if (listener == oldListener) {
0636: return;
0637: } else if (oldListener == null)
0638: listeners.remove(i);
0639: }
0640:
0641: listeners.add(listener);
0642: }
0643:
0644: if (_lifecycle.isActive())
0645: listener.classLoaderInit(this );
0646: }
0647:
0648: /**
0649: * Adds a listener to detect class loader changes.
0650: */
0651: public final void removeListener(ClassLoaderListener listener) {
0652: ArrayList<ClassLoaderListener> listeners = _listeners;
0653:
0654: if (listeners == null)
0655: return;
0656:
0657: synchronized (listeners) {
0658: for (int i = listeners.size() - 1; i >= 0; i--) {
0659: ClassLoaderListener oldListener = listeners.get(i);
0660:
0661: if (listener == oldListener) {
0662: listeners.remove(i);
0663: return;
0664: } else if (oldListener == null)
0665: listeners.remove(i);
0666: }
0667: }
0668: }
0669:
0670: /**
0671: * Returns the listeners.
0672: */
0673: protected ArrayList<ClassLoaderListener> getListeners() {
0674: ArrayList<ClassLoaderListener> listeners;
0675: listeners = new ArrayList<ClassLoaderListener>();
0676:
0677: ArrayList<ClassLoaderListener> listenerList;
0678: listenerList = _listeners;
0679:
0680: if (listenerList != null) {
0681: synchronized (listenerList) {
0682: for (int i = 0; i < listenerList.size(); i++) {
0683: ClassLoaderListener listener = listenerList.get(i);
0684:
0685: if (listener != null)
0686: listeners.add(listener);
0687: else {
0688: listenerList.remove(i);
0689: i--;
0690: }
0691: }
0692: }
0693: }
0694:
0695: return listeners;
0696: }
0697:
0698: /**
0699: * Adds a listener to detect class loader changes.
0700: */
0701: protected final void sendAddLoaderEvent() {
0702: if (_hasNewLoader) {
0703: _hasNewLoader = false;
0704:
0705: scan();
0706:
0707: sendAddLoaderEventImpl();
0708: }
0709: }
0710:
0711: /**
0712: * Adds a listener to detect class loader changes.
0713: */
0714: protected void sendAddLoaderEventImpl() {
0715: }
0716:
0717: /**
0718: * Add to the list of packages that don't use the hack.
0719: */
0720: public void addParentPriorityPackages(String[] pkg) {
0721: for (int i = 0; pkg != null && i < pkg.length; i++) {
0722: addParentPriorityPackage(pkg[i]);
0723: }
0724: }
0725:
0726: /**
0727: * Add to the list of packages that don't use the {@link #setServletHack(boolean)}.
0728: */
0729: public void addParentPriorityPackage(String pkg) {
0730: if (_parentPriorityPackages == null)
0731: _parentPriorityPackages = new String[0];
0732:
0733: int oldLength = _parentPriorityPackages.length;
0734: String[] newPkgs = new String[oldLength + 1];
0735:
0736: System.arraycopy(_parentPriorityPackages, 0, newPkgs, 0,
0737: oldLength);
0738:
0739: if (!pkg.endsWith("."))
0740: pkg = pkg + '.';
0741:
0742: newPkgs[oldLength] = pkg;
0743: _parentPriorityPackages = newPkgs;
0744: }
0745:
0746: /**
0747: * Add to the list of packages that take priority over the parent
0748: */
0749: public void addPriorityPackage(String pkg) {
0750: if (_priorityPackages == null)
0751: _priorityPackages = new String[0];
0752:
0753: int oldLength = _priorityPackages.length;
0754: String[] newPkgs = new String[oldLength + 1];
0755:
0756: System.arraycopy(_priorityPackages, 0, newPkgs, 0, oldLength);
0757:
0758: if (!pkg.endsWith("."))
0759: pkg = pkg + '.';
0760:
0761: newPkgs[oldLength] = pkg;
0762: _priorityPackages = newPkgs;
0763: }
0764:
0765: /**
0766: * Returns the permission collection for the given code source.
0767: */
0768: protected PermissionCollection getPermissions(CodeSource codeSource) {
0769: PermissionCollection perms = super .getPermissions(codeSource);
0770:
0771: ArrayList<Permission> permissions = _permissions;
0772:
0773: for (int i = 0; permissions != null && i < permissions.size(); i++) {
0774: Permission permission = permissions.get(i);
0775:
0776: perms.add(permission);
0777: }
0778:
0779: return perms;
0780: }
0781:
0782: protected void addCodeBasePath(String path) {
0783: }
0784:
0785: /**
0786: * Sets any enhancer.
0787: */
0788: public void addTransformer(ClassFileTransformer transformer) {
0789: if (_classFileTransformerList == null)
0790: _classFileTransformerList = new ArrayList<ClassFileTransformer>();
0791:
0792: _classFileTransformerList.add(transformer);
0793: }
0794:
0795: protected ArrayList<ClassFileTransformer> getTransformerList() {
0796: return _classFileTransformerList;
0797: }
0798:
0799: /**
0800: * Fill data for the class path. fillClassPath() will add all
0801: * .jar and .zip files in the directory list.
0802: */
0803: public final String getClassPath() {
0804: StringBuilder head = new StringBuilder();
0805:
0806: buildClassPath(head);
0807:
0808: return head.toString();
0809: }
0810:
0811: /**
0812: * Fill data for the class path. fillClassPath() will add all
0813: * .jar and .zip files in the directory list.
0814: */
0815: protected final void buildClassPath(StringBuilder head) {
0816: ClassLoader parent = getParent();
0817:
0818: if (parent instanceof DynamicClassLoader)
0819: ((DynamicClassLoader) parent).buildClassPath(head);
0820: else {
0821: head.append(CauchoSystem.getClassPath());
0822:
0823: for (; parent != null; parent = parent.getParent()) {
0824: // XXX: should be reverse order
0825: if (parent instanceof URLClassLoader) {
0826: URLClassLoader urlLoader = (URLClassLoader) parent;
0827:
0828: for (URL url : urlLoader.getURLs()) {
0829: if (head.length() > 0)
0830: head.append(CauchoSystem
0831: .getPathSeparatorChar());
0832: head.append(url);
0833: }
0834: }
0835: }
0836: }
0837:
0838: ArrayList<Loader> loaders = getLoaders();
0839: for (int i = 0; i < loaders.size(); i++) {
0840: Loader loader = loaders.get(i);
0841:
0842: loader.buildClassPath(head);
0843: }
0844: }
0845:
0846: /**
0847: * Fill data for the class path. fillClassPath() will add all
0848: * .jar and .zip files in the directory list.
0849: */
0850: public final String getLocalClassPath() {
0851: StringBuilder head = new StringBuilder();
0852:
0853: ArrayList<Loader> loaders = getLoaders();
0854: for (int i = 0; i < loaders.size(); i++) {
0855: Loader loader = loaders.get(i);
0856:
0857: buildClassPath(head);
0858: }
0859:
0860: return head.toString();
0861: }
0862:
0863: /**
0864: * Returns the source path. The source path is used for looking up
0865: * resources.
0866: */
0867: public final String getSourcePath() {
0868: StringBuilder head = new StringBuilder();
0869:
0870: buildSourcePath(head);
0871:
0872: return head.toString();
0873: }
0874:
0875: /**
0876: * Fill data for the class path. fillSourcePath() will add all
0877: * .jar and .zip files in the directory list.
0878: */
0879: protected final void buildSourcePath(StringBuilder head) {
0880: ClassLoader parent = getParent();
0881:
0882: if (parent instanceof DynamicClassLoader)
0883: ((DynamicClassLoader) parent).buildSourcePath(head);
0884: else
0885: head.append(CauchoSystem.getClassPath());
0886:
0887: ArrayList<Loader> loaders = getLoaders();
0888: for (int i = 0; i < loaders.size(); i++) {
0889: Loader loader = loaders.get(i);
0890:
0891: loader.buildSourcePath(head);
0892: }
0893: }
0894:
0895: /**
0896: * Returns the resource path with most specific first.
0897: */
0898: public final String getResourcePathSpecificFirst() {
0899: ArrayList<String> pathList = new ArrayList<String>();
0900:
0901: buildResourcePathSpecificFirst(pathList);
0902:
0903: StringBuilder sb = new StringBuilder();
0904: char sep = CauchoSystem.getPathSeparatorChar();
0905:
0906: if (pathList.size() == 0)
0907: return "";
0908:
0909: sb.append(pathList.get(0));
0910: for (int i = 1; i < pathList.size(); i++) {
0911: sb.append(sep);
0912: sb.append(pathList.get(i));
0913: }
0914:
0915: return sb.toString();
0916: }
0917:
0918: /**
0919: * Returns the resource path with most specific first.
0920: */
0921: protected final void buildResourcePathSpecificFirst(
0922: ArrayList<String> pathList) {
0923: ClassLoader parent = getParent();
0924:
0925: ArrayList<Loader> loaders = getLoaders();
0926: int size = loaders != null ? loaders.size() : 0;
0927: for (int i = 0; i < size; i++) {
0928: Loader loader = loaders.get(i);
0929:
0930: loader.buildSourcePath(pathList);
0931: }
0932:
0933: if (parent instanceof DynamicClassLoader)
0934: ((DynamicClassLoader) parent)
0935: .buildResourcePathSpecificFirst(pathList);
0936: else {
0937: String tail = CauchoSystem.getClassPath();
0938:
0939: if (tail != null) {
0940: char sep = CauchoSystem.getPathSeparatorChar();
0941:
0942: String[] values = tail.split("[" + sep + "]");
0943:
0944: for (int i = 0; i < values.length; i++) {
0945: pathList.add(values[i]);
0946: }
0947: }
0948: }
0949: }
0950:
0951: /**
0952: * Returns true if any of the classes have been modified.
0953: */
0954: public final boolean isModified() {
0955: return isModified(_isEnableDependencyCheck);
0956: }
0957:
0958: /**
0959: * Returns true if any of the classes have been modified.
0960: */
0961: public final boolean isModified(boolean enable) {
0962: if (_lifecycle.isDestroyed()) {
0963: return true;
0964: }
0965:
0966: DependencyContainer dependencies = _dependencies;
0967:
0968: if (dependencies == null) {
0969: return true;
0970: }
0971:
0972: if (enable) {
0973: boolean isModified = dependencies.isModified();
0974:
0975: return isModified;
0976: } else {
0977: boolean isModified = isModified(getParent());
0978:
0979: return isModified;
0980: }
0981: }
0982:
0983: /**
0984: * Returns true if any of the classes have been modified, forcing a check.
0985: */
0986: public final boolean isModifiedNow() {
0987: if (_lifecycle.isDestroyed())
0988: return true;
0989:
0990: DependencyContainer dependencies = _dependencies;
0991:
0992: if (dependencies == null)
0993: return true;
0994:
0995: return dependencies.isModifiedNow();
0996: }
0997:
0998: /**
0999: * Logs the reason for modification.
1000: */
1001: public final boolean logModified(Logger log) {
1002: if (_lifecycle.isDestroyed())
1003: return true;
1004:
1005: DependencyContainer dependencies = _dependencies;
1006:
1007: if (dependencies != null)
1008: return dependencies.logModified(log);
1009: else
1010: return false;
1011: }
1012:
1013: /**
1014: * Returns true if any of the classes have been modified.
1015: */
1016: public final void resetDependencyCheckInterval() {
1017: if (_lifecycle.isDestroyed())
1018: return;
1019:
1020: DependencyContainer dependencies = _dependencies;
1021:
1022: if (dependencies == null)
1023: return;
1024:
1025: dependencies.resetDependencyCheckInterval();
1026: }
1027:
1028: /**
1029: * Returns true if any of the classes have been modified.
1030: */
1031: public final void clearModified() {
1032: if (_lifecycle.isDestroyed())
1033: return;
1034:
1035: DependencyContainer dependencies = _dependencies;
1036:
1037: if (dependencies == null)
1038: return;
1039:
1040: dependencies.clearModified();
1041: }
1042:
1043: /**
1044: * Returns true if any of the classes have been modified.
1045: */
1046: public static boolean isModified(ClassLoader loader) {
1047: for (; loader != null; loader = loader.getParent()) {
1048: if (loader instanceof DynamicClassLoader)
1049: return ((DynamicClassLoader) loader).isModified();
1050: }
1051:
1052: return false;
1053: }
1054:
1055: /**
1056: * Makes any changed classes for the virtual class loader.
1057: */
1058: public final void make() throws Exception {
1059: for (ClassLoader loader = getParent(); loader != null; loader = loader
1060: .getParent()) {
1061: if (loader instanceof Make) {
1062: ((Make) loader).make();
1063: break;
1064: }
1065: }
1066:
1067: if (_makeList != null)
1068: _makeList.make();
1069: }
1070:
1071: /**
1072: * Defines a new package.
1073: */
1074: protected Package definePackage(String name, String a1, String a2,
1075: String a3, String b1, String b2, String b3, URL url) {
1076: name = name.replace('/', '.');
1077:
1078: if (name.endsWith("."))
1079: name = name.substring(0, name.length() - 1);
1080:
1081: return super .definePackage(name, a1, a2, a3, b1, b2, b3, url);
1082: }
1083:
1084: /**
1085: * Initialize the class loader.
1086: */
1087: public void init() {
1088: if (!_lifecycle.toActive())
1089: return;
1090:
1091: try {
1092: ArrayList<ClassLoaderListener> listeners = getListeners();
1093:
1094: if (listeners != null) {
1095: for (int i = 0; i < listeners.size(); i++) {
1096: ClassLoaderListener listener = listeners.get(i);
1097:
1098: listener.classLoaderInit(this );
1099: }
1100: }
1101: } catch (Exception e) {
1102: log().log(Level.WARNING, e.toString(), e);
1103: }
1104: }
1105:
1106: /**
1107: * Validates the class loader.
1108: */
1109: public void validate() throws ConfigException {
1110: ArrayList<Loader> loaders = getLoaders();
1111:
1112: if (loaders == null)
1113: throw new IllegalStateException(
1114: _L
1115: .l(
1116: "Class loader {0} is closed during initialization.",
1117: this ));
1118:
1119: for (int i = 0; i < loaders.size(); i++)
1120: loaders.get(i).validate();
1121: }
1122:
1123: public void scan() {
1124: }
1125:
1126: public Class<?> loadClass(String name)
1127: throws ClassNotFoundException {
1128: // the Sun JDK implementation of ClassLoader delegates this call
1129: // to loadClass(name, false), but there is no guarantee that other
1130: // implementations do.
1131: return loadClass(name, false);
1132: }
1133:
1134: /**
1135: * Load a class using this class loader
1136: *
1137: * @param name the classname to load
1138: * @param resolve if true, resolve the class
1139: *
1140: * @return the loaded classes
1141: */
1142: protected Class loadClass(String name, boolean resolve)
1143: throws ClassNotFoundException {
1144: synchronized (this ) {
1145: Class cl = loadClassImpl(name, resolve);
1146:
1147: if (cl != null)
1148: return cl;
1149: else
1150: throw new ClassNotFoundException(name + " in " + this );
1151: }
1152: }
1153:
1154: /**
1155: * Load a class using this class loader
1156: *
1157: * @param name the classname to load
1158: * @param resolve if true, resolve the class
1159: *
1160: * @return the loaded classes
1161: */
1162: protected Class loadClassImpl(String name, boolean resolve)
1163: throws ClassNotFoundException {
1164: if (_entryCache != null) {
1165: ClassEntry entry = _entryCache.get(name);
1166:
1167: if (entry != null) {
1168: Class cl = entry.getEntryClass();
1169:
1170: if (cl != null)
1171: return cl;
1172: }
1173: }
1174:
1175: // The JVM has already cached the classes, so we don't need to
1176: Class cl = findLoadedClass(name);
1177:
1178: if (cl != null) {
1179: if (resolve)
1180: resolveClass(cl);
1181: return cl;
1182: }
1183:
1184: if (_lifecycle.isDestroyed()) {
1185: log()
1186: .fine(
1187: L()
1188: .l(
1189: "Loading class {0} when class loader {1} has been closed.",
1190: name, this ));
1191:
1192: return super .loadClass(name, resolve);
1193: }
1194:
1195: boolean normalJdkOrder = isNormalJdkOrder(name);
1196:
1197: if (_lifecycle.isBeforeInit())
1198: init();
1199:
1200: if (normalJdkOrder) {
1201: try {
1202: ClassLoader parent = getParent();
1203:
1204: if (parent instanceof DynamicClassLoader)
1205: cl = ((DynamicClassLoader) parent).loadClassImpl(
1206: name, resolve);
1207: else if (parent != null) {
1208: cl = Class.forName(name, false, parent);
1209: } else
1210: cl = findSystemClass(name);
1211: } catch (ClassNotFoundException e) {
1212: }
1213:
1214: if (cl == null) {
1215: cl = findClassImpl(name);
1216: }
1217: } else {
1218: try {
1219: cl = findClass(name);
1220: } catch (ClassNotFoundException e) {
1221: ClassLoader parent = getParent();
1222: if (parent != null)
1223: cl = Class.forName(name, false, parent);
1224: else
1225: cl = findSystemClass(name);
1226: }
1227: }
1228:
1229: if (resolve && cl != null)
1230: resolveClass(cl);
1231:
1232: return cl;
1233: }
1234:
1235: /**
1236: * Load a class using this class loader
1237: *
1238: * @param name the classname using either '/' or '.'
1239: *
1240: * @return the loaded class
1241: */
1242: protected Class findClass(String name)
1243: throws ClassNotFoundException {
1244: Class cl = findClassImpl(name);
1245:
1246: if (cl != null)
1247: return cl;
1248: else
1249: throw new ClassNotFoundException(name);
1250: }
1251:
1252: /**
1253: * Load a class using this class loader
1254: *
1255: * @param name the classname using either '/' or '.'
1256: *
1257: * @return the loaded class
1258: */
1259: protected Class findClassImpl(String name)
1260: throws ClassNotFoundException {
1261: if (_isVerbose)
1262: verbose(name, "findClass");
1263:
1264: if (_lifecycle.isDestroyed()) {
1265: log().fine("Class loader has been closed.");
1266: return super .findClass(name);
1267: }
1268:
1269: if (_lifecycle.isBeforeInit())
1270: init();
1271:
1272: /*
1273: if (! _lifecycle.isActive())
1274: return super.findClass(name);
1275: */
1276:
1277: name = name.replace('/', '.');
1278:
1279: ClassEntry entry = null;
1280:
1281: synchronized (this ) {
1282: entry = _entryCache == null ? null : _entryCache.get(name);
1283:
1284: if (entry == null)
1285: entry = getClassEntry(name);
1286:
1287: if (entry == null)
1288: return null;
1289:
1290: if (entry != null && _isVerbose)
1291: verbose(name, (isNormalJdkOrder(name) ? "found"
1292: : "found (took priority from parent)"));
1293:
1294: if (_isEnableDependencyCheck)
1295: entry.addDependencies(_dependencies);
1296:
1297: // Currently, the entry must be in the entry cache for synchronization
1298: // to work. The same entry must be returned for two separate threads
1299: // trying to load the class at the same time.
1300:
1301: if (_entryCache == null)
1302: _entryCache = new Hashtable<String, ClassEntry>(8);
1303:
1304: _entryCache.put(name, entry);
1305: }
1306:
1307: try {
1308: return loadClass(entry);
1309: } catch (RuntimeException e) {
1310: throw e;
1311: } catch (ClassNotFoundException e) {
1312: throw e;
1313: } catch (Exception e) {
1314: log().log(Level.FINE, e.toString(), e);
1315:
1316: throw new ClassNotFoundException(name + " [" + e + "]", e);
1317: }
1318: }
1319:
1320: /**
1321: * Returns the matching class entry.
1322: */
1323: protected ClassEntry getClassEntry(String name)
1324: throws ClassNotFoundException {
1325: String pathName = name.replace('.', '/') + ".class";
1326:
1327: ArrayList<Loader> loaders = getLoaders();
1328: for (int i = 0; i < loaders.size(); i++) {
1329: Loader loader = loaders.get(i);
1330:
1331: ClassEntry entry = loader.getClassEntry(name, pathName);
1332:
1333: if (entry != null)
1334: return entry;
1335: }
1336:
1337: return null;
1338: }
1339:
1340: /**
1341: * Loads the class from the loader. The loadClass must be in the
1342: * top classLoader because the defineClass must be owned by the top.
1343: */
1344: protected Class loadClass(ClassEntry entry) throws IOException,
1345: ClassNotFoundException {
1346: synchronized (entry) {
1347: Class cl = entry.getEntryClass();
1348:
1349: if (cl != null)
1350: return cl;
1351:
1352: entry.preLoad();
1353:
1354: String name = entry.getName();
1355: int p = name.lastIndexOf('.');
1356: if (p > 0) {
1357: String packageName = name.substring(0, p);
1358: Package pkg = getPackage(packageName);
1359:
1360: ClassPackage classPackage = entry.getClassPackage();
1361:
1362: if (pkg != null) {
1363: } else if (classPackage != null) {
1364: definePackage(packageName, classPackage
1365: .getSpecificationTitle(), classPackage
1366: .getSpecificationVersion(), classPackage
1367: .getSpecificationVendor(), classPackage
1368: .getImplementationTitle(), classPackage
1369: .getImplementationVersion(), classPackage
1370: .getImplementationVendor(), null);
1371: } else {
1372: definePackage(packageName, null, null, null, null,
1373: null, null, null);
1374: }
1375: }
1376:
1377: ByteBuffer buffer = new ByteBuffer();
1378:
1379: entry.load(buffer);
1380:
1381: byte[] bBuf = buffer.getBuffer();
1382: int bLen = buffer.length();
1383:
1384: if (_classFileTransformerList != null) {
1385: Class redefineClass = null;
1386: String className = name.replace('.', '/');
1387:
1388: if (bBuf.length != bLen) {
1389: byte[] tempBuf = new byte[bLen];
1390: System.arraycopy(bBuf, 0, tempBuf, 0, bLen);
1391: bBuf = tempBuf;
1392: }
1393:
1394: ProtectionDomain protectionDomain = null;
1395:
1396: for (int i = 0; i < _classFileTransformerList.size(); i++) {
1397: ClassFileTransformer transformer = _classFileTransformerList
1398: .get(i);
1399:
1400: try {
1401: byte[] enhancedBuffer = transformer.transform(
1402: this , className, redefineClass,
1403: protectionDomain, bBuf);
1404:
1405: if (enhancedBuffer != null) {
1406: bBuf = enhancedBuffer;
1407: bLen = enhancedBuffer.length;
1408:
1409: if (_isVerbose || true)
1410: verbose(name, String
1411: .valueOf(transformer));
1412: }
1413: /* RSN-109
1414: } catch (RuntimeException e) {
1415: throw e;
1416: } catch (Error e) {
1417: throw e;
1418: */
1419: } catch (EnhancerRuntimeException e) {
1420: throw e;
1421: } catch (Throwable e) {
1422: log().log(Level.WARNING, e.toString(), e);
1423: }
1424: }
1425: }
1426:
1427: try {
1428: cl = defineClass(entry.getName(), bBuf, 0, bLen, entry
1429: .getCodeSource());
1430: } catch (RuntimeException e) {
1431: log().log(Level.FINE,
1432: entry.getName() + " [" + e.toString() + "]", e);
1433:
1434: throw e;
1435: } catch (Exception e) {
1436: log().log(Level.FINE,
1437: entry.getName() + " [" + e.toString() + "]", e);
1438:
1439: ClassNotFoundException exn;
1440: exn = new ClassNotFoundException(entry.getName() + " ["
1441: + e + "]", e);
1442: //exn.initCause(e);
1443:
1444: throw exn;
1445: }
1446:
1447: entry.setEntryClass(cl);
1448:
1449: if (entry.postLoad()) {
1450: _dependencies.add(AlwaysModified.create());
1451: _dependencies.setModified(true);
1452: }
1453:
1454: return cl;
1455: }
1456: }
1457:
1458: /**
1459: * Gets the named resource
1460: *
1461: * @param name name of the resource
1462: */
1463: public URL getResource(String name) {
1464: if (_resourceCache == null) {
1465: long expireInterval = getDependencyCheckInterval();
1466:
1467: _resourceCache = new TimedCache<String, URL>(256,
1468: expireInterval);
1469: }
1470:
1471: URL url = _resourceCache.get(name);
1472:
1473: if (url == NULL_URL)
1474: return null;
1475: else if (url != null)
1476: return url;
1477:
1478: if (name.startsWith("/"))
1479: name = name.substring(1);
1480:
1481: if (name.endsWith("/"))
1482: name = name.substring(0, name.length() - 1);
1483:
1484: boolean isNormalJdkOrder = isNormalJdkOrder(name);
1485:
1486: if (isNormalJdkOrder) {
1487: url = getParentResource(name);
1488:
1489: if (url != null)
1490: return url;
1491: }
1492:
1493: ArrayList<Loader> loaders = getLoaders();
1494:
1495: for (int i = 0; loaders != null && i < loaders.size(); i++) {
1496: Loader loader = loaders.get(i);
1497:
1498: url = loader.getResource(name);
1499:
1500: if (url != null) {
1501: _resourceCache.put(name, url);
1502:
1503: return url;
1504: }
1505: }
1506:
1507: if (!isNormalJdkOrder) {
1508: url = getParentResource(name);
1509:
1510: if (url != null)
1511: return url;
1512: }
1513:
1514: _resourceCache.put(name, NULL_URL);
1515:
1516: return null;
1517: }
1518:
1519: private URL getParentResource(String name) {
1520: ClassLoader parent = getParent();
1521:
1522: ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
1523:
1524: URL url;
1525:
1526: if (parent != null) {
1527: url = parent.getResource(name);
1528:
1529: if (url != null) {
1530: _resourceCache.put(name, url);
1531:
1532: return url;
1533: }
1534: } else if (this != systemLoader) {
1535: url = getSystemResource(name);
1536:
1537: if (url != null) {
1538: _resourceCache.put(name, url);
1539:
1540: return url;
1541: }
1542: }
1543:
1544: return null;
1545: }
1546:
1547: /**
1548: * Opens a stream to a resource somewhere in the classpath
1549: *
1550: * @param name the path to the resource
1551: *
1552: * @return an input stream to the resource
1553: */
1554: public InputStream getResourceAsStream(String name) {
1555: if (name.startsWith("/"))
1556: name = name.substring(1);
1557:
1558: if (name.endsWith("/"))
1559: name = name.substring(0, name.length() - 1);
1560:
1561: boolean isNormalJdkOrder = isNormalJdkOrder(name);
1562: InputStream is = null;
1563:
1564: if (isNormalJdkOrder) {
1565: is = getParentResourceAsStream(name);
1566:
1567: if (is != null)
1568: return is;
1569: }
1570:
1571: ArrayList<Loader> loaders = getLoaders();
1572:
1573: for (int i = 0; loaders != null && i < loaders.size(); i++) {
1574: Loader loader = loaders.get(i);
1575:
1576: is = loader.getResourceAsStream(name);
1577:
1578: if (is != null)
1579: return is;
1580: }
1581:
1582: if (!isNormalJdkOrder) {
1583: is = getParentResourceAsStream(name);
1584: }
1585:
1586: return is;
1587: }
1588:
1589: private InputStream getParentResourceAsStream(String name) {
1590: ClassLoader parent = getParent();
1591:
1592: ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
1593:
1594: InputStream is;
1595:
1596: if (parent != null) {
1597: is = parent.getResourceAsStream(name);
1598:
1599: if (is != null)
1600: return is;
1601: } else if (this != systemLoader) {
1602: is = getSystemResourceAsStream(name);
1603:
1604: if (is != null) {
1605: return is;
1606: }
1607: }
1608:
1609: return null;
1610: }
1611:
1612: /**
1613: * Returns an enumeration of matching resources.
1614: */
1615: public Enumeration<URL> findResources(String name) {
1616: if (name.startsWith("/"))
1617: name = name.substring(1);
1618:
1619: // server/249b
1620: /*
1621: if (name.endsWith("/"))
1622: name = name.substring(0, name.length() - 1);
1623: */
1624:
1625: Vector<URL> resources = new Vector<URL>();
1626:
1627: ArrayList<Loader> loaders = getLoaders();
1628: for (int i = 0; i < loaders.size(); i++) {
1629: Loader loader = loaders.get(i);
1630:
1631: loader.getResources(resources, name);
1632: }
1633:
1634: return resources.elements();
1635: }
1636:
1637: /**
1638: * Returns the full library path for the name.
1639: */
1640: public String findLibrary(String name) {
1641: String systemName = System.mapLibraryName(name);
1642:
1643: ArrayList<Loader> loaders = getLoaders();
1644: for (int i = 0; i < loaders.size(); i++) {
1645: Loader loader = loaders.get(i);
1646:
1647: Path path = loader.getPath(systemName);
1648:
1649: if (path != null && path.canRead()) {
1650: return path.getNativePath();
1651: }
1652: }
1653:
1654: for (int i = 0; i < _nativePath.size(); i++) {
1655: Path path = _nativePath.get(i);
1656:
1657: if (path.canRead())
1658: return path.getNativePath();
1659: }
1660:
1661: return super .findLibrary(name);
1662: }
1663:
1664: /**
1665: * Returns the matching single-level path.
1666: */
1667: public Path findPath(String name) {
1668: ArrayList<Loader> loaders = getLoaders();
1669: for (int i = 0; i < loaders.size(); i++) {
1670: Loader loader = loaders.get(i);
1671:
1672: Path path = loader.getPath(name);
1673:
1674: if (path != null && path.canRead()) {
1675: return path;
1676: }
1677: }
1678:
1679: return null;
1680: }
1681:
1682: /**
1683: * Returns true if the class loader should use the normal order,
1684: * i.e. looking at the parents first.
1685: */
1686: private boolean isNormalJdkOrder(String className) {
1687: if (_priorityPackages != null) {
1688: String canonName = className.replace('/', '.');
1689:
1690: for (String priorityPackage : _priorityPackages) {
1691: if (canonName.startsWith(priorityPackage))
1692: return false;
1693: }
1694: }
1695:
1696: if (!_useServletHack)
1697: return true;
1698:
1699: String canonName = className.replace('/', '.');
1700: String[] pkgs = _parentPriorityPackages;
1701:
1702: for (int i = 0; pkgs != null && i < pkgs.length; i++) {
1703: if (canonName.startsWith(pkgs[i]))
1704: return true;
1705: }
1706:
1707: return false;
1708: }
1709:
1710: /**
1711: * stops the class loader.
1712: */
1713: public void stop() {
1714: }
1715:
1716: /**
1717: * Destroys the class loader.
1718: */
1719: public void destroy() {
1720: try {
1721: stop();
1722: } catch (Throwable e) {
1723: }
1724:
1725: if (!_lifecycle.toDestroying())
1726: return;
1727:
1728: try {
1729: ClassLoader parent = getParent();
1730: for (; parent != null; parent = parent.getParent()) {
1731: if (parent instanceof DynamicClassLoader) {
1732: DynamicClassLoader loader = (DynamicClassLoader) parent;
1733:
1734: if (_closeListener != null)
1735: loader.removeListener(_closeListener);
1736: }
1737: }
1738:
1739: ArrayList<ClassLoaderListener> listeners = _listeners;
1740: _listeners = null;
1741:
1742: Thread thread = Thread.currentThread();
1743: ClassLoader oldLoader = thread.getContextClassLoader();
1744:
1745: try {
1746: // Use reverse order so the last resources will be destroyed first.
1747: if (listeners != null) {
1748: for (int i = listeners.size() - 1; i >= 0; i--) {
1749: ClassLoaderListener listener = listeners.get(i);
1750:
1751: try {
1752: thread.setContextClassLoader(this );
1753:
1754: listener.classLoaderDestroy(this );
1755: } catch (Throwable e) {
1756: log().log(Level.WARNING, e.toString(), e);
1757: }
1758: }
1759: }
1760: } finally {
1761: thread.setContextClassLoader(oldLoader);
1762: }
1763:
1764: ArrayList<Loader> loaders = getLoaders();
1765: for (int i = loaders.size() - 1; i >= 0; i--) {
1766: Loader loader = loaders.get(i);
1767:
1768: try {
1769: loader.destroy();
1770: } catch (Throwable e) {
1771: log().log(Level.WARNING, e.toString(), e);
1772: }
1773: }
1774: } finally {
1775: _closeListener = null;
1776: _listeners = null;
1777: _entryCache = null;
1778: _makeList = null;
1779: _loaders = null;
1780: _jarLoader = null;
1781: _dependencies = null;
1782: _permissions = null;
1783: _securityManager = null;
1784: _codeSource = null;
1785: _classFileTransformerList = null;
1786:
1787: _lifecycle.toDestroy();
1788: }
1789: }
1790:
1791: /**
1792: * Sets the old loader if not destroyed.
1793: */
1794: public static void setOldLoader(Thread thread, ClassLoader oldLoader) {
1795: if (!(oldLoader instanceof DynamicClassLoader)) {
1796: thread.setContextClassLoader(oldLoader);
1797: return;
1798: }
1799:
1800: DynamicClassLoader dynLoader = (DynamicClassLoader) oldLoader;
1801:
1802: if (!dynLoader.isDestroyed())
1803: thread.setContextClassLoader(oldLoader);
1804: else
1805: thread.setContextClassLoader(ClassLoader
1806: .getSystemClassLoader());
1807: }
1808:
1809: public ClassLoader getInstrumentableClassLoader() {
1810: return this ;
1811: }
1812:
1813: public ClassLoader getThrowawayClassLoader() {
1814: return getNewTempClassLoader();
1815: }
1816:
1817: public ClassLoader getNewTempClassLoader() {
1818: return new TempDynamicClassLoader(this );
1819: }
1820:
1821: /**
1822: * Copies the loader.
1823: */
1824: protected void replace(DynamicClassLoader source) {
1825: _id = source._id;
1826:
1827: _loaders.addAll(source._loaders);
1828: _jarLoader = source._jarLoader;
1829:
1830: _dependencies = source._dependencies;
1831:
1832: _makeList = source._makeList;
1833: _useServletHack = source._useServletHack;
1834: _parentPriorityPackages = source._parentPriorityPackages;
1835:
1836: if (source._listeners != null) {
1837: if (_listeners == null)
1838: _listeners = new ArrayList<ClassLoaderListener>();
1839:
1840: _listeners.addAll(source._listeners);
1841: source._listeners.clear();
1842: }
1843:
1844: _securityManager = source._securityManager;
1845: if (source._permissions != null) {
1846: if (_permissions == null)
1847: _permissions = new ArrayList<Permission>();
1848:
1849: _permissions.addAll(source._permissions);
1850: }
1851:
1852: _codeSource = source._codeSource;
1853:
1854: _lifecycle.copyState(source._lifecycle);
1855: }
1856:
1857: public String toString() {
1858: if (_id != null)
1859: return getClass().getSimpleName() + "[" + _id + "]";
1860: else
1861: return getClass().getSimpleName() + getLoaders();
1862: }
1863:
1864: private static L10N L() {
1865: if (_L == null)
1866: _L = new L10N(DynamicClassLoader.class);
1867:
1868: return _L;
1869: }
1870:
1871: private static Logger log() {
1872: if (_log == null)
1873: _log = Logger.getLogger(DynamicClassLoader.class.getName());
1874:
1875: return _log;
1876: }
1877:
1878: // XXX: GC issues
1879: /*n
1880: protected void finalize()
1881: {
1882: destroy();
1883: }
1884: */
1885:
1886: static {
1887: URL url = null;
1888:
1889: try {
1890: url = new URL("file:/caucho/null");
1891: } catch (Throwable e) {
1892: }
1893:
1894: NULL_URL = url;
1895: }
1896: }
|