You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2013/05/14 22:57:18 UTC

svn commit: r1482590 - in /tomcat/trunk/java/org/apache/catalina/webresources: AbstractFileResourceSet.java AbstractResourceSet.java JarResource.java JarResourceSet.java

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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org