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 2011/06/02 13:12:05 UTC

svn commit: r1130497 - in /tomcat/trunk: java/org/apache/catalina/startup/ java/org/apache/jasper/compiler/ java/org/apache/tomcat/util/scan/ webapps/docs/

Author: markt
Date: Thu Jun  2 11:12:04 2011
New Revision: 1130497

URL: http://svn.apache.org/viewvc?rev=1130497&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=51276
Provide an abstraction for accessing content in JARs so the most efficient method can be selected depending on the type of URL used to identify the JAR. This improves startup time when JARs are located in $CATALINA_BASE/lib.

Added:
    tomcat/trunk/java/org/apache/tomcat/util/scan/FileUrlJar.java   (with props)
    tomcat/trunk/java/org/apache/tomcat/util/scan/Jar.java   (with props)
    tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java   (with props)
    tomcat/trunk/java/org/apache/tomcat/util/scan/UrlJar.java   (with props)
Modified:
    tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java
    tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java
    tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java?rev=1130497&r1=1130496&r2=1130497&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java Thu Jun  2 11:12:04 2011
@@ -43,8 +43,6 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
 
 import javax.servlet.ServletContainerInitializer;
 import javax.servlet.ServletContext;
@@ -92,6 +90,8 @@ import org.apache.tomcat.util.bcel.class
 import org.apache.tomcat.util.digester.Digester;
 import org.apache.tomcat.util.digester.RuleSet;
 import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.scan.Jar;
+import org.apache.tomcat.util.scan.JarFactory;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXParseException;
 
@@ -1375,29 +1375,13 @@ public class ContextConfig
         
         for (WebXml fragment : fragments) {
             URL url = fragment.getURL();
-            JarInputStream jarInputStream = null;
+            Jar jar = null;
             InputStream is = null;
             ServletContainerInitializer sci = null;
             try {
                 if ("jar".equals(url.getProtocol())) {
-                    JarURLConnection jarConn =
-                        (JarURLConnection) url.openConnection();
-                    URL resourceURL = jarConn.getJarFileURL();
-                    URLConnection resourceConn = resourceURL.openConnection();
-                    resourceConn.setUseCaches(false);
-                    
-                    jarInputStream =
-                        new JarInputStream(resourceConn.getInputStream());
-                    JarEntry entry = jarInputStream.getNextJarEntry();
-                    while (entry != null) {
-                        if (SCI_LOCATION.equals(entry.getName())) {
-                            break;
-                        }
-                        entry = jarInputStream.getNextJarEntry();
-                    }
-                    if (entry != null) {
-                        is = jarInputStream;
-                    }
+                    jar = JarFactory.newInstance(url);
+                    is = jar.getInputStream(SCI_LOCATION);
                 } else if ("file".equals(url.getProtocol())) {
                     String path = url.getPath();
                     File file = new File(path, SCI_LOCATION);
@@ -1422,12 +1406,8 @@ public class ContextConfig
                         // Ignore
                     }
                 }
-                if (jarInputStream != null) {
-                    try {
-                        jarInputStream.close();
-                    } catch (IOException e) {
-                        // Ignore
-                    }
+                if (jar != null) {
+                    jar.close();
                 }
             }
             
@@ -1514,25 +1494,12 @@ public class ContextConfig
     protected void processResourceJARs(Set<WebXml> fragments) {
         for (WebXml fragment : fragments) {
             URL url = fragment.getURL();
-            JarInputStream jarInputStream = null;
+            Jar jar = null;
             try {
                 // Note: Ignore file URLs for now since only jar URLs will be accepted
                 if ("jar".equals(url.getProtocol())) {
-                    JarURLConnection jarConn =
-                        (JarURLConnection) url.openConnection();
-                    URL resourceURL = jarConn.getJarFileURL();
-                    URLConnection resourceConn = resourceURL.openConnection();
-                    resourceConn.setUseCaches(false);
-                    jarInputStream =
-                        new JarInputStream(resourceConn.getInputStream());
-                    JarEntry entry = jarInputStream.getNextJarEntry();
-                    while (entry != null) {
-                        if ("META-INF/resources/".equals(entry.getName())) {
-                            break;
-                        }
-                        entry = jarInputStream.getNextJarEntry();
-                    }
-                    if (entry != null) {
+                    jar = JarFactory.newInstance(url);
+                    if (jar.entryExists("META-INF/resources/")) {
                         context.addResourceJarUrl(url);
                     }
                 }
@@ -1540,12 +1507,8 @@ public class ContextConfig
                 log.error(sm.getString("contextConfig.resourceJarFail", url,
                         context.getName()));
             } finally {
-                if (jarInputStream != null) {
-                    try {
-                        jarInputStream.close();
-                    } catch (IOException e) {
-                        // Ignore
-                    }
+                if (jar != null) {
+                    jar.close();
                 }
             }
         }
@@ -1800,46 +1763,42 @@ public class ContextConfig
 
 
     protected void processAnnotationsJar(URL url, WebXml fragment) {
-        JarInputStream jarInputStream = null;
+
+        Jar jar = null;
+        InputStream is;
         
         try {
-            URLConnection urlConn = url.openConnection();
-            JarURLConnection jarConn;
-            if (!(urlConn instanceof JarURLConnection)) {
-                // This should never happen
-                sm.getString("contextConfig.jarUrl", url);
-                return;
-            }
+            jar = JarFactory.newInstance(url);
             
-            jarConn = (JarURLConnection) urlConn;
-            jarConn.setUseCaches(false);
-            URL resourceURL = jarConn.getJarFileURL();
-            URLConnection resourceConn = resourceURL.openConnection();
-
-            jarInputStream = new JarInputStream(resourceConn.getInputStream());
-
-            JarEntry entry = jarInputStream.getNextJarEntry();
-            while (entry != null) {
-                String entryName = entry.getName();
+            jar.nextEntry();
+            String entryName = jar.getEntryName();
+            while (entryName != null) {
                 if (entryName.endsWith(".class")) {
+                    is = null;
                     try {
-                        processAnnotationsStream(jarInputStream, fragment);
+                        is = jar.getEntryInputStream();
+                        processAnnotationsStream(is, fragment);
                     } catch (IOException e) {
                         log.error(sm.getString("contextConfig.inputStreamJar",
                                 entryName, url),e);
+                    } finally {
+                        if (is != null) {
+                            try {
+                                is.close();
+                            } catch (IOException ioe) {
+                                // Ignore
+                            }
+                        }
                     }
                 }
-                entry = jarInputStream.getNextJarEntry();
+                jar.nextEntry();
+                entryName = jar.getEntryName();
             }
         } catch (IOException e) {
             log.error(sm.getString("contextConfig.jarFile", url), e);
         } finally {
-            if (jarInputStream != null) {
-                try {
-                    jarInputStream.close();
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                }
+            if (jar != null) {
+                jar.close();
             }
         }
     }
@@ -2317,46 +2276,38 @@ public class ContextConfig
         @Override
         public void scan(JarURLConnection jarConn) throws IOException {
             
-            // JarURLConnection#getJarFile() creates temporary copies of the JAR
-            // if the underlying resource is not a file URL. That can be slow so
-            // the InputStream for the resource is used
+            URL url = jarConn.getURL();
             URL resourceURL = jarConn.getJarFileURL();
-
-            JarInputStream jarInputStream = null;
+            Jar jar = null;
+            InputStream is = null;
             WebXml fragment = new WebXml();
 
             try {
-                URLConnection resourceConn = resourceURL.openConnection();
-                resourceConn.setUseCaches(false);
-                jarInputStream =
-                    new JarInputStream(resourceConn.getInputStream());
-                JarEntry entry = jarInputStream.getNextJarEntry();
-                while (entry != null) {
-                    if (FRAGMENT_LOCATION.equals(entry.getName())) {
-                        break;
-                    }
-                    entry = jarInputStream.getNextJarEntry();
-                }
+                jar = JarFactory.newInstance(url);
+                is = jar.getInputStream(FRAGMENT_LOCATION);
 
-                if (entry == null) {
+                if (is == null) {
                     // If there is no web.xml, normal JAR no impact on
                     // distributable
                     fragment.setDistributable(true);
                 } else {
                     InputSource source = new InputSource(
                             resourceURL.toString() + "!/" + FRAGMENT_LOCATION);
-                    source.setByteStream(jarInputStream);
+                    source.setByteStream(is);
                     parseWebXml(source, fragment, true);
                 }
             } finally {
-                if (jarInputStream != null) {
+                if (is != null) {
                     try {
-                        jarInputStream.close();
-                    } catch (Throwable t) {
-                        ExceptionUtils.handleThrowable(t);
+                        is.close();
+                    } catch (IOException ioe) {
+                        // Ignore
                     }
                 }
-                fragment.setURL(jarConn.getURL());
+                if (jar != null) {
+                    jar.close();
+                }
+                fragment.setURL(url);
                 if (fragment.getName() == null) {
                     fragment.setName(fragment.getURL().toString());
                 }

Modified: tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java?rev=1130497&r1=1130496&r2=1130497&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java Thu Jun  2 11:12:04 2011
@@ -21,15 +21,12 @@ import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.JarURLConnection;
-import java.net.URL;
-import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
 import java.util.StringTokenizer;
-import java.util.jar.JarEntry;
 
 import javax.servlet.ServletContext;
 import javax.servlet.descriptor.TaglibDescriptor;
@@ -44,7 +41,8 @@ import org.apache.tomcat.JarScannerCallb
 import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.digester.Digester;
 import org.apache.tomcat.util.res.StringManager;
-import org.apache.tomcat.util.scan.NonClosingJarInputStream;
+import org.apache.tomcat.util.scan.Jar;
+import org.apache.tomcat.util.scan.JarFactory;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
@@ -510,38 +508,40 @@ public final class TldConfig  implements
      */
     private void tldScanJar(JarURLConnection jarConn) {
 
-        // JarURLConnection#getJarFile() creates temporary copies of the JAR if
-        // the underlying resource is not a file URL. That can be slow so the
-        // InputStream for the resource is used
-        URL resourceURL = jarConn.getJarFileURL();
-        NonClosingJarInputStream jarInputStream = null;
-        String name = null;
-
+        Jar jar = null;
+        InputStream is;
+        
         try {
-            URLConnection resourceConn = resourceURL.openConnection();
-            resourceConn.setUseCaches(false);
-            jarInputStream =
-                new NonClosingJarInputStream(resourceConn.getInputStream());
-
-            JarEntry entry = jarInputStream.getNextJarEntry();
-            while (entry != null) {
-                name = entry.getName();
-                if (name.startsWith("META-INF/") && name.endsWith(".tld")) {
-                    XmlErrorHandler handler = tldScanStream(jarInputStream);
-                    handler.logFindings(log, jarConn.getURL() + name);
+            jar = JarFactory.newInstance(jarConn.getURL());
+            
+            jar.nextEntry();
+            String entryName = jar.getEntryName();
+            while (entryName != null) {
+                if (entryName.startsWith("META-INF/") &&
+                        entryName.endsWith(".tld")) {
+                    is = null;
+                    try {
+                        is = jar.getEntryInputStream();
+                        XmlErrorHandler handler = tldScanStream(is);
+                        handler.logFindings(log, jarConn.getURL() + entryName);
+                    } finally {
+                        if (is != null) {
+                            try {
+                                is.close();
+                            } catch (IOException ioe) {
+                                // Ignore
+                            }
+                        }
+                    }
                 }
-                entry = jarInputStream.getNextJarEntry();
+                jar.nextEntry();
+                entryName = jar.getEntryName();
             }
         } catch (IOException ioe) {
-            log.warn(sm.getString("tldConfig.jarFail", jarConn.getURL() + name),
-                    ioe);
+            log.warn(sm.getString("tldConfig.jarFail", jarConn.getURL()), ioe);
         } finally {
-            if (jarInputStream != null) {
-                try {
-                    jarInputStream.reallyClose();
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                }
+            if (jar != null) {
+                jar.close();
             }
         }
     }

Modified: tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java?rev=1130497&r1=1130496&r2=1130497&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java (original)
+++ tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java Thu Jun  2 11:12:04 2011
@@ -22,13 +22,11 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.JarURLConnection;
 import java.net.URL;
-import java.net.URLConnection;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Set;
 import java.util.StringTokenizer;
-import java.util.jar.JarEntry;
 
 import javax.servlet.ServletContext;
 
@@ -40,7 +38,8 @@ import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.JarScanner;
 import org.apache.tomcat.JarScannerCallback;
-import org.apache.tomcat.util.scan.NonClosingJarInputStream;
+import org.apache.tomcat.util.scan.Jar;
+import org.apache.tomcat.util.scan.JarFactory;
 
 
 /**
@@ -399,38 +398,45 @@ public class TldLocationsCache {
      */
     private void tldScanJar(JarURLConnection jarConn) throws IOException {
 
-        // JarURLConnection#getJarFile() creates temporary copies of the JAR if
-        // the underlying resource is not a file URL. That can be slow so the
-        // InputStream for the resource is used
+        Jar jar = null;
+        InputStream is;
+        boolean foundTld = false;
+        
         URL resourceURL = jarConn.getJarFileURL();
         String resourcePath = resourceURL.toString();
         
-        NonClosingJarInputStream jarInputStream = null;
-        
-        boolean foundTld = false;
         try {
-            URLConnection resourceConn = resourceURL.openConnection();
-            resourceConn.setUseCaches(false);
-            jarInputStream =
-                new NonClosingJarInputStream(resourceConn.getInputStream());
-            JarEntry entry = jarInputStream.getNextJarEntry();
-            while (entry != null) {
-                String name = entry.getName();
-                if (name.startsWith("META-INF/") && name.endsWith(".tld")) {
-                    foundTld = true;
-                    tldScanStream(resourcePath, name, jarInputStream);
+            jar = JarFactory.newInstance(jarConn.getURL());
+            
+            jar.nextEntry();
+            String entryName = jar.getEntryName();
+            while (entryName != null) {
+                if (entryName.startsWith("META-INF/") &&
+                        entryName.endsWith(".tld")) {
+                    is = null;
+                    try {
+                        is = jar.getEntryInputStream();
+                        foundTld = true;
+                        tldScanStream(resourcePath, entryName, is);
+                    } finally {
+                        if (is != null) {
+                            try {
+                                is.close();
+                            } catch (IOException ioe) {
+                                // Ignore
+                            }
+                        }
+                    }
                 }
-                entry = jarInputStream.getNextJarEntry();
+                jar.nextEntry();
+                entryName = jar.getEntryName();
             }
         } finally {
-            if (jarInputStream != null) {
-                try {
-                    jarInputStream.reallyClose();
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                }
+            if (jar != null) {
+                jar.close();
             }
         }
+
         if (!foundTld) {
             log.info(Localizer.getMessage("jsp.tldCache.noTldInJar",
                     resourcePath));

Added: tomcat/trunk/java/org/apache/tomcat/util/scan/FileUrlJar.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/scan/FileUrlJar.java?rev=1130497&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/scan/FileUrlJar.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/scan/FileUrlJar.java Thu Jun  2 11:12:04 2011
@@ -0,0 +1,105 @@
+/*
+ * 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.tomcat.util.scan;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+/**
+ * Implementation of {@link Jar} that is optimised for file based JAR URLs (e.g
+ * URLs of the form jar:file:...).
+ */
+public class FileUrlJar implements Jar {
+
+    private JarFile jarFile;
+    private Enumeration<JarEntry> entries;
+    private JarEntry entry = null;
+
+    public FileUrlJar(URL url) throws IOException {
+        JarURLConnection jarConn = (JarURLConnection) url.openConnection();
+        jarFile = jarConn.getJarFile();
+    }
+
+    @Override
+    public boolean entryExists(String name) {
+        ZipEntry entry = jarFile.getEntry(name);
+        return entry != null;
+    }
+
+    @Override
+    public InputStream getInputStream(String name) throws IOException {
+        ZipEntry entry = jarFile.getEntry(name);
+        if (entry == null) {
+            return null;
+        } else {
+            return jarFile.getInputStream(entry);
+        }
+    }
+
+    @Override
+    public void close() {
+        if (jarFile != null) {
+            try {
+                jarFile.close();
+            } catch (IOException e) {
+                // Ignore
+            }
+        }
+    }
+
+    @Override
+    public void nextEntry() {
+        if (entries == null) {
+            entries = jarFile.entries();
+        }
+        if (entries.hasMoreElements()) {
+            entry = entries.nextElement();
+        } else {
+            entry = null;
+        }
+    }
+
+    @Override
+    public String getEntryName() {
+        if (entry == null) {
+            return null;
+        } else {
+            return entry.getName();
+        }
+    }
+
+    @Override
+    public InputStream getEntryInputStream() throws IOException {
+        if (entry == null) {
+            return null;
+        } else {
+            return jarFile.getInputStream(entry);
+        }
+    }
+
+    @Override
+    public void reset() throws IOException {
+        entries = null;
+        entry = null;
+    }
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/util/scan/FileUrlJar.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tomcat/trunk/java/org/apache/tomcat/util/scan/Jar.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/scan/Jar.java?rev=1130497&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/scan/Jar.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/scan/Jar.java Thu Jun  2 11:12:04 2011
@@ -0,0 +1,85 @@
+/*
+ * 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.tomcat.util.scan;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Provides an abstraction for use by the various classes that need to scan
+ * JARs. The classes provided by the JRE for accessing JARs ({@link JarFile} and
+ * {@link JarInputStream}) have significantly different performance
+ * characteristics depending on the form of the URL used to access the JAR.
+ * For file based JAR {@link URL}s, {@link JarFile} is faster but for non-file
+ * based {@link URL}s, {@link JarFile} creates a copy of the JAR in the
+ * temporary directory so {@link JarInputStream} is faster.
+ */
+public interface Jar {
+
+    /**
+     * Determines if a specific entry exists within the JAR.
+     * 
+     * @param name  Entry to look for
+     * @return      <code>true</code> if the specified entry exists else
+     *               <code>false</code>
+     */
+    boolean entryExists(String name) throws IOException;
+    
+    
+    /**
+     * Obtain an {@link InputStream} for a given entry in a JAR. The caller is
+     * responsible for closing the stream.
+     * 
+     * @param name  Entry to obtain an {@link InputStream} for
+     * @return      An {@link InputStream} for the specified entry or null if
+     *              the entry does not exist
+     */
+    InputStream getInputStream(String name) throws IOException;
+
+    /**
+     * Close any resources associated with this JAR.
+     */
+    void close();
+    
+    /**
+     * Moves the internal pointer to the next entry in the JAR.
+     */
+    void nextEntry();
+    
+    /**
+     * Obtains the name of the current entry.
+     * 
+     * @return  The entry name
+     */
+    String getEntryName();
+    
+    /**
+     * Obtains the input stream for the current entry.
+     * 
+     * @return  The input stream
+     * @throws IOException  If the stream cannot be obtained
+     */
+    InputStream getEntryInputStream() throws IOException;
+    
+    /**
+     * Resets the internal pointer used to track JAR entries to the beginning of
+     * the JAR.
+     * 
+     * @throws IOException  If the pointer cannot be reset
+     */
+    void reset() throws IOException;
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/util/scan/Jar.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java?rev=1130497&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java Thu Jun  2 11:12:04 2011
@@ -0,0 +1,39 @@
+/*
+ * 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.tomcat.util.scan;
+
+import java.io.IOException;
+import java.net.URL;
+
+/**
+ * Provide a mechanism to obtain objects that implement {@link Jar}.
+ */
+public class JarFactory {
+
+    private JarFactory() {
+        // Factory class. Hide public constructor.
+    }
+
+    public static Jar newInstance(URL url) throws IOException {
+        String jarUrl = url.toString();
+        if (jarUrl.startsWith("jar:file:")) {
+            return new FileUrlJar(url);
+        } else {
+            return new UrlJar(url);
+        }
+    }
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tomcat/trunk/java/org/apache/tomcat/util/scan/UrlJar.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/scan/UrlJar.java?rev=1130497&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/scan/UrlJar.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/scan/UrlJar.java Thu Jun  2 11:12:04 2011
@@ -0,0 +1,118 @@
+/*
+ * 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.tomcat.util.scan;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.jar.JarEntry;
+
+/**
+ * Implementation of {@link Jar} that is optimised for non-file based JAR URLs
+ * (e.g. JNDI based URLs of the form jar:jndi:...).
+ */
+public class UrlJar implements Jar {
+
+    private NonClosingJarInputStream jarInputStream = null;
+    private URL url = null;
+    private JarEntry entry = null;
+
+    public UrlJar(URL url) throws IOException {
+        this.url = url;
+        this.jarInputStream = createJarInputStream();
+    }
+
+    @Override
+    public boolean entryExists(String name) throws IOException {
+        JarEntry entry = jarInputStream.getNextJarEntry();
+        while (entry != null) {
+            if (name.equals(entry.getName())) {
+                break;
+            }
+            entry = jarInputStream.getNextJarEntry();
+        }
+        
+        return entry != null;
+    }
+
+    @Override
+    public InputStream getInputStream(String name) throws IOException {
+        JarEntry entry = jarInputStream.getNextJarEntry();
+        while (entry != null) {
+            if (name.equals(entry.getName())) {
+                break;
+            }
+            entry = jarInputStream.getNextJarEntry();
+        }
+        
+        if (entry == null) {
+            return null;
+        } else {
+            return jarInputStream;
+        }
+    }
+
+    @Override
+    public void close() {
+        if (jarInputStream != null) {
+            try {
+                jarInputStream.reallyClose();
+            } catch (IOException ioe) {
+                // Ignore
+            }
+        }
+    }
+
+    private NonClosingJarInputStream createJarInputStream() throws IOException {
+        JarURLConnection jarConn = (JarURLConnection) url.openConnection();
+        URL resourceURL = jarConn.getJarFileURL();
+        URLConnection resourceConn = resourceURL.openConnection();
+        resourceConn.setUseCaches(false);
+        return new NonClosingJarInputStream(resourceConn.getInputStream());
+    }
+
+    @Override
+    public void nextEntry() {
+        try {
+            entry = jarInputStream.getNextJarEntry();
+        } catch (IOException ioe) {
+            entry = null;
+        }
+    }
+
+    @Override
+    public String getEntryName() {
+        if (entry == null) {
+            return null;
+        } else {
+            return entry.getName();
+        }
+    }
+
+    @Override
+    public InputStream getEntryInputStream() throws IOException {
+        return jarInputStream;
+    }
+
+    @Override
+    public void reset() throws IOException {
+        close();
+        jarInputStream = createJarInputStream();
+    }
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/util/scan/UrlJar.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1130497&r1=1130496&r2=1130497&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Jun  2 11:12:04 2011
@@ -68,6 +68,12 @@
         Patch provided by Eiji Takahashi. (markt)
       </fix>
       <fix>
+        <bug>51276</bug>: Provide an abstraction for accessing content in JARs
+        so the most efficient method can be selected depending on the type of
+        URL used to identify the JAR. This improves startup time when JARs are
+        located in $CATALINA_BASE/lib. (mark)
+      </fix>
+      <fix>
         <bug>51277</bug>: Improve error message if an application is deployed
         with an incomplete FORM authentication configuration. (markt)
       </fix>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org