Package org.olat.core.util

Source Code of org.olat.core.util.UserSession

/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) 1999-2006 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/

package org.olat.core.util;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

import org.apache.log4j.Logger;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.gui.control.Disposable;
import org.olat.core.gui.control.Event;
import org.olat.core.id.Identity;
import org.olat.core.id.IdentityEnvironment;
import org.olat.core.id.OLATResourceable;
import org.olat.core.id.Roles;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.Tracing;
import org.olat.core.logging.activity.CoreLoggingResourceable;
import org.olat.core.logging.activity.OlatLoggingAction;
import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
import org.olat.core.logging.activity.ThreadLocalUserActivityLoggerInstaller;
import org.olat.core.logging.activity.UserActivityLoggerImpl;
import org.olat.core.service.ServiceCreatorFactory;
import org.olat.core.service.ServiceFactory;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.event.EventBus;
import org.olat.core.util.event.GenericEventListener;
import org.olat.core.util.prefs.Preferences;
import org.olat.core.util.prefs.PreferencesFactory;
import org.olat.core.util.resource.OresHelper;

/**
* Description: <BR/>the httpsession contains an instance of this class. the
* UserSession is either authenticated or not; and if it is, then it also
* contains things like the Identity, the locale etc. of the current user. <P/>
*
* @author Felix Jost
*/
public class UserSession implements HttpSessionBindingListener, GenericEventListener  {
  private static final String USERSESSIONKEY = UserSession.class.getName();
  public static final OLATResourceable ORES_USERSESSION = OresHelper.createOLATResourceableType(UserSession.class);
  public static final String STORE_KEY_KILLED_EXISTING_SESSION = "killedExistingSession";

  //clusterNOK cache ??
  private static Set<UserSession> authUserSessions = new HashSet<UserSession>(101);
  private static Map<String, Identity> userNameToIdentity = new HashMap<String, Identity>(101);
  private static int sessionTimeoutInSec = 1800;
  private static Set<String> authUsersNamesOtherNodes = new HashSet<String>(101);

  // things to put into that should not be clear when signing on (e.g. remember
  // url for a direct jump)
  private Map nonClearedStore = new HashMap();

  // the environment (identity, locale, ..) of the identity
  private IdentityEnvironment identityEnvironment;
  private SessionInfo sessionInfo = null;
  private Map store = null;
  private boolean authenticated = false;
  private boolean registeredWithBus = false;
  private Preferences guiPreferences;
  private EventBus singleUserSystemBus;

  // brasato:: find a better place?
  private Map<String, Object> sessionServiceInstances;
 
  /**
   *
   * @param serviceInterfaceName
   * @return an instance of the service which belongs to exactly this usersession (= user scope)
   */
  public Object getServiceInstance(Class serviceInterfaceName) {
    ServiceCreatorFactory scf = (ServiceCreatorFactory) ServiceFactory.getService(ServiceCreatorFactory.class);
    String key = serviceInterfaceName.getName();
    synchronized(this) { //o_clusterOK by:fj // also helper classes and timers and so on may ask for a service -> sync on instance
      Object cachedService = sessionServiceInstances.get(key);
      if (cachedService == null) {
        cachedService = scf.createNonNullServiceFor(serviceInterfaceName);
        sessionServiceInstances.put(key, cachedService);
      }
      return cachedService;
    }
  }
 
 
  private UserSession() {
    //System.out.println("<init> UserSession... hash="+hashCode());
    //Logger.getLogger(getClass().getName()).debug("UserSession<init> START");
    //(new Exception("UserSession<init>")).printStackTrace(System.out);
    init();
    //usersession is listening for SignOnOffEvents from other clusternodes
    CoordinatorManager.getCoordinator().getEventBus().registerFor(this, null, ORES_USERSESSION);
    registeredWithBus = true;
    Logger.getLogger(getClass().getName()).debug("UserSession<init> END");
  }

  /**
   *
   */
  private void init() {
    store = new HashMap(4);
    identityEnvironment = new IdentityEnvironment();
    singleUserSystemBus = CoordinatorManager.getCoordinator().createSingleUserInstance();
    authenticated = false;
    sessionInfo = null;
    sessionServiceInstances = new HashMap<String, Object>();
  }

