?? repositoryclassloader.java
字號:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.jackrabbit.classloader;import java.beans.Introspector;import java.io.IOException;import java.net.URL;import java.net.URLClassLoader;import java.security.AccessController;import java.security.PrivilegedExceptionAction;import java.util.ArrayList;import java.util.Collections;import java.util.Date;import java.util.Enumeration;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.NoSuchElementException;import java.util.jar.Attributes;import java.util.jar.Manifest;import javax.jcr.RepositoryException;import javax.jcr.Session;import org.apache.jackrabbit.net.JCRURLConnection;import org.apache.jackrabbit.net.URLFactory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * The <code>RepositoryClassLoader</code> class extends the * <code>URLClassLoader</code> and provides the functionality to load classes * and resources from JCR Repository. * <p> * This class loader supports loading classes from the Repository hierarchy, * such as a <em>classes</em> 'folder', but also from Jar and Zip files stored * in the Repository. * <p> * For enhanced performance, this class loader keeps a list of resources and * classes which have already been loaded through this class loader. If later * requests ask for already cached resources, these are returned without * checking whether the underlying repository actually still exists. * <p> * This class is not intended to be extended by clients. * * @author Felix Meschberger */public class RepositoryClassLoader extends URLClassLoader { /** default log category */ private static final Logger log = LoggerFactory.getLogger(RepositoryClassLoader.class); /** An empty list of url paths to call superclass constructor */ private static final URL[] NULL_PATH = {}; /** * The special resource representing a resource which could not be * found in the class path. * * @see #cache * @see #findClassLoaderResource(String) */ /* package */ static final ClassLoaderResource NOT_FOUND_RESOURCE = new ClassLoaderResource(null, "[sentinel]", null) { public boolean isExpired() { return false; } }; /** * The classpath which this classloader searches for class definitions. * Each element of the vector should be either a directory, a .zip * file, or a .jar file. * <p> * It may be empty when only system classes are controlled. */ private ClassPathEntry[] repository; /** * The list of handles to use as a classpath. These is the unprocessed * list of handles given to the constructor. */ private PatternPath handles; /** * The <code>Session</code> grants access to the Repository to access the * resources. * <p> * This field is not final such that it may be cleared when the class loader * is destroyed. */ private Session session; /** * Cache of resources found or not found in the class path. The map is * indexed by resource name and contains mappings to instances of the * {@link ClassLoaderResource} class. If a resource has been tried to be * loaded, which could not be found, the resource is cached with the * special mapping to {@link #NOT_FOUND_RESOURCE}. * * @see #NOT_FOUND_RESOURCE * @see #findClassLoaderResource(String) */ private Map cache; /** * Flag indicating whether the {@link #destroy()} method has already been * called (<code>true</code>) or not (<code>false</code>) */ private boolean destroyed; /** * Creates a <code>RepositoryClassLoader</code> from a list of item path * strings containing globbing pattens for the paths defining the class * path. * * @param session The <code>Session</code> to use to access the class items. * @param classPath The list of path strings making up the (initial) class * path of this class loader. The strings may contain globbing * characters which will be resolved to build the actual class path. * @param parent The parent <code>ClassLoader</code>, which may be * <code>null</code>. * * @throws NullPointerException if either the session or the handles list is * <code>null</code>. */ public RepositoryClassLoader(Session session, String[] classPath, ClassLoader parent) { this(session, new DynamicPatternPath(session, classPath), parent); } /** * Creates a <code>RepositoryClassLoader</code> from a * {@link PatternPath} containing globbing pattens for the handles * defining the class path. * * @param session The <code>Session</code> to use to access the class items. * @param handles The {@link PatternPath} of handles. * @param parent The parent <code>ClassLoader</code>, which may be * <code>null</code>. * * @throws NullPointerException if either the session or the handles list is * <code>null</code>. */ /* package */ RepositoryClassLoader(Session session, PatternPath handles, ClassLoader parent) { // initialize the super class with an empty class path super(NULL_PATH, parent); // check session and handles if (session == null) { throw new NullPointerException("session"); } if (handles == null) { throw new NullPointerException("handles"); } // set fields this.session = session; this.setHandles(handles); this.cache = new HashMap(); this.destroyed = false; // build the class repositories list buildRepository(); log.debug("RepositoryClassLoader: {} ready", this); } /** * Returns <code>true</code> if this class loader has already been destroyed * by calling {@link #destroy()}. */ protected boolean isDestroyed() { return destroyed; } /** * Destroys this class loader. This process encompasses all steps needed * to remove as much references to this class loader as possible. * <p> * <em>NOTE</em>: This method just clears all internal fields and especially * the class path to render this class loader unusable. * <p> * This implementation does not throw any exceptions. */ public void destroy() { // we expect to be called only once, so we stop destroyal here if (isDestroyed()) { log.debug("Instance is already destroyed"); return; } // set destroyal guard destroyed = true; // clear caches and references setRepository(null); setHandles(null); session = null; // clear the cache of loaded resources and flush cached class // introspections of the JavaBean framework if (cache != null) { for (Iterator ci=cache.values().iterator(); ci.hasNext(); ) { ClassLoaderResource res = (ClassLoaderResource) ci.next(); if (res.getLoadedClass() != null) { Introspector.flushFromCaches(res.getLoadedClass()); res.setLoadedClass(null); } ci.remove(); } } } //---------- URLClassLoader overwrites ------------------------------------- /** * Finds and loads the class with the specified name from the class path. * * @param name the name of the class * @return the resulting class * * @throws ClassNotFoundException If the named class could not be found or * if this class loader has already been destroyed. */ protected Class findClass(final String name) throws ClassNotFoundException { if (isDestroyed()) { throw new ClassNotFoundException(name + " (Classloader destroyed)"); } log.debug("findClass: Try to find class {}", name); try { return (Class) AccessController .doPrivileged(new PrivilegedExceptionAction() { public Object run() throws ClassNotFoundException { return findClassPrivileged(name); } }); } catch (java.security.PrivilegedActionException pae) { throw (ClassNotFoundException) pae.getException(); } } /** * Finds the resource with the specified name on the search path. * * @param name the name of the resource * * @return a <code>URL</code> for the resource, or <code>null</code> * if the resource could not be found or if the class loader has * already been destroyed. */ public URL findResource(String name) { if (isDestroyed()) { log.warn("Destroyed class loader cannot find a resource"); return null; } log.debug("findResource: Try to find resource {}", name); ClassLoaderResource res = findClassLoaderResource(name); if (res != null) { log.debug("findResource: Getting resource from {}, created {}", res, new Date(res.getLastModificationTime())); return res.getURL();
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -