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/03 19:31:44 UTC

[1/6] incubator-freemarker git commit: Slight modification to spare the extra pd.getReadMethod() when we have an IndexedPropertyDescriptor and preferIndexedReadMethod is false.

Repository: incubator-freemarker
Updated Branches:
  refs/heads/2.3 8f56810ff -> f73b8447c


Slight modification to spare the extra pd.getReadMethod() when we have an IndexedPropertyDescriptor and preferIndexedReadMethod is false.


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

Branch: refs/heads/2.3
Commit: a072921d212e63ddb6bff6ec71b95509d6c91e9f
Parents: 66af279
Author: ddekany <dd...@apache.org>
Authored: Tue Oct 3 15:24:20 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Oct 3 15:24:20 2017 +0200

----------------------------------------------------------------------
 src/main/java/freemarker/ext/beans/BeanModel.java | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a072921d/src/main/java/freemarker/ext/beans/BeanModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/beans/BeanModel.java b/src/main/java/freemarker/ext/beans/BeanModel.java
index 4139b09..01d779a 100644
--- a/src/main/java/freemarker/ext/beans/BeanModel.java
+++ b/src/main/java/freemarker/ext/beans/BeanModel.java
@@ -220,14 +220,15 @@ implements
         TemplateModel resultModel = UNKNOWN;
         if (desc instanceof IndexedPropertyDescriptor) {
             IndexedPropertyDescriptor pd = (IndexedPropertyDescriptor) desc;
-            if (!wrapper.getPreferIndexedReadMethod() && pd.getReadMethod() != null) {
-                resultModel = wrapper.invokeMethod(object, pd.getReadMethod(), null);
+            Method readMethod;
+            if (!wrapper.getPreferIndexedReadMethod() && (readMethod = pd.getReadMethod()) != null) {
+                resultModel = wrapper.invokeMethod(object, readMethod, null);
                 // cachedModel remains null, as we don't cache these
             } else {
-                Method readMethod = pd.getIndexedReadMethod(); 
+                Method indexedReadMethod = pd.getIndexedReadMethod(); 
                 resultModel = cachedModel = 
-                    new SimpleMethodModel(object, readMethod, 
-                            ClassIntrospector.getArgTypes(classInfo, readMethod), wrapper);
+                    new SimpleMethodModel(object, indexedReadMethod, 
+                            ClassIntrospector.getArgTypes(classInfo, indexedReadMethod), wrapper);
             }
         } else if (desc instanceof PropertyDescriptor) {
             PropertyDescriptor pd = (PropertyDescriptor) desc;


[4/6] incubator-freemarker git commit: FREEMARKER-80: Avoid calling synchonized PropertyDescriptor.getReadMethod() when getting a property in a template. Will see if it matters.

Posted by dd...@apache.org.
FREEMARKER-80: Avoid calling synchonized PropertyDescriptor.getReadMethod() when getting a property in a template. Will see if it matters.


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

Branch: refs/heads/2.3
Commit: 8f787963600b5ebaafd39bbdcc10121d8f82ce9a
Parents: c01f1a2
Author: ddekany <dd...@apache.org>
Authored: Tue Oct 3 19:53:49 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Oct 3 19:54:15 2017 +0200

----------------------------------------------------------------------
 .../java/freemarker/ext/beans/BeanModel.java    | 33 +++++-----
 .../freemarker/ext/beans/ClassIntrospector.java | 64 +++++++-------------
 .../ext/beans/FastPropertyDescriptor.java       | 46 ++++++++++++++
 3 files changed, 84 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8f787963/src/main/java/freemarker/ext/beans/BeanModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/beans/BeanModel.java b/src/main/java/freemarker/ext/beans/BeanModel.java
index 01d779a..1f885fa 100644
--- a/src/main/java/freemarker/ext/beans/BeanModel.java
+++ b/src/main/java/freemarker/ext/beans/BeanModel.java
@@ -19,8 +19,6 @@
 
 package freemarker.ext.beans;
 
-import java.beans.IndexedPropertyDescriptor;
-import java.beans.PropertyDescriptor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -63,8 +61,7 @@ import freemarker.template.utility.StringUtil;
  */
 
 public class BeanModel
-implements
-    TemplateHashModelEx, AdapterTemplateModel, WrapperTemplateModel, TemplateModelWithAPISupport {
+implements TemplateHashModelEx, AdapterTemplateModel, WrapperTemplateModel, TemplateModelWithAPISupport {
     private static final Logger LOG = Logger.getLogger("freemarker.beans");
     protected final Object object;
     protected final BeansWrapper wrapper;
@@ -218,22 +215,22 @@ implements
         }
 
         TemplateModel resultModel = UNKNOWN;
-        if (desc instanceof IndexedPropertyDescriptor) {
-            IndexedPropertyDescriptor pd = (IndexedPropertyDescriptor) desc;
-            Method readMethod;
-            if (!wrapper.getPreferIndexedReadMethod() && (readMethod = pd.getReadMethod()) != null) {
-                resultModel = wrapper.invokeMethod(object, readMethod, null);
-                // cachedModel remains null, as we don't cache these
+        if (desc instanceof FastPropertyDescriptor) {
+            FastPropertyDescriptor pd = (FastPropertyDescriptor) desc;
+            Method indexedReadMethod = pd.getIndexedReadMethod(); 
+            if (indexedReadMethod != null) {
+                if (!wrapper.getPreferIndexedReadMethod() && (pd.getReadMethod()) != null) {
+                    resultModel = wrapper.invokeMethod(object, pd.getReadMethod(), null);
+                    // cachedModel remains null, as we don't cache these
+                } else {
+                    resultModel = cachedModel = 
+                        new SimpleMethodModel(object, indexedReadMethod, 
+                                ClassIntrospector.getArgTypes(classInfo, indexedReadMethod), wrapper);
+                }
             } else {
-                Method indexedReadMethod = pd.getIndexedReadMethod(); 
-                resultModel = cachedModel = 
-                    new SimpleMethodModel(object, indexedReadMethod, 
-                            ClassIntrospector.getArgTypes(classInfo, indexedReadMethod), wrapper);
+                resultModel = wrapper.invokeMethod(object, pd.getReadMethod(), null);
+                // cachedModel remains null, as we don't cache these
             }
-        } else if (desc instanceof PropertyDescriptor) {
-            PropertyDescriptor pd = (PropertyDescriptor) desc;
-            resultModel = wrapper.invokeMethod(object, pd.getReadMethod(), null);
-            // cachedModel remains null, as we don't cache these
         } else if (desc instanceof Field) {
             resultModel = wrapper.wrap(((Field) desc).get(object));
             // cachedModel remains null, as we don't cache these

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8f787963/src/main/java/freemarker/ext/beans/ClassIntrospector.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/beans/ClassIntrospector.java b/src/main/java/freemarker/ext/beans/ClassIntrospector.java
index 72e8855..ce8bbd3 100644
--- a/src/main/java/freemarker/ext/beans/ClassIntrospector.java
+++ b/src/main/java/freemarker/ext/beans/ClassIntrospector.java
@@ -218,7 +218,7 @@ class ClassIntrospector {
      * Gets the class introspection data from {@link #cache}, automatically creating the cache entry if it's missing.
      * 
      * @return A {@link Map} where each key is a property/method/field name (or a special {@link Object} key like
-     *         {@link #CONSTRUCTORS_KEY}), each value is a {@link PropertyDescriptor} or {@link Method} or
+     *         {@link #CONSTRUCTORS_KEY}), each value is a {@link FastPropertyDescriptor} or {@link Method} or
      *         {@link OverloadedMethods} or {@link Field} (but better check the source code...).
      */
     Map<Object, Object> get(Class<?> clazz) {
@@ -335,8 +335,7 @@ class ClassIntrospector {
             int mdsSize = mds.size();
             IdentityHashMap<Method, Void> argTypesUsedByIndexerPropReaders = null;
             for (int i = mdsSize - 1; i >= 0; --i) {
-                final MethodDescriptor md = mds.get(i);
-                final Method method = getMatchingAccessibleMethod(md.getMethod(), accessibleMethods);
+                final Method method = getMatchingAccessibleMethod(mds.get(i).getMethod(), accessibleMethods);
                 if (method != null && isAllowedToExpose(method)) {
                     decision.setDefaults(method);
                     if (methodAppearanceFineTuner != null) {
@@ -350,7 +349,7 @@ class ClassIntrospector {
                     }
 
                     PropertyDescriptor propDesc = decision.getExposeAsProperty();
-                    if (propDesc != null && !(introspData.get(propDesc.getName()) instanceof PropertyDescriptor)) {
+                    if (propDesc != null && !(introspData.get(propDesc.getName()) instanceof FastPropertyDescriptor)) {
                         addPropertyDescriptorToClassIntrospectionData(
                                 introspData, propDesc, clazz, accessibleMethods);
                     }
@@ -373,7 +372,7 @@ class ClassIntrospector {
                             // Already overloaded method - add new overload
                             ((OverloadedMethods) previous).addMethod(method);
                         } else if (decision.getMethodShadowsProperty()
-                                || !(previous instanceof PropertyDescriptor)) {
+                                || !(previous instanceof FastPropertyDescriptor)) {
                             // Simple method (this far)
                             introspData.put(methodKey, method);
                             Class<?>[] replaced = getArgTypesByMethod(introspData).put(method,
@@ -661,45 +660,28 @@ class ClassIntrospector {
 
     private void addPropertyDescriptorToClassIntrospectionData(Map<Object, Object> introspData,
             PropertyDescriptor pd, Class<?> clazz, Map<MethodSignature, List<Method>> accessibleMethods) {
+        Method readMethod = getMatchingAccessibleMethod(pd.getReadMethod(), accessibleMethods);
+        if (readMethod != null && !isAllowedToExpose(readMethod)) {
+            readMethod = null;
+        }
+        
+        Method indexedReadMethod;
         if (pd instanceof IndexedPropertyDescriptor) {
-            IndexedPropertyDescriptor ipd =
-                    (IndexedPropertyDescriptor) pd;
-            Method readMethod = ipd.getIndexedReadMethod();
-            Method publicReadMethod = getMatchingAccessibleMethod(readMethod, accessibleMethods);
-            if (publicReadMethod != null && isAllowedToExpose(publicReadMethod)) {
-                try {
-                    if (readMethod != publicReadMethod) {
-                        ipd = new IndexedPropertyDescriptor(
-                                ipd.getName(), ipd.getReadMethod(),
-                                null, publicReadMethod,
-                                null);
-                    }
-                    introspData.put(ipd.getName(), ipd);
-                    getArgTypesByMethod(introspData).put(publicReadMethod, publicReadMethod.getParameterTypes());
-                } catch (IntrospectionException e) {
-                    LOG.warn("Failed creating a publicly-accessible " +
-                            "property descriptor for " + clazz.getName() +
-                            " indexed property " + pd.getName() +
-                            ", read method " + publicReadMethod,
-                            e);
-                }
+            indexedReadMethod = getMatchingAccessibleMethod(
+                    ((IndexedPropertyDescriptor) pd).getIndexedReadMethod(), accessibleMethods);
+            if (indexedReadMethod != null && !isAllowedToExpose(indexedReadMethod)) {
+                indexedReadMethod = null;
             }
-        } else {
-            Method readMethod = pd.getReadMethod();
-            Method publicReadMethod = getMatchingAccessibleMethod(readMethod, accessibleMethods);
-            if (publicReadMethod != null && isAllowedToExpose(publicReadMethod)) {
-                try {
-                    if (readMethod != publicReadMethod) {
-                        pd = new PropertyDescriptor(pd.getName(), publicReadMethod, null);
-                    }
-                    introspData.put(pd.getName(), pd);
-                } catch (IntrospectionException e) {
-                    LOG.warn("Failed creating a publicly-accessible " +
-                            "property descriptor for " + clazz.getName() +
-                            " property " + pd.getName() + ", read method " +
-                            publicReadMethod, e);
-                }
+            if (indexedReadMethod != null) {
+                getArgTypesByMethod(introspData).put(
+                        indexedReadMethod, indexedReadMethod.getParameterTypes());
             }
+        } else {
+            indexedReadMethod = null;
+        }
+        
+        if (readMethod != null || indexedReadMethod != null) {
+            introspData.put(pd.getName(), new FastPropertyDescriptor(readMethod, indexedReadMethod));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8f787963/src/main/java/freemarker/ext/beans/FastPropertyDescriptor.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/beans/FastPropertyDescriptor.java b/src/main/java/freemarker/ext/beans/FastPropertyDescriptor.java
new file mode 100644
index 0000000..12d43de
--- /dev/null
+++ b/src/main/java/freemarker/ext/beans/FastPropertyDescriptor.java
@@ -0,0 +1,46 @@
+/*
+ * 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 freemarker.ext.beans;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+
+/**
+ * Used instead of {@link PropertyDescriptor}, because the methods of that are synchronized.
+ * 
+ * @since 2.3.27
+ */
+final class FastPropertyDescriptor {
+    private final Method readMethod;
+    private final Method indexedReadMethod;
+    
+    public FastPropertyDescriptor(Method readMethod, Method indexedReadMethod) {
+        this.readMethod = readMethod;
+        this.indexedReadMethod = indexedReadMethod;
+    }
+
+    public Method getReadMethod() {
+        return readMethod;
+    }
+
+    public Method getIndexedReadMethod() {
+        return indexedReadMethod;
+    }
+    
+}


[2/6] incubator-freemarker git commit: preparing 2.3.27-gae release.

Posted by dd...@apache.org.
preparing 2.3.27-gae release.


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

Branch: refs/heads/2.3
Commit: 137506085e4daa4741191dcfc60db292e81e2b2f
Parents: a072921
Author: Woonsan Ko <wo...@bloomreach.com>
Authored: Tue Oct 3 09:39:55 2017 -0400
Committer: Woonsan Ko <wo...@bloomreach.com>
Committed: Tue Oct 3 09:39:55 2017 -0400

----------------------------------------------------------------------
 src/main/resources/freemarker/version.properties | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/13750608/src/main/resources/freemarker/version.properties
----------------------------------------------------------------------
diff --git a/src/main/resources/freemarker/version.properties b/src/main/resources/freemarker/version.properties
index 9a1a8c5..fc1445d 100644
--- a/src/main/resources/freemarker/version.properties
+++ b/src/main/resources/freemarker/version.properties
@@ -58,11 +58,11 @@
 # - When the major version number is increased, major backward
 #   compatibility violations are allowed, but still should be avoided.
 # During Apache Incubation, "-incubating" is added to this string.
-version=2.3.27-nightly_@timestampInVersion@-incubating
+version=2.3.27-incubating
 # This exists as for Maven we use "-SNAPSHOT" for non-final releases.
 # For final releases it's the same as "version". During Apache
 # Incubation, "-incubating" is added *before* "-SNAPSHOT".
-mavenVersion=2.3.27-incubating-SNAPSHOT
+mavenVersion=2.3.27-incubating
 
 # Version string that conforms to OSGi
 # ------------------------------------
@@ -76,7 +76,7 @@ mavenVersion=2.3.27-incubating-SNAPSHOT
 #   2.4.0.pre01
 #   2.4.0.nightly_@timestampInVersion@
 # During Apache Incubation, "-incubating" is added to this string.
-versionForOSGi=2.3.27.nightly_@timestampInVersion@-incubating
+versionForOSGi=2.3.27.stable-incubating
 
 # Version string that conforms to legacy MF
 # -----------------------------------------
@@ -95,7 +95,7 @@ versionForOSGi=2.3.27.nightly_@timestampInVersion@-incubating
 # "97 denotes "nightly", 98 denotes "pre", 99 denotes "rc" build.
 # In general, for the nightly/preview/rc Y of version 2.X, the versionForMf is
 # 2.X-1.(99|98).Y. Note the X-1.
-versionForMf=2.3.26.97
+versionForMf=2.3.27
 
 # The date of the build.
 # This should be automatically filled by the building tool (Ant).


[5/6] incubator-freemarker git commit: Reverting version to 2.3.27-nightly for now...

Posted by dd...@apache.org.
Reverting version to 2.3.27-nightly for now...


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

Branch: refs/heads/2.3
Commit: 1986341b959797dfebafcf49c54ccae221d6500c
Parents: 8f78796
Author: ddekany <dd...@apache.org>
Authored: Tue Oct 3 20:26:30 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Oct 3 20:26:30 2017 +0200

----------------------------------------------------------------------
 src/main/resources/freemarker/version.properties | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/1986341b/src/main/resources/freemarker/version.properties
----------------------------------------------------------------------
diff --git a/src/main/resources/freemarker/version.properties b/src/main/resources/freemarker/version.properties
index fc1445d..9a1a8c5 100644
--- a/src/main/resources/freemarker/version.properties
+++ b/src/main/resources/freemarker/version.properties
@@ -58,11 +58,11 @@
 # - When the major version number is increased, major backward
 #   compatibility violations are allowed, but still should be avoided.
 # During Apache Incubation, "-incubating" is added to this string.
-version=2.3.27-incubating
+version=2.3.27-nightly_@timestampInVersion@-incubating
 # This exists as for Maven we use "-SNAPSHOT" for non-final releases.
 # For final releases it's the same as "version". During Apache
 # Incubation, "-incubating" is added *before* "-SNAPSHOT".
-mavenVersion=2.3.27-incubating
+mavenVersion=2.3.27-incubating-SNAPSHOT
 
 # Version string that conforms to OSGi
 # ------------------------------------
@@ -76,7 +76,7 @@ mavenVersion=2.3.27-incubating
 #   2.4.0.pre01
 #   2.4.0.nightly_@timestampInVersion@
 # During Apache Incubation, "-incubating" is added to this string.
-versionForOSGi=2.3.27.stable-incubating
+versionForOSGi=2.3.27.nightly_@timestampInVersion@-incubating
 
 # Version string that conforms to legacy MF
 # -----------------------------------------
@@ -95,7 +95,7 @@ versionForOSGi=2.3.27.stable-incubating
 # "97 denotes "nightly", 98 denotes "pre", 99 denotes "rc" build.
 # In general, for the nightly/preview/rc Y of version 2.X, the versionForMf is
 # 2.X-1.(99|98).Y. Note the X-1.
-versionForMf=2.3.27
+versionForMf=2.3.26.97
 
 # The date of the build.
 # This should be automatically filled by the building tool (Ant).


[6/6] incubator-freemarker git commit: Merge remote-tracking branch 'origin/2.3-gae' into 2.3

Posted by dd...@apache.org.
Merge remote-tracking branch 'origin/2.3-gae' into 2.3


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

Branch: refs/heads/2.3
Commit: f73b8447c466e9f74c440557794f473af029b42c
Parents: 8f56810 1986341
Author: ddekany <dd...@apache.org>
Authored: Tue Oct 3 21:31:26 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Oct 3 21:31:26 2017 +0200

----------------------------------------------------------------------
 .../java/freemarker/ext/beans/BeanModel.java    |  30 ++-
 .../freemarker/ext/beans/ClassIntrospector.java |  64 +++----
 .../ext/beans/FastPropertyDescriptor.java       |  46 +++++
 .../core/TheadInterruptingSupportTest.java      | 162 ----------------
 .../core/ThreadInterruptingSupportTest.java     | 184 +++++++++++++++++++
 5 files changed, 267 insertions(+), 219 deletions(-)
----------------------------------------------------------------------



[3/6] incubator-freemarker git commit: Fixed template interruption test (could hang if the template fails for some reason).

Posted by dd...@apache.org.
Fixed template interruption test (could hang if the template fails for some reason).


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

Branch: refs/heads/2.3
Commit: c01f1a223a04dcff27eb3b71bbbdc759c1628384
Parents: 1375060
Author: ddekany <dd...@apache.org>
Authored: Tue Oct 3 19:50:40 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Oct 3 19:54:13 2017 +0200

----------------------------------------------------------------------
 .../core/TheadInterruptingSupportTest.java      | 162 ----------------
 .../core/ThreadInterruptingSupportTest.java     | 184 +++++++++++++++++++
 2 files changed, 184 insertions(+), 162 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c01f1a22/src/test/java/freemarker/core/TheadInterruptingSupportTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/TheadInterruptingSupportTest.java b/src/test/java/freemarker/core/TheadInterruptingSupportTest.java
deleted file mode 100644
index cbba0c3..0000000
--- a/src/test/java/freemarker/core/TheadInterruptingSupportTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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 freemarker.core;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import freemarker.core.ThreadInterruptionSupportTemplatePostProcessor.TemplateProcessingThreadInterruptedException;
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import freemarker.template.TemplateDirectiveBody;
-import freemarker.template.TemplateDirectiveModel;
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateModel;
-import freemarker.template.utility.NullWriter;
-
-public class TheadInterruptingSupportTest {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(TheadInterruptingSupportTest.class);
-
-    private static final int TEMPLATE_INTERRUPTION_TIMEOUT = 5000;
-    private final Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
-
-    @Test
-    public void test() throws IOException, InterruptedException {
-        assertCanBeInterrupted("<#list 1.. as x></#list>");
-        assertCanBeInterrupted("<#list 1.. as x>${x}</#list>");
-        assertCanBeInterrupted("<#list 1.. as x>t${x}</#list>");
-        assertCanBeInterrupted("<#list 1.. as x><#list 1.. as y>${y}</#list></#list>");
-        assertCanBeInterrupted("<#list 1.. as x>${x}<#else>nope</#list>");
-        assertCanBeInterrupted("<#list 1..>[<#items as x>${x}</#items>]<#else>nope</#list>");
-        assertCanBeInterrupted("<@customLoopDirective />");
-        assertCanBeInterrupted("<@customLoopDirective>x</@>");
-        assertCanBeInterrupted("<@customLoopDirective><#if true>x</#if></@>");
-        assertCanBeInterrupted("<#macro selfCalling><@sleepDirective/><@selfCalling /></#macro><@selfCalling />");
-        assertCanBeInterrupted("<#function selfCalling><@sleepDirective/>${selfCalling()}</#function>${selfCalling()}");
-        assertCanBeInterrupted("<#list 1.. as _><#attempt><@sleepDirective/><#recover>suppress</#attempt></#list>");
-        assertCanBeInterrupted("<#attempt><#list 1.. as _></#list><#recover>suppress</#attempt>");
-    }
-
-    private void assertCanBeInterrupted(final String templateSourceCode) throws IOException, InterruptedException {
-        TemplateRunnerThread trt = new TemplateRunnerThread(templateSourceCode);
-        trt.start();
-        synchronized (trt) {
-            while (!trt.isStarted()) {
-                trt.wait();
-            }
-        }
-        Thread.sleep(50); // Just to ensure (hope...) that the template execution reaches "deep" enough
-        trt.interrupt();
-        trt.join(TEMPLATE_INTERRUPTION_TIMEOUT);
-        assertTrue(trt.isTemplateProcessingInterrupted());
-    }
-
-    public class TemplateRunnerThread extends Thread {
-
-        private final Template template;
-        private boolean started;
-        private boolean templateProcessingInterrupted;
-
-        public TemplateRunnerThread(String templateSourceCode) throws IOException {
-            template = new Template(null, "<@startedDirective/>" + templateSourceCode, cfg);
-            _CoreAPI.addThreadInterruptedChecks(template);
-        }
-
-        @Override
-        public void run() {
-            try {
-                template.process(this, NullWriter.INSTANCE);
-            } catch (TemplateProcessingThreadInterruptedException e) {
-                //LOG.debug("Template processing interrupted", e);
-                synchronized (this) {
-                    templateProcessingInterrupted = true;
-                }
-            } catch (Throwable e) {
-                LOG.error("Template processing failed", e);
-            }
-        }
-
-        public synchronized boolean isTemplateProcessingInterrupted() {
-            return templateProcessingInterrupted;
-        }
-        
-        public synchronized boolean isStarted() {
-            return started;
-        }
-        
-        public TemplateDirectiveModel getStartedDirective() {
-            return new StartedDirective();
-        }
-
-        public TemplateDirectiveModel getCustomLoopDirective() {
-            return new CustomLoopDirective();
-        }
-        
-        public TemplateDirectiveModel getSleepDirective() {
-            return new SleepDirective();
-        }
-
-        public class StartedDirective implements TemplateDirectiveModel {
-            
-            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                    throws TemplateException, IOException {
-                synchronized (TemplateRunnerThread.this) {
-                    started = true;
-                    TemplateRunnerThread.this.notifyAll();
-                }
-            }
-            
-        }
-
-        public class CustomLoopDirective implements TemplateDirectiveModel {
-
-            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                    throws TemplateException, IOException {
-                while (true) {
-                    body.render(NullWriter.INSTANCE);
-                }
-            }
-            
-        }
-        
-        public class SleepDirective implements TemplateDirectiveModel {
-
-            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                    throws TemplateException, IOException {
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
-                    // Thread.sleep has reset the interrupted flag (because it has thrown InterruptedException).  
-                    Thread.currentThread().interrupt();
-                }
-            }
-            
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c01f1a22/src/test/java/freemarker/core/ThreadInterruptingSupportTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/ThreadInterruptingSupportTest.java b/src/test/java/freemarker/core/ThreadInterruptingSupportTest.java
new file mode 100644
index 0000000..6b9d86a
--- /dev/null
+++ b/src/test/java/freemarker/core/ThreadInterruptingSupportTest.java
@@ -0,0 +1,184 @@
+/*
+ * 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 freemarker.core;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import freemarker.core.ThreadInterruptionSupportTemplatePostProcessor.TemplateProcessingThreadInterruptedException;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateDirectiveModel;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModel;
+import freemarker.template.utility.NullWriter;
+
+public class ThreadInterruptingSupportTest {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(ThreadInterruptingSupportTest.class);
+
+    private static final int TEMPLATE_INTERRUPTION_TIMEOUT = 5000;
+    private final Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
+
+    @Test
+    public void test() throws IOException, InterruptedException, TemplateException {
+        assertCanBeInterrupted("<#list 1.. as x></#list>");
+        assertCanBeInterrupted("<#list 1.. as x>${x}</#list>");
+        assertCanBeInterrupted("<#list 1.. as x>t${x}</#list>");
+        assertCanBeInterrupted("<#list 1.. as x><#list 1.. as y>${y}</#list></#list>");
+        assertCanBeInterrupted("<#list 1.. as x>${x}<#else>nope</#list>");
+        assertCanBeInterrupted("<#list 1..>[<#items as x>${x}</#items>]<#else>nope</#list>");
+        assertCanBeInterrupted("<@customLoopDirective />");
+        assertCanBeInterrupted("<@customLoopDirective>x</@>");
+        assertCanBeInterrupted("<@customLoopDirective><#if true>x</#if></@>");
+        assertCanBeInterrupted("<#macro selfCalling><@sleepDirective/><@selfCalling /></#macro><@selfCalling />");
+        assertCanBeInterrupted("<#function selfCalling><@sleepDirective/>${selfCalling()}</#function>${selfCalling()}");
+        assertCanBeInterrupted("<#list 1.. as _><#attempt><@sleepDirective/><#recover>suppress</#attempt></#list>");
+        assertCanBeInterrupted("<#attempt><#list 1.. as _></#list><#recover>suppress</#attempt>");
+    }
+
+    private void assertCanBeInterrupted(final String templateSourceCode)
+            throws IOException, InterruptedException, TemplateException {
+        TemplateRunnerThread trt = new TemplateRunnerThread(templateSourceCode);
+        trt.start();
+        synchronized (trt) {
+            while (!trt.isStartedOrFailed()) {
+                trt.wait();
+            }
+        }
+        if (trt.failedWith != null) {
+            if (trt.failedWith instanceof TemplateException) {
+                throw (TemplateException) trt.failedWith;
+            } else if (trt.failedWith instanceof IOException) {
+                throw (IOException) trt.failedWith;
+            } else {
+                throw new RuntimeException("Template processing has failed", trt.failedWith);
+            }
+        }
+        Thread.sleep(50); // Just to ensure (hope...) that the template execution reaches "deep" enough
+        trt.interrupt();
+        trt.join(TEMPLATE_INTERRUPTION_TIMEOUT);
+        assertTrue(trt.isTemplateProcessingInterrupted());
+    }
+
+    public class TemplateRunnerThread extends Thread {
+
+        private final Template template;
+        private boolean started;
+        private Throwable failedWith;
+        private boolean templateProcessingInterrupted;
+
+        public TemplateRunnerThread(String templateSourceCode) throws IOException {
+            template = new Template(null, "<@startedDirective/>" + templateSourceCode, cfg);
+            _CoreAPI.addThreadInterruptedChecks(template);
+        }
+
+        @Override
+        public void run() {
+            try {
+                template.process(this, NullWriter.INSTANCE);
+            } catch (TemplateProcessingThreadInterruptedException e) {
+                //LOG.debug("Template processing interrupted", e);
+                synchronized (this) {
+                    templateProcessingInterrupted = true;
+                }
+            } catch (Throwable e) {
+                LOG.error("Template processing failed", e);
+                synchronized (TemplateRunnerThread.this) {
+                    failedWith = e;
+                    TemplateRunnerThread.this.notifyAll();
+                }
+            } finally {
+                synchronized (TemplateRunnerThread.this) {
+                    if (!started && failedWith == null) {
+                        failedWith = new IllegalStateException("Start directive was never called");
+                        TemplateRunnerThread.this.notifyAll();
+                    }
+                }
+            }
+        }
+
+        public synchronized boolean isTemplateProcessingInterrupted() {
+            return templateProcessingInterrupted;
+        }
+        
+        public synchronized boolean isStartedOrFailed() {
+            return started || failedWith != null;
+        }
+        
+        public TemplateDirectiveModel getStartedDirective() {
+            return new StartedDirective();
+        }
+
+        public TemplateDirectiveModel getCustomLoopDirective() {
+            return new CustomLoopDirective();
+        }
+        
+        public TemplateDirectiveModel getSleepDirective() {
+            return new SleepDirective();
+        }
+
+        public class StartedDirective implements TemplateDirectiveModel {
+            
+            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                    throws TemplateException, IOException {
+                synchronized (TemplateRunnerThread.this) {
+                    started = true;
+                    TemplateRunnerThread.this.notifyAll();
+                }
+            }
+            
+        }
+
+        public class CustomLoopDirective implements TemplateDirectiveModel {
+
+            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                    throws TemplateException, IOException {
+                while (true) {
+                    body.render(NullWriter.INSTANCE);
+                }
+            }
+            
+        }
+        
+        public class SleepDirective implements TemplateDirectiveModel {
+
+            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                    throws TemplateException, IOException {
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    // Thread.sleep has reset the interrupted flag (because it has thrown InterruptedException).  
+                    Thread.currentThread().interrupt();
+                }
+            }
+            
+        }
+        
+    }
+
+}