  /**
   * @param session
   * @return associated user session
   */
  public static UserSession getUserSession(HttpSession session) {
    UserSession us;
    synchronized (session) {//o_clusterOK by:fj
      us = (UserSession) session.getAttribute(USERSESSIONKEY);
      if (us == null) {
        us = new UserSession();
        session.setAttribute(USERSESSIONKEY, us); // triggers the
        // valueBoundEvent -> nothing
        // more to do here
      }
    }
    //set a possible changed session timeout interval
    session.setMaxInactiveInterval(UserSession.sessionTimeoutInSec);
    return us;
  }

  /**
   * @param hreq
   * @return associated user session
   */
  public static UserSession getUserSession(HttpServletRequest hreq) {
    // get existing or create new session
    return getUserSession(hreq.getSession(true));
  }
 
  /**
   * Return the UserSession of the given request if it is already set or null otherwise
   * @param hreq
   * @return
   */
  public static UserSession getUserSessionIfAlreadySet(HttpServletRequest hreq) {
    HttpSession session = hreq.getSession(false);
    if (session==null) {
      return null;
    }
    session.setMaxInactiveInterval(UserSession.sessionTimeoutInSec);
    synchronized (session) {//o_clusterOK by:se
      return (UserSession) session.getAttribute(USERSESSIONKEY);
    }
  }

  /**
   * @return true if is authenticated
   */
  public boolean isAuthenticated() {
    return authenticated;
  }

  /**
   * @param key
   * @param o
   */
  public void putEntry(String key, Object o) {
    store.put(key, o);
  }

  /**
   * @param key
   * @return entry
   */
  public Object getEntry(String key) {
    if (key == null) return null;
    if (store.get(key) != null) return store.get(key);
    if (nonClearedStore.get(key) != null) return nonClearedStore.get(key);
    else return null;
  }

  /**
   * @param key
   * @return removed entry
   */
  public Object removeEntry(Object key) {
    return store.remove(key);
  }

  /**
   * put an entry in the usersession that even survives login/logouts from the
   * users. needed e.g. for a direct jump url, when the url is remembered in the
   * dmz, but used in auth. since a login occurs, all data from the previous
   * user will be cleared, that is why we introduced this store.
   *
   * @param key
   * @param o
   */
  public void putEntryInNonClearedStore(Object key, Object o) {
    nonClearedStore.put(key, o);
  }

  /**
   * @param key
   * @return removed entry
   */
  public Object removeEntryFromNonClearedStore(Object key) {
    return nonClearedStore.remove(key);
  }

  /**
   * @return Locale
   */
  public Locale getLocale() {
    Locale locale = identityEnvironment.getLocale();
    return locale;
  }

  /**
   * @return Identity
   */
  public Identity getIdentity() {
    return identityEnvironment.getIdentity();
  }

  /**
   * Sets the locale.
   *
   * @param locale The locale to set
   */
  public void setLocale(Locale locale) {
    identityEnvironment.setLocale(locale);
  }

  /**
   * Sets the identity.
   *
   * @param identity The identity to set
   */
  public void setIdentity(Identity identity) {
    identityEnvironment.setIdentity(identity);
  }

  /**
   * @return Roles
   */
  public Roles getRoles() {
    Roles result = identityEnvironment.getRoles();
    if (result==null) {
      Tracing.logWarn("getRoles: null, this="+this, new RuntimeException("getRoles"), UserSession.class);
    }
    return result;
  }

  /**
   * Sets the roles.
   *
   * @param roles The roles to set
   */
  public void setRoles(Roles roles) {
    identityEnvironment.setRoles(roles);
  }

  /**
   * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)
   */
  public void valueBound(HttpSessionBindingEvent be) {
    if (Tracing.isDebugEnabled(UserSession.class)) {
      Tracing.logDebug("Opened UserSession:" + this.toString(), UserSession.class);
    }
  }

  /**
   * called when the session is invalidated either by app. server timeout or manual session.invalidate (logout)
   *
   * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)
   */
  public void valueUnbound(HttpSessionBindingEvent be) {
    try {
      // the identity can be null if an loginscreen only session gets invalidated
      // (no user was authenticated yet but a tomcat session was created)
      Identity ident = identityEnvironment.getIdentity();
      signOffAndClear();
      if (Tracing.isDebugEnabled(UserSession.class)) {
        Tracing.logDebug("Closed UserSession: identity = " + (ident == null ? "n/a":ident.getName()), UserSession.class);
      }
      //we do not have a request in the null case (app. server triggered) and user not yet logged in
      //-> in this case we use the special empty activity logger
      if (ident == null) {
        ThreadLocalUserActivityLoggerInstaller.initEmptyUserActivityLogger();
      }
    } catch (Exception e) {
      // safely retrieve
      Identity ident = identityEnvironment.getIdentity();
      Tracing.logError("exception while session was unbound!", e, UserSession.class);
    }
    // called by tomcat's timer thread -> we need to close!! since the next unbound will be called from the same tomcat-thread
    finally {
      //o_clusterNOK: put into managed transaction wrapper
      DBFactory.getInstance(false).commitAndCloseSession();
    }
  }

  /**
   * called from signOffAndClear()
   * called from event -> MUEvent
   * the real work to do during sign off but without sending the multiuserevent
   * this is used in case the user logs in to node1 and was logged in on node2 =>
   * node2 catches the sign on event and invalidates the user on node2 "silently", e.g.
   * without firing an event.
   */
  private void signOffAndClearWithout(){
    Tracing.logDebug("signOffAndClearWithout() START", getClass());
    final Identity ident = identityEnvironment.getIdentity();
    //System.out.println("signOffAndClearWithout, ident="+ident+", hash="+this.hashCode()+", identityenv "+identityEnvironment.hashCode());
    // handle safely
    boolean isDebug = Tracing.isDebugEnabled(UserSession.class);
    if (isDebug) {
      Tracing.logDebug("UserSession:::logging off: " + sessionInfo, this.getClass());
    }

    /**
     * use not RunnableWithException, as exceptionHandlng is inside the run
     */
    Runnable run = new Runnable() {
      public void run() {
        Object obj = null;
        try {
         
          // do logging
          if (ident != null) {
            ThreadLocalUserActivityLogger.log(OlatLoggingAction.OLAT_LOGOUT, UserSession.class, CoreLoggingResourceable.wrap(ident));
          } else {
            //System.out.println("identity is null!!!!!!!!!!!!!!!!!!!!!");
          }
          // notify all variables in the store (the values) about the disposal
          // if
          // Disposable

          for (Iterator it_storevals = new ArrayList(store.values()).iterator(); it_storevals.hasNext();) {
            obj = it_storevals.next();
            if (obj instanceof Disposable) {
              // synchronous, since triggered by tomcat session timeout or user
              // click and
              // asynchronous, if kicked out by administrator.
              // we assume synchronous
              // !!!!
              // As a reminder, this .dispose() calls dispose on
              // DefaultController which is synchronized.
              // (Windows/WindowManagerImpl/WindowBackOfficeImpl/BaseChiefController/../
              // dispose()
              // !!!! was important for bug OLAT-3390

              ((Disposable) obj).dispose();
            }
          }
        } catch (Exception e) {

          String objtostr = "n/a";
          try {
            objtostr = obj.toString();
          } catch (Exception ee) {
            // ignore
          }
          Tracing.logError("exception in signOffAndClear: while disposing object:" + objtostr, e, UserSession.class);
        }
      }
    };

    ThreadLocalUserActivityLoggerInstaller.runWithUserActivityLogger(run, UserActivityLoggerImpl.newLoggerForValueUnbound(this));

    synchronized (authUserSessions) {  //o_clusterOK by:fj
      if(authUserSessions.remove(this)){
        //remove only from identityEnvironment if found in sessions.
        //see also SIDEEFFECT!! line in signOn(..)
        Identity previousSignedOn = identityEnvironment.getIdentity();
        if (previousSignedOn != null) {
          Tracing.logDebug("signOffAndClearWithout() removing from userNameToIdentity: "+previousSignedOn.getName().toLowerCase(), getClass());
          userNameToIdentity.remove(previousSignedOn.getName().toLowerCase());
        }
      }else{
        if (isDebug) {
          Tracing.logInfo("UserSession already removed! for ["+ident+"]", UserSession.class);
        }     
      }
    }
    Tracing.logDebug("signOffAndClearWithout() END", getClass());
  }
 
 
  /**
   * called to make sure the current authenticated user (if there is one at all)
   * is cleared and signed off. This method is firing the SignOnOffEvent Multiuserevent.
   */
  public synchronized void signOffAndClear() {  //o_clusterOK by:fj
    Tracing.logDebug("signOffAndClear() START", getClass());
    //
    signOffAndClearWithout();
    // handle safely
    try {
      if (isAuthenticated()) {
        Identity identity = identityEnvironment.getIdentity();
        Tracing.logAudit("Logged off: " + sessionInfo, this.getClass());
        CoordinatorManager.getCoordinator().getEventBus().fireEventToListenersOf(new SignOnOffEvent(identity, false), ORES_USERSESSION);
        Tracing.logDebug("signOffAndClear() deregistering usersession from eventbus, id="+sessionInfo, getClass());
        CoordinatorManager.getCoordinator().getEventBus().deregisterFor(this, ORES_USERSESSION);
        registeredWithBus = false;
      }
    } catch (Exception e) {
      Tracing.logError("exception in signOffAndClear: while sending signonoffevent!", e, UserSession.class);
    }
    // clear all instance variables, set authenticated to false
    init();
    Tracing.logDebug("signOffAndClear() END", getClass());
  }

  /**
   * prior to calling this method, all instance vars must be set.
   */
  public synchronized void signOn() {
    //   ^^^^^^^^^^^^ Added synchronized to be symmetric with sign off and to
    //                fix a possible dead-lock see also OLAT-3390
    Tracing.logDebug("signOn() START", getClass());
    if (isAuthenticated()) throw new AssertException("sign on: already signed on!");
    Identity identity = identityEnvironment.getIdentity();
    if (identity == null) throw new AssertException("identity is null in identityEnvironment!");
    if (sessionInfo == null) throw new AssertException("sessionInfo was null for identity " + identity);
    //String login = identity.getName();
    authenticated = true;

    if (sessionInfo.isWebDAV()) {
      // load user prefs
      guiPreferences = PreferencesFactory.getInstance().getPreferencesFor(identity, identityEnvironment.getRoles().isGuestOnly());

      synchronized (authUserSessions) {  //o_clusterOK by:se
        // we're only adding this webdav session to the authUserSessions - not to the userNameToIdentity.
        // userNameToIdentity is only needed for IM which can't do anything with a webdav session
        authUserSessions.add(this);
      }
      Tracing.logAudit("Logged on [via webdav]: " + sessionInfo.toString(), this.getClass());
      return;
    }
   
    Tracing.logDebug("signOn() authUsersNamesOtherNodes.contains "+identity.getName()+": "+authUsersNamesOtherNodes.contains(identity.getName()), getClass());
   
    UserSession invalidatedSession = null;
    synchronized (authUserSessions) {  //o_clusterOK by:fj
        // check if allready a session exist for this user
        if ( (userNameToIdentity.containsKey(identity.getName().toLowerCase()) || authUsersNamesOtherNodes.contains(identity.getName()) )
             && !sessionInfo.isWebDAV() && !this.getRoles().isGuestOnly()) {
            Tracing.logInfo("Loggin-process II: User has already a session => signOffAndClear existing session", this.getClass());
           
            invalidatedSession = getUserSessionFor(identity.getName().toLowerCase());
            //remove session to be invalidated
            //SIDEEFFECT!! to signOffAndClear
            //if invalidatedSession is removed from authUserSessions
            //signOffAndClear does not remove the identity.getName().toLowerCase() from the userNameToIdentity
            //
            authUserSessions.remove(invalidatedSession);
        }
        authUserSessions.add(this);
      // user can choose upercase letters in identity name, but this has no effect on the
      // database queries, the login form or the IM account. IM works only with lowercase
      // characters -> map stores values as such
      Tracing.logDebug("signOn() adding to userNameToIdentity: "+identity.getName().toLowerCase(), getClass());
      userNameToIdentity.put(identity.getName().toLowerCase(), identity);
    }
    // load user prefs
    guiPreferences = PreferencesFactory.getInstance().getPreferencesFor(identity, identityEnvironment.getRoles().isGuestOnly());

    if (!registeredWithBus) {
      // OLAT-3706
      CoordinatorManager.getCoordinator().getEventBus().registerFor(this, null, ORES_USERSESSION);
    }

    Tracing.logAudit("Logged on: " + sessionInfo.toString(), this.getClass());
    CoordinatorManager.getCoordinator().getEventBus().fireEventToListenersOf(new SignOnOffEvent(identity, true), ORES_USERSESSION);
   
   
    // THE FOLLOWING CHECK MUST BE PLACED HERE NOT TO PRODUCE A DEAD-LOCK WITH SIGNOFFANDCLEAR
    // check if a session from any browser was invalidated (IE has a cookie set per Browserinstance!!)
    if (invalidatedSession != null || authUsersNamesOtherNodes.contains(identity.getName())) {
      // put flag killed-existing-session into session-store to show info-message 'only one session for each user' on user-home screen
      this.putEntry(STORE_KEY_KILLED_EXISTING_SESSION, Boolean.TRUE);
      Tracing.logDebug("signOn() removing from authUsersNamesOtherNodes: "+identity.getName(), getClass());
      authUsersNamesOtherNodes.remove(identity.getName());
      //OLAT-3381 & OLAT-3382
      if(invalidatedSession != null) invalidatedSession.signOffAndClear();
    }
   
    Tracing.logDebug("signOn() END", getClass());
  }


  /**
   * Lookup non-webdav UserSession for username.
   * @param userName
   * @return user-session or null when no session was founded.
   */
  private UserSession getUserSessionFor(String userName) {
    //do not call from somewhere else then signOffAndClear!!
    Set authUserSessionsCopy = new HashSet(authUserSessions);
    for (Iterator iterator = authUserSessionsCopy.iterator(); iterator.hasNext();) {
      UserSession userSession = (UserSession) iterator.next();     
      if (userName.equalsIgnoreCase(userSession.getIdentity().getName()) && userSession.getSessionInfo()!=null && !userSession.getSessionInfo().isWebDAV()) {
        return userSession;
      }
    }
    return null;
  }



    /**
   * @param userName
   * @return the identity or null if no user with userName is currently logged
   *         on
   */
  public static Identity getSignedOnIdentity(String userName) {
    synchronized (authUserSessions) {  //o_clusterOK by:fj
      return (Identity) userNameToIdentity.get(userName.toLowerCase());
    }
  }
 
  /**
   * @return set of authenticated active user sessions
   */
  public static Set getAuthenticatedUserSessions() {
    Set copy;
    synchronized (authUserSessions) {  //o_clusterOK by:fj
      copy = new HashSet(authUserSessions);
    }
    return copy;
  }

  /**
   * @see java.lang.Object#toString()
   */
  public String toString() {
    return "Session of " + identityEnvironment + ", " + super.toString();
  }

  /**
   * @return identity environment
   */
  public IdentityEnvironment getIdentityEnvironment() {
    return identityEnvironment;
  }

  /**
   * may be null
   * <p>
   * @return session info object
   */
  public SessionInfo getSessionInfo() {
    return sessionInfo;
  }

  /**
   * @param sessionInfo
   */
  public void setSessionInfo(SessionInfo sessionInfo) {
    this.sessionInfo = sessionInfo;
  }

  /**
   * @return Returns the userSessionsCnt.
   */
  public static int getUserSessionsCnt() {
    //clusterNOK ?? return only number of locale sessions ?
    return authUserSessions.size();
  }

  /**
   * @return Returns the guiPreferences.
   */
  public Preferences getGuiPreferences() {
      return guiPreferences;
  }

  /**
   * This is the olatsystembus to broadcast event amongst controllers of a single user only
   * (the one whom this usersession belongs to)
   *
   * @return the olatsystembus for the local user
   */
  public EventBus getSingleUserEventCenter() {
    return singleUserSystemBus;
  }


