Skip to content

Commit

Permalink
WW-5355 Use LRU cache by default
Browse files Browse the repository at this point in the history
  • Loading branch information
kusalk committed Oct 13, 2023
1 parent 67da669 commit 74d2fdc
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@
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();
}
});
}
Expand Down
55 changes: 31 additions & 24 deletions core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -673,9 +673,15 @@ public void copy(final Object from, final Object to, final Map<String, Object> c
* 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;
}

Expand All @@ -689,8 +695,7 @@ public void copy(final Object from, final Object to, final Map<String, Object> c
fromPds = getPropertyDescriptors(from);
if (editable != null) {
toPds = getPropertyDescriptors(editable);
}
else {
} else {
toPds = getPropertyDescriptors(to);
}
} catch (IntrospectionException e) {
Expand All @@ -705,29 +710,31 @@ public void copy(final Object from, final Object to, final Map<String, Object> c
}

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);
}
}
}

Expand All @@ -746,7 +753,7 @@ public void copy(Object from, Object to, Map<String, Object> context) {
}

/**
* 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.
Expand Down
8 changes: 4 additions & 4 deletions core/src/main/resources/org/apache/struts2/default.properties
Original file line number Diff line number Diff line change
Expand Up @@ -243,25 +243,25 @@ 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
### content will be cleared (can help prevent memory leaks).
### 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
Expand Down

0 comments on commit 74d2fdc

Please sign in to comment.