I am trying to handle session timeout requests in my struts2 application using an Interceptor. Below are the files related to this:
Web.xml:
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<session-config>
<session-timeout>1</session-timeout>
</session-config>
Struts.xml:
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="sessionInterceptor"
class="com.platform.web.security.SessionInterceptor" />
</interceptors>
<action name="doLogin"
class="com.platform.web.action.LoginAction">
<result name="input">/login/login.jsp</result>
<result name="error">/login/login.jsp</result>
<result type="chain">menuAction</result>
</action>
<action name="menuAction"
class="com.platform.web.action.MenuAction">
<interceptor-ref name="sessionInterceptor"/> //Interceptor included here
<result name="SUCCESS">/jsp/main.jsp</result>
<result name="ERROR">/login/login.jsp</result>
<result name="input">/jsp/myFavourite.jsp</result>
</action>
Interceptor Class:
public class SessionInterceptor extends AbstractInterceptor implements StrutsStatics {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public String intercept(ActionInvocation invocation) throws Exception {
final ActionContext context = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context
.get(HTTP_REQUEST);
HttpSession session = request.getSession(false);
// Is there a "user" object stored in the user's HttpSession?
//Object user = session.getAttribute("User");
if (session == null) {
// The user has not logged in yet.
// Is the user attempting to log in right now?
//String loginAttempt = request.getParameter(LOGIN_ATTEMPT);
/* The user is attempting to log in. */
/*if (!StringUtils.isBlank(loginAttempt)) {
return invocation.invoke();
}*/
return "timeout";
} else {
return invocation.invoke();
}
}
}
LoginAction:
public class LoginAction extends MesActionSupport implements ServletRequestAware {
@Override
public String execute() throws Exception {
setActionNameForAudit("execute123");
FILE_LOGGER.debug("Entering into execute() ... ");
String strSessionId = "";
if (isValidUser == true) {
user = getUser();
strSessionId = request.getSession(true).getId();
setServletRequest(request);
session.put("SessionId", strSessionId);
setSession(session, user);
ServletActionContext.getRequest().getSession().setAttribute("User", user);
FILE_LOGGER.debug("Exit from LoginAction.execute() ... ");
return SUCCESS;
} else {
return ERROR;
}
}
MenuAction:
public class MenuAction extends MesActionSupport implements SessionAware, ParameterAware, RequestAware {
@Override
public String execute() throws Exception {
setActionNameForAudit("execute ");
User user = null; // To store current user
Map<String, ArrayList<String>> category = null; // To store all Menu
// Categories.
StringBuffer menu = new StringBuffer(""); // To store Menu String
StringBuffer dashboardMenu = new StringBuffer("");
// user = (User)(request.getSession().getAttribute("User")==null ? null : request.getSession().getAttribute("User")); //Request object IS NULL HERE!!
user = (User) (mapSession.get("User") == null ? null : mapSession
.get("User")); // mapSession object IS NULL HERE
FILE_LOGGER.debug("user is " + user == null);
if (user != null) {
menu = menuView.getMenu(user);
mapSession.put("Menu", menu.toString());
mapSession.put("dbMenu", dashboardMenu.toString());
ret = "SUCCESS";
} else if (user == null) {
ret = ERROR;
} else {
ret = SUCCESS;
}
return ret;
}
Flow is like this: 1. Login screen opens 2. User enters credentials and submits 3. LoginAction is called, user is authenticated 4. If valid user - MenuAction is called. Else redirect to Login.jsp
According to the above code, the session gets created in the LoginAction, control reaches the Interceptor where the session object is checked. If session exists the control reaches MenuAction.
But when this happens, the request
object gets reset to NULL! Earlier when I was not using an interceptor, the flow was working completely fine between LoginAction and MenuAction.
Does the interceptor resets the HTTPRequest? and hence the Session? As a result I am not able to proceed.
Any help?
I have many comments on this code/configuration, some trivial, some not.
There's zero reason to create your own session; don't.
When you declare an interceptor in an action configuration you must declare all interceptors. As configured, only the session interceptor is running for
menuAction
.That means no parameters will be filled, since no other interceptors are running.
In general, only use
SessionAware
to access the session. There is very rarely a need to access the request directly.Obviously the interceptor doesn't "set the request to null", that doesn't even make sense.
I have no idea what your
LoginAction
is supposed to be doing. What's the intent of lines likesetServletRequest(request);
orsetSession(session, user);
? There's nothing about those two lines that look correct.Name your success and error results just that,
"success"
and"error"
(lower case), if you're going to use theActionSupport.SUCCESS
andActionSupport.ERROR
constants. If you're not using those constants in this code, I'd recommend using other names for them, because it will confuse anybody that has actually used Struts 2 before.When posting code samples please remove stuff that isn't relevant. Particularly when you don't explicitly set syntax highlighting it makes things much more difficult to read.
Don't use code like
if (isValidUser == true)
, useif (isValidUser)
.Mind your conditionals: stuff like
if (user == null) ... else if (user != null) ... else ...
makes zero sense. The user is null, or it isn't: there's no third option.Avoid unnecessary, confusing logic, like
User currentUser = (User) (mapSession.get("User") == null ? null : mapSession.get("User"));
which basically says "If it's null, use null, otherwise return the value you just got, but get it again." WHY???Comments like
User user = null; // To store current user
are completely worthless. Isn't it obvious whatUser user
is? A user. Not obvious enough? How aboutUser currentUser
???Name plurals (e.g., collections) as something plural. A map of category names to lists isn't a single category.
Don't declare variables far away from where they're used; it's very confusing.
Put your JSP pages under
WEB-INF
somewhere to disallow direct client access.Avoid unnecessary language constructs, like when an
if
branch returns, anelse
isn't strictly necessary, and IMO, it adds noise. Similarly, consider returning as soon as you know you're returning. The latter is a bit more controversial, but I think people are coming around to realizing it's okay to have multiple return points in short methods, and IMO it's easier to think about.Use less code to say things. Create little utility methods to wrap up trivial functionality so it doesn't pollute the mainline code.
Use action chaining almost never.
There's more, but that's enough for now. Here's the actual relevant code, cleaned up. Some of it isn't actually relevant but I left it in anyway.
There's no way you can tell between whether the session has timed out or it just hasn't been created yet in your interceptor, unless you add some tracking to your front-end, in primitive case it could be just a single request parameter.
A combination of HttpSessionListener and Servlet3 + AJAX Push notifications would be the right way to do it.