Ties cache extension points with implementation

This commit is contained in:
Lukasz Lenart
2022-05-02 09:23:31 +02:00
parent 199f356669
commit 05ca1ff087
14 changed files with 104 additions and 56 deletions
@@ -28,9 +28,10 @@ import com.opensymphony.xwork2.conversion.*;
import com.opensymphony.xwork2.conversion.impl.*;
import com.opensymphony.xwork2.factory.*;
import com.opensymphony.xwork2.inject.*;
import com.opensymphony.xwork2.ognl.BeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory;
import com.opensymphony.xwork2.ognl.OgnlCacheFactory;
import com.opensymphony.xwork2.ognl.ExpressionCacheFactory;
import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
import com.opensymphony.xwork2.ognl.OgnlUtil;
import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
@@ -297,8 +298,8 @@ public class DefaultConfiguration implements Configuration {
builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
builder.factory(OgnlCacheFactory.class, "ognlExpressionCacheFactory", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON);
builder.factory(OgnlCacheFactory.class, "ognlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON);
builder.factory(ExpressionCacheFactory.class, "defaultOgnlExpressionCacheFactory", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON);
builder.factory(BeanInfoCacheFactory.class, "defaultOgnlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON);
builder.factory(OgnlUtil.class, Scope.SINGLETON);
builder.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
@@ -26,6 +26,8 @@ import com.opensymphony.xwork2.StrutsTextProviderFactory;
import com.opensymphony.xwork2.TextProviderFactory;
import com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory;
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
import com.opensymphony.xwork2.ognl.BeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.ExpressionCacheFactory;
import com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor;
import com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor;
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
@@ -96,7 +98,6 @@ import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.LocalizedTextProvider;
import com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory;
import com.opensymphony.xwork2.ognl.OgnlCacheFactory;
import com.opensymphony.xwork2.util.StrutsLocalizedTextProvider;
import com.opensymphony.xwork2.util.OgnlTextParser;
import com.opensymphony.xwork2.util.PatternMatcher;
@@ -216,8 +217,8 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
.factory(TextProviderFactory.class, StrutsTextProviderFactory.class, Scope.SINGLETON)
.factory(LocaleProviderFactory.class, DefaultLocaleProviderFactory.class, Scope.SINGLETON)
.factory(OgnlCacheFactory.class, "ognlExpressionCacheFactory", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
.factory(OgnlCacheFactory.class, "ognlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
.factory(ExpressionCacheFactory.class, "defaultOgnlExpressionCacheFactory", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
.factory(BeanInfoCacheFactory.class, "defaultOgnlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
.factory(OgnlUtil.class, Scope.SINGLETON)
.factory(CollectionConverter.class, Scope.SINGLETON)
.factory(ArrayConverter.class, Scope.SINGLETON)
@@ -0,0 +1,23 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed 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 com.opensymphony.xwork2.ognl;
/**
* A proxy interface to be used with Struts DI mechanism
*/
public interface BeanInfoCacheFactory<Key, Value> extends OgnlCacheFactory <Key, Value> {
}
@@ -20,13 +20,14 @@ import org.apache.struts2.StrutsConstants;
/**
* Default OGNL Cache factory implementation.
*
*
* Currently used for BeanInfo cache creation.
*
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public class DefaultOgnlBeanInfoCacheFactory<Key, Value> extends DefaultOgnlCacheFactory {
public class DefaultOgnlBeanInfoCacheFactory<Key, Value> extends DefaultOgnlCacheFactory<Key, Value>
implements BeanInfoCacheFactory<Key, Value> {
@Override
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE, required = false)
@@ -21,13 +21,13 @@ import org.apache.commons.lang3.BooleanUtils;
/**
* Default OGNL Cache factory implementation.
*
*
* Currently used for Expression cache and BeanInfo cache creation.
*
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public class DefaultOgnlCacheFactory<Key, Value> implements OgnlCacheFactory {
public class DefaultOgnlCacheFactory<Key, Value> implements OgnlCacheFactory<Key, Value> {
private final AtomicBoolean useLRUCache = new AtomicBoolean(false);
private final AtomicInteger cacheMaxSize = new AtomicInteger(25000);
@@ -20,13 +20,14 @@ import org.apache.struts2.StrutsConstants;
/**
* Default OGNL Expression Cache factory implementation.
*
*
* Currently used for Expression cache creation.
*
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public class DefaultOgnlExpressionCacheFactory<Key, Value> extends DefaultOgnlCacheFactory {
public class DefaultOgnlExpressionCacheFactory<Key, Value> extends DefaultOgnlCacheFactory<Key, Value>
implements ExpressionCacheFactory<Key, Value> {
@Override
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE, required = false)
@@ -0,0 +1,23 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed 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 com.opensymphony.xwork2.ognl;
/**
* A proxy interface to be used with Struts DI mechanism
*/
public interface ExpressionCacheFactory<Key, Value> extends OgnlCacheFactory <Key, Value> {
}
@@ -18,11 +18,11 @@ package com.opensymphony.xwork2.ognl;
/**
* Used by {@link com.opensymphony.xwork2.ognl.OgnlUtil} to create appropriate OGNL
* caches based on configuration.
*
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public interface OgnlCacheFactory<Key, Value> {
interface OgnlCacheFactory<Key, Value> {
OgnlCache<Key, Value> buildOgnlCache();
OgnlCache<Key, Value> buildOgnlCache(int evictionLimit, int initialCapacity, float loadFactor, boolean lruCache);
int getCacheMaxSize();
@@ -55,8 +55,6 @@ public class OgnlUtil {
// Flag used to reduce flooding logs with WARNs about using DevMode excluded packages
private final AtomicBoolean warnReported = new AtomicBoolean(false);
private final OgnlCacheFactory<String, Object> ognlExpressionCacheFactory;
private final OgnlCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory;
private final OgnlCache<String, Object> expressionCache;
private final OgnlCache<Class<?>, BeanInfo> beanInfoCache;
private TypeConverter defaultConverter;
@@ -80,8 +78,8 @@ public class OgnlUtil {
/**
* Construct a new OgnlUtil instance for use with the framework
*
* @deprecated It is recommended to utilize the {@link OgnlUtil#OgnlUtil(com.opensymphony.xwork2.ognl.OgnlCacheFactory, com.opensymphony.xwork2.ognl.OgnlCacheFactory) method instead.
*
* @deprecated It is recommended to utilize the {@link OgnlUtil#OgnlUtil(com.opensymphony.xwork2.ognl.ExpressionCacheFactory, com.opensymphony.xwork2.ognl.BeanInfoCacheFactory) method instead.
*/
@Deprecated
public OgnlUtil() {
@@ -91,18 +89,17 @@ public class OgnlUtil {
/**
* Construct a new OgnlUtil instance for use with the framework, with optional
* cache factories for OGNL Expression and BeanInfo caches.
*
*
* NOTE: Although the extension points are defined for the optional cache factories, developer-defined overrides do
* do not appear to function at this time (it always appears to instantiate the default factories).
* Construction injectors do not allow the optional flag, so the definitions must be defined.
*
*
* @param ognlExpressionCacheFactory factory for Expression cache instance. If null, it uses a default
* @param ognlBeanInfoCacheFactory factory for BeanInfo cache instance. If null, it uses a default
*/
@Inject
public OgnlUtil(
@Inject(value = "ognlExpressionCacheFactory") OgnlCacheFactory<String, Object> ognlExpressionCacheFactory,
@Inject(value = "ognlBeanInfoCacheFactory") OgnlCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_FACTORY, required = false) ExpressionCacheFactory<String, Object> ognlExpressionCacheFactory,
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_FACTORY, required = false) BeanInfoCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory
) {
excludedClasses = Collections.unmodifiableSet(new HashSet<>());
excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
@@ -112,11 +109,11 @@ public class OgnlUtil {
devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
devModeExcludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
this.ognlExpressionCacheFactory = (ognlExpressionCacheFactory != null ? ognlExpressionCacheFactory : new DefaultOgnlExpressionCacheFactory<>());
this.ognlBeanInfoCacheFactory = (ognlBeanInfoCacheFactory != null ? ognlBeanInfoCacheFactory : new DefaultOgnlBeanInfoCacheFactory<>());
OgnlCacheFactory<String, Object> ognlExpressionCacheFactory1 = (ognlExpressionCacheFactory != null ? ognlExpressionCacheFactory : new DefaultOgnlExpressionCacheFactory<>());
OgnlCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory1 = (ognlBeanInfoCacheFactory != null ? ognlBeanInfoCacheFactory : new DefaultOgnlBeanInfoCacheFactory<>());
this.expressionCache = this.ognlExpressionCacheFactory.buildOgnlCache();
this.beanInfoCache = this.ognlBeanInfoCacheFactory.buildOgnlCache();
this.expressionCache = ognlExpressionCacheFactory1.buildOgnlCache();
this.beanInfoCache = ognlBeanInfoCacheFactory1.buildOgnlCache();
}
@Inject
@@ -256,28 +256,28 @@ public final class StrutsConstants {
/**
* Specifies an OGNL expression cache factory implementation. A default implementation is provided, but
* could be replaced by a custom one if desired.
*
*
* @since 2.6
*/
public static final String STRUTS_OGNL_EXPRESSIONCACHE_FACTORY = "struts.ognl.expressionCacheFactory";
public static final String STRUTS_OGNL_EXPRESSION_CACHE_FACTORY = "struts.ognl.expressionCacheFactory";
/**
* Specifies an OGNL BeanInfo cache factory implementation. A default implementation is provided, but
* could be replaced by a custom one if desired.
*
*
* @since 2.6
*/
public static final String STRUTS_OGNL_BEANINFOCACHE_FACTORY = "struts.ognl.beanInfoCacheFactory";
public static final String STRUTS_OGNL_BEANINFO_CACHE_FACTORY = "struts.ognl.beanInfoCacheFactory";
/**
* Specifies a maximum number of cached BeanInfo used by OgnlUtility. Not specified/set by default. If
* a positive integer is specified, it will set a limit whose behaviour depends on whether the
* normal (default) cache or optional LRU cache is in place.
*
*
* For the normal (default) cache, exceeding the maximum will cause the entire cache to flush (clear).
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
* removed when a new entry needs to be added (cache is fully-utilized).
*
*
* @since 2.6
*/
public static final String STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE = "struts.ognl.beanInfoCacheMaxSize";
@@ -286,10 +286,10 @@ public final class StrutsConstants {
* Set the cache mode of the BeanInfo cache used by OgnlUtility. A value of true means enable
* least-recently-used (LRU) mode, a value of false (or any non-true value) means to use the
* default cache.
*
*
* Note: When enabling LRU cache mode you must also set a maximum size (via {@link #STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE})
* for it to be effective. Otherwise, there is no condition to evict a LRU entry (cache has no limit).
*
*
* @since 2.6
*/
public static final String STRUTS_OGNL_BEANINFO_CACHE_LRU_MODE = "struts.ognl.beanInfoCacheLRUMode";
@@ -323,11 +323,11 @@ public final class StrutsConstants {
* Specifies a maximum number of cached parsed OGNL expressions. Not specified/set by default. If
* a positive integer is specified, it will set a limit whose behaviour depends on whether the
* normal (default) cache or optional LRU cache is in place.
*
*
* For the normal (default) cache, exceeding the maximum will cause the entire cache to flush (clear).
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
* removed when a new entry needs to be added (cache is fully-utilized).
*
*
* @since 2.6
*/
public static final String STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE = "struts.ognl.expressionCacheMaxSize";
@@ -336,10 +336,10 @@ public final class StrutsConstants {
* Set the cache mode of the parsed OGNL expression cache. A value of true means enable
* least-recently-used (LRU) mode, a value of false (or any non-true value) means to use the
* default cache.
*
*
* Note: When enabling LRU cache mode you must also set a maximum size (via {@link #STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE})
* for it to be effective. Otherwise, there is no condition to evict a LRU entry (cache has no limit).
*
*
* @since 2.6
*/
public static final String STRUTS_OGNL_EXPRESSION_CACHE_LRU_MODE = "struts.ognl.expressionCacheLRUMode";
@@ -23,6 +23,8 @@ import com.opensymphony.xwork2.LocaleProviderFactory;
import com.opensymphony.xwork2.LocalizedTextProvider;
import com.opensymphony.xwork2.TextProviderFactory;
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
import com.opensymphony.xwork2.ognl.BeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.ExpressionCacheFactory;
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
import com.opensymphony.xwork2.FileManager;
@@ -49,7 +51,6 @@ import com.opensymphony.xwork2.factory.ResultFactory;
import com.opensymphony.xwork2.factory.ValidatorFactory;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.inject.Scope;
import com.opensymphony.xwork2.ognl.OgnlCacheFactory;
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
import com.opensymphony.xwork2.util.PatternMatcher;
import com.opensymphony.xwork2.util.TextParser;
@@ -425,8 +426,8 @@ public class StrutsBeanSelectionProvider extends AbstractBeanSelectionProvider {
alias(DateFormatter.class, StrutsConstants.STRUTS_DATE_FORMATTER, builder, props, Scope.SINGLETON);
alias(OgnlCacheFactory.class, StrutsConstants.STRUTS_OGNL_EXPRESSIONCACHE_FACTORY, builder, props, Scope.SINGLETON);
alias(OgnlCacheFactory.class, StrutsConstants.STRUTS_OGNL_BEANINFOCACHE_FACTORY, builder, props, Scope.SINGLETON);
alias(ExpressionCacheFactory.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_FACTORY, builder, props, Scope.SINGLETON);
alias(BeanInfoCacheFactory.class, StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_FACTORY, builder, props, Scope.SINGLETON);
switchDevMode(props);
}
@@ -276,8 +276,8 @@ public class ConstantConfig {
map.put(StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS, Objects.toString(disallowProxyMemberAccess, null));
map.put(StrutsConstants.STRUTS_OGNL_AUTO_GROWTH_COLLECTION_LIMIT, Objects.toString(ognlAutoGrowthCollectionLimit, null));
map.put(StrutsConstants.STRUTS_UI_STATIC_CONTENT_PATH, Objects.toString(staticContentPath, StaticContentLoader.DEFAULT_STATIC_CONTENT_PATH));
map.put(StrutsConstants.STRUTS_OGNL_EXPRESSIONCACHE_FACTORY, beanConfToString(expressionCacheFactory));
map.put(StrutsConstants.STRUTS_OGNL_BEANINFOCACHE_FACTORY, beanConfToString(beaninfoCacheFactory));
map.put(StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_FACTORY, beanConfToString(expressionCacheFactory));
map.put(StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_FACTORY, beanConfToString(beaninfoCacheFactory));
return map;
}
@@ -230,9 +230,9 @@ struts.ognl.logMissingProperties=false
struts.ognl.enableExpressionCache=true
### Specify the OGNL expression cache factory and BeanInfo cache factory to use.
### Currently the default implementations are used, but can be replaced with custom ones if desired.
struts.ognl.expressionCacheFactory=ognlExpressionCacheFactory
struts.ognl.beanInfoCacheFactory=ognlBeanInfoCacheFactory
### Currently, the default implementations are used, but can be replaced with custom ones if desired.
struts.ognl.expressionCacheFactory=defaultOgnlExpressionCacheFactory
struts.ognl.beanInfoCacheFactory=defaultOgnlBeanInfoCacheFactory
### Specify a limit to the number of entries in the OGNL expressionCache.
### For the standard expressionCache mode, when the limit is exceeded the entire cache's
@@ -1857,7 +1857,7 @@ public class OgnlUtilTest extends XWorkTestCase {
}
/**
* Unit test primarily for code coverage
* Unit test primarily for code coverage
*/
public void testOgnlDefaultCacheFactoryCoverage() {
OgnlCache<String, Object> ognlCache;
@@ -1885,13 +1885,13 @@ public class OgnlUtilTest extends XWorkTestCase {
/**
* Generate a new OgnlUtil instance (not configured by the {@link ContainerBuilder}) that can be used for
* basic tests, with its Expression and BeanInfo factories set to LRU mode.
*
*
* @return OgnlUtil instance with LRU enabled Expression and BeanInfo factories
*/
private OgnlUtil generateOgnlUtilInstanceWithDefaultLRUCacheFactories() {
final OgnlUtil result;
final DefaultOgnlCacheFactory expressionFactory = new DefaultOgnlExpressionCacheFactory<String, Object>();
final DefaultOgnlCacheFactory beanInfoFactory = new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>();
final DefaultOgnlExpressionCacheFactory<String, Object> expressionFactory = new DefaultOgnlExpressionCacheFactory<>();
final DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo> beanInfoFactory = new DefaultOgnlBeanInfoCacheFactory<>();
expressionFactory.setUseLRUCache("true");
expressionFactory.setCacheMaxSize("25");
beanInfoFactory.setUseLRUCache("true");