5

I have following action mapping

<action name="theAction" ...>
...
    <param name="param1">one</param>
    <param name="param2">two</param>
    ...
    <param name="paramN">nth-number</param>
...
</action>

I can get parameter map using following line in Interceptor

Map<String, Object> params = ActionContext.getContext().getParameters();

Just as above, is there any way to get interceptor parameters as defined in following mapping.

<action name="theAction" ...>
...
    <interceptor-ref name="theInterceptor">
        <param name="param1">one</param>
        <param name="param2">two</param>
        ...
        <param name="paramN">nth-number</param>
    </interceptor-ref>
...
</action>

And action parameters are defined in following way, action parameters and interceptor parameters should be accessible separately.

<action name="theAction" ...>
...
    <param name="param1">one</param>
    <param name="param2">two</param>
    ...
    <param name="paramN">nth-number</param>
    ....
    <interceptor-ref name="theInterceptor">
        <param name="param1">one</param>
        <param name="param2">two</param>
        ...
        <param name="paramN">nth-number</param>
    </interceptor-ref>
...
</action>

Please note that I don't want to declare parameter fields in my interceptor as

//all fields with their getters and setters
private String param1;
private String param2;
...
private String paramN;

After Dev Blanked's asnwer, I implemented his technique. It did not work so I am sharing my code here. I am using Struts 2.3.1.2.

Libraries

  • asm-3.3.jar
  • asm-commons-3.3.jar
  • asm-tree-3.3.jar
  • commons-fileupload-1.2.2.jar
  • commons-io-2.0.1.jar
  • commons-lang-2.5.jar
  • freemarker-2.3.18.jar
  • javassist-3.11.0.GA.jar
  • ognl-3.0.4.jar
  • struts2-core-2.3.1.2.jar
  • xwork-core-2.3.1.2.jar

Struts.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <constant name="struts.devMode" value="true" />

    <package name="the-base" namespace="/" extends="struts-default" abstract="true">

        <interceptors>
            <interceptor name="header" class="demo.interceptors.HttpHeaderInterceptor"></interceptor>

        <interceptor-stack name="theStack">
            <interceptor-ref name="defaultStack"></interceptor-ref>
                <interceptor-ref name="header"></interceptor-ref>
            </interceptor-stack>
        </interceptors>

        <default-interceptor-ref name="theStack"></default-interceptor-ref>

    </package>

    <package name="the-module" extends="the-base">
        <action name="theAction">
            <result>/the-action.jsp</result>
            <interceptor-ref name="theStack">
                <param name="header.Cache-control">no-store,no-cache</param>
                <param name="header.Pragma">no-cache</param>
                <param name="header.Expires">-1</param>
                <param name="header.arbitrary">true</param>
            </interceptor-ref>
        </action>
    </package>
</struts>

Interceptor

package demo.interceptors;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.StrutsStatics;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class HttpHeaderInterceptor extends AbstractInterceptor {

    private final Map<String, String> interceptorConfigs = new HashMap<String, String>();

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("Calling 'intercept' method.");
        HttpServletResponse response = (HttpServletResponse) invocation.getInvocationContext().get(StrutsStatics.HTTP_RESPONSE);

        for(Entry<String, String> entry: interceptorConfigs.entrySet()) {
            String header = entry.getKey();
            String value = entry.getValue();
            System.out.printf("Adding header: %s=%s\n",header,value);
            response.setHeader(header, value);
        }

        return invocation.invoke();
    }

    public Map<String, String> getInterceptorConfigs() {
        System.out.println("calling method 'getInterceptorConfigs'");
        return interceptorConfigs;
    }

    public void addInterceptorConfig(final String configName, final String configValue) {
        System.out.printf("Calling method 'addInterceptorConfig' with params configName = %s, configValue=%.\n",configName, configValue);
        interceptorConfigs.put(configName, configValue);
    }

}

Console Output when theAction is hit.

Calling 'intercept' method. 
Roman C
  • 49,761
  • 33
  • 66
  • 176
Bilal Mirza
  • 2,576
  • 4
  • 30
  • 57

2 Answers2

2

In your custom interceptor you can define a map like below

private final Map<String, String> interceptorConfigs = new HashMap<String, String>();

public Map<String, String> getInterceptorConfigs() {
    return interceptorConfigs;
}


public void addInterceptorConfig(final String configName, final String configValue) {
    interceptorConfigs.put(configName, configValue);
}

Then in your action mappings you can pass in parameters like below .. these will be stored in the map of the interceptor

    <action name="yourAction" class="your.actionClass">
        <result name="success">some.jsp</result>
        <interceptor-ref name="defaultStack">
            <param name="yourInterceptor.interceptorConfigs.key">value</param>
            <param name="yourInterceptor.interceptorConfigs.aParamName">paramValue</param>            </interceptor-ref>
    </action>

"yourInterceptor" refers to the name of the interceptor you have given when adding your interceptor to the struts.xml. When configured like above 'interceptorConfigs' map inside the interceptor will have , key/value pairs.

If you want to make these available to your action, you can just set the map as a context variable in the ActionContext. This can then be retrieved inside the action.

Roman C
  • 49,761
  • 33
  • 66
  • 176
