You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2017/01/09 09:08:08 UTC

[3/3] struts git commit: WW-4687 Allows define interceptors with dynamic parameters

WW-4687 Allows define interceptors with dynamic parameters


Project: http://git-wip-us.apache.org/repos/asf/struts/repo
Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/2b12f06b
Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/2b12f06b
Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/2b12f06b

Branch: refs/heads/master
Commit: 2b12f06b01f01fb02f4fae0370ae1be48bf81be3
Parents: b9c05a7
Author: Lukasz Lenart <lu...@apache.org>
Authored: Mon Jan 9 10:07:20 2017 +0100
Committer: Lukasz Lenart <lu...@apache.org>
Committed: Mon Jan 9 10:07:20 2017 +0100

----------------------------------------------------------------------
 .../xwork2/DefaultActionInvocation.java         | 20 ++++++-
 .../config/entities/InterceptorMapping.java     | 14 ++++-
 .../config/providers/InterceptorBuilder.java    | 10 ++--
 .../factory/DefaultInterceptorFactory.java      | 12 +++-
 .../xwork2/interceptor/WithLazyParams.java      | 63 ++++++++++++++++++++
 .../xwork2/DefaultActionInvocationTest.java     | 34 +++++++++++
 .../xwork2/mock/MockLazyInterceptor.java        | 39 ++++++++++++
 core/src/test/resources/xwork-sample.xml        |  8 +++
 core/src/test/resources/xwork-test-default.xml  |  3 +-
 9 files changed, 191 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts/blob/2b12f06b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
index 639bf95..754ae5a 100644
--- a/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
@@ -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) {

http://git-wip-us.apache.org/repos/asf/struts/blob/2b12f06b/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorMapping.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorMapping.java b/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorMapping.java
index 846575e..36ba95c 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorMapping.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorMapping.java
@@ -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 + "]" ;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/struts/blob/2b12f06b/core/src/main/java/com/opensymphony/xwork2/config/providers/InterceptorBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/providers/InterceptorBuilder.java b/core/src/main/java/com/opensymphony/xwork2/config/providers/InterceptorBuilder.java
index fcf2484..8044c1a 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/providers/InterceptorBuilder.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/providers/InterceptorBuilder.java
@@ -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) {

http://git-wip-us.apache.org/repos/asf/struts/blob/2b12f06b/core/src/main/java/com/opensymphony/xwork2/factory/DefaultInterceptorFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/factory/DefaultInterceptorFactory.java b/core/src/main/java/com/opensymphony/xwork2/factory/DefaultInterceptorFactory.java
index 407aa35..3cdf6b5 100644
--- a/core/src/main/java/com/opensymphony/xwork2/factory/DefaultInterceptorFactory.java
+++ b/core/src/main/java/com/opensymphony/xwork2/factory/DefaultInterceptorFactory.java
@@ -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;

http://git-wip-us.apache.org/repos/asf/struts/blob/2b12f06b/core/src/main/java/com/opensymphony/xwork2/interceptor/WithLazyParams.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/WithLazyParams.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/WithLazyParams.java
new file mode 100644
index 0000000..e54cc73
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/WithLazyParams.java
@@ -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;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/2b12f06b/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java b/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java
index 7b7b3fe..98e3b1f 100644
--- a/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java
@@ -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 {

http://git-wip-us.apache.org/repos/asf/struts/blob/2b12f06b/core/src/test/java/com/opensymphony/xwork2/mock/MockLazyInterceptor.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/mock/MockLazyInterceptor.java b/core/src/test/java/com/opensymphony/xwork2/mock/MockLazyInterceptor.java
new file mode 100644
index 0000000..b43ee66
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/mock/MockLazyInterceptor.java
@@ -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();
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/2b12f06b/core/src/test/resources/xwork-sample.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/xwork-sample.xml b/core/src/test/resources/xwork-sample.xml
index 7f5e547..2cdee20 100644
--- a/core/src/test/resources/xwork-sample.xml
+++ b/core/src/test/resources/xwork-sample.xml
@@ -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>

http://git-wip-us.apache.org/repos/asf/struts/blob/2b12f06b/core/src/test/resources/xwork-test-default.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/xwork-test-default.xml b/core/src/test/resources/xwork-test-default.xml
index bceeb32..fdfc609 100644
--- a/core/src/test/resources/xwork-test-default.xml
+++ b/core/src/test/resources/xwork-test-default.xml
@@ -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"/>