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 18:23:39 UTC

[1/2] incubator-freemarker git commit: Forward ported from 2.3-gae: Fixed template interruption test (could hang if the template fails for some reason).

Repository: incubator-freemarker
Updated Branches:
  refs/heads/3 441367655 -> ef4674e84


Forward ported from 2.3-gae: 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/fa92465b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/fa92465b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/fa92465b

Branch: refs/heads/3
Commit: fa92465b4348222e692bd17392854a3b91762d33
Parents: 4413676
Author: ddekany <dd...@apache.org>
Authored: Tue Oct 3 19:58:31 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Oct 3 20:23:09 2017 +0200

----------------------------------------------------------------------
 .../core/TheadInterruptingSupportTest.java      | 32 +++++++++++++++++---
 1 file changed, 27 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa92465b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
index 1468e59..933a9de 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
@@ -42,7 +42,7 @@ public class TheadInterruptingSupportTest {
     private final Configuration cfg = new TestConfigurationBuilder().build();
 
     @Test
-    public void test() throws IOException, InterruptedException {
+    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>");
@@ -59,14 +59,24 @@ public class TheadInterruptingSupportTest {
         assertCanBeInterrupted("<#attempt><#list 1.. as _></#list><#recover>suppress</#attempt>");
     }
 
-    private void assertCanBeInterrupted(final String templateSourceCode) throws IOException, InterruptedException {
+    private void assertCanBeInterrupted(final String templateSourceCode)
+            throws IOException, InterruptedException, TemplateException {
         TemplateRunnerThread trt = new TemplateRunnerThread(templateSourceCode);
         trt.start();
         synchronized (trt) {
-            while (!trt.isStarted()) {
+            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);
@@ -77,6 +87,7 @@ public class TheadInterruptingSupportTest {
 
         private final Template template;
         private boolean started;
+        private Throwable failedWith;
         private boolean templateProcessingInterrupted;
 
         public TemplateRunnerThread(String templateSourceCode) throws IOException {
@@ -95,6 +106,17 @@ public class TheadInterruptingSupportTest {
                 }
             } 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();
+                    }
+                }
             }
         }
 
@@ -102,8 +124,8 @@ public class TheadInterruptingSupportTest {
             return templateProcessingInterrupted;
         }
         
-        public synchronized boolean isStarted() {
-            return started;
+        public synchronized boolean isStartedOrFailed() {
+            return started || failedWith != null;
         }
         
         public TemplateDirectiveModel getStartedDirective() {


[2/2] incubator-freemarker git commit: Forward ported from 2.3-gae: FREEMARKER-80: Avoid calling synchonized PropertyDescriptor.getReadMethod() when getting a property in a template. Will see if it matters.

Posted by dd...@apache.org.
Forward ported from 2.3-gae: 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/ef4674e8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/ef4674e8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/ef4674e8

Branch: refs/heads/3
Commit: ef4674e84dd8802112555c456a1fdcc884f92f6c
Parents: fa92465
Author: ddekany <dd...@apache.org>
Authored: Tue Oct 3 20:23:32 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Oct 3 20:23:32 2017 +0200

----------------------------------------------------------------------
 .../freemarker/core/model/impl/BeanModel.java   | 20 ++------
 .../core/model/impl/ClassIntrospector.java      | 51 +++-----------------
 .../core/model/impl/FastPropertyDescriptor.java | 39 +++++++++++++++
 3 files changed, 50 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ef4674e8/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
index accadaf..9dbe5b6 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
@@ -19,8 +19,6 @@
 
 package org.apache.freemarker.core.model.impl;
 
-import java.beans.IndexedPropertyDescriptor;
-import java.beans.PropertyDescriptor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -180,21 +178,9 @@ public class BeanModel
         }
 
         TemplateModel resultModel = UNKNOWN;
-        if (desc instanceof PropertyDescriptor) {
-            PropertyDescriptor pd = (PropertyDescriptor) desc;
-            Method readMethod = pd.getReadMethod();
-            if (readMethod != null) {
-                // Unlike in FreeMarker 2, we prefer the normal read method even if there's an indexed read method.
-                resultModel = wrapper.invokeMethod(object, readMethod, null);
-                // cachedModel remains null, as we don't cache these
-            } else if (desc instanceof IndexedPropertyDescriptor) {
-                // In FreeMarker 2 we have exposed such indexed properties as sequences, but they can't support
-                // the getCollectionSize() method, so we have discontinued that. People has to call the indexed read
-                // method like any other method.
-                resultModel = UNKNOWN;
-            } else {
-                throw new IllegalStateException("PropertyDescriptor.readMethod shouldn't be null");
-            }
+        if (desc instanceof FastPropertyDescriptor) {
+            // Unlike in FreeMarker 2, we always use the normal read method, and ignore the indexed read method.
+            resultModel = wrapper.invokeMethod(object, ((FastPropertyDescriptor) desc).getReadMethod(), null);
         } 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/ef4674e8/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
index cc083d4..94eca36 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
@@ -206,7 +206,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) {
@@ -321,8 +321,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) {
@@ -336,7 +335,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);
                     }
@@ -359,7 +358,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,
@@ -377,6 +376,7 @@ class ClassIntrospector {
         } // end if (exposureLevel < EXPOSE_PROPERTIES_ONLY)
     }
 
+    // TODO [FM3] As we ignore indexed property getters in FM3, this might could be simplified. 
     /**
      * Very similar to {@link BeanInfo#getPropertyDescriptors()}, but can deal with Java 8 default methods too.
      */
@@ -647,44 +647,9 @@ class ClassIntrospector {
 
     private void addPropertyDescriptorToClassIntrospectionData(Map<Object, Object> introspData,
             PropertyDescriptor pd, Class<?> clazz, Map<MethodSignature, List<Method>> accessibleMethods) {
-        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 {} indexed property {}, read method {}",
-                            clazz.getName(), pd.getName(), publicReadMethod,
-                            e);
-                }
-            }
-        } 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 {} property {}, read method {}",
-                            clazz.getName(), pd.getName(), publicReadMethod,
-                            e);
-                }
-            }
+        Method readMethod = getMatchingAccessibleMethod(pd.getReadMethod(), accessibleMethods);
+        if (readMethod != null && isAllowedToExpose(readMethod)) {
+            introspData.put(pd.getName(), new FastPropertyDescriptor(readMethod));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ef4674e8/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/FastPropertyDescriptor.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/FastPropertyDescriptor.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/FastPropertyDescriptor.java
new file mode 100644
index 0000000..1019ba9
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/FastPropertyDescriptor.java
@@ -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.freemarker.core.model.impl;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+
+/**
+ * Used instead of {@link PropertyDescriptor}, because the methods of that are synchronized.
+ * Note that if a property has no read method (a non-indexed an one), then we don't treat is as a property.
+ */
+final class FastPropertyDescriptor {
+    private final Method readMethod;
+    
+    public FastPropertyDescriptor(Method readMethod) {
+        this.readMethod = readMethod;
+    }
+
+    public Method getReadMethod() {
+        return readMethod;
+    }
+    
+}