Author: lukaszlenart Date: Tue Jan 22 12:44:45 2013 New Revision: 1436878 URL: http://svn.apache.org/viewvc?rev=1436878&view=rev Log: WW-3971 adds ContainerHolder to reduce numbers of calls to getConfiguration() and optimize RuntimeConfiguration class to more thread friendly
Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ContainerHolder.java Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ContainerHolder.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ContainerHolder.java?rev=1436878&view=auto ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ContainerHolder.java (added) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ContainerHolder.java Tue Jan 22 12:44:45 2013 @@ -0,0 +1,33 @@ +package org.apache.struts2.dispatcher; + +import com.opensymphony.xwork2.inject.Container; +import org.apache.struts2.StrutsConstants; + +/** + * Simple class to hold Container instance per thread to minimise number of attempts + * to read configuration and build each time a new configuration. + * + * Thus depends on {@link StrutsConstants#STRUTS_CONFIGURATION_XML_RELOAD} flag, + * if set to false just use stored container, configuration will do not change. + */ +class ContainerHolder { + + private static ThreadLocal<Container> instance = new ThreadLocal<Container>(); + + public static void store(Container instance) { + boolean reloadConfigs = Boolean.valueOf(instance.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)); + if (!reloadConfigs) { + // reloadConfigs is false, configuration will do not change, just keep it + ContainerHolder.instance.set(instance); + } + } + + public static Container get() { + return ContainerHolder.instance.get(); + } + + public static void clear() { + ContainerHolder.instance.set(null); + } + +} Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java?rev=1436878&r1=1436877&r2=1436878&view=diff ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java Tue Jan 22 12:44:45 2013 @@ -432,6 +432,8 @@ public class Dispatcher { boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD)); LocalizedTextUtil.setReloadBundles(reloadi18n); + ContainerHolder.store(container); + return container; } @@ -908,8 +910,10 @@ public class Dispatcher { * Modify the ConfigurationManager instance * * @param mgr The configuration manager + * @deprecated should be removed as is used only in tests */ public void setConfigurationManager(ConfigurationManager mgr) { + ContainerHolder.clear(); this.configurationManager = mgr; } @@ -918,6 +922,9 @@ public class Dispatcher { * @return Our dependency injection container */ public Container getContainer() { + if (ContainerHolder.get() != null) { + return ContainerHolder.get(); + } ConfigurationManager mgr = getConfigurationManager(); if (mgr == null) { throw new IllegalStateException("The configuration manager shouldn't be null"); @@ -926,8 +933,11 @@ public class Dispatcher { if (config == null) { throw new IllegalStateException("Unable to load configuration"); } else { - return config.getContainer(); + Container container = config.getContainer(); + ContainerHolder.store(container); + return container; } } } + } Modified: struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java?rev=1436878&r1=1436877&r2=1436878&view=diff ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java (original) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java Tue Jan 22 12:44:45 2013 @@ -194,6 +194,8 @@ public class DispatcherTest extends Stru Mock mockContainer = new Mock(Container.class); String reloadConfigs = container.getInstance(String.class, XWorkConstants.RELOAD_XML_CONFIGURATION); + mockContainer.expectAndReturn("getInstance", C.args(C.eq(String.class), C.eq(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)), + reloadConfigs); mockContainer.expectAndReturn("getInstance", C.args(C.eq(String.class), C.eq(XWorkConstants.RELOAD_XML_CONFIGURATION)), reloadConfigs); mockContainer.expectAndReturn("getInstance", C.args(C.eq(ObjectFactory.class)), destroyedObjectFactory); @@ -228,6 +230,8 @@ public class DispatcherTest extends Stru Mock mockContainer = new Mock(Container.class); mockContainer.matchAndReturn("getInstance", C.args(C.eq(ObjectFactory.class)), new ObjectFactory()); String reloadConfigs = container.getInstance(String.class, XWorkConstants.RELOAD_XML_CONFIGURATION); + mockContainer.expectAndReturn("getInstance", C.args(C.eq(String.class), C.eq(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)), + reloadConfigs); mockContainer.expectAndReturn("getInstance", C.args(C.eq(String.class), C.eq(XWorkConstants.RELOAD_XML_CONFIGURATION)), reloadConfigs); Modified: struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java?rev=1436878&r1=1436877&r2=1436878&view=diff ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java (original) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java Tue Jan 22 12:44:45 2013 @@ -38,6 +38,7 @@ import org.apache.struts2.StrutsConstant import org.apache.struts2.TestAction; import org.apache.struts2.TestConfigurationProvider; import org.apache.struts2.components.Form; +import org.apache.struts2.dispatcher.Dispatcher; import org.apache.struts2.views.jsp.AbstractUITagTest; import org.apache.struts2.views.jsp.ActionTag; import org.easymock.EasyMock; @@ -249,6 +250,8 @@ public class FormTagTest extends Abstrac } }); + Dispatcher.getInstance().setConfigurationManager(configurationManager); + FormTag tag = new FormTag(); tag.setPageContext(pageContext); tag.setName("myForm"); @@ -336,6 +339,8 @@ public class FormTagTest extends Abstrac } }); + Dispatcher.getInstance().setConfigurationManager(configurationManager); + FormTag tag = new FormTag(); tag.setPageContext(pageContext); tag.setName("myForm"); @@ -420,6 +425,8 @@ public class FormTagTest extends Abstrac } }); + Dispatcher.getInstance().setConfigurationManager(configurationManager); + FormTag tag = new FormTag(); tag.setPageContext(pageContext); tag.setName("myForm"); @@ -501,6 +508,8 @@ public class FormTagTest extends Abstrac } }); + Dispatcher.getInstance().setConfigurationManager(configurationManager); + FormTag tag = new FormTag(); tag.setPageContext(pageContext); tag.setName("myForm"); Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java?rev=1436878&r1=1436877&r2=1436878&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java (original) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java Tue Jan 22 12:44:45 2013 @@ -69,6 +69,7 @@ import com.opensymphony.xwork2.util.refl import ognl.PropertyAccessor; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -337,8 +338,6 @@ public class DefaultConfiguration implem configs.put(actionName, buildFullActionConfig(packageConfig, baseConfig)); } - - namespaceActionConfigs.put(namespace, configs); if (packageConfig.getFullDefaultActionRef() != null) { namespaceConfigs.put(namespace, packageConfig.getFullDefaultActionRef()); @@ -346,7 +345,9 @@ public class DefaultConfiguration implem } } - return new RuntimeConfigurationImpl(namespaceActionConfigs, namespaceConfigs); + PatternMatcher<int[]> matcher = container.getInstance(PatternMatcher.class); + return new RuntimeConfigurationImpl(Collections.unmodifiableMap(namespaceActionConfigs), + Collections.unmodifiableMap(namespaceConfigs), matcher); } private void setDefaultResults(Map<String, ResultConfig> results, PackageConfig packageContext) { @@ -396,8 +397,6 @@ public class DefaultConfiguration implem } } - - return new ActionConfig.Builder(baseConfig) .addParams(params) .addResultConfigs(results) @@ -408,25 +407,24 @@ public class DefaultConfiguration implem } - private class RuntimeConfigurationImpl implements RuntimeConfiguration { + private static class RuntimeConfigurationImpl implements RuntimeConfiguration { + private Map<String, Map<String, ActionConfig>> namespaceActionConfigs; private Map<String, ActionConfigMatcher> namespaceActionConfigMatchers; private NamespaceMatcher namespaceMatcher; private Map<String, String> namespaceConfigs; - public RuntimeConfigurationImpl(Map<String, Map<String, ActionConfig>> namespaceActionConfigs, Map<String, String> namespaceConfigs) { + public RuntimeConfigurationImpl(Map<String, Map<String, ActionConfig>> namespaceActionConfigs, + Map<String, String> namespaceConfigs, + PatternMatcher<int[]> matcher) { this.namespaceActionConfigs = namespaceActionConfigs; this.namespaceConfigs = namespaceConfigs; - PatternMatcher<int[]> matcher = container.getInstance(PatternMatcher.class); - this.namespaceActionConfigMatchers = new LinkedHashMap<String, ActionConfigMatcher>(); this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet()); for (String ns : namespaceActionConfigs.keySet()) { - namespaceActionConfigMatchers.put(ns, - new ActionConfigMatcher(matcher, - namespaceActionConfigs.get(ns), true)); + namespaceActionConfigMatchers.put(ns, new ActionConfigMatcher(matcher, namespaceActionConfigs.get(ns), true)); } } @@ -439,7 +437,7 @@ public class DefaultConfiguration implem * @param namespace the namespace for the action or null for the empty namespace, "" * @return the configuration information for action requested */ - public synchronized ActionConfig getActionConfig(String namespace, String name) { + public ActionConfig getActionConfig(String namespace, String name) { ActionConfig config = findActionConfigInNamespace(namespace, name); // try wildcarded namespaces @@ -466,7 +464,7 @@ public class DefaultConfiguration implem return config; } - ActionConfig findActionConfigInNamespace(String namespace, String name) { + private ActionConfig findActionConfigInNamespace(String namespace, String name) { ActionConfig config = null; if (namespace == null) { namespace = ""; @@ -494,7 +492,7 @@ public class DefaultConfiguration implem * * @return a Map of namespace - > Map of ActionConfig objects, with the key being the action name */ - public synchronized Map<String, Map<String, ActionConfig>> getActionConfigs() { + public Map<String, Map<String, ActionConfig>> getActionConfigs() { return namespaceActionConfigs; }