public static void add(HttpSession session) {
    String sessionId = session.getId();

    if (CompoundSessionIdSplitterUtil.hasSessionDelimiter()) {
      sessionId = CompoundSessionIdSplitterUtil.parseSessionId(sessionId);
    }

    Map<String, HttpSession> sessions = _sessions.get(sessionId);

    if (sessions == null) {
      sessions = new ConcurrentHashMap<String, HttpSession>();

      Map<String, HttpSession> previousSessions = _sessions.putIfAbsent(sessionId, sessions);

      if (previousSessions != null) {
        sessions = previousSessions;
      }
    }

    ServletContext servletContext = session.getServletContext();

    String contextPath = servletContext.getContextPath();

    // ConcurrentHashMap's read is faster than its write. This check is
    // logically unnecessary, but is a performance improvement.

    if (!sessions.containsKey(contextPath)) {
      sessions.put(contextPath, session);
    }
  }
  public static void invalidate(String sessionId) {
    if (CompoundSessionIdSplitterUtil.hasSessionDelimiter()) {
      sessionId = CompoundSessionIdSplitterUtil.parseSessionId(sessionId);
    }

    Map<String, HttpSession> sessions = _sessions.remove(sessionId);

    if (sessions == null) {
      return;
    }

    for (HttpSession session : sessions.values()) {
      try {
        session.invalidate();
      } catch (Exception e) {
      }
    }
  }