?? dynamicrepositoryclassloader.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.util.Arrays;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import javax.jcr.Property;import javax.jcr.RepositoryException;import javax.jcr.Session;import javax.jcr.observation.Event;import javax.jcr.observation.EventIterator;import javax.jcr.observation.EventListener;import javax.jcr.observation.ObservationManager;import org.apache.jackrabbit.classloader.DynamicPatternPath.Listener;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * The <code>DynamicRepositoryClassLoader</code> class extends the * {@link org.apache.jackrabbit.classloader.RepositoryClassLoader} and provides the * functionality to load classes and resources from the JCR Repository. * Additionally, this class supports the notion of getting 'dirty', which means, * that if a resource loaded through this class loader has been modified in the * Repository, this class loader marks itself dirty, which flag can get * retrieved. This helps the user of this class loader to decide on whether to * {@link #reinstantiate(Session, ClassLoader) reinstantiate} it or continue * using this class loader. * <p> * When a user of the class loader recognizes an instance to be dirty, it can * easily be reinstantiated with the {@link #reinstantiate} method. This * reinstantiation will also rebuild the internal real class path from the same * list of path patterns as was used to create the internal class path for the * original class loader. The resulting internal class path need not be the * same, though. * <p> * As an additional feature the class loaders provides the functionality for * complete reconfiguration of the list of path patterns defined at class loader * construction time through the {@link #reconfigure(String[])} method. This * reconfiguration replaces the internal class path with a new one built from * the new path list and also replaces that path list. Reinstantiating a * reconfigured class loader gets a class loader containing the same path list * as the original class loader had after reconfiguration. That is the original * configuration is lost. While reconfiguration is not able to throw away * classes already loaded, it will nevertheless mark the class loader dirty, if * any classes have already been loaded through it. * <p> * This class is not intended to be extended by clients. * * @author Felix Meschberger */public class DynamicRepositoryClassLoader extends RepositoryClassLoader implements EventListener, Listener { /** default log category */ private static final Logger log = LoggerFactory.getLogger(DynamicRepositoryClassLoader.class); /** * Cache of resources used to check class loader expiry. The map is indexed * by the paths of the expiry properties of the cached resources. This map * is not complete in terms of resources which have been loaded through this * class loader. That is for resources loaded through an archive class path * entry, only one of those resources (the last one loaded) is kept in this * cache, while the others are ignored. * * @see #onEvent(EventIterator) * @see #findClassLoaderResource(String) */ private Map modTimeCache; /** * Flag indicating whether there are loaded classes which have later been * expired (e.g. invalidated or modified) */ private boolean dirty; /** * The list of repositories added through either the {@link #addURL} or the * {@link #addHandle} method. */ private ClassPathEntry[] addedRepositories; /** * Creates a <code>DynamicRepositoryClassLoader</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 DynamicRepositoryClassLoader(Session session, String[] classPath, ClassLoader parent) { // initialize the super class with an empty class path super(session, new DynamicPatternPath(session, classPath), parent); // set fields dirty = false; modTimeCache = new HashMap(); // register with observation service and path pattern list registerModificationListener(); log.debug("DynamicRepositoryClassLoader: {} ready", this); } /** * Creates a <code>DynamicRepositoryClassLoader</code> with the same * configuration as the given <code>DynamicRepositoryClassLoader</code>. * This constructor is used by the {@link #reinstantiate} method. * <p> * Before returning from this constructor the <code>old</code> class loader * is destroyed and may not be used any more. * * @param session The session to associate with this class loader. * @param old The <code>DynamicRepositoryClassLoader</code> to copy the * cofiguration from. * @param parent The parent <code>ClassLoader</code>, which may be * <code>null</code>. */ private DynamicRepositoryClassLoader(Session session, DynamicRepositoryClassLoader old, ClassLoader parent) { // initialize the super class with an empty class path super(session, old.getHandles(), parent); // set the configuration and fields dirty = false; modTimeCache = new HashMap(); // create a repository from the handles - might get a different one setRepository(resetClassPathEntries(old.getRepository())); setAddedRepositories(resetClassPathEntries(old.getAddedRepositories())); buildRepository(); // register with observation service and path pattern list registerModificationListener(); // finally finalize the old class loader old.destroy(); log.debug( "DynamicRepositoryClassLoader: Copied {}. Do not use that anymore", old); } /** * 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; } // remove ourselves as listeners from other places unregisterListener(); addedRepositories = null; super.destroy(); } //---------- reload support ------------------------------------------------ /** * Checks whether this class loader already loaded the named resource and * would load another version if it were instructed to do so. As a side * effect the class loader sets itself dirty in this case. * <p> * Calling this method yields the same result as calling * {@link #shouldReload(String, boolean)} with the <code>force</code> * argument set to <code>false</code>. * * @param name The name of the resource to check. * * @return <code>true</code> if the resource is loaded and reloading would * take another version than currently loaded. * * @see #isDirty */ public synchronized boolean shouldReload(String name) { return shouldReload(name, false); } /** * Checks whether this class loader already loaded the named resource and * whether the class loader should be set dirty depending on the * <code>force</code> argument. If the argument is <code>true</code>, the * class loader is marked dirty and <code>true</code> is returned if the * resource has been loaded, else the loaded resource is checked for expiry * and the class loader is only set dirty if the loaded resource has * expired. * * @param name The name of the resource to check. * @param force <code>true</code> if the class loader should be marked dirty * if the resource is loaded, else the class loader is only marked * dirty if the resource is loaded and has expired. * * @return <code>true</code> if the resource is loaded and * <code>force</code> is <code>true</code> or if the resource has * expired. <code>true</code> is also returned if this class loader * has already been destroyed. * * @see #isDirty */ public synchronized boolean shouldReload(String name, boolean force) { if (isDestroyed()) { log.warn("Classloader already destroyed, reload required"); return true; } ClassLoaderResource res = getCachedResource(name); if (res != null) { log.debug("shouldReload: Expiring cache entry {}", res); if (force) { log.debug("shouldReload: Forced dirty flag"); dirty = true; return true; } return expireResource(res); } return false; } /** * Returns <code>true</code> if any of the loaded classes need reload. Also * sets this class loader dirty. If the class loader is already set dirty * or if this class loader has been destroyed before calling this method, * it returns immediately. * * @return <code>true</code> if any class loader needs to be reinstantiated. * * @see #isDirty */ public synchronized boolean shouldReload() { // check whether we are already dirty if (isDirty()) { log.debug("shouldReload: Dirty, need reload"); return true; } // Check whether any class has changed for (Iterator iter = getCachedResources(); iter.hasNext();) { if (expireResource((ClassLoaderResource) iter.next())) { log.debug("shouldReload: Found expired resource, need reload"); return true; } } // No changes, no need to reload log.debug("shouldReload: No expired resource found, no need to reload"); return false; } /** * Returns whether the class loader is dirty. This can be the case if any * of the {@link #shouldReload(String)} or {@link #shouldReload()} * methods returned <code>true</code> or if a loaded class has been expired * through the observation. * <p> * This method may also return <code>true</code> if the <code>Session</code> * associated with this class loader is not valid anymore. * <p> * Finally the method always returns <code>true</code> if the class loader * has already been destroyed. Note, however, that a destroyed class loader * cannot be reinstantiated. See {@link #reinstantiate(Session, ClassLoader)}. * <p> * If the class loader is dirty, it should be reinstantiated through the * {@link #reinstantiate} method. * * @return <code>true</code> if the class loader is dirty and needs * reinstantiation. */ public boolean isDirty() { return isDestroyed() || dirty || !getSession().isLive(); } /** * Reinstantiates this class loader. That is, a new ClassLoader with no * loaded class is created with the same configuration as this class loader. * <p> * When the new class loader is returned, this class loader has been * destroyed and may not be used any more. * * @param parent The parent <code>ClassLoader</code> for the reinstantiated * <code>DynamicRepositoryClassLoader</code>, which may be * <code>null</code>. * * @return a new instance with the same configuration as this class loader.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -