Getting Interceptor Parameters in Struts 2
Asked Answered
L

2

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. 
Leucas answered 8/5, 2013 at 12:43 Comment(4)
Maybe with list parameter inside interceptor. Something like in this question: https://mcmap.net/q/1633844/-passing-array-of-string-as-static-param-in-struts-2/1700321.Unasked
It is not clear what you are trying to achieve :|Malvin
@Andrea Ligios, I have edited my question. However, my goal is to get parameters map defined inside <interceptor-ref> tag body.Leucas
@Aleksandr M, Thank you for the link. But in this case, any name of parameter can be defined in configuration.Leucas
C
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.

Cholla answered 12/5, 2013 at 9:59 Comment(13)
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?Leucas
@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 mappingCholla
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, interceptors are instantiated once, and not for eache request. Would you please explain it to me?Leucas
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 ?Cholla
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.Leucas
@BilalMizra you have put the interceptor you wrote into the default stack with the name 'yourInterceptor' i assumeCholla
@DevBlanked, Yes, I replace yourInterceprot with interceptor name I have given in struts.xml.Leucas
@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.1Cholla
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.Leucas
@BilalMirza <param name="header.Pragma">no-cache</param> is wrong. It should be <param name="header.interceptorConfigs.Pragma">no-cache</param>Cholla
Cache-control as a key might not work with OGNL because of the '-' but others should work without any issueCholla
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.Leucas
addInterceptorConfig method is not needed. It is not called at all.Leucas
I
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.

Inflate answered 9/5, 2013 at 16:59 Comment(9)
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?Leucas
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.Inflate
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.Leucas
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.Leucas
@BilalMirza Probably you are not configured them with the interceptors tag, and the code you should run in the intercept method.Inflate
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.Leucas
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.Leucas
@BilalMirza I suggest you to edit the question and add your code to the end, then others might see it and give you tips.Inflate
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.Leucas

© 2022 - 2024 — McMap. All rights reserved.