?? archiveclasspathentry.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.io.IOException;import java.io.InputStream;import java.net.MalformedURLException;import java.net.URL;import java.util.HashMap;import java.util.Map;import java.util.jar.JarEntry;import java.util.jar.JarInputStream;import java.util.jar.Manifest;import javax.jcr.Property;import javax.jcr.RepositoryException;import org.apache.jackrabbit.net.URLFactory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * The <code>ArchiveClassPathEntry</code> implements the {@link ClassPathEntry} * abstract class with support for archives containing classes and other * resources. The path used to construct the instance is the path of an item * resolving to a property containing the jar archive to access. * * @author Felix Meschberger */class ArchiveClassPathEntry extends ClassPathEntry { /** Default logger */ private static final Logger log = LoggerFactory.getLogger(ArchiveClassPathEntry.class); /** The property containing the archive */ private final Property prop; /** * Cache all entries in the archive for faster decision on whether such * an entry is contained. */ private Map entryMap; /** * The JAR file manifest. Set on demand by the {@link #getManifest()} * method. */ private Manifest jarManifest; /** * Flag to indicate, whether the {@link #jarManifest} has already been read * from the archive. This field is used and set by the * {@link #getManifest()} to decide, whether to try to read the manifest. */ private boolean jarManifestRead; /** * Creates an instance of the <code>ArchiveClassPathEntry</code> class. * * @param prop The <code>Property</code> containing the archive and * the session used to access the repository. * @param path The original class path entry leading to the creation of * this instance. This is not necessairily the same path as the * properties path if the property was found through the primary * item chain. * * @throws RepositoryException If an error occurrs retrieving the session * from the property. */ ArchiveClassPathEntry(Property prop, String path) throws RepositoryException { super(prop.getSession(), path); this.prop = prop; } /** * Clones the indicated <code>ArchiveClassPathEntry</code> object by * taking over its path, session and property. * * @param base The base <code>ArchiveClassPath</code> entry to clone. * * @see ClassPathEntry#ClassPathEntry(ClassPathEntry) */ protected ArchiveClassPathEntry(ArchiveClassPathEntry base) { super(base); this.prop = base.prop; } /** * Returns the <code>Property</code> containing the JAR file of this * archive class path entry. */ protected Property getProperty() { return prop; } /** * Returns a {@link ClassLoaderResource} for the named resource if it * can be found in the archive identified by the path given at * construction time. Note that if the archive property would exist but is * not readable by the current session, no resource is returned. * <p> * This method accesses the archive through an <code>InputStream</code> * retrievedfrom the property. This <code>InputStream</code> is closed before * returning to the caller to release the resources behind the stream * such that it might be updated, etc. For this reason the resource * instance returned will again open an <code>InputStream</code> on the * archive property to access the resource. Users of the resource * <code>InputStream</code> are encouraged to close the stream when no * longer used to prevent lockups in the Repository. * * @param name The name of the resource to return. If the resource would * be a class the name must already be modified to denote a valid * path, that is dots replaced by slashes and the <code>.class</code> * extension attached. * * @return The {@link ClassLoaderResource} identified by the name or * <code>null</code> if no resource is found for that name. */ public ClassLoaderResource getResource(final String name) { JarInputStream zins = null; try { // get the archive and try to find the entry zins = getJarInputStream(prop); JarEntry entry = findEntry(zins, name); // if found create the resource to return if (entry != null) { return new ArchiveClassPathResource(this, entry); } log.debug("getResource: resource {} not found in archive {}", name, path); } catch (IOException ioe) { log.warn("getResource: problem accessing the archive {} for {}", new Object[]{ path, name}, ioe); } catch (RepositoryException re) { log.warn("getResource: problem accessing the archive {} for {}", new Object[]{ path, name}, re); } finally { // make sure streams are closed at the end if (zins != null) { try { zins.close(); } catch (IOException ignore) { } } } // invariant : not found or problem accessing the archive return null; } /** * Returns a <code>ClassPathEntry</code> with the same configuration as * this <code>ClassPathEntry</code>. * <p> * The <code>ArchiveClassPathEntry</code> class has internal state. * Therefore a new instance is created from the unmodifiable configuration * of this instance. */ ClassPathEntry copy() { return new ArchiveClassPathEntry(this); } /** * Returns a JAR URL with no entry as the base URL of this class path entry. */ public URL toURL() { if (baseURL == null) { try { baseURL = URLFactory.createJarURL(session, path, null); } catch (MalformedURLException mue) { log.warn("Problem creating baseURI for " + path, mue); } } return baseURL; } //----------- internal helper to find the entry ------------------------ /** * Returns a JAR URL to access the named resource within the archive * underlying this class path entry. This is a helper method for the * {@link ClassLoaderResource} instance returned by * {@link #getResource(String)} method. * <p> * This method does not check, whether the named entry actually exists in * the underlying archive. * * @param name The name of the resource for which to create the JAR URL. */ protected URL getURL(String name) { try { return URLFactory.createJarURL(session, path, name); } catch (MalformedURLException mue) { log.error("getURL: Cannot create URL for " + name, mue); } return null; } /** * Returns an URL to access the underlying archive itself of this class * path entry. The URL returned may be used as the code source for Java * securtiy protection domains. This is a helper method for the * {@link ClassLoaderResource} instance returned by * {@link #getResource(String)} method. * * @return The URL to access the underlying archive. */ protected URL getCodeSourceURL() { try { return URLFactory.createURL(session, path); } catch (MalformedURLException mue) { log.warn("getCodeSourceURL: Cannot getURL for " + path, mue); } return null; } /** * Returns a <code>JarInputStream</code> from the property. * * @param property The <code>Property</code> containing the archive to * access. * * @return A valid <code>JarInputStream</code>. * * @throws RepositoryException If an <code>InputStream</code> cannot be * retrieved from the property. * @throws IOException If the <code>JarInputStream</code> cannot be * created. */ static JarInputStream getJarInputStream(Property property) throws RepositoryException, IOException { return new JarInputStream(property.getStream()); } /** * Returns the <code>Manifest</code> object of the JAR archive file * underlying this archive class path entry. If no manifest exists in the * JAR file or if the archive is not a JAR file at - e.g. a plain ZIP * file - this method returns <code>null</code>. If an error occurrs * trying to access the manifest, <code>null</code> is also returned. Later * calls to this method, will not try again to read the manifest file, * though. * <p> * This method is synchronized to prevent two threads from trying to access * the manifest at the same time, which might result in false negative * returned. * * @return The manifest contained in the underlying JAR file or * <code>null</code> if none exists or an error occurrs trying to * load the manifest. */ protected synchronized Manifest getManifest() { if (jarManifest == null && !jarManifestRead) { // immediately mark the manifest read, to prevent repeated read // in the case of missing manifest jarManifestRead = true; JarInputStream zipIns = null; try { zipIns = new JarInputStream(prop.getStream()); jarManifest = zipIns.getManifest();
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -