📄 dynamicrepositoryclassloader.java
字号:
* * @throws IllegalStateException if <code>this</code> * {@link DynamicRepositoryClassLoader} has already been destroyed * through the {@link #destroy()} method. */ public DynamicRepositoryClassLoader reinstantiate(Session session, ClassLoader parent) { log.debug("reinstantiate: Copying {} with parent {}", this, parent); if (isDestroyed()) { throw new IllegalStateException("Destroyed class loader cannot be recreated"); } // create the new loader DynamicRepositoryClassLoader newLoader = new DynamicRepositoryClassLoader(session, this, parent); // return the new loader return newLoader; } //---------- URLClassLoader overwrites ------------------------------------- /** * Reconfigures this class loader with the pattern list. That is the new * pattern list completely replaces the current pattern list. This new * pattern list will also be used later to configure the reinstantiated * class loader. * <p> * If this class loader already has loaded classes using the old, replaced * path list, it is set dirty. * <p> * If this class loader has already been destroyed, this method has no * effect. * * @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. */ public void reconfigure(String[] classPath) { if (log.isDebugEnabled()) { log.debug("reconfigure: Reconfiguring the with {}", Arrays.asList(classPath)); } // whether the loader is destroyed if (isDestroyed()) { log.warn("Cannot reconfigure this destroyed class loader"); return; } // deregister to old handles ((DynamicPatternPath) getHandles()).removeListener(this); // assign new handles and register setHandles(new DynamicPatternPath(getSession(), classPath)); buildRepository(); ((DynamicPatternPath) getHandles()).addListener(this); dirty = !hasLoadedResources(); log.debug("reconfigure: Class loader is dirty now: {}", (isDirty() ? "yes" : "no")); } //---------- RepositoryClassLoader overwrites ----------------------------- /** * Calls the base class implementation to actually retrieve the resource. * If the resource could be found and provides a non-<code>null</code> * {@link ClassLoaderResource#getExpiryProperty() expiry property}, the * resource is registered with an internal cache to check with when * a repository modification is observed in {@link #onEvent(EventIterator)}. * * @param name The name of the resource to be found * * @return the {@link ClassLoaderResource} found for the name or * <code>null</code> if no such resource is available in the class * path. * * @throws NullPointerException If this class loader has already been * destroyed. */ /* package */ ClassLoaderResource findClassLoaderResource(String name) { // call the base class implementation to actually search for it ClassLoaderResource res = super.findClassLoaderResource(name); // if it could be found, we register it with the caches if (res != null) { // register the resource in the expiry map, if an appropriate // property is available Property prop = res.getExpiryProperty(); if (prop != null) { try { modTimeCache.put(prop.getPath(), res); } catch (RepositoryException re) { log.warn("Cannot register the resource " + res + " for expiry", re); } } } // and finally return the resource return res; } /** * Builds the repository list from the list of path patterns and appends * the path entries from any added handles. This method may be used multiple * times, each time replacing the currently defined repository list. * * @throws NullPointerException If this class loader has already been * destroyed. */ protected synchronized void buildRepository() { super.buildRepository(); // add added repositories ClassPathEntry[] addedPath = getAddedRepositories(); if (addedPath != null && addedPath.length > 0) { ClassPathEntry[] oldClassPath = getRepository(); ClassPathEntry[] newClassPath = new ClassPathEntry[oldClassPath.length + addedPath.length]; System.arraycopy(oldClassPath, 0, newClassPath, 0, oldClassPath.length); System.arraycopy(addedPath, 0, newClassPath, oldClassPath.length, addedPath.length); setRepository(newClassPath); } } //---------- ModificationListener interface ------------------------------- /** * Handles a repository item modifcation events checking whether a class * needs to be expired. As a side effect, this method sets the class loader * dirty if a loaded class has been modified in the repository. * * @param events The iterator of repository events to be handled. */ public void onEvent(EventIterator events) { while (events.hasNext()) { Event event = events.nextEvent(); String path; try { path = event.getPath(); } catch (RepositoryException re) { log.warn("onEvent: Cannot get path of event, ignoring", re); continue; } log.debug( "onEvent: Item {} has been modified, checking with cache", path); ClassLoaderResource resource = (ClassLoaderResource) modTimeCache.get(path); if (resource != null) { log.debug("pageModified: Expiring cache entry {}", resource); expireResource(resource); } else { // might be in not-found cache - remove from there if (event.getType() == Event.NODE_ADDED || event.getType() == Event.PROPERTY_ADDED) { log.debug("pageModified: Clearing not-found cache for possible new class"); cleanCache(); } } } } // ----------- PatternPath.Listener interface ------------------------- /** * Handles modified matched path set by setting the class loader dirty. * The internal class path is only rebuilt when the class loader is * reinstantiated. */ public void pathChanged() { log.debug("handleListChanged: The path list has changed"); buildRepository(); dirty = true; } //----------- Object overwrite --------------------------------------------- /** * Returns a string representation of this class loader. */ public String toString() { if (isDestroyed()) { return super.toString(); } StringBuffer buf = new StringBuffer(super.toString()); buf.append(", dirty: "); buf.append(isDirty()); return buf.toString(); } //---------- internal ------------------------------------------------------ /** * Sets the list of class path entries to add to the class path after * reconfiguration or reinstantiation. * * @param addedRepositories The list of class path entries to keep for * readdition. */ protected void setAddedRepositories(ClassPathEntry[] addedRepositories) { this.addedRepositories = addedRepositories; } /** * Returns the list of added class path entries to readd them to the class * path after reconfiguring the class loader. */ protected ClassPathEntry[] getAddedRepositories() { return addedRepositories; } /** * Adds the class path entry to the current class path list. If the class * loader has already been destroyed, this method creates a single entry * class path list with the new class path entry. * <p> * Besides adding the entry to the current class path, it is also added to * the list to be readded after reconfiguration and/or reinstantiation. * * @see #getAddedRepositories() * @see #setAddedRepositories(ClassPathEntry[]) */ protected void addClassPathEntry(ClassPathEntry cpe) { super.addClassPathEntry(cpe); // add the repsitory to the list of added repositories ClassPathEntry[] oldClassPath = getAddedRepositories(); ClassPathEntry[] newClassPath = addClassPathEntry(oldClassPath, cpe); setAddedRepositories(newClassPath); } /** * Registers this class loader with the observation service to get * information on page updates in the class path and to the path * pattern list to get class path updates. * * @throws NullPointerException if this class loader has already been * destroyed. */ private final void registerModificationListener() { ((DynamicPatternPath) getHandles()).addListener(this); log.debug("registerModificationListener: Registering to the observation service"); try { ObservationManager om = getSession().getWorkspace().getObservationManager(); om.addEventListener(this, 255, "/", true, null, null, false); } catch (RepositoryException re) { log.error("registerModificationListener: Cannot register " + this + " with observation manager", re); } } /** * Removes this instances registrations from the observation service and * the path pattern list. * * @throws NullPointerException if this class loader has already been * destroyed. */ private final void unregisterListener() { ((DynamicPatternPath) getHandles()).removeListener(this); log.debug("registerModificationListener: Deregistering from the observation service"); try { ObservationManager om = getSession().getWorkspace().getObservationManager(); om.removeEventListener(this); } catch (RepositoryException re) { log.error("unregisterListener: Cannot unregister " + this + " from observation manager", re); } } /** * Checks whether the page backing the resource has been updated with a * version, such that this new version would be used to access the resource. * In this case the resource has expired and the class loader needs to be * set dirty. * * @param resource The <code>ClassLoaderResource</code> to check for * expiry. */ private boolean expireResource(ClassLoaderResource resource) { // check whether the resource is expired (only if a class has been loaded) boolean exp = resource.getLoadedClass() != null && resource.isExpired(); // update dirty flag accordingly dirty |= exp; log.debug("expireResource: Loader dirty: {}", new Boolean(isDirty())); // return the expiry status return exp; } /** * Returns the list of classpath entries after resetting each of them. * * @param list The list of {@link ClassPathEntry}s to reset * * @return The list of reset {@link ClassPathEntry}s. */ private static ClassPathEntry[] resetClassPathEntries( ClassPathEntry[] oldClassPath) { if (oldClassPath != null) { for (int i=0; i < oldClassPath.length; i++) { ClassPathEntry entry = oldClassPath[i]; log.debug("resetClassPathEntries: Cloning {}", entry); oldClassPath[i] = entry.copy(); } } else { log.debug("resetClassPathEntries: No list to reset"); } return oldClassPath; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -