Jonathan,

Sample HTTPSessionListener and SessionMonitor classes below – if you are
using a clustered environment you would want to adjust this to leverage a db
oriented solution – you’ll probably find some holes in it but for my
purposes it works as required.  I use it to display a grid of
SessionMonitors that auto refreshes every x seconds.  It displays some
useful user info and allows a kill of the user’s session.  I call the
updateLastSeen method each time a user hits a new page.  You can get most of
this information from the http log anyway, but you might find it a useful
base to perform other operations with.

package com.a.b.util.beans;

import java.io.Serializable;
import java.util.Date;

/**
* Utility class to store details about session creation
* @author Jim
*
*/
public class SessionMonitor implements Serializable, Comparable {
                /**
                * 
                 */
                private static final long serialVersionUID =
-7043353042185132418L;
                
                private Date createTime;
                private String sessionId;
                private String iPAddress;
                private String UserName;
                private String lastSeen;
                private boolean active;
                
                private transient String createTimeStr;
                // A convenience placeholder to replace with an actionlink
in a grid to allow kill of a session
                private transient String killSession;
                
                public String getCreateTimeStr(){
                                return createTime.toString();
                }

                public Date getCreateTime() {
                                return createTime;
                }
                public void setCreateTime(Date createTime) {
                                this.createTime = createTime;
                }
                public String getSessionId() {
                                return sessionId;
                }
                public void setSessionId(String sessionId) {
                                this.sessionId = sessionId;
                }
                public String getIPAddress() {
                                return iPAddress;
                }

                public void setIPAddress(String address) {
                                iPAddress = address;
                }

                public SessionMonitor(Date createTime, String sessionId) {
                                this.createTime = createTime;
                                this.sessionId = sessionId;
                                this.active = true;
                }

                public String getUserName() {
                                return UserName;
                }

                public void setUserName(String userName) {
                                UserName = userName;
                }

                public String getLastSeen() {
                                return lastSeen;
                }

                public void setLastSeen(String lastSeen) {
                                this.lastSeen = lastSeen;
                }

                public boolean isActive() {
                                return active;
                }

                public void setActive(boolean active) {
                                this.active = active;
                }

                public String getKillSession() {
                                return killSession;
                }

                public void setKillSession(String killSession) {
                                this.killSession = killSession;
                }

                public int compareTo(Object o) {
                                return
(this.createTime.compareTo(((SessionMonitor)o).createTime) < 0) ? 0 : -1;
                }
                
}

package com.a.b.listeners;

import java.io.*;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.tapestry5.TapestryFilter;
import org.apache.tapestry5.ioc.Registry;
import org.apache.tapestry5.services.ApplicationGlobals;
import org.apache.tapestry5.services.RequestGlobals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.a.b.entities.core.SessionContext;
import com.a.b.entities.core.user.UserAccessLog;
import com.a.b.services.UserAccessLogEntityManager;
import com.a.b.util.DateUtils;
import com.a.b.util.beans.SessionMonitor;

/**
* jc1 - 2010.02.04 Used to count the number of sessions
*  
 * @author jc1
*
*/
public class MySessionListener implements HttpSessionListener {
                private static final String HASHMAP_NAME = "sessionMap"; 
                // The number of days after which to purge old sessions from
the session map
                public static final int PURGE_DAYS = 1;
                
                private final static Logger log =
LoggerFactory.getLogger(MySessionListener.class); 
                
                LinkedHashMap<String, SessionMonitor> sessionMap = null;
                ServletContext context = null;

                /**
                * TODO: - rethink this for clustering - a DB persisted
entity will probably have to be used to 
                 * CRUD the SessionMonitor objects as the ServletContext may
not be replicated depending on the 
                 * cluster provider.  Other relevant notes:
                * 
                 *  - in a cluster the sessionId often has an affinity node
ID appended - this will need truncation
                *    for correct lookups
                *    
                 *  - in a cluster if we are in a different session context
we will lose the ability to kill the 
                 *    HttpSession - a DB oriented solution is required to
kill the user
                */
                
