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/14 20:09:30 UTC
incubator-freemarker git commit: Forward ported from 2.3-gae:
Resource loading JarURLConnection glitch workarounds. JSP taglib loading
thread context class loader usage fix.
Repository: incubator-freemarker
Updated Branches:
refs/heads/3 121b11b51 -> 22ecffb4b
Forward ported from 2.3-gae: Resource loading JarURLConnection glitch workarounds. JSP taglib loading thread context class loader usage fix.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/22ecffb4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/22ecffb4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/22ecffb4
Branch: refs/heads/3
Commit: 22ecffb4bc5140b8f300b944dd12976694808fd5
Parents: 121b11b
Author: ddekany <dd...@apache.org>
Authored: Sat Oct 14 22:09:25 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sat Oct 14 22:09:25 2017 +0200
----------------------------------------------------------------------
.../apache/freemarker/core/Configuration.java | 28 ++---
.../org/apache/freemarker/core/Version.java | 1 +
.../core/model/impl/UnsafeMethods.java | 38 ++----
.../freemarker/core/util/_ClassUtils.java | 117 +++++++++++++++++++
.../freemarker/servlet/jsp/TaglibFactory.java | 31 ++---
5 files changed, 149 insertions(+), 66 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/22ecffb4/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
index 9f4d04b..f0f3285 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
@@ -22,7 +22,6 @@ package org.apache.freemarker.core;
import static org.apache.freemarker.core.Configuration.ExtendableBuilder.*;
import java.io.IOException;
-import java.io.InputStream;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@@ -131,7 +130,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
*/
public final class Configuration implements TopLevelConfiguration, CustomStateScope {
- private static final String VERSION_PROPERTIES_PATH = "org/apache/freemarker/core/version.properties";
+ private static final String VERSION_PROPERTIES_PATH = "/org/apache/freemarker/core/version.properties";
private static final Map<String, OutputFormat> STANDARD_OUTPUT_FORMATS;
static {
@@ -156,24 +155,10 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc
private static final Version VERSION;
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();
- }
-
- String versionString = getRequiredVersionProperty(vp, "version");
-
- final Boolean gaeCompliant = Boolean.valueOf(getRequiredVersionProperty(vp, "isGAECompliant"));
-
- VERSION = new Version(versionString, gaeCompliant, null);
- }
+ Properties props = _ClassUtils.loadProperties(Configuration.class, VERSION_PROPERTIES_PATH);
+ String versionString = getRequiredVersionProperty(props, "version");
+ final Boolean gaeCompliant = Boolean.valueOf(getRequiredVersionProperty(props, "isGAECompliant"));
+ VERSION = new Version(versionString, gaeCompliant, null);
} catch (IOException e) {
throw new RuntimeException("Failed to load and parse " + VERSION_PROPERTIES_PATH, e);
}
@@ -777,6 +762,7 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc
return (MarkupOutputFormat) of;
}
+ @Override
public Collection<OutputFormat> getRegisteredCustomOutputFormats() {
return registeredCustomOutputFormats;
}
@@ -2215,11 +2201,13 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc
localizedTemplateLookupSet = false;
}
+ @Override
public Collection<OutputFormat> getRegisteredCustomOutputFormats() {
return isRegisteredCustomOutputFormatsSet() ? registeredCustomOutputFormats
: getDefaultRegisteredCustomOutputFormats();
}
+ @Override
public boolean isRegisteredCustomOutputFormatsSet() {
return registeredCustomOutputFormats != null;
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/22ecffb4/freemarker-core/src/main/java/org/apache/freemarker/core/Version.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Version.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Version.java
index da7e1fc..55793ac 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/Version.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Version.java
@@ -53,6 +53,7 @@ public final class Version implements Serializable {
this(stringValue, null, null);
}
+ // TODO [FM3] gaeCompliant should be removed
/**
* @throws IllegalArgumentException if the version string is malformed
*/
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/22ecffb4/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/UnsafeMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/UnsafeMethods.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/UnsafeMethods.java
index f1b54bf..54771cd 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/UnsafeMethods.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/UnsafeMethods.java
@@ -19,11 +19,9 @@
package org.apache.freemarker.core.model.impl;
-import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -37,7 +35,7 @@ class UnsafeMethods {
private static final Logger LOG = LoggerFactory.getLogger(UnsafeMethods.class);
private static final String UNSAFE_METHODS_PROPERTIES = "unsafeMethods.properties";
- private static final Set UNSAFE_METHODS = createUnsafeMethodsSet();
+ private static final Set<Method> UNSAFE_METHODS = createUnsafeMethodsSet();
private UnsafeMethods() { }
@@ -45,37 +43,25 @@ class UnsafeMethods {
return UNSAFE_METHODS.contains(method);
}
- private static Set createUnsafeMethodsSet() {
- Properties props = new Properties();
- InputStream in = DefaultObjectWrapper.class.getResourceAsStream(UNSAFE_METHODS_PROPERTIES);
- if (in == null) {
- throw new IllegalStateException("Class loader resource not found: "
- + DefaultObjectWrapper.class.getPackage().getName() + UNSAFE_METHODS_PROPERTIES);
- }
- String methodSpec = null;
+ private static Set<Method> createUnsafeMethodsSet() {
try {
- try {
- props.load(in);
- } finally {
- in.close();
- }
- Set set = new HashSet(props.size() * 4 / 3, 1f);
- Map primClasses = createPrimitiveClassesMap();
- for (Iterator iterator = props.keySet().iterator(); iterator.hasNext(); ) {
- methodSpec = (String) iterator.next();
+ Properties props = _ClassUtils.loadProperties(DefaultObjectWrapper.class, UNSAFE_METHODS_PROPERTIES);
+ Set<Method> set = new HashSet<>(props.size() * 4 / 3, 1f);
+ Map<String, Class<?>> primClasses = createPrimitiveClassesMap();
+ for (Object key : props.keySet()) {
try {
- set.add(parseMethodSpec(methodSpec, primClasses));
+ set.add(parseMethodSpec((String) key, primClasses));
} catch (ClassNotFoundException | NoSuchMethodException e) {
LOG.debug("Failed to get unsafe method", e);
}
}
return set;
} catch (Exception e) {
- throw new RuntimeException("Could not load unsafe method " + methodSpec + " " + e.getClass().getName() + " " + e.getMessage());
+ throw new RuntimeException("Could not load unsafe method set", e);
}
}
- private static Method parseMethodSpec(String methodSpec, Map primClasses)
+ private static Method parseMethodSpec(String methodSpec, Map<String, Class<?>> primClasses)
throws ClassNotFoundException,
NoSuchMethodException {
int brace = methodSpec.indexOf('(');
@@ -88,7 +74,7 @@ class UnsafeMethods {
Class[] argTypes = new Class[argcount];
for (int i = 0; i < argcount; i++) {
String argClassName = tok.nextToken();
- argTypes[i] = (Class) primClasses.get(argClassName);
+ argTypes[i] = primClasses.get(argClassName);
if (argTypes[i] == null) {
argTypes[i] = _ClassUtils.forName(argClassName);
}
@@ -96,8 +82,8 @@ class UnsafeMethods {
return clazz.getMethod(methodName, argTypes);
}
- private static Map createPrimitiveClassesMap() {
- Map map = new HashMap();
+ private static Map<String, Class<?>> createPrimitiveClassesMap() {
+ Map<String, Class<?>> map = new HashMap<>();
map.put("boolean", Boolean.TYPE);
map.put("byte", Byte.TYPE);
map.put("char", Character.TYPE);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/22ecffb4/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ClassUtils.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ClassUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ClassUtils.java
index d229c2d..21e62c0 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ClassUtils.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ClassUtils.java
@@ -19,6 +19,11 @@
package org.apache.freemarker.core.util;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Properties;
+
import org.apache.freemarker.core.model.impl.BeanModel;
public class _ClassUtils {
@@ -164,5 +169,117 @@ public class _ClassUtils {
return Number.class.isAssignableFrom(type)
|| 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} if {@code optional} is {@code false}, and attempts to work around "IllegalStateException: zip file
+ * closed" and similar {@code sun.net.www.protocol.jar.JarURLConnection}-related glitches. These are caused by bugs
+ * outside of FreeMarker. Note that in cases where the JAR resource becomes broken concurrently, similar errors can
+ * still occur later when the {@link InputStream} is read ({@link #loadProperties(Class, String)} works that
+ * around as well).
+ *
+ * @return If {@code optional} is {@code false}, it's never {@code null}, otherwise {@code null} indicates that the
+ * resource doesn't exist.
+ * @throws IOException
+ * If the resource wasn't found, or other {@link IOException} occurs.
+ */
+ public static InputStream getReasourceAsStream(Class<?> baseClass, String resource, boolean optional)
+ throws IOException {
+ InputStream ins;
+ try {
+ // This is how we did this earlier. May uses some JarURLConnection caches, which leads to the problems.
+ ins = baseClass.getResourceAsStream(resource);
+ } catch (Exception e) {
+ // Workaround for "IllegalStateException: zip file closed", and other related exceptions. This happens due
+ // to bugs outside of FreeMarker, but we try to work it around anyway.
+ URL url = baseClass.getResource(resource);
+ ins = url != null ? url.openStream() : null;
+ }
+ if (!optional) {
+ checkInputStreamNotNull(ins, baseClass, resource);
+ }
+ return ins;
+ }
+
+ /**
+ * Same as {@link #getReasourceAsStream(Class, String, boolean)}, but uses a {@link ClassLoader} directly
+ * instead of a {@link Class}.
+ */
+ public static InputStream getReasourceAsStream(ClassLoader classLoader, String resource, boolean optional)
+ throws IOException {
+ // See source commends in the other overload of this method.
+ InputStream ins;
+ try {
+ ins = classLoader.getResourceAsStream(resource);
+ } catch (Exception e) {
+ URL url = classLoader.getResource(resource);
+ ins = url != null ? url.openStream() : null;
+ }
+ if (ins == null && !optional) {
+ throw new IOException("Class-loader resource not found (shown quoted): "
+ + _StringUtils.jQuote(resource) + ". The base ClassLoader was: " + classLoader);
+ }
+ return ins;
+ }
+
+ /**
+ * Loads a class loader resource into a {@link Properties}; tries to work around "zip file closed" and related
+ * {@code sun.net.www.protocol.jar.JarURLConnection} glitches.
+ */
+ public static Properties loadProperties(Class<?> baseClass, String resource) throws IOException {
+ Properties props = new Properties();
+
+ InputStream ins = null;
+ try {
+ try {
+ // This is how we did this earlier. May uses some JarURLConnection caches, which leads to the problems.
+ ins = baseClass.getResourceAsStream(resource);
+ } catch (Exception e) {
+ throw new MaybeZipFileClosedException();
+ }
+ checkInputStreamNotNull(ins, baseClass, resource);
+ try {
+ props.load(ins);
+ } catch (Exception e) {
+ throw new MaybeZipFileClosedException();
+ } finally {
+ try {
+ ins.close();
+ } catch (Exception e) {
+ // Do nothing to suppress "ZipFile closed" and related exceptions.
+ }
+ ins = null;
+ }
+ } catch (MaybeZipFileClosedException e) {
+ // Workaround for "zip file closed" exception, and other related exceptions. This happens due to bugs
+ // outside of FreeMarker, but we try to work it around anyway.
+ URL url = baseClass.getResource(resource);
+ ins = url != null ? url.openStream() : null;
+ checkInputStreamNotNull(ins, baseClass, resource);
+ props.load(ins);
+ } finally {
+ if (ins != null) {
+ try {
+ ins.close();
+ } catch (Exception e) {
+ // Do nothing to suppress "ZipFile closed" and related exceptions.
+ }
+ }
+ }
+ return props;
+ }
+
+ private static void checkInputStreamNotNull(InputStream ins, Class<?> baseClass, String resource)
+ throws IOException {
+ if (ins == null) {
+ throw new IOException("Class-loader resource not found (shown quoted): "
+ + _StringUtils.jQuote(resource) + ". The base class was " + baseClass.getName() + ".");
+ }
+ }
+
+ /** Used internally to work around some JarURLConnection glitches */
+ private static class MaybeZipFileClosedException extends Exception {
+ //
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/22ecffb4/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java
index 26231f9..9d113bb 100644
--- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java
+++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java
@@ -239,7 +239,7 @@ public class TaglibFactory implements TemplateHashModel {
public TemplateModel get(final String taglibUri) throws TemplateException {
synchronized (lock) {
{
- final Taglib taglib = (Taglib) taglibs.get(taglibUri);
+ final Taglib taglib = taglibs.get(taglibUri);
if (taglib != null) {
return taglib;
}
@@ -296,7 +296,7 @@ public class TaglibFactory implements TemplateHashModel {
}
if (!normalizedTaglibUri.equals(taglibUri)) {
- final Taglib taglib = (Taglib) taglibs.get(normalizedTaglibUri);
+ final Taglib taglib = taglibs.get(normalizedTaglibUri);
if (taglib != null) {
return taglib;
}
@@ -484,7 +484,7 @@ public class TaglibFactory implements TemplateHashModel {
}
for (int srcIdx = srcIdxStart; srcIdx < metaInfTldSources.size(); srcIdx++) {
- MetaInfTldSource miTldSource = (MetaInfTldSource) metaInfTldSources.get(srcIdx);
+ MetaInfTldSource miTldSource = metaInfTldSources.get(srcIdx);
if (miTldSource == WebInfPerLibJarMetaInfTldSource.INSTANCE) {
addTldLocationsFromWebInfPerLibJarMetaInfTlds();
@@ -609,7 +609,7 @@ public class TaglibFactory implements TemplateHashModel {
}
for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements(); ) {
- final JarEntry curEntry = (JarEntry) entries.nextElement();
+ final JarEntry curEntry = entries.nextElement();
final String curEntryPath = normalizeJarEntryPath(curEntry.getName(), false);
if (curEntryPath.startsWith(metaInfEntryPath) && curEntryPath.endsWith(".tld")) {
addTldLocationFromTld(new ServletContextJarEntryTldLocation(jarResourcePath, curEntryPath));
@@ -700,7 +700,7 @@ public class TaglibFactory implements TemplateHashModel {
}
for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements(); ) {
- final JarEntry curEntry = (JarEntry) entries.nextElement();
+ final JarEntry curEntry = entries.nextElement();
final String curEntryPath = normalizeJarEntryPath(curEntry.getName(), false);
if (curEntryPath.startsWith(baseEntryPath) && curEntryPath.endsWith(".tld")) {
@@ -1286,25 +1286,20 @@ 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;
+ InputStream ins = _ClassUtils.getReasourceAsStream(tccl, resourcePath, true);
+ if (ins != null) {
+ return ins;
}
}
- final InputStream in = getClass().getResourceAsStream(resourcePath);
- if (in == null) {
- throw newResourceNotFoundException();
- }
-
- return in;
+ return _ClassUtils.getReasourceAsStream(getClass(), resourcePath, false);
}
@Override
public String getXmlSystemId() throws IOException {
ClassLoader tccl = tryGetThreadContextClassLoader();
if (tccl != null) {
- final URL url = getClass().getResource(resourcePath);
+ final URL url = tccl.getResource(resourcePath);
if (url != null) {
return url.toExternalForm();
}
@@ -1314,10 +1309,6 @@ public class TaglibFactory implements TemplateHashModel {
return url == null ? null : url.toExternalForm();
}
- private IOException newResourceNotFoundException() {
- return new IOException("Resource not found: classpath:" + resourcePath);
- }
-
}
private abstract class JarEntryTldLocation implements TldLocation {
@@ -1509,7 +1500,7 @@ public class TaglibFactory implements TemplateHashModel {
@Override
public TemplateModel get(String key) {
- return (TemplateModel) tagsAndFunctions.get(key);
+ return tagsAndFunctions.get(key);
}
@Override