Dev Blanked
  • 8,555
  • 3
  • 26
  • 32
  • I tried it but it didn't work. Methods `addInterceptorConfig` and/or `getInterceptorConfigs` are not being called when request is made. Do I need to implement some interface? – Bilal Mirza May 13 '13 at 05:02
  • @BilalMirza these methods would be called when application starts up and when struts.xml is being read. They won't be called for each request. The parameters you specify in the action mappings are going to remain the same for every request for that particular action. Struts will keep separate interceptor instances for each action mapping – Dev Blanked May 13 '13 at 16:52
  • I have experienced that these methods are not called anyway. Moreover, if Struts keeps separate interceptor instances for each request then each instance should be initialized for each instance and one of these methods should be called to set `interceptorConfigs`. But according to [this link](http://www.bullraider.com/java/struts2/tutorials/struts2-interceptor-life-cycle), interceptors are instantiated once, and not for eache request. Would you please explain it to me? – Bilal Mirza May 14 '13 at 04:50
  • As i've stated earlier 'Struts will keep separate interceptor instances for each action mapping' :-) and not for each request. Interceptor instance will be for each action-mapping not for each request. A given action mapping can serve any number of requests. For all these requests (for a given action mapping) one interceptor instance would be used. For that particular instance the configuration parameters you define would stay the same. Did u debug and find out that neither of the methods are called in the interceptor ? – Dev Blanked May 14 '13 at 10:38
  • Thanks, I got your point. And yes, I debugged the code, wrote log statements in methods, and applied breakpoints. Methods are not being called at all. – Bilal Mirza May 14 '13 at 11:49
  • @BilalMizra you have put the interceptor you wrote into the default stack with the name 'yourInterceptor' i assume – Dev Blanked May 14 '13 at 11:56
  • @DevBlanked, Yes, I replace `yourInterceprot` with interceptor name I have given in `struts.xml`. – Bilal Mirza May 14 '13 at 12:33
  • @BilalMizra is it possible to post your action mapping and the interceptor stack definition of the action mapping.. i've tested this on struts 2.3.4.1 – Dev Blanked May 14 '13 at 12:42
  • Oops... According to some contract, I can't share it. However, I will share the dummy reflection shortly after a day or two. I am going to retry your technique after one day break. – Bilal Mirza May 14 '13 at 12:46
  • 1
    @BilalMirza no-cache is wrong. It should be no-cache – Dev Blanked May 15 '13 at 13:05
  • 1
    Cache-control as a key might not work with OGNL because of the '-' but others should work without any issue – Dev Blanked May 15 '13 at 13:08
  • aaagh... `header.interceptorConfigs.` This is what I was missing. It was there in you answer but I was unable to see this clear thing. Thank you very much for your patience and support. – Bilal Mirza May 16 '13 at 05:29
  • 1
    `addInterceptorConfig` method is not needed. It is not called at all. – Bilal Mirza May 16 '13 at 05:31
1

To be short I'll say no, you can't get interceptor parameters if you defined them in the interceptor-ref element. The parameters are set and applied to the interceptor during build time. However, if you put parameters to the interceptor element like

<interceptor name="theInterceptor" class="com.struts.interceptor.TheInterceptor">
  <param name="param1">one</param>
  <param name="param2">two</param>
</interceptor>

you could retrieve them on the fly

PackageConfig packageConfig = Dispatcher.getInstance().getConfigurationManager().getConfiguration().getPackageConfig("default");
Map<String, Object> interceptorConfigs = packageConfig.getInterceptorConfigs();
InterceptorConfig interceptorConfig =  (InterceptorConfig)interceptorConfigs.get("theInterceptor");
Map<String, String> params = interceptorConfig.getParams();  

If you don't want to define properties on the interceptor to hold the values then OGNL will not set the values but will try, so I don't see the reasons to not to define these properties, the xml configuration marked invalid if your interceptor bean doesn't contain these properties and builder might be throw an exception in this case. So, not defining properties for params I'm not recommending.

Roman C
  • 49,761
  • 33
  • 66
  • 176
  • I have tried it but I am getting `interceprotConfigs` empty. As a result `inteptorConfig` is found null and NullPointerException is thrown while getting `params`. I have place my interceptor at last position in default stack. I have matched interceptor name from interceptor code and configuration (struts.xml). What did I miss? – Bilal Mirza May 14 '13 at 05:11
  • You got it empty because you didn't specify the package name used to map your interceptor. So, I needed to substitute a fictitious name, the same with other interceptor name because you didn't posted the code to configure interceptor I needed to do it. The package name is `"default"` you need to put it in the `struts.xml`. – Roman C May 14 '13 at 11:21
  • I changed package name and interceptor name according to my code. I am getting `packageConfig` with correct configuration as I defined in `struts.xml`. It means provided package name is correct. I wonder why I am not getting `interceptorConfigs`. – Bilal Mirza May 14 '13 at 12:00
  • As you said, the thing I was trying is not possible so I am accepting it as correct answer. But I have to know the other thing you told in your answer. – Bilal Mirza May 14 '13 at 12:04
  • @BilalMirza Probably you are not configured them with the `interceptors` tag, and the code you should run in the `intercept` method. – Roman C May 14 '13 at 12:30
  • I defined interceptor in `interceptors` tag, included it into a stack at last position, made that stack as default, called an action and found intercept method is being called. I placed your code in interceptor method and shared my findings. – Bilal Mirza May 14 '13 at 12:41
  • I am going to give it a little break. I will re do it after a little time. May be I am doing some stupid thing and unable to locate it at the moment. – Bilal Mirza May 14 '13 at 12:42
  • @BilalMirza I suggest you to edit the question and add your code to the end, then others might see it and give you tips. – Roman C May 14 '13 at 12:53
  • Dev Blanked's technique is fulfilling my needs. I am marking his answer as correct. Yet I am still want to learn your technique. I am and will be extremely thankful to you for guidance. – Bilal Mirza May 16 '13 at 05:36