  /**
   * only for SignOffEvents
   * - Usersession keeps book about usernames
   * - WindowManager responsible to dispose controller chain
   * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event)
   */
  public void event(Event event) {
    Tracing.logDebug("event() START", getClass());
    SignOnOffEvent se = (SignOnOffEvent) event;
    Tracing.logDebug("event() is SignOnOffEvent. isSignOn="+se.isSignOn(), getClass());
    if (!se.isEventOnThisNode()) {
      // - signOnOff from other node
      // - Single OLAT Instance is never passing by here.
      if (se.isSignOn()) {
        // it is a logged on event
        // -> remember other nodes logged usernames
        Tracing.logDebug("event() adding to authUsersNamesOtherNodes: "+se.getIdentityName(), getClass());
        authUsersNamesOtherNodes.add(se.getIdentityName());
        if (sessionInfo != null && se.getIdentityName().equals(sessionInfo.getLogin()) && !sessionInfo.isWebDAV()
            && !this.getRoles().isGuestOnly()) {
          // if this listening UserSession instance is from the same user
          // and it is not a WebDAV Session, and it is not GuestSession
          // => log user off on this node
          this.signOffAndClearWithout();
          Tracing.logDebug("event() deregistering usersession from eventbus, id="+se.getIdentityName(), getClass());
          CoordinatorManager.getCoordinator().getEventBus().deregisterFor(this, ORES_USERSESSION);
          registeredWithBus = false;
          init();
        }
      } else {
        // it is logged off event
        // -> remove from other nodes logged on list.
        Tracing.logDebug("event() removing from authUsersNamesOtherNodes: "+se.getIdentityName(), getClass());
        authUsersNamesOtherNodes.remove(se.getIdentityName());
      }
    }
    Tracing.logDebug("event() END", getClass());
  }
 
  /**
   * Invalidate all sessions except admin-sessions.
   * @return  Number of invalidated sessions.
   */
  public static int invalidateAllSessions() {
    Tracing.logDebug("invalidateAllSessions() START", UserSession.class);
    int invalidateCounter = 0;
    Tracing.logAudit("All sessions were invalidated by an administrator", UserSession.class);
    //clusterNOK ?? invalidate only locale sessions ?
    Set iterCopy = new HashSet(authUserSessions);
    for (Iterator iterator = iterCopy.iterator(); iterator.hasNext();) {
      UserSession userSession = (UserSession) iterator.next();
      Roles userRoles = userSession != null ? userSession.getRoles() : null;
      if (userRoles != null && !userRoles.isOLATAdmin()) {
        //do not logout administrators
        try {
          userSession.signOffAndClear();
          invalidateCounter++;
        } catch(Exception ex) {
          // Session already signed off => do nothing and continues
        }
      }
    }
    Tracing.logDebug("invalidateAllSessions() END", UserSession.class);
    return invalidateCounter;
  }
 
  /**
   * Invalidate a given number of oldest (last-click-time) sessions except admin-sessions.
   * @param nbrSessions  number of sessions whisch will be invalidated
   * @return  Number of invalidated sessions.
   */
  public static int invalidateOldestSessions(int nbrSessions) {
    int invalidateCounter = 0;
    // 1. Copy authUserSessions in sorted TreeMap
    // This is the Comparator that will be used to sort the TreeSet:
    Comparator sessionComparator = new Comparator() {
      public int compare(Object o1, Object o2) {
        Long long1 = new Long(((UserSession) o1).getSessionInfo().getLastClickTime());
        Long long2 = new Long(((UserSession) o2).getSessionInfo().getLastClickTime());
        return long1.compareTo(long2);
      }
    };
    // clusterNOK ?? invalidate only locale sessions ?
    TreeSet sortedSet = new TreeSet(sessionComparator);
    sortedSet.addAll(authUserSessions);
    int i = 0
    for (Iterator iterator = sortedSet.iterator(); iterator.hasNext() && i++<nbrSessions;) {
      try {
        UserSession userSession = (UserSession) iterator.next();
        if (!userSession.getRoles().isOLATAdmin() && !userSession.getSessionInfo().isWebDAV()) {
          userSession.signOffAndClear();
          invalidateCounter++;
        }
      } catch (Throwable th) {
        Tracing.logWarn("Error signOffAndClear ", th, UserSession.class);
      }
    }
    return invalidateCounter;   
  }

  /**
   * set session timeout on http session -
   * @param sessionTimeoutInSec
   */
  public static void setGlobalSessionTimeout(int sessionTimeoutInSec) {
    UserSession.sessionTimeoutInSec = sessionTimeoutInSec;
    Set<UserSession> sessionSnapShot = new HashSet<UserSession>(authUserSessions);
    for (UserSession session : sessionSnapShot) {
      try{
        SessionInfo sessionInfo2 = session.getSessionInfo();
        if(sessionInfo2 != null){
          sessionInfo2.getSession().setMaxInactiveInterval(sessionTimeoutInSec);
        }
      }catch(Throwable th){
        Tracing.logError("error setting sesssionTimeout", th, UserSession.class);
      }
    }
  }
 
}
TOP

Related Classes of org.olat.core.util.UserSession

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.