diff --git a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java index 01c9eee20..ea401213d 100644 --- a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java +++ b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java @@ -82,30 +82,37 @@ public class DefaultConfiguration implements Configuration { } + @Override public PackageConfig getPackageConfig(String name) { return packageContexts.get(name); } + @Override public List getUnknownHandlerStack() { return unknownHandlerStack; } + @Override public void setUnknownHandlerStack(List unknownHandlerStack) { this.unknownHandlerStack = unknownHandlerStack; } + @Override public Set getPackageConfigNames() { return packageContexts.keySet(); } + @Override public Map getPackageConfigs() { return packageContexts; } + @Override public Set getLoadedFileNames() { return loadedFileNames; } + @Override public RuntimeConfiguration getRuntimeConfiguration() { return runtimeConfiguration; } @@ -113,10 +120,12 @@ public class DefaultConfiguration implements Configuration { /** * @return the container */ + @Override public Container getContainer() { return container; } + @Override public void addPackageConfig(String name, PackageConfig packageContext) { PackageConfig check = packageContexts.get(name); if (check != null) { @@ -134,6 +143,7 @@ public class DefaultConfiguration implements Configuration { packageContexts.put(name, packageContext); } + @Override public PackageConfig removePackageConfig(String packageName) { return packageContexts.remove(packageName); } @@ -141,11 +151,13 @@ public class DefaultConfiguration implements Configuration { /** * Allows the configuration to clean up any resources used */ + @Override public void destroy() { packageContexts.clear(); loadedFileNames.clear(); } + @Override public void rebuildRuntimeConfiguration() { runtimeConfiguration = buildRuntimeConfiguration(); } @@ -154,10 +166,12 @@ public class DefaultConfiguration implements Configuration { * Calls the ConfigurationProviderFactory.getConfig() to tell it to reload the configuration and then calls * buildRuntimeConfiguration(). * + * @param providers list of ContainerProvider * @return list of package providers * * @throws ConfigurationException in case of any configuration errors */ + @Override public synchronized List reloadContainer(List providers) throws ConfigurationException { packageContexts.clear(); loadedFileNames.clear(); @@ -175,6 +189,7 @@ public class DefaultConfiguration implements Configuration { props.setConstants(builder); builder.factory(Configuration.class, new Factory() { + @Override public Configuration create(Context context) throws Exception { return DefaultConfiguration.this; } @@ -282,13 +297,12 @@ 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(OgnlUtil.class, Scope.SINGLETON); builder.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON); - builder.factory(OgnlCacheFactory.class, StrutsConstants.STRUTS_OGNL_EXPRESSIONCACHE_FACTORY, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON); - builder.factory(OgnlCacheFactory.class, StrutsConstants.STRUTS_OGNL_BEANINFOCACHE_FACTORY, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON); - builder.constant(StrutsConstants.STRUTS_DEVMODE, "false"); builder.constant(StrutsConstants.STRUTS_OGNL_LOG_MISSING_PROPERTIES, "false"); builder.constant(StrutsConstants.STRUTS_OGNL_ENABLE_EVAL_EXPRESSION, "false"); @@ -423,10 +437,10 @@ public class DefaultConfiguration implements Configuration { private static class RuntimeConfigurationImpl implements RuntimeConfiguration { - private Map> namespaceActionConfigs; - private Map namespaceActionConfigMatchers; - private NamespaceMatcher namespaceMatcher; - private Map namespaceConfigs; + private final Map> namespaceActionConfigs; + private final Map namespaceActionConfigMatchers; + private final NamespaceMatcher namespaceMatcher; + private final Map namespaceConfigs; public RuntimeConfigurationImpl(Map> namespaceActionConfigs, Map namespaceConfigs, @@ -454,6 +468,7 @@ public class DefaultConfiguration implements Configuration { * @param namespace the namespace for the action or null for the empty namespace, "" * @return the configuration information for action requested */ + @Override public ActionConfig getActionConfig(String namespace, String name) { ActionConfig config = findActionConfigInNamespace(namespace, name); @@ -509,6 +524,7 @@ public class DefaultConfiguration implements Configuration { * * @return a Map of namespace - > Map of ActionConfig objects, with the key being the action name */ + @Override public Map> getActionConfigs() { return namespaceActionConfigs; } diff --git a/core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java index 30551d6b3..d5b6eb0ea 100644 --- a/core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java +++ b/core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java @@ -216,6 +216,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(OgnlUtil.class, Scope.SINGLETON) .factory(CollectionConverter.class, Scope.SINGLETON) .factory(ArrayConverter.class, Scope.SINGLETON) @@ -232,9 +234,6 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider .factory(DateFormatter.class, "simpleDateFormatter", SimpleDateFormatAdapter.class, Scope.SINGLETON) .factory(DateFormatter.class, "dateTimeFormatter", DateTimeFormatterAdapter.class, Scope.SINGLETON) - - .factory(OgnlCacheFactory.class, StrutsConstants.STRUTS_OGNL_EXPRESSIONCACHE_FACTORY, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON) - .factory(OgnlCacheFactory.class, StrutsConstants.STRUTS_OGNL_BEANINFOCACHE_FACTORY, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON) ; props.setProperty(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, Boolean.FALSE.toString()); 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 cbcc777ee..26ed7f4f4 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java @@ -90,15 +90,19 @@ public class OgnlUtil { /** * Construct a new OgnlUtil instance for use with the framework, with optional - * cache factories for Ognl Expression and BeanInfo caches. + * cache factories for OGNL Expression and BeanInfo caches. * - * @param ognlExpressionCacheFactory factory for Expression cache instance. If null, use default - * @param ognlBeanInfoCacheFactory for BeanInfo cache instance. If null, use default + * 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 = StrutsConstants.STRUTS_OGNL_EXPRESSIONCACHE_FACTORY, required = false) OgnlCacheFactory ognlExpressionCacheFactory, - @Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFOCACHE_FACTORY, required = false) OgnlCacheFactory, BeanInfo> ognlBeanInfoCacheFactory + @Inject(value = "ognlExpressionCacheFactory") OgnlCacheFactory ognlExpressionCacheFactory, + @Inject(value = "ognlBeanInfoCacheFactory") OgnlCacheFactory, BeanInfo> ognlBeanInfoCacheFactory ) { excludedClasses = Collections.unmodifiableSet(new HashSet<>()); excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>()); @@ -107,19 +111,12 @@ public class OgnlUtil { devModeExcludedClasses = Collections.unmodifiableSet(new HashSet<>()); devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>()); devModeExcludedPackageNames = Collections.unmodifiableSet(new HashSet<>()); - this.ognlExpressionCacheFactory = ognlExpressionCacheFactory; - this.ognlBeanInfoCacheFactory = ognlBeanInfoCacheFactory; - if (ognlExpressionCacheFactory != null) { - this.expressionCache = ognlExpressionCacheFactory.buildOgnlCache(); - } else { - this.expressionCache = new OgnlDefaultCache<>(25000, 16, 0.75f); - } - if (ognlBeanInfoCacheFactory != null) { - this.beanInfoCache = ognlBeanInfoCacheFactory.buildOgnlCache(); - } else { - this.beanInfoCache = new OgnlDefaultCache<>(25000, 16, 0.75f); - } + this.ognlExpressionCacheFactory = (ognlExpressionCacheFactory != null ? ognlExpressionCacheFactory : new DefaultOgnlExpressionCacheFactory<>()); + this.ognlBeanInfoCacheFactory = (ognlBeanInfoCacheFactory != null ? ognlBeanInfoCacheFactory : new DefaultOgnlBeanInfoCacheFactory<>()); + + this.expressionCache = this.ognlExpressionCacheFactory.buildOgnlCache(); + this.beanInfoCache = this.ognlBeanInfoCacheFactory.buildOgnlCache(); } @Inject diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java index a5cf7e0f6..7356d6374 100644 --- a/core/src/main/java/org/apache/struts2/StrutsConstants.java +++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java @@ -256,12 +256,16 @@ 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"; /** * 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"; diff --git a/core/src/main/java/org/apache/struts2/config/StrutsBeanSelectionProvider.java b/core/src/main/java/org/apache/struts2/config/StrutsBeanSelectionProvider.java index 69aa9258e..ba0c76f03 100644 --- a/core/src/main/java/org/apache/struts2/config/StrutsBeanSelectionProvider.java +++ b/core/src/main/java/org/apache/struts2/config/StrutsBeanSelectionProvider.java @@ -49,6 +49,7 @@ 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; @@ -366,6 +367,7 @@ import org.apache.struts2.views.util.UrlHelper; */ public class StrutsBeanSelectionProvider extends AbstractBeanSelectionProvider { + @Override public void register(ContainerBuilder builder, LocatableProperties props) { alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props); alias(ActionFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY_ACTIONFACTORY, builder, props); @@ -423,6 +425,9 @@ 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); + switchDevMode(props); } diff --git a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java index 013608216..2edf33fd1 100644 --- a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java +++ b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java @@ -144,6 +144,8 @@ public class ConstantConfig { private Boolean disallowProxyMemberAccess; private Integer ognlAutoGrowthCollectionLimit; private String staticContentPath; + private BeanConfig expressionCacheFactory; + private BeanConfig beaninfoCacheFactory; protected String beanConfToString(BeanConfig beanConf) { return beanConf == null ? null : beanConf.getName(); @@ -274,6 +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)); return map; } @@ -1341,4 +1345,28 @@ public class ConstantConfig { public void setStaticContentPath(String staticContentPath) { this.staticContentPath = StaticContentLoader.Validator.validateStaticContentPath(staticContentPath); } + + public BeanConfig getExpressionCacheFactory() { + return expressionCacheFactory; + } + + public void setExpressionCacheFactory(BeanConfig expressionCacheFactory) { + this.expressionCacheFactory = expressionCacheFactory; + } + + public void setExpressionCacheFactory(Class clazz) { + this.expressionCacheFactory = new BeanConfig(clazz, clazz.getName()); + } + + public BeanConfig getBeaninfoCacheFactory() { + return beaninfoCacheFactory; + } + + public void setBeaninfoCacheFactory(BeanConfig beaninfoCacheFactory) { + this.beaninfoCacheFactory = beaninfoCacheFactory; + } + + public void setBeaninfoCacheFactory(Class clazz) { + this.beaninfoCacheFactory = new BeanConfig(clazz, clazz.getName()); + } } diff --git a/core/src/main/resources/org/apache/struts2/default.properties b/core/src/main/resources/org/apache/struts2/default.properties index 74a85f137..4949d6434 100644 --- a/core/src/main/resources/org/apache/struts2/default.properties +++ b/core/src/main/resources/org/apache/struts2/default.properties @@ -229,6 +229,11 @@ struts.ognl.logMissingProperties=false ### if the application generates a lot of different expressions 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 + ### 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 ### content will be cleared (can help prevent memory leaks). diff --git a/core/src/main/resources/struts-default.xml b/core/src/main/resources/struts-default.xml index 775b3fbbf..f493fceac 100644 --- a/core/src/main/resources/struts-default.xml +++ b/core/src/main/resources/struts-default.xml @@ -231,8 +231,8 @@ - - + +