                @SuppressWarnings("unchecked")
                public void sessionCreated(HttpSessionEvent event) {
                                HttpSession session = event.getSession();
                                if (context == null){
                                                context =
session.getServletContext();
                                }
                                sessionMap = (LinkedHashMap<String,
SessionMonitor>) context.getAttribute(HASHMAP_NAME);
                                if (sessionMap == null) {
                                               
context.setAttribute(HASHMAP_NAME, new LinkedHashMap());
                                                sessionMap =
(LinkedHashMap<String, SessionMonitor>) context.getAttribute(HASHMAP_NAME);
                                }
                                sessionMap.put(session.getId(), new
SessionMonitor(new Date(), session.getId()));
                                // put a key -> value pair of the session
into the servlet context - this will allow us to look it up and kill it from
another session
                                context.setAttribute(session.getId(),
session);
                }

                public void sessionDestroyed(HttpSessionEvent event) {
                                HttpSession session = event.getSession();
                                try {
                                               
((SessionMonitor)sessionMap.get(session.getId())).setActive(false);
                                } catch (Exception e) {
                                                // ignore - this was
triggering an NPE if executed after natural session timeout
                                }
                                //Remove the reference to the session in the
servlet context 
                                if (context == null){
                                                context =
session.getServletContext();
                                }                              
                                context.removeAttribute(session.getId());
                                // Log when the user's session times out
                                Registry registry = (Registry)
context.getAttribute(TapestryFilter.REGISTRY_CONTEXT_NAME);
                                if (registry != null){
                                                UserAccessLogEntityManager
ualem = registry.getService(UserAccessLogEntityManager.class);
                                                if (ualem != null){
                                                                try {
                                 
                                              // The sso: prefix below was
taken from the Persist.java source used to do session persistence in T5.2.0
- if this breaks probably the prefix / strategy has changed and the new
source should be checked for a solution.
                                                                            
    ualem.saveUserAccessLogWithCommit(new UserAccessLog("User Session
Timeout / Killed"), (SessionContext)session.getAttribute("sso:"+
SessionContext.class.getName()));
                                                                } catch
(Exception e) {
                                                                            
    log.error("Unable to log User Session Timeout / Killed event", e);
                                                               
}                                                              
                                                }
                                }

                }
                
                /**
                * TODO - should this be synchronised? - sessionId should be
unique even across a cluster so no concurrent modification events should
take place?
                * @param applicationGlobals
                * @param sessionId
                * @param lastSeen
                */
                public static void updateLastSeen(ApplicationGlobals
applicationGlobals, String sessionId, String lastSeen){
                                ServletContext servletContext =
applicationGlobals.getServletContext();
                                Map sessionMap =
(Map)servletContext.getAttribute(MySessionListener.HASHMAP_NAME);
                                if (sessionMap == null) {return;}
                                SessionMonitor sessionMonitor =
(SessionMonitor)sessionMap.get(sessionId);
                                if (sessionMonitor == null) {return;}
                                sessionMonitor.setLastSeen(lastSeen); 
                }
                
                public static void setUserName(ApplicationGlobals
applicationGlobals, RequestGlobals requestGlobals, String sessionId, String
userName){
                                ServletContext servletContext =
applicationGlobals.getServletContext();
                                Map sessionMap =
(Map)servletContext.getAttribute(MySessionListener.HASHMAP_NAME);
                                SessionMonitor sessionMonitor =
(SessionMonitor)sessionMap.get(sessionId);
                                sessionMonitor.setUserName(userName);
                                HttpServletRequest req =
requestGlobals.getHTTPServletRequest();
                               
sessionMonitor.setIPAddress(req.getRemoteAddr() + '/' 
                                                                +
req.getHeader("VIA") + '/' 
                                                                +
req.getHeader("X-FORWARDED-FOR"));
                }
                
                public static void setInActive(ApplicationGlobals
applicationGlobals, String sessionId){
                                ServletContext servletContext =
applicationGlobals.getServletContext();
                                Map sessionMap =
(Map)servletContext.getAttribute(MySessionListener.HASHMAP_NAME);
                               
((SessionMonitor)sessionMap.get(sessionId)).setActive(false); 
                }              
                
