mirror of
https://github.com/apache/struts.git
synced 2026-08-06 15:17:00 +00:00
WW-4687 Allows define interceptors with dynamic parameters
This commit is contained in:
@@ -21,7 +21,9 @@ import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.interceptor.PreResultListener;
|
||||
import com.opensymphony.xwork2.interceptor.WithLazyParams;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
@@ -67,6 +69,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
protected Container container;
|
||||
protected UnknownHandlerManager unknownHandlerManager;
|
||||
protected OgnlUtil ognlUtil;
|
||||
protected WithLazyParams.LazyParamInjector lazyParamInjector;
|
||||
|
||||
public DefaultActionInvocation(final Map<String, Object> extraContext, final boolean pushAction) {
|
||||
this.extraContext = extraContext;
|
||||
@@ -233,11 +236,15 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
}
|
||||
|
||||
if (interceptors.hasNext()) {
|
||||
final InterceptorMapping interceptor = interceptors.next();
|
||||
String interceptorMsg = "interceptor: " + interceptor.getName();
|
||||
final InterceptorMapping interceptorMapping = interceptors.next();
|
||||
String interceptorMsg = "interceptorMapping: " + interceptorMapping.getName();
|
||||
UtilTimerStack.push(interceptorMsg);
|
||||
try {
|
||||
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
|
||||
Interceptor interceptor = interceptorMapping.getInterceptor();
|
||||
if (interceptor instanceof WithLazyParams) {
|
||||
interceptor = lazyParamInjector.injectParams(interceptor, interceptorMapping.getParams(), invocationContext);
|
||||
}
|
||||
resultCode = interceptor.intercept(DefaultActionInvocation.this);
|
||||
} finally {
|
||||
UtilTimerStack.pop(interceptorMsg);
|
||||
}
|
||||
@@ -400,6 +407,13 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
invocationContext.setName(proxy.getActionName());
|
||||
|
||||
createInterceptors(proxy);
|
||||
|
||||
prepareLazyParamInjector(invocationContext.getValueStack());
|
||||
}
|
||||
|
||||
protected void prepareLazyParamInjector(ValueStack valueStack) {
|
||||
lazyParamInjector = new WithLazyParams.LazyParamInjector(valueStack);
|
||||
container.inject(lazyParamInjector);
|
||||
}
|
||||
|
||||
protected void createInterceptors(ActionProxy proxy) {
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.opensymphony.xwork2.config.entities;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <code>InterceptorMapping</code>
|
||||
@@ -30,10 +32,16 @@ public class InterceptorMapping implements Serializable {
|
||||
|
||||
private String name;
|
||||
private Interceptor interceptor;
|
||||
private final Map<String, String> params;
|
||||
|
||||
public InterceptorMapping(String name, Interceptor interceptor) {
|
||||
this(name, interceptor, new HashMap<String, String>());
|
||||
}
|
||||
|
||||
public InterceptorMapping(String name, Interceptor interceptor, Map<String, String> params) {
|
||||
this.name = name;
|
||||
this.interceptor = interceptor;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -44,6 +52,10 @@ public class InterceptorMapping implements Serializable {
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
public Map<String, String> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -65,7 +77,7 @@ public class InterceptorMapping implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InterceptorMapping: [" + name + "] => [" + interceptor.getClass().getName() + ']';
|
||||
return "InterceptorMapping: [" + name + "] => [" + interceptor.getClass().getName() + "] with params [" + params + "]" ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.util.location.Location;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -43,7 +44,6 @@ public class InterceptorBuilder {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(InterceptorBuilder.class);
|
||||
|
||||
|
||||
/**
|
||||
* Builds a list of interceptors referenced by the refName in the supplied PackageConfig (InterceptorMapping object).
|
||||
*
|
||||
@@ -67,13 +67,11 @@ public class InterceptorBuilder {
|
||||
InterceptorConfig config = (InterceptorConfig) referencedConfig;
|
||||
Interceptor inter;
|
||||
try {
|
||||
|
||||
inter = objectFactory.buildInterceptor(config, refParams);
|
||||
result.add(new InterceptorMapping(refName, inter));
|
||||
result.add(new InterceptorMapping(refName, inter, refParams));
|
||||
} catch (ConfigurationException ex) {
|
||||
LOG.warn("Unable to load config class {} at {} probably due to a missing jar, which might be fine if you never plan to use the {} interceptor",
|
||||
config.getClassName(), ex.getLocation(), config.getName());
|
||||
LOG.error("Unable to load config class {}", config.getClassName(), ex);
|
||||
LOG.warn(new ParameterizedMessage("Unable to load config class {} at {} probably due to a missing jar, which might be fine if you never plan to use the {} interceptor",
|
||||
config.getClassName(), ex.getLocation(), config.getName()), ex);
|
||||
}
|
||||
|
||||
} else if (referencedConfig instanceof InterceptorStackConfig) {
|
||||
|
||||
@@ -5,7 +5,10 @@ import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.interceptor.WithLazyParams;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -15,6 +18,8 @@ import java.util.Map;
|
||||
*/
|
||||
public class DefaultInterceptorFactory implements InterceptorFactory {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultInterceptorFactory.class);
|
||||
|
||||
private ObjectFactory objectFactory;
|
||||
private ReflectionProvider reflectionProvider;
|
||||
|
||||
@@ -40,7 +45,12 @@ public class DefaultInterceptorFactory implements InterceptorFactory {
|
||||
try {
|
||||
// interceptor instances are long-lived and used across user sessions, so don't try to pass in any extra context
|
||||
Object o = objectFactory.buildBean(interceptorClassName, null);
|
||||
reflectionProvider.setProperties(params, o);
|
||||
if (o instanceof WithLazyParams) {
|
||||
LOG.debug("Interceptor {} is marked with interface {} and params will be set during action invocation",
|
||||
interceptorClassName, WithLazyParams.class.getName());
|
||||
} else {
|
||||
reflectionProvider.setProperties(params, o);
|
||||
}
|
||||
|
||||
if (o instanceof Interceptor) {
|
||||
Interceptor interceptor = (Interceptor) o;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.TextParser;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interceptors marked with this interface won't be fully initialised during initialisation.
|
||||
* Appropriated params will be injected just before usage of the interceptor.
|
||||
*
|
||||
* Please be aware that in such case {@link Interceptor#init()} method must be prepared for this.
|
||||
*
|
||||
* @since 2.5.9
|
||||
*/
|
||||
public interface WithLazyParams {
|
||||
|
||||
class LazyParamInjector {
|
||||
|
||||
protected OgnlUtil ognlUtil;
|
||||
protected TextParser textParser;
|
||||
protected ReflectionProvider reflectionProvider;
|
||||
|
||||
private final TextParseUtil.ParsedValueEvaluator valueEvaluator;
|
||||
|
||||
public LazyParamInjector(final ValueStack valueStack) {
|
||||
valueEvaluator = new TextParseUtil.ParsedValueEvaluator() {
|
||||
public Object evaluate(String parsedValue) {
|
||||
return valueStack.findValue(parsedValue); // no asType !!!
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setTextParser(TextParser textParser) {
|
||||
this.textParser = textParser;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
|
||||
this.reflectionProvider = reflectionProvider;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setOgnlUtil(OgnlUtil ognlUtil) {
|
||||
this.ognlUtil = ognlUtil;
|
||||
}
|
||||
|
||||
public Interceptor injectParams(Interceptor interceptor, Map<String, String> params, ActionContext invocationContext) {
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
Object paramValue = textParser.evaluate(new char[]{ '$' }, entry.getValue(), valueEvaluator, TextParser.DEFAULT_LOOP_COUNT);
|
||||
ognlUtil.setProperty(entry.getKey(), paramValue, interceptor, invocationContext.getContextMap());
|
||||
}
|
||||
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,20 @@ package com.opensymphony.xwork2;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
|
||||
import com.opensymphony.xwork2.mock.MockActionProxy;
|
||||
import com.opensymphony.xwork2.mock.MockContainer;
|
||||
import com.opensymphony.xwork2.mock.MockInterceptor;
|
||||
import com.opensymphony.xwork2.mock.MockLazyInterceptor;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
@@ -298,6 +302,36 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
|
||||
assertEquals("success", result);
|
||||
}
|
||||
|
||||
public void testInvokeWithLazyParams() throws Exception {
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("blah", "this is blah");
|
||||
|
||||
HashMap<String, Object> extraContext = new HashMap<>();
|
||||
extraContext.put(ActionContext.PARAMETERS, HttpParameters.create(params).build());
|
||||
|
||||
DefaultActionInvocation defaultActionInvocation = new DefaultActionInvocation(extraContext, true);
|
||||
container.inject(defaultActionInvocation);
|
||||
|
||||
ActionProxy actionProxy = actionProxyFactory.createActionProxy( "", "LazyFoo", null, extraContext);
|
||||
defaultActionInvocation.init(actionProxy);
|
||||
defaultActionInvocation.invoke();
|
||||
|
||||
SimpleAction action = (SimpleAction) defaultActionInvocation.getAction();
|
||||
|
||||
assertEquals("this is blah", action.getBlah());
|
||||
assertEquals("this is blah", action.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
// ensure we're using the default configuration, not simple config
|
||||
XmlConfigurationProvider configurationProvider = new XmlConfigurationProvider("xwork-sample.xml");
|
||||
container.inject(configurationProvider);
|
||||
loadConfigurationProviders(configurationProvider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DefaultActionInvocationTester extends DefaultActionInvocation {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2006,2009 The 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.mock;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.SimpleAction;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.interceptor.WithLazyParams;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class MockLazyInterceptor extends AbstractInterceptor implements WithLazyParams {
|
||||
|
||||
private String foo = "";
|
||||
|
||||
public void setFoo(String foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (invocation.getAction() instanceof SimpleAction) {
|
||||
((SimpleAction) invocation.getAction()).setName(foo);
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,14 @@
|
||||
<interceptor-ref name="defaultStack"/>
|
||||
</action>
|
||||
|
||||
<action name="LazyFoo" class="com.opensymphony.xwork2.SimpleAction">
|
||||
<result name="error" type="void" />
|
||||
<interceptor-ref name="params"/>
|
||||
<interceptor-ref name="lazy">
|
||||
<param name="foo">${blah}</param>
|
||||
</interceptor-ref>
|
||||
</action>
|
||||
|
||||
<action name="WildCard" class="com.opensymphony.xwork2.SimpleAction">
|
||||
<param name="foo">17</param>
|
||||
<param name="bar">23</param>
|
||||
|
||||
@@ -19,10 +19,11 @@
|
||||
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
|
||||
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
|
||||
<interceptor name="validation" class="com.opensymphony.xwork2.validator.ValidationInterceptor"/>
|
||||
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
|
||||
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
|
||||
<interceptor name="test" class="com.opensymphony.xwork2.mock.MockInterceptor">
|
||||
<param name="foo">expectedFoo</param>
|
||||
</interceptor>
|
||||
<interceptor name="lazy" class="com.opensymphony.xwork2.mock.MockLazyInterceptor"/>
|
||||
|
||||
<interceptor-stack name="defaultStack">
|
||||
<interceptor-ref name="staticParams"/>
|
||||
|
||||
Reference in New Issue
Block a user