You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/10/08 18:43:10 UTC

[2/5] incubator-freemarker git commit: Added workaround against IllegalStateException: zip file closed issues (caused by bugs outside of FreeMarker) when loading resources included in the FreeMarker jar (see freemarker.template.utility.ClassUtil.getReaso

Added workaround against IllegalStateException: zip file closed issues (caused by bugs outside of FreeMarker) when loading resources included in the FreeMarker jar (see freemarker.template.utility.ClassUtil.getReasourceAsStream). Related to https://github.com/apache/incubator-freemarker/pull/37.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/bd7498e8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/bd7498e8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/bd7498e8

Branch: refs/heads/2.3
Commit: bd7498e8d7e724c7bbc1f769f001b3f7df56debf
Parents: 5cee74f
Author: ddekany <dd...@apache.org>
Authored: Fri Oct 6 21:34:48 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Fri Oct 6 21:34:48 2017 +0200

----------------------------------------------------------------------
 .../freemarker/ext/beans/UnsafeMethods.java     |  6 +-
 .../java/freemarker/ext/jsp/TaglibFactory.java  | 15 +----
 .../java/freemarker/template/Configuration.java | 68 ++++++++++----------
 .../freemarker/template/utility/ClassUtil.java  | 48 ++++++++++++++
 src/manual/en_US/book.xml                       |  8 +++
 5 files changed, 92 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/main/java/freemarker/ext/beans/UnsafeMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/beans/UnsafeMethods.java b/src/main/java/freemarker/ext/beans/UnsafeMethods.java
index ed6d248..f590085 100644
--- a/src/main/java/freemarker/ext/beans/UnsafeMethods.java
+++ b/src/main/java/freemarker/ext/beans/UnsafeMethods.java
@@ -44,13 +44,9 @@ class UnsafeMethods {
     
     private static final Set createUnsafeMethodsSet() {
         Properties props = new Properties();
-        InputStream in = BeansWrapper.class.getResourceAsStream("unsafeMethods.properties");
-        if (in == null) {
-            throw new IllegalStateException("Class loader resource not found: "
-                        + BeansWrapper.class.getPackage().getName() + UNSAFE_METHODS_PROPERTIES);
-        }
         String methodSpec = null;
         try {
+            InputStream in = ClassUtil.getReasourceAsStream(BeansWrapper.class, UNSAFE_METHODS_PROPERTIES);
             try {
                 props.load(in);
             } finally {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/main/java/freemarker/ext/jsp/TaglibFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/jsp/TaglibFactory.java b/src/main/java/freemarker/ext/jsp/TaglibFactory.java
index fbb11a4..0dc07b1 100644
--- a/src/main/java/freemarker/ext/jsp/TaglibFactory.java
+++ b/src/main/java/freemarker/ext/jsp/TaglibFactory.java
@@ -1257,17 +1257,10 @@ public class TaglibFactory implements TemplateHashModel {
         public InputStream getInputStream() throws IOException {
             ClassLoader tccl = tryGetThreadContextClassLoader();
             if (tccl != null) {
-                final InputStream in = getClass().getResourceAsStream(resourcePath);
-                if (in != null) { 
-                    return in;
-                }
+                return ClassUtil.getReasourceAsStream(getClass(), resourcePath);
             }
             
-            final InputStream in = getClass().getResourceAsStream(resourcePath);
-            if (in == null) {
-                throw newResourceNotFoundException();
-            }
-            return in;
+            return ClassUtil.getReasourceAsStream(getClass(), resourcePath);
         }
 
         public String getXmlSystemId() throws IOException {
@@ -1282,10 +1275,6 @@ public class TaglibFactory implements TemplateHashModel {
             final URL url = getClass().getResource(resourcePath);
             return url == null ? null : url.toExternalForm();
         }
-        
-        private IOException newResourceNotFoundException() {
-            return new IOException("Resource not found: classpath:" + resourcePath);
-        }
     
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/main/java/freemarker/template/Configuration.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/Configuration.java b/src/main/java/freemarker/template/Configuration.java
index 95d4172..53358b1 100644
--- a/src/main/java/freemarker/template/Configuration.java
+++ b/src/main/java/freemarker/template/Configuration.java
@@ -151,7 +151,7 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     
     private static final Logger CACHE_LOG = Logger.getLogger("freemarker.cache");
     
-    private static final String VERSION_PROPERTIES_PATH = "freemarker/version.properties";
+    private static final String VERSION_PROPERTIES_PATH = "/freemarker/version.properties";
     
     /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */
     public static final String DEFAULT_ENCODING_KEY_SNAKE_CASE = "default_encoding"; 
@@ -436,36 +436,31 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     static {
         try {
             Properties vp = new Properties();
-            InputStream ins = Configuration.class.getClassLoader()
-                    .getResourceAsStream(VERSION_PROPERTIES_PATH);
-            if (ins == null) {
-                throw new RuntimeException("Version file is missing.");
-            } else {
-                try {
-                    vp.load(ins);
-                } finally {
-                    ins.close();
+            InputStream ins = ClassUtil.getReasourceAsStream(Configuration.class, VERSION_PROPERTIES_PATH);
+            try {
+                vp.load(ins);
+            } finally {
+                ins.close();
+            }
+            
+            String versionString  = getRequiredVersionProperty(vp, "version");
+            
+            Date buildDate;
+            {
+                String buildDateStr = getRequiredVersionProperty(vp, "buildTimestamp");
+                if (buildDateStr.endsWith("Z")) {
+                    buildDateStr = buildDateStr.substring(0, buildDateStr.length() - 1) + "+0000";
                 }
-                
-                String versionString  = getRequiredVersionProperty(vp, "version");
-                
-                Date buildDate;
-                {
-                    String buildDateStr = getRequiredVersionProperty(vp, "buildTimestamp");
-                    if (buildDateStr.endsWith("Z")) {
-                        buildDateStr = buildDateStr.substring(0, buildDateStr.length() - 1) + "+0000";
-                    }
-                    try {
-                        buildDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US).parse(buildDateStr);
-                    } catch (java.text.ParseException e) {
-                        buildDate = null;
-                    }
+                try {
+                    buildDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US).parse(buildDateStr);
+                } catch (java.text.ParseException e) {
+                    buildDate = null;
                 }
-                
-                final Boolean gaeCompliant = Boolean.valueOf(getRequiredVersionProperty(vp, "isGAECompliant"));
-                
-                VERSION = new Version(versionString, gaeCompliant, buildDate);
             }
+            
+            final Boolean gaeCompliant = Boolean.valueOf(getRequiredVersionProperty(vp, "isGAECompliant"));
+            
+            VERSION = new Version(versionString, gaeCompliant, buildDate);
         } catch (IOException e) {
             throw new RuntimeException("Failed to load and parse " + VERSION_PROPERTIES_PATH, e);
         }
@@ -537,6 +532,8 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     private ConcurrentMap localeToCharsetMap = new ConcurrentHashMap();
     
     /**
+     * Same as {@link #Configuration(Version) Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS)}.
+     * 
      * @deprecated Use {@link #Configuration(Version)} instead. Note that the version can be still modified later with
      *     {@link Configuration#setIncompatibleImprovements(Version)} (or
      *     {@link Configuration#setSettings(Properties)}).  
@@ -555,11 +552,11 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
      *
      * <p>This setting value is the FreeMarker version number where the not 100% backward compatible bug fixes and
      * improvements that you want to enable were already implemented. In new projects you should set this to the
-     * FreeMarker version that you are actually using. In older projects it's also usually better to keep this high,
-     * however you better check the changes activated (find them below), at least if not only the 3rd version number
-     * (the micro version) of {@code incompatibleImprovements} is increased. Generally, as far as you only increase the
-     * last version number of this setting, the changes are always low risk. The default value is 2.3.0 to maximize
-     * backward compatibility, but that value isn't recommended.
+     * version of FreeMarker that you start the development with. In older projects it's also usually better to keep
+     * this high, however you should check the changes activated (find them below), especially if not only the 3rd
+     * version number (the micro version) of {@code incompatibleImprovements} is increased. Generally, as far as you
+     * only increase the last version number of this setting, the changes are low risk. The default value is 2.3.0 to
+     * maximize backward compatibility, but that value isn't recommended.
      * 
      * <p>Bugfixes and improvements that are fully backward compatible, also those that are important security fixes,
      * are enabled regardless of the incompatible improvements setting.
@@ -576,8 +573,9 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
      * <p>Currently the effects of this setting are:
      * <ul>
      *   <li><p>
-     *     2.3.0: This is the lowest supported value, the version used in older projects. This is the default in the
-     *     FreeMarker 2.3.x series.
+     *     2.3.0: This is the lowest supported value, the version used in very old projects. This is the default in the
+     *     FreeMarker 2.3.x series (the one used by the deprecated {@link #Configuration()} constructor) for maximum
+     *     backward compatibility.
      *   </li>
      *   <li><p>
      *     2.3.19 (or higher): Bug fix: Wrong {@code #} tags were printed as static text instead of

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/main/java/freemarker/template/utility/ClassUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/utility/ClassUtil.java b/src/main/java/freemarker/template/utility/ClassUtil.java
index 0aa40cb..7d97839 100644
--- a/src/main/java/freemarker/template/utility/ClassUtil.java
+++ b/src/main/java/freemarker/template/utility/ClassUtil.java
@@ -19,6 +19,9 @@
 
 package freemarker.template.utility;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -379,4 +382,49 @@ public class ClassUtil {
                 || type.isPrimitive() && type != Boolean.TYPE && type != Character.TYPE && type != Void.TYPE;
     }
     
+    /**
+     * Very similar to {@link Class#getResourceAsStream(String)}, but throws {@link IOException} instead of returning
+     * {@code null}, and attempts to work around "IllegalStateException: zip file closed" issues (caused by bugs
+     * outside of FreeMarker).
+     *   
+     * @return Never {@code null} 
+     * @throws IOException If the resource wasn't found, or other {@link IOException} occurs. 
+     */
+    public static InputStream getReasourceAsStream(Class<?> baseClass, String resource) throws IOException {
+        InputStream ins;
+        try {
+            ins = baseClass.getResourceAsStream(resource);
+        } catch (IllegalStateException e) {
+            // Workaround for "IllegalStateException: zip file closed". This happens due to bugs outside of FreeMarker
+            // (sometimes caused by the caching of jar URL connection streams), but we try to work it around anyway.
+            URL url = baseClass.getResource(resource);
+            ins = url != null ? url.openStream() : null;
+        }
+        if (ins == null) {
+            throw new IOException("Class-loader resource not found (shown quoted): \""
+                    + StringUtil.jQuote(resource) + "\". The base class was " + baseClass.getName() + ".");
+        }
+        return ins;
+    }
+
+    /**
+     * Same as {@link #getReasourceAsStream(Class, String)}, but uses a {@link ClassLoader} directly instead of a
+     * {@link Class}.
+     */
+    public static InputStream getReasourceAsStream(ClassLoader classLoader, String resource)
+            throws IOException {
+        InputStream ins;
+        try {
+            ins = classLoader.getResourceAsStream(resource);
+        } catch (IllegalStateException e) {
+            URL url = classLoader.getResource(resource);
+            ins = url != null ? url.openStream() : null;
+        }
+        if (ins == null) {
+            throw new IOException("Class-loader resource not found (shown quoted): \""
+                    + StringUtil.jQuote(resource) + "\". The base ClassLoader was: " + classLoader);
+        }
+        return ins;
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 4573010..2068fe3 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -27349,6 +27349,14 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
                 </listitem>
               </itemizedlist>
             </listitem>
+
+            <listitem>
+              <para>Added workaround against <quote>IllegalStateException: zip
+              file closed</quote> issues (caused by bugs outside of
+              FreeMarker) when loading resources included in the FreeMarker
+              jar (see
+              <literal>freemarker.template.utility.ClassUtil.getReasourceAsStream</literal>).</para>
+            </listitem>
           </itemizedlist>
         </section>
       </section>