This is an automated email from the ASF dual-hosted git repository. kusal pushed a commit to branch WW-5355-cache-lru in repository https://gitbox.apache.org/repos/asf/struts.git
commit 74d2fdcc6cd7563eb87d475e92fd2a7edb6f3d02 Author: Kusal Kithul-Godage <g...@kusal.io> AuthorDate: Fri Oct 13 21:56:25 2023 +1100 WW-5355 Use LRU cache by default --- .../opensymphony/xwork2/ognl/OgnlDefaultCache.java | 4 +- .../com/opensymphony/xwork2/ognl/OgnlLRUCache.java | 6 +-- .../com/opensymphony/xwork2/ognl/OgnlUtil.java | 55 ++++++++++++---------- .../org/apache/struts2/default.properties | 8 ++-- 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlDefaultCache.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlDefaultCache.java index a32736da6..43b24bb18 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlDefaultCache.java +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlDefaultCache.java @@ -30,10 +30,10 @@ import java.util.concurrent.atomic.AtomicInteger; public class OgnlDefaultCache<Key, Value> implements OgnlCache<Key, Value> { private final ConcurrentHashMap<Key, Value> ognlCache; - private final AtomicInteger cacheEvictionLimit = new AtomicInteger(25000); + private final AtomicInteger cacheEvictionLimit = new AtomicInteger(); public OgnlDefaultCache(int evictionLimit, int initialCapacity, float loadFactor) { - this.cacheEvictionLimit.set(evictionLimit); + cacheEvictionLimit.set(evictionLimit); ognlCache = new ConcurrentHashMap<>(initialCapacity, loadFactor); } diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlLRUCache.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlLRUCache.java index 93ab56d36..81286af34 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlLRUCache.java +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlLRUCache.java @@ -36,15 +36,15 @@ import java.util.concurrent.atomic.AtomicInteger; public class OgnlLRUCache<Key, Value> implements OgnlCache<Key, Value> { private final Map<Key, Value> ognlLRUCache; - private final AtomicInteger cacheEvictionLimit = new AtomicInteger(2500); + private final AtomicInteger cacheEvictionLimit = new AtomicInteger(); public OgnlLRUCache(int evictionLimit, int initialCapacity, float loadFactor) { - this.cacheEvictionLimit.set(evictionLimit); + cacheEvictionLimit.set(evictionLimit); // Access-order mode selected (order mode true in LinkedHashMap constructor). ognlLRUCache = Collections.synchronizedMap (new LinkedHashMap<Key, Value>(initialCapacity, loadFactor, true) { @Override protected boolean removeEldestEntry(Map.Entry<Key,Value> eldest) { - return (this.size() > cacheEvictionLimit.get()); + return size() > cacheEvictionLimit.get(); } }); } 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 4bddad63a..16c80d99d 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java @@ -673,9 +673,15 @@ public class OgnlUtil { * note if exclusions AND inclusions are supplied and not null nothing will get copied. * @param editable the class (or interface) to restrict property setting to */ - public void copy(final Object from, final Object to, final Map<String, Object> context, Collection<String> exclusions, Collection<String> inclusions, Class<?> editable) { + public void copy(final Object from, + final Object to, + final Map<String, Object> context, + Collection<String> exclusions, + Collection<String> inclusions, + Class<?> editable) { if (from == null || to == null) { - LOG.warn("Attempting to copy from or to a null source. This is illegal and is bein skipped. This may be due to an error in an OGNL expression, action chaining, or some other event."); + LOG.warn( + "Skipping attempt to copy from, or to, a null source.", new RuntimeException()); return; } @@ -689,8 +695,7 @@ public class OgnlUtil { fromPds = getPropertyDescriptors(from); if (editable != null) { toPds = getPropertyDescriptors(editable); - } - else { + } else { toPds = getPropertyDescriptors(to); } } catch (IntrospectionException e) { @@ -705,29 +710,31 @@ public class OgnlUtil { } for (PropertyDescriptor fromPd : fromPds) { - if (fromPd.getReadMethod() != null) { - boolean copy = true; - if (exclusions != null && exclusions.contains(fromPd.getName())) { - copy = false; - } else if (inclusions != null && !inclusions.contains(fromPd.getName())) { - copy = false; - } - - if (copy) { - PropertyDescriptor toPd = toPdHash.get(fromPd.getName()); - if ((toPd != null) && (toPd.getWriteMethod() != null)) { - try { - Object value = ognlGet(fromPd.getName(), contextFrom, from, null, context, this::checkEnableEvalExpression); - ognlSet(fromPd.getName(), contextTo, to, value, context); - } catch (OgnlException e) { - LOG.debug("Got OGNL exception", e); - } - } + if (fromPd.getReadMethod() == null) { + continue; + } - } + if (exclusions != null && exclusions.contains(fromPd.getName()) || + inclusions != null && !inclusions.contains(fromPd.getName())) { + continue; + } + PropertyDescriptor toPd = toPdHash.get(fromPd.getName()); + if (toPd == null || toPd.getWriteMethod() == null) { + continue; } + try { + Object value = ognlGet(fromPd.getName(), + contextFrom, + from, + null, + context, + this::checkEnableEvalExpression); + ognlSet(fromPd.getName(), contextTo, to, value, context); + } catch (OgnlException e) { + LOG.debug("Got OGNL exception", e); + } } } @@ -746,7 +753,7 @@ public class OgnlUtil { } /** - * Get's the java beans property descriptors for the given source. + * Gets the java beans property descriptors for the given source. * * @param source the source object. * @return property descriptors. diff --git a/core/src/main/resources/org/apache/struts2/default.properties b/core/src/main/resources/org/apache/struts2/default.properties index 56bc714de..60257465b 100644 --- a/core/src/main/resources/org/apache/struts2/default.properties +++ b/core/src/main/resources/org/apache/struts2/default.properties @@ -243,12 +243,12 @@ struts.ognl.enableExpressionCache=true ### For expressionCacheLRUMode true, the limit will ensure the cache does not exceed ### that size, dropping the oldest (least-recently-used) expressions to add new ones. ### NOTE: If not set, the default is 25000, which may be excessive. -# struts.ognl.expressionCacheMaxSize=1000 +struts.ognl.expressionCacheMaxSize=10000 ### Indicates if the OGNL expressionCache should use LRU mode. ### NOTE: When true, make sure to set the expressionCacheMaxSize to a reasonable value ### for your application. Otherwise the default limit will never (practically) be reached. -# struts.ognl.expressionCacheLRUMode=false +struts.ognl.expressionCacheLRUMode=true ### Specify a limit to the number of entries in the OGNL beanInfoCache. ### For the standard beanInfoCache mode, when the limit is exceeded the entire cache's @@ -256,12 +256,12 @@ struts.ognl.enableExpressionCache=true ### For beanInfoCacheLRUMode true, the limit will ensure the cache does not exceed ### that size, dropping the oldest (least-recently-used) expressions to add new ones. ### NOTE: If not set, the default is 25000, which may be excessive. -# struts.ognl.beanInfoCacheMaxSize=1000 +struts.ognl.beanInfoCacheMaxSize=5000 ### Indicates if the OGNL beanInfoCache should use LRU mode. ### NOTE: When true, make sure to set the beanInfoCacheMaxSize to a reasonable value ### for your application. Otherwise the default limit will never (practically) be reached. -# struts.ognl.beanInfoCacheLRUMode=false +struts.ognl.beanInfoCacheLRUMode=true ### Indicates if Dispatcher should handle unexpected exceptions by calling sendError() ### or simply rethrow it as a ServletException to allow future processing by other frameworks like Spring Security