/**
   * Retrieves the session ID from the session cookie in the given {@link ToadletContext}, checks if
   * it contains a valid (existing and not expired) session and if yes, returns the {@link Session}.
   *
   * <p>If the session was valid, then its validity is extended by {@link MAX_SESSION_IDLE_TIME}.
   *
   * <p>If the session is not valid anymore, <code>null</code> is returned if the new constructor
   * was used (for example by PluginRespirator). If the deprecated constructor was used, a
   * RedirectException to the login URI is thrown.
   *
   * @throws RedirectException if login redirect URI was set
   */
  public synchronized Session useSession(ToadletContext context) throws RedirectException {
    UUID sessionID = getSessionID(context);
    if (sessionID == null) {
      if (mLogInRedirectURI == null) return null;
      throw new RedirectException(mLogInRedirectURI);
    }

    // We must synchronize around the fetching of the time and mSessionsByID.push() because
    // mSessionsByID is no sorting data structure: It's a plain
    // LRUHashtable so to ensure that it stays sorted the operation "getTime(); push();" must be
    // atomic.
    long time = CurrentTimeUTC.getInMillis();

    removeExpiredSessions(time);

    Session session = mSessionsByID.get(sessionID);

    if (session == null) {
      if (mLogInRedirectURI == null) return null;
      throw new RedirectException(mLogInRedirectURI);
    }

    session.updateExpiresAtTime(time);
    mSessionsByID.push(session.getID(), session);

    setSessionCookie(session, context);

    return session;
  }
  /**
   * Deletes the session with the given ID.
   *
   * @return True if a session with the given ID existed.
   */
  private synchronized boolean deleteSession(UUID sessionID) {
    Session session = mSessionsByID.get(sessionID);

    if (session == null) return false;

    mSessionsByID.removeKey(sessionID);
    mSessionsByUserID.remove(session.getUserID());
    return true;
  }