/**
   * Construct and return a new session object, based on the default settings specified by this
   * Manager's properties. The session id specified will be used as the session id. If a new session
   * cannot be created for any reason, return <code>null</code>.
   *
   * @param sessionId The session id which should be used to create the new session; if <code>null
   *     </code>, a new session id will be generated
   * @exception IllegalStateException if a new session cannot be instantiated for any reason
   */
  @Override
  public Session createSession(String sessionId) {

    if ((maxActiveSessions >= 0) && (getActiveSessions() >= maxActiveSessions)) {
      rejectedSessions++;
      throw new IllegalStateException(sm.getString("managerBase.createSession.ise"));
    }

    // Recycle or create a Session instance
    Session session = createEmptySession();

    // Initialize the properties of the new session and return it
    session.setNew(true);
    session.setValid(true);
    session.setCreationTime(System.currentTimeMillis());
    session.setMaxInactiveInterval(this.maxInactiveInterval);
    String id = sessionId;
    if (id == null) {
      id = generateSessionId();
    }
    session.setId(id);
    sessionCounter++;

    SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
    synchronized (sessionCreationTiming) {
      sessionCreationTiming.add(timing);
      sessionCreationTiming.poll();
    }
    return (session);
  }
  /**
   * Reinstantiates a serialized session from the data passed in. This will first call
   * createSession() so that we get a fresh instance with all the managers set and all the transient
   * fields validated. Then it calls Session.readObjectData(byte[]) to deserialize the object
   *
   * @param data - a byte array containing session data
   * @return a valid Session object, null if an error occurs
   */
  protected Session readSession(byte[] data, String sessionId) {
    try {
      ReplicationStream session_in = getReplicationStream(data);

      Session session = sessionId != null ? this.findSession(sessionId) : null;
      boolean isNew = (session == null);
      // clear the old values from the existing session
      if (session != null) {
        ReplicatedSession rs = (ReplicatedSession) session;
        rs.expire(false); // cleans up the previous values, since we are not doing removes
        session = null;
      } // end if

      if (session == null) {
        session = createSession(null, false, false);
        sessions.remove(session.getIdInternal());
      }

      boolean hasPrincipal = session_in.readBoolean();
      SerializablePrincipal p = null;
      if (hasPrincipal) p = (SerializablePrincipal) session_in.readObject();
      ((ReplicatedSession) session).readObjectData(session_in);
      if (hasPrincipal) session.setPrincipal(p.getPrincipal(getContainer().getRealm()));
      ((ReplicatedSession) session).setId(sessionId, isNew);
      ReplicatedSession rsession = (ReplicatedSession) session;
      rsession.setAccessCount(1);
      session.setManager(this);
      session.setValid(true);
      rsession.setLastAccessedTime(System.currentTimeMillis());
      rsession.setThisAccessedTime(System.currentTimeMillis());
      ((ReplicatedSession) session).setAccessCount(0);
      session.setNew(false);
      if (log.isTraceEnabled())
        log.trace(
            "Session loaded id="
                + sessionId
                + " actualId="
                + session.getId()
                + " exists="
                + this.sessions.containsKey(sessionId)
                + " valid="
                + rsession.isValid());
      return session;

    } catch (Exception x) {
      log.error("Failed to deserialize the session!", x);
    }
    return null;
  }
  /**
   * Construct and return a new session object, based on the default settings specified by this
   * Manager's properties. The session id specified will be used as the session id. If a new session
   * cannot be created for any reason, return <code>null</code>.
   *
   * @param sessionId The session id which should be used to create the new session; if <code>null
   *     </code>, a new session id will be generated
   * @exception IllegalStateException if a new session cannot be instantiated for any reason
   */
  public Session createSession(String sessionId, Random random) {

    // Recycle or create a Session instance
    Session session = createEmptySession();

    // Initialize the properties of the new session and return it
    session.setNew(true);
    session.setValid(true);
    session.setCreationTime(System.currentTimeMillis());
    session.setMaxInactiveInterval(this.maxInactiveInterval);
    if (sessionId == null) {
      sessionId = generateSessionId(random);
    }
    session.setId(sessionId);
    sessionCounter++;

    return (session);
  }
  /**
   * Creates a HTTP session. Most of the code in here is copied from the StandardManager. This is
   * not pretty, yeah I know, but it was necessary since the StandardManager had hard coded the
   * session instantiation to the a StandardSession, when we actually want to instantiate a
   * ReplicatedSession<br>
   * If the call comes from the Tomcat servlet engine, a SessionMessage goes out to the other nodes
   * in the cluster that this session has been created.
   *
   * @param notify - if set to true the other nodes in the cluster will be notified. This flag is
   *     needed so that we can create a session before we deserialize a replicated one
   * @see ReplicatedSession
   */
  protected Session createSession(String sessionId, boolean notify, boolean setId) {

    // inherited from the basic manager
    if ((getMaxActiveSessions() >= 0) && (sessions.size() >= getMaxActiveSessions())) {
      throw new TooManyActiveSessionsException(
          sm.getString("standardManager.createSession.ise"), getMaxActiveSessions());
    }

    Session session = new ReplicatedSession(this);

    // Initialize the properties of the new session and return it
    session.setNew(true);
    session.setValid(true);
    session.setCreationTime(System.currentTimeMillis());
    session.setMaxInactiveInterval(this.maxInactiveInterval);
    if (sessionId == null) sessionId = generateSessionId();
    if (setId) session.setId(sessionId);
    if (notify && (cluster != null)) {
      ((ReplicatedSession) session).setIsDirty(true);
    }
    return (session);
  } // createSession