                synchronized public static void
removeOldSessionsFromMap(ApplicationGlobals applicationGlobals){
                                try {
                                                ServletContext
servletContext = applicationGlobals.getServletContext();
                                                Map sessionMap =
(Map)servletContext.getAttribute(MySessionListener.HASHMAP_NAME);
                                                Collection sessionMonitors =
sessionMap.values();
                                                Iterator
sessionMonitorsIterator = sessionMonitors.iterator();
       Date now = new java.util.Date();
                                                while
(sessionMonitorsIterator.hasNext()){
                                                               
SessionMonitor sessionMonitor =
(SessionMonitor)sessionMonitorsIterator.next();
                                                                if
(DateUtils.getDifferenceInDays(sessionMonitor.getCreateTime(), now) >
PURGE_DAYS){
                                                                            
    sessionMonitorsIterator.remove();
                                                                }
                                                }
                                } catch (Exception e){
                                                log.error("Could remove old
sessions from map", e);                                   
                                }
                }

                synchronized public static void
removeDeadSessionsFromMap(ApplicationGlobals applicationGlobals){
                                try {
                                                ServletContext
servletContext = applicationGlobals.getServletContext();
                                                Map sessionMap =
(Map)servletContext.getAttribute(MySessionListener.HASHMAP_NAME);
                                                Collection sessionMonitors =
sessionMap.values();
                                                Iterator
sessionMonitorsIterator = sessionMonitors.iterator();
                                                while
(sessionMonitorsIterator.hasNext()){
                                                               
SessionMonitor sessionMonitor =
(SessionMonitor)sessionMonitorsIterator.next();
                                                                if
(sessionMonitor.isActive() == false){
                                                                            
    sessionMonitorsIterator.remove();
                                                                }
                                                }
                                } catch (Exception e){
                                                log.error("Could remove dead
sessions from map", e);                                                
                                }
                                                
                }
                
                synchronized public static void
invalidateSession(ApplicationGlobals applicationGlobals, String sessionId){
                                ServletContext servletContext =
applicationGlobals.getServletContext();
                                try {
                                                HttpSession session =
(HttpSession)servletContext.getAttribute(sessionId);
                                                session.invalidate();
                                                log.info("Forced kill of
session: " + sessionId);
                                                //             TODO: look
into decrementing db login count etc.
                                } catch (Exception e){
                                                log.error("Could not force
kill session: " + sessionId + " - session may be already invalidated",
e);                                    
                                }
                                
                }
                
                public static List getSessionList(ApplicationGlobals
applicationGlobals){
                                ServletContext servletContext =
applicationGlobals.getServletContext();
                                // Using LinkedHashMap as the key order is
preserved.
                                LinkedHashMap sessionMap =
(LinkedHashMap)servletContext.getAttribute(MySessionListener.HASHMAP_NAME);
                                if (sessionMap == null){
                                                sessionMap = new
LinkedHashMap();
                                }
                                List retVal = new ArrayList();
                                for (Iterator i =
sessionMap.keySet().iterator(); i .hasNext();){
                                               
retVal.add(sessionMap.get(i.next()));
                                }
                                return retVal;                        
                }
                
}

You’ll also need to register the listener in your web.xml:

    <listener>
           
<listener-class>com.a.b.listeners.MySessionListener</listener-class>
    </listener>

Regards,
Jim.

From: Jonathan Barker [mailto:jonathan.theit...@gmail.com] 
Sent: 31 March 2011 03:25
To: Tapestry users
Subject: Re: Logon notification

Jim,

I would be interested in seeing your HTTPSessionListener implementation.


David,

I'm going to hazard a guess that indeed you would need to do some
configuration through tapestry-ioc.  Can I assume that the events that you
do see are from services that you have configured entirely in Spring?


Regards,

Jonathan


On Wed, Mar 30, 2011 at 12:14 PM, Jim O'Callaghan
<jc1000...@yahoo.co.uk>wrote:

> Hi David,
>
> Is there something specific in the ApplicationListener approach you
> require?  I use TSS and have a login page that in its onSuccess method
> sends
> a redirect like so:
>
> @Inject
> private HttpServletResponse response;
> .
> .
> .
>          Object onSuccess() throws IOException
>          {
>                 response.sendRedirect(request.getContextPath() + checkUrl
+
> "?j_username=" +
>                              login.getUserName() + "&j_password=" +
> login.getPassword() +
>                            "&_spring_security_remember_me=" +
> (login.isRememberMe() ? "checked" : ""));
>
> and then in it’s onActivate method:
>
>            void onActivate(String extra) {
>                if (extra.equals("failed")) {
>                   failed = true;
>
> form.recordError(messages.get("login.invalidUsernameOrPassword"));
>                } else {
>                      // do your thing
>                      .
>                      .
>                      .
>            }
>
>
> I use a registered listener that implements HTTPSessionListener to update
a
> hashtable of where a user has last been etc. for a kind of dashboard page,
> and some db calls to update a persisted logged on flag on a user table –
> would this approach be of any use to you?
>
> Regards,
> Jim.
>
> From: David Uttley [mailto:dutt...@democracysystems.com]
> Sent: 30 March 2011 16:29
> To: Tapestry users
> Subject: Re: Logon notification
>
> Hi Peter,
>
> If it was as easy as what you suggest I wouldn't have bothered with the
> mailing list, this is a last resort I don't use these mailing lists
lightly
> only when I  start banging my head against a wall, I had already done the
> registering of the ApplicationListener. As for lack of detail I am not
> really sure what to post that would be of help. I would also argue that it
> is a Tapestry question as I am using Tapestry Spring Security which is
> configured directly by T5. Spring is reporting events to the
> ApplicationListener its the events that occur in Tapestry Spring Security
> that are not appearing. If I use the first example then I get other events
> from the container but not from TSS.
>
> I have been in contact with the guy from TSS and he told me his Spring
> knowledge was limited and directed me to the Tapestry mailing board.
>
> From looking through the debugger it appears that TSS has no application
> listeners to notify when it wishes to send an event. However, Spring has
an
> application listener as I am getting other events from it. Therefore, I am
> confused how the ApplicationListener is set on TSS, I wonder if I have to
> specifically add the ApplicationListener for Tapestry in the AppModule. It
> seems like the TSS is initialised before the Spring context files and
> annotations.
>
> It looks like TSS has little support and I probably should cut my losses
> now
> and remove it and just go for a pure Spring based implementation.
>
> Thanks
> David
>
>
> On 30 Mar 2011, at 16:00, p.stavrini...@albourne.com wrote:
>
> > Hi David,
> >
> > Apart from the lack of details in your question, this is also hardly a
> Tapestry question. You should direct it to the Spring forums instead, but
> if
> this reply helps so be it:
> >
> > You will need in your applicationContext.xml to define a bean that will
> automatically start receiving events (I assume you know how)... I am not
> familiar with Spring security, but the API docs are quite clear:
> >
> >
>
>
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframe
> work/context/ApplicationListener.html
> >
> > So code that might have looked something like this in the past:
> >
> > public void onApplicationEvent(ApplicationEvent applicationEvent)
> > {
> >    if (applicationEvent instanceof AuthenticationSuccessEvent)
> >    {
> >        AuthenticationSuccessEvent event = (AuthenticationSuccessEvent)
> applicationEvent;
> >        UserDetails userDetails = (UserDetails)
> event.getAuthentication().getPrincipal();
> >
> >        //notify here now, etc.
> >    }
> > }
> >
> > 'In theory' (untested of course) can now be replaced by:
> >
> > public void onApplicationEvent(AuthenticationSuccessEvent successEvent)
> > {
> >    UserDetails userDetails = (UserDetails)
> successEvent.getAuthentication().getPrincipal();
> >    //notify here etc.
> >
> > }
> >
> > And thats all?!
> >
> > Cheers,
> > Peter
> >
> >
> >
> > ----- Original Message -----
> > From: "David Uttley" <dutt...@democracysystems.com>
> > To: "Tapestry users" <users@tapestry.apache.org>
> > Sent: Wednesday, 30 March, 2011 16:50:26 GMT +02:00 Athens, Beirut,
> Bucharest, Istanbul
> > Subject: Logon notification
> >
> > So do I have any takers for this problem?
> >
> > Somebody must be recording logins somewhere, I don't have to use Spring
> to
> do it.
> >
> > ------Original message
> >
> > I am trying to get spring security to notify me of a successful logon
> using the Spring ApplicationListener. However, the ApplicationListener
> doesn't seem to be notified of the events.
> >
> > Any help or pointers will be appreciated.
> >
> > I am using t5.2 Spring 3.0 and the 3.0.0-snapshot of t5 Spring Security.
> >
> >
> > -------
> >
> > Thanks
> > David
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
> > For additional commands, e-mail: users-h...@tapestry.apache.org
> >
> ________________________________________
> No virus found in this message.
> Checked by AVG - www.avg.com
> Version: 10.0.1209 / Virus Database: 1500/3538 - Release Date: 03/29/11
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
> For additional commands, e-mail: users-h...@tapestry.apache.org
>
>


--
Jonathan Barker
ITStrategic
________________________________________
No virus found in this message.
Checked by AVG - www.avg.com
Version: 10.0.1209 / Virus Database: 1500/3540 - Release Date: 03/30/11

Reply via email to