below are my interceptors & global-results as defined in struts.xml
<package name="auth_basic" extends="struts-default,tiles-default">
<interceptors>
<interceptor name="nlogin" class="interceptors.LoginInterceptor"/>
<interceptor-stack name="loginStack">
<interceptor-ref name="nlogin"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="loginStack"/>
<global-results>
<result name="login" type="redirectAction">gotostart</result>
<result name="input" type="redirectAction">gotostart</result>
</global-results>
.
.
.
</package>
The above configuration works fine, but when I use result chain
instead of redirectAction
it gives java.lang.StackOverflowError
Also when I use tiles
instead of chain, then also it throws java.lang.StackOverflowError
Can I not use action-chaining in global-results ?
Below is my interceptor code. Also, I would like to EMPHASIZE on the point that result type redirectAction is working fine, only tiles & chain are creating problems.
public String intercept(ActionInvocation ai) throws Exception {
try {
if (ai.getInvocationContext().getSession().get("user") == null) {
System.out.println("Session Expired/Invalid");
Object action = ai.getAction();
if (action instanceof ValidationAware) {
((ValidationAware) action).addActionError("Unauthorized access. Please Login first");
}
return "login";
}
return ai.invoke();
} catch (Exception e) {
e.printStackTrace();
}
return ai.invoke();
}
edited to include more code from struts.xml
<package name="default" extends="struts-default,tiles-default,json-default">
<default-action-ref name="gotostart"/>
<global-results>
<result name="input" type="tiles">tiles-home</result>
</global-results>
<action name="gotostart" class="actions.IndexAction" method="start">
<result name="success" type="tiles">tiles-home</result>
<result name="input" type="tiles">tiles-home</result>
</action>
</package>
Ok, got it.
If not logged in, you are returning an global result, login
, that is a chain
result type, then a call to another action.
The login
result type is under the same Interceptor Stack containing the nLogin Interceptor
.
This means that when you try to chain your login
result, you pass AGAIN inside your nLogin Interceptor
, checking again if user
is null, and returning login
result, in and endless loop.
You can:
return a JSP instead of chaining to another Action, like this:
<result name="login">myLogin.jsp</result>
or move your global result login
outside your custom Interceptor Stack scope (putting it under the default stack in a parent package, for example), like this:
<struts>
<package name="defaultPackage" extends="struts-default" >
<default-interceptor-ref name="defaultStack"/>
<global-results>
<result name="login" type="chain">
<param name="actionName">myLoginAction</param>
</result>
</global-results>
</package>
<package name="myLoginProtectedPackage" extends="defaultPackage">
<interceptors>
<interceptor name="nlogin" class="interceptors.LoginInterceptor"/>
<interceptor-stack name="loginStack">
<interceptor-ref name="nlogin"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="loginStack"/>
<global-results>
<result name="input" type="chain">
<param name="actionName">myLoginAction</param>
</result>
</global-results>
<action name="myLoginAction" class="...">
<result>myLogin.jsp</result>
</action>
</package>
</struts>
Don't ask me why with redirectAction works... it should be the same, but probably is due to their different behavior.
Please note that, according to the guide,
As a rule, Action Chaining is not recommended. First explore other options, such as the Redirect After Post technique.