Yes, I think what you caught yourself is what I was driving towards :) Just for comparisons' sake, here's the filter and listener I came up with to deal with this (this is condensed for space, just showing the main bits of the puzzle)... this is what's going in JWP (unless someone points out a major flaw of course!)...
The filter: import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class SessionLimiterFilter implements Filter { private static String forwardTo; public void destroy() { } public void init(FilterConfig filterConfig) throws ServletException { int maxSessions = Integer.parseInt( filterConfig.getInitParameter("maxSessions")); SessionLimiterListener.setMaxSessions(maxSessions); forwardTo = filterConfig.getInitParameter("forwardTo"); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { filterChain.doFilter(request, response); HttpSession session = ((HttpServletRequest)request).getSession(); String ds = (String)session.getAttribute("SessionLimiter_DisallowSession"); if (ds != null) { session.setAttribute("SessionLimiter_NoDecreaseCount", "true"); session.invalidate(); request.getRequestDispatcher(forwardTo).forward(request, response); } } } The listener: import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class SessionLimiterListener implements HttpSessionListener { private static Log log = LogFactory.getLog(SessionLimiterListener.class); private static int maxSessions; private static volatile int sessionCount; public static void setMaxSessions(int inMaxSessions) { maxSessions = inMaxSessions; } public synchronized void sessionCreated(HttpSessionEvent se) { if (sessionCount == maxSessions) { HttpSession session = se.getSession(); session.setAttribute("SessionLimiter_DisallowSession", "true"); } else { sessionCount++; } } public synchronized void sessionDestroyed(HttpSessionEvent se) { HttpSession session = se.getSession(); String ndc = (String)session.getAttribute("SessionLimiter_NoDecreaseCount"); if (ndc == null) { sessionCount--; } } } Our code looks pretty similar... that's to be expected based on the solution path we took :) This code allows you to not really care how or where the session got created, and it of course allows you to set any number of sessions as the maximum. Basically, the flow is this: 1. Filter fires, nothing happens initially, chain continues. 2. Listener fires when session is created. If max sessions is already in use, set a flag in session and return. If max sessions NOT already in use, bump up session count and return. 3. We wind up back in the filter, which checks for the flag that may have been set in sessionCreated(). If it's found, we set a flag in session indicating NOT to decrease the session count (because the session that was just created doesn't really count towards reaching max sessions), invalidate the session (which of course executes sessionDestroyed() in the listener) and forward to the configured landing page. If the flag WAS NOT found, filter is done. 4. Now, when a session is destroyed, we of course reach sessionDestroyed() in the listener. In this case we check for that flag mentioned above that could have been set by the filter. If it's NOT present we decrease the session count because we know this was the result of logoff or timeout. If the flag IS found, count is not touched. In the end we came up with an almost identical solution really :) Great minds and all that jazz right?!? -- Frank W. Zammetti Founder and Chief Software Architect Omnytex Technologies http://www.omnytex.com On Thu, July 28, 2005 2:24 am, Tamas Szabo said: > Hi Frank, > >> Doesn't the sessionCount get decremented regardless of whether the >> session is being destroyed as the result of a regular logoff or >> timeout as well as if it was a rejected logon (i.e., max sessions >> already in use)? I dealt with this problem in the code I'm adding to >> Java Web Parts tomorrow, but maybe you found a better way than I did :) > > Yes, the sessionCount is decremented everytime a session is destroyed > regardless of regular logoff, 'forced' logoff (max sessions in use) :-)) > or timeout. > But that's what I wanted. Do you see a problem with it? > sessionCount is the number of existing sessions, so I decrement the > sessionCount everytime a session is destroyed(no matter why it was > destroyed). > >> Also, I was a bit surprised to learn that filters fire BEFORE >> listeners... it seemed more logical the other way around, but it's not >> reality. Any problem with what you've done with that in mind? >> > A SessionContextListener's sessionCreated method will execute when a new > HttpSession is created. > HttpSessions are created by some servlet or jsp code. > So if you use a Filter that catches any request, the Filter will fire > before any code that could create a session has a chance to execute. > > If the request is not for the 'special' appInUse.jsp or logout.jsp(by > the way I think that it's ok if we only treat appInUse.jsp specially, > logout.jsp can be > treated like all other resources) then I always get a session in the > usual way: > > HttpSession session = request.getSession(); > > As you know this will create a session if one doesn't exist or it will > get an existing session. > Because this is a Filter that catches everything, all the sessions will > be created at this point. > > This is also the point where the sessionCreated will be executed if the > session.isNew(). > In the sessionCreated a session is always created, but if maxSessions > was exceeded then we > flag the session. > > Back to the filter code, if the session is flagged then we invalidate it > and we redirect. > > It is always benefic to try to write down in words what your code does. > I think I found a a little problem in my solution :-) : > > Ex.: > MAX_SESSIONS = 1 > and there is one active session (User A) > > User B tries to connect, filter fires, flagged session is created > sessionCount is 2 now. > We are back in the filter before session.invalidate(). > > In another thread User A's session is destroyed and the > sessionDestroyed() is executed which decremenets sessionCount. > sessionCount = 1 > > User C comes in, in another thread the filter fires for his request, but > he will get a flagged session too, 'cause sessionCount is still 1. > > However this is a minor issue and it probably can be easily changed by > not incrementing/decrementing sessionCount in > sessionCreated()/sessionDestroyed() > if the session is flagged. > This is what you suggested in the first place? :-) > > Tamas > > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]