You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by ya...@apache.org on 2019/09/07 10:02:08 UTC

[struts] branch struts-2-5-x updated: Proposed WW-5035 enhancement: - Provide cache clearing methods for OgnlUtil (expression cache, BeanInfo cache). - Provide methods to check the cache sizes (entry number for expression cache, BeanInfo cache). - Provide static method to clear the OgnlRuntime cache (convenience method).

This is an automated email from the ASF dual-hosted git repository.

yasserzamani pushed a commit to branch struts-2-5-x
in repository https://gitbox.apache.org/repos/asf/struts.git


The following commit(s) were added to refs/heads/struts-2-5-x by this push:
     new 9216e8e  Proposed WW-5035 enhancement: - Provide cache clearing methods for OgnlUtil (expression cache, BeanInfo cache). - Provide methods to check the cache sizes (entry number for expression cache, BeanInfo cache). - Provide static method to clear the OgnlRuntime cache (convenience method).
     new 4ae1a6a  Merge pull request #361 from JCgH4164838Gh792C124B5/localS2_25x_OgnlCachecontrol
9216e8e is described below

commit 9216e8e22c67393f29665186dd25ac5c4bf753e4
Author: JCgH4164838Gh792C124B5 <43...@users.noreply.github.com>
AuthorDate: Sat Jun 15 11:40:58 2019 -0400

    Proposed WW-5035 enhancement:
    - Provide cache clearing methods for OgnlUtil (expression cache, BeanInfo
    cache).
    - Provide methods to check the cache sizes (entry number for expression
    cache, BeanInfo cache).
    - Provide static method to clear the OgnlRuntime cache (convenience
    method).
---
 .../com/opensymphony/xwork2/ognl/OgnlUtil.java     |  70 +++++++++++++
 .../com/opensymphony/xwork2/ognl/OgnlUtilTest.java | 112 +++++++++++++++++++++
 2 files changed, 182 insertions(+)

diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
index 20be3dc..071ed71 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
@@ -189,6 +189,76 @@ public class OgnlUtil {
     }
 
     /**
+     * Convenience mechanism to clear the OGNL Runtime Cache via OgnlUtil.  May be utilized
+     * by applications that generate many unique OGNL expressions over time.
+     *
+     * Note: This call affects the global OGNL cache, see ({@link ognl.OgnlRuntime#clearCache()} for details.
+     *
+     * Warning: Frequent calling if this method may negatively impact performance, but may be required
+     *          to avoid memory exhaustion (resource leak) with too many OGNL expressions being cached.
+     *
+     * @since 2.5.21
+     */
+    public static void clearRuntimeCache() {
+        OgnlRuntime.clearCache();
+    }
+
+    /**
+     * Provide a mechanism to clear the OGNL expression cache.  May be utilized by applications
+     * that generate many unique OGNL expressions over time.
+     *
+     * Note: This call affects the current OgnlUtil instance.  For Struts this is often a Singleton
+     *       instance so it can be "effectively global".
+     *
+     * Warning: Frequent calling if this method may negatively impact performance, but may be required
+     *          to avoid memory exhaustion (resource leak) with too many OGNL expressions being cached.
+     *
+     * @since 2.5.21
+     */
+    public void clearExpressionCache() {
+        expressions.clear();
+    }
+
+    /**
+     * Check the size of the expression cache (current number of elements).
+     *
+     * @return current number of elements in the expression cache.
+     *
+     * @since 2.5.21
+     */
+    public int expressionCacheSize() {
+        return expressions.size();
+    }
+
+    /**
+     * Provide a mechanism to clear the BeanInfo cache.  May be utilized by applications
+     * that request BeanInfo and/or PropertyDescriptors for many unique classes or objects over time
+     * (especially dynamic objects).
+     *
+     * Note: This call affects the current OgnlUtil instance.  For Struts this is often a Singleton
+     *       instance so it can be "effectively global".
+     *
+     * Warning: Frequent calling if this method may negatively impact performance, but may be required
+     *          to avoid memory exhaustion (resource leak) with too many BeanInfo elements being cached.
+     *
+     * @since 2.5.21
+     */
+    public void clearBeanInfoCache() {
+        beanInfoCache.clear();
+    }
+
+    /**
+     * Check the size of the BeanInfo cache (current number of elements).
+     *
+     * @return current number of elements in the BeanInfo cache.
+     *
+     * @since 2.5.21
+     */
+    public int beanInfoCacheSize() {
+        return beanInfoCache.size();
+    }
+
+    /**
      * Sets the object's properties using the default type converter, defaulting to not throw
      * exceptions for problems setting the properties.
      *
diff --git a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
index 9c5e59b..5f1a5a5 100644
--- a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
@@ -31,6 +31,7 @@ import com.opensymphony.xwork2.test.User;
 import com.opensymphony.xwork2.util.*;
 import com.opensymphony.xwork2.util.location.LocatableProperties;
 import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
+import java.beans.IntrospectionException;
 import ognl.*;
 import org.apache.struts2.StrutsConstants;
 
@@ -113,6 +114,84 @@ public class OgnlUtilTest extends XWorkTestCase {
         assertSame(expr0, expr2);
     }
 
+    public void testClearExpressionCache() throws OgnlException {
+        ognlUtil.setEnableExpressionCache("true");
+        // Test that the expression cache is functioning as expected.
+        Object expr0 = ognlUtil.compile("test");
+        Object expr1 = ognlUtil.compile("test");
+        Object expr2 = ognlUtil.compile("test");
+        // Cache in effect, so expr0, expr1, expr2 should be the same.
+        assertSame(expr0, expr1);
+        assertSame(expr0, expr2);
+        assertTrue("Expression cache empty before clear ?", ognlUtil.expressionCacheSize() > 0);
+        // Clear the Epxression cache and confirm subsequent requests are new.
+        ognlUtil.clearExpressionCache();
+        assertTrue("Expression cache not empty after clear ?", ognlUtil.expressionCacheSize() == 0);
+        Object expr3 = ognlUtil.compile("test");
+        Object expr4 = ognlUtil.compile("test");
+        Object expr5 = ognlUtil.compile("test");
+        // Cache cleared, expr3 should be a new instance.
+        assertNotSame(expr0, expr3);
+        // Cache still in effect, so expr3, expr4, expr5 should be the same.
+        assertSame(expr3, expr4);
+        assertSame(expr3, expr5);
+        assertTrue("Expression cache empty after usage ?", ognlUtil.expressionCacheSize() > 0);
+    }
+
+    public void testClearBeanInfoCache() throws IntrospectionException {
+        final TestBean1 testBean1 = new TestBean1();
+        final TestBean2 testBean2 = new TestBean2();
+        // Test that the BeanInfo cache is functioning as expected.
+        Object beanInfo1_1 = ognlUtil.getBeanInfo(testBean1);
+        Object beanInfo1_2 = ognlUtil.getBeanInfo(testBean1);
+        Object beanInfo1_3 = ognlUtil.getBeanInfo(testBean1);
+        // Cache in effect, so beanInfo1_1, beanInfo1_2, beanInfo1_3 should be the same.
+        assertSame(beanInfo1_1, beanInfo1_2);
+        assertSame(beanInfo1_1, beanInfo1_3);
+        Object beanInfo2_1 = ognlUtil.getBeanInfo(testBean2);
+        Object beanInfo2_2 = ognlUtil.getBeanInfo(testBean2);
+        Object beanInfo2_3 = ognlUtil.getBeanInfo(testBean2);
+        // Cache in effect, so beanInfo2_1, beanInfo2_2, beanInfo2_3 should be the same.
+        assertSame(beanInfo2_1, beanInfo2_2);
+        assertSame(beanInfo2_1, beanInfo2_3);
+        // BeanInfo for TestBean1 and TestBean2 should always be different.
+        assertNotSame(beanInfo1_1, beanInfo2_1);
+        assertTrue("BeanInfo cache empty before clear ?", ognlUtil.beanInfoCacheSize() > 0);
+        // Clear the BeanInfo cache and confirm subsequent requests are new.
+        ognlUtil.clearBeanInfoCache();
+        assertTrue("BeanInfo cache not empty after clear ?", ognlUtil.beanInfoCacheSize() == 0);
+        Object beanInfo1_4 = ognlUtil.getBeanInfo(testBean1);
+        Object beanInfo1_5 = ognlUtil.getBeanInfo(testBean1);
+        Object beanInfo1_6 = ognlUtil.getBeanInfo(testBean1);
+        // Cache in effect, so beanInfo1_4, beanInfo1_5, beanInfo1_6 should be the same.
+        assertSame(beanInfo1_4, beanInfo1_5);
+        assertSame(beanInfo1_4, beanInfo1_6);
+        // Cache was cleared in-between, so beanInfo1_1/beanInfo1_2/beanInfo1_3 should differ
+        // from beanInfo1_4/beanInfo1_5/beanInfo1_6.
+        assertNotSame(beanInfo1_1, beanInfo1_4);
+        assertNotSame(beanInfo1_2, beanInfo1_5);
+        assertNotSame(beanInfo1_3, beanInfo1_6);
+        Object beanInfo2_4 = ognlUtil.getBeanInfo(testBean2);
+        Object beanInfo2_5 = ognlUtil.getBeanInfo(testBean2);
+        Object beanInfo2_6 = ognlUtil.getBeanInfo(testBean2);
+        // Cache in effect, so beanInfo2_4, beanInfo2_5, beanInfo2_6 should be the same.
+        assertSame(beanInfo2_4, beanInfo2_5);
+        assertSame(beanInfo2_4, beanInfo2_6);
+        // Cache was cleared in-between, so beanInfo2_1/beanInfo2_2/beanInfo2_3 should differ
+        // from beanInfo2_4/beanInfo2_5/beanInfo2_6.
+        assertNotSame(beanInfo2_1, beanInfo2_4);
+        assertNotSame(beanInfo2_2, beanInfo2_5);
+        assertNotSame(beanInfo2_3, beanInfo2_6);
+        // BeanInfo for TestBean1 and TestBean2 should always be different.
+        assertNotSame(beanInfo1_4, beanInfo2_4);
+        assertTrue("BeanInfo cache empty after usage ?", ognlUtil.beanInfoCacheSize() > 0);
+    }
+
+    public void testClearRuntimeCache() {
+        // Confirm that no exceptions or failures arise when calling the convenience global clear method.
+        OgnlUtil.clearRuntimeCache();
+    }
+
      public void testCacheDisabled() throws OgnlException {
         ognlUtil.setEnableExpressionCache("false");
         Object expr0 = ognlUtil.compile("test");
@@ -1333,4 +1412,37 @@ public class OgnlUtilTest extends XWorkTestCase {
     	}
     	
     }
+
+    class TestBean1 {
+        private String testBeanProperty;
+
+        public TestBean1() {
+            testBeanProperty = "defaultTestBean1Property";
+        }
+
+        public String getTestBeanProperty() {
+            return testBeanProperty;
+        }
+
+        public void setTestBeanProperty(String testBeanProperty) {
+            this.testBeanProperty = testBeanProperty;
+        }
+    }
+
+    class TestBean2 {
+        private String testBeanProperty;
+
+        public TestBean2() {
+            testBeanProperty = "defaultTestBean2Property";
+        }
+
+        public String getTestBeanProperty() {
+            return testBeanProperty;
+        }
+
+        public void setTestBeanProperty(String testBeanProperty) {
+            this.testBeanProperty = testBeanProperty;
+        }
+    }
+
 }