Author: markt Date: Tue May 14 20:57:17 2013 New Revision: 1482590 URL: http://svn.apache.org/r1482590 Log: Refactor handling of JAR resources so that JAR files containing resources (including WARs) are not permanently locked.
Modified: tomcat/trunk/java/org/apache/catalina/webresources/AbstractFileResourceSet.java tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java Modified: tomcat/trunk/java/org/apache/catalina/webresources/AbstractFileResourceSet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/AbstractFileResourceSet.java?rev=1482590&r1=1482589&r2=1482590&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/AbstractFileResourceSet.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/AbstractFileResourceSet.java Tue May 14 20:57:17 2013 @@ -121,10 +121,5 @@ public abstract class AbstractFileResour } - @Override - protected void destroyInternal() throws LifecycleException { - // NO-OP - } - protected abstract void checkType(File file); } Modified: tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java?rev=1482590&r1=1482589&r2=1482590&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java Tue May 14 20:57:17 2013 @@ -91,4 +91,9 @@ public abstract class AbstractResourceSe protected final void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); } + + @Override + protected final void destroyInternal() throws LifecycleException { + // NO-OP + } } Modified: tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java?rev=1482590&r1=1482589&r2=1482590&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java Tue May 14 20:57:17 2013 @@ -35,12 +35,12 @@ public class JarResource extends Abstrac private static final Log log = LogFactory.getLog(JarResource.class); - private final JarFile base; + private final String base; private final String baseUrl; private final JarEntry resource; private final String name; - public JarResource(WebResourceRoot root, JarFile base, String baseUrl, + public JarResource(WebResourceRoot root, String base, String baseUrl, JarEntry jarEntry, String internalPath, String webAppPath) { super(root, webAppPath); this.base = base; @@ -117,7 +117,9 @@ public class JarResource extends Abstrac @Override public InputStream getInputStream() { try { - return base.getInputStream(resource); + JarFile jarFile = new JarFile(base); + InputStream is = jarFile.getInputStream(resource); + return new JarInputStreamWrapper(jarFile, is); } catch (IOException e) { if (log.isDebugEnabled()) { log.debug(sm.getString("fileResource.getInputStreamFail", @@ -149,4 +151,72 @@ public class JarResource extends Abstrac protected Log getLog() { return log; } + + private static class JarInputStreamWrapper extends InputStream { + + private final JarFile jarFile; + private final InputStream is; + + + public JarInputStreamWrapper(JarFile jarFile, InputStream is) { + this.jarFile = jarFile; + this.is = is; + } + + + @Override + public int read() throws IOException { + return is.read(); + } + + + @Override + public int read(byte[] b) throws IOException { + return is.read(b); + } + + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return is.read(b, off, len); + } + + + @Override + public long skip(long n) throws IOException { + return is.skip(n); + } + + + @Override + public int available() throws IOException { + return is.available(); + } + + + @Override + public void close() throws IOException { + // Closing the JarFile releases the file lock on the JAR and also + // closes all input streams created from the JarFile. + jarFile.close(); + } + + + @Override + public synchronized void mark(int readlimit) { + is.mark(readlimit); + } + + + @Override + public synchronized void reset() throws IOException { + is.reset(); + } + + + @Override + public boolean markSupported() { + return is.markSupported(); + } + } } Modified: tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java?rev=1482590&r1=1482589&r2=1482590&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java Tue May 14 20:57:17 2013 @@ -22,6 +22,8 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -36,7 +38,7 @@ import org.apache.catalina.util.Resource */ public class JarResourceSet extends AbstractResourceSet { - private JarFile base; + private HashMap<String,JarEntry> jarFileEntries = new HashMap<>(); private String baseUrl; private final String internalPath; @@ -90,8 +92,8 @@ public class JarResourceSet extends Abst * requested without the '/' subsequent calls to JarEntry.isDirectory() * will return false. * - * Paths in JARs never start with '/'. Leading '/' need to be removed - * before any JarFile.getEntry() call. + * Paths in JARs never start with '/'. Leading '/' need to be removed + * before any JarFile.getEntry() call. */ // If the JAR has been mounted below the web application root, return @@ -106,23 +108,23 @@ public class JarResourceSet extends Abst } if (pathInJar.equals("")) { // Special case - return new JarResourceRoot(root, new File(base.getName()), + return new JarResourceRoot(root, new File(getBase()), pathInJar, path); } else { JarEntry jarEntry = null; if (!(pathInJar.charAt(pathInJar.length() - 1) == '/')) { - jarEntry = base.getJarEntry(pathInJar + '/'); + jarEntry = jarFileEntries.get(pathInJar + '/'); if (jarEntry != null) { path = path + '/'; } } if (jarEntry == null) { - jarEntry = base.getJarEntry(pathInJar); + jarEntry = jarFileEntries.get(pathInJar); } if (jarEntry == null) { return new EmptyResource(root, path); } else { - return new JarResource(root, base, baseUrl, jarEntry, + return new JarResource(root, getBase(), baseUrl, jarEntry, internalPath, path); } } @@ -144,10 +146,9 @@ public class JarResourceSet extends Abst if (pathInJar.charAt(0) == '/') { pathInJar = pathInJar.substring(1); } - Enumeration<JarEntry> entries = base.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - String name = entry.getName(); + Iterator<String> entries = jarFileEntries.keySet().iterator(); + while (entries.hasNext()) { + String name = entries.next(); if (name.length() > pathInJar.length() && name.startsWith(pathInJar)) { if (name.charAt(name.length() - 1) == '/') { @@ -202,10 +203,9 @@ public class JarResourceSet extends Abst pathInJar = pathInJar.substring(1); } - Enumeration<JarEntry> entries = base.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - String name = entry.getName(); + Iterator<String> entries = jarFileEntries.keySet().iterator(); + while (entries.hasNext()) { + String name = entries.next(); if (name.length() > pathInJar.length() && name.startsWith(pathInJar)) { int nextSlash = name.indexOf('/', pathInJar.length()); @@ -257,24 +257,20 @@ public class JarResourceSet extends Abst @Override protected void initInternal() throws LifecycleException { - try { - this.base = new JarFile(getBase()); + try (JarFile jarFile = new JarFile(getBase())) { + Enumeration<JarEntry> entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + jarFileEntries.put(entry.getName(), entry); + } } catch (IOException ioe) { throw new IllegalArgumentException(ioe); } + try { this.baseUrl = (new File(getBase())).toURI().toURL().toString(); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } } - - @Override - protected void destroyInternal() throws LifecycleException { - try { - this.base.close(); - } catch (IOException ioe) { - throw new LifecycleException(ioe); - } - } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org