コード例 #1
0
 /**
  * Get a new session-id from the distributed store
  *
  * @return new session-id
  */
 protected String getNextId() {
   return sessionIDGenerator_.getSessionId();
 }
コード例 #2
0
/**
 * Base abstract implementation of Tomcat manager without the concept of session operations, e.g.,
 * add, remove, etc.
 *
 * @author Ben Wang
 * @author Hany Mesha
 * @author Brian Stansberry
 * @version $Revision: 91181 $
 */
public abstract class JBossManager
    implements AbstractJBossManager, Lifecycle, JBossManagerMBean, PropertyChangeListener {
  // ------------------------------------------------------------------ Fields

  protected ReplicationStatistics stats_ = new ReplicationStatistics();

  /**
   * Session passivation flag set in jboss-web.xml by the user. If true, then the session
   * passivation is enabled for this web application, otherwise, it's disabled
   */
  protected boolean passivationMode_ = false;

  /**
   * Min time (milliseconds) the session must be idle since lastAccesstime before it's eligible for
   * passivation if passivation is enabled and more than maxActiveAllowed_ sessions are in memory.
   * Setting to -1 means it's ignored.
   */
  protected long passivationMinIdleTime_ = -1;

  /**
   * Max time (milliseconds) the session must be idle since lastAccesstime before it will be
   * passivated if passivation is enabled. Setting to -1 means session should not be forced out.
   */
  protected long passivationMaxIdleTime_ = -1;

  /** The lifecycle_ event support for this component. */
  protected LifecycleSupport lifecycle_ = new LifecycleSupport(this);

  /** Has this component been started_ yet? */
  protected boolean started_ = false;

  /**
   * Are we allowing backgroundProcess() to execute? We use an object so stop() can lock on it to
   * wait for
   */
  protected AtomicBoolean backgroundProcessAllowed = new AtomicBoolean();

  /** The objectname this Manager is associated with */
  protected ObjectName objectName_;

  /** The Log object for this class */
  protected Logger log_ = Logger.getLogger(this.getClass().getName());

  /**
   * Whether trace logging is enabled for our logger. Rechecked every time backgroundProcess() is
   * invoked.
   */
  protected boolean trace_ = log_.isTraceEnabled();

  /** The Container with which this Manager is associated. */
  protected Container container_;

  /**
   * /** The distributable flag for Sessions created by this Manager. If this flag is set to <code>
   * true</code>, any user attributes added to a session controlled by this Manager must be
   * Serializable.
   */
  protected boolean distributable_ = true;

  /** The default maximum inactive interval for Sessions created by this Manager. */
  protected int maxInactiveInterval_ = 60;

  /** Maximum of active sessions allowed. -1 is unlimited. */
  protected int maxActiveAllowed_ = -1;

  /** Number of sessions created by this manager */
  protected AtomicInteger createdCounter_ = new AtomicInteger();

  /** number of sessions rejected because the number active sessions exceeds maxActive */
  protected AtomicInteger rejectedCounter_ = new AtomicInteger();

  /** Number of active sessions */
  protected AtomicInteger localActiveCounter_ = new AtomicInteger();

  /** Maximum number of concurrently locally active sessions */
  protected AtomicInteger maxLocalActiveCounter_ = new AtomicInteger();

  /** Maximum number of active sessions seen so far */
  protected AtomicInteger maxActiveCounter_ = new AtomicInteger();

  /** Number of sessions that have been active locally that are now expired. */
  protected AtomicInteger expiredCounter_ = new AtomicInteger();

  /** Number of ms since last call to reset() */
  protected long timeSinceLastReset_ = 0;

  /** Cumulative time spent in backgroundProcess */
  protected AtomicLong processingTime_ = new AtomicLong();

  /** Stores the locally active sessions. */
  protected final Map<String, ClusteredSession<? extends OutgoingDistributableSessionData>>
      sessions_ =
          new ConcurrentHashMap<
              String, ClusteredSession<? extends OutgoingDistributableSessionData>>();

  /** The property change support for this component. */
  protected PropertyChangeSupport support_ = new PropertyChangeSupport(this);

  /** Generates ids for new sessions */
  protected SessionIDGenerator sessionIDGenerator_ = SessionIDGenerator.getInstance();;

  /** Our containing engine's jvmRoute (if it has one) */
  protected String jvmRoute_;

  /** Our JMX Server */
  protected MBeanServer mserver_ = null;

  /** How often calls to backgroundProcess() should trigger expiration/passivation processing */
  protected volatile int processExpiresFrequency = 1;

  /**
   * How many times backgroundProcess() has been called since we last processed
   * expiration/passivation.
   */
  protected int backgroundProcessCount = 0;

  /** Maximum time in ms a now expired session has been alive */
  protected AtomicInteger maxAliveTime = new AtomicInteger();

  /** Average time in ms a now expired session has been alive */
  protected AtomicInteger averageAliveTime = new AtomicInteger();

  /**
   * Number of times our session id generator has generated an id that matches an existing session.
   */
  protected AtomicInteger duplicates_ = new AtomicInteger();

  // TODO Need a string manager to handle localization

  // ------------------------------------------------------------ Constructors

  /** Creates a new JBossManager */
  protected JBossManager() {}

  // -------------------------------------------------------------- Properties

  public boolean getUseSessionPassivation() {
    return passivationMode_;
  }

  public void setUseSessionPassivation(boolean enabled) {
    this.passivationMode_ = enabled;
  }

  public long getPassivationMinIdleTime() {
    return passivationMinIdleTime_;
  }

  public void setPassivationMinIdleTime(long passivationMinIdleTime) {
    this.passivationMinIdleTime_ = passivationMinIdleTime;
  }

  public long getPassivationMaxIdleTime() {
    return passivationMaxIdleTime_;
  }

  public void setPassivationMaxIdleTime(long passivationMaxIdleTime) {
    this.passivationMaxIdleTime_ = passivationMaxIdleTime;
  }

  // ---------------------------------------------------- AbstractJBossManager

  /** {@inheritDoc} */
  public void init(String name, JBossWebMetaData webMetaData)
      throws ClusteringNotSupportedException {
    if (webMetaData.getMaxActiveSessions() != null) {
      maxActiveAllowed_ = webMetaData.getMaxActiveSessions().intValue();
    }

    PassivationConfig pConfig = webMetaData.getPassivationConfig();
    if (pConfig != null) {
      if (pConfig.getUseSessionPassivation() != null) {
        setUseSessionPassivation(pConfig.getUseSessionPassivation().booleanValue());
        if (getUseSessionPassivation()) {
          Integer min = pConfig.getPassivationMinIdleTime();
          if (min != null) setPassivationMinIdleTime(min.intValue());
          Integer max = pConfig.getPassivationMaxIdleTime();
          if (max != null) setPassivationMaxIdleTime(max.intValue());
        }
      }
    }

    log_.debug(
        "init(): maxActiveSessions allowed is "
            + maxActiveAllowed_
            + " and passivationMode is "
            + passivationMode_);
  }

  /** {@inheritDoc} */
  public String getJvmRoute() {
    if (jvmRoute_ == null) {
      Engine e = getEngine();
      jvmRoute_ = (e == null ? null : e.getJvmRoute());
    }
    return jvmRoute_;
  }

  /** {@inheritDoc} */
  public void setNewSessionCookie(String sessionId, HttpServletResponse response) {
    if (response != null) {
      Context context = (Context) container_;
      Connector connector = ((Response) response).getConnector();
      if (context.getCookies()) {
        // set a new session cookie
        TomcatCookie cookie = new TomcatCookie(Globals.SESSION_COOKIE_NAME, sessionId);
        // JBAS-6206. Configure cookie a la o.a.c.connector.Request.configureSessionCookie()
        cookie.setMaxAge(-1);
        if (context.getSessionCookie().getPath() != null) {
          cookie.setPath(context.getSessionCookie().getPath());
        } else {
          String contextPath = context.getEncodedPath();
          if ("".equals(contextPath)) {
            contextPath = "/";
          }
          cookie.setPath(contextPath);
        }
        if (context.getSessionCookie().getComment() != null) {
          cookie.setComment(context.getSessionCookie().getComment());
        }
        if (context.getSessionCookie().getDomain() != null) {
          cookie.setDomain(context.getSessionCookie().getDomain());
        }
        if (context.getSessionCookie().isHttpOnly()) {
          cookie.setHttpOnly(true);
        }
        if (context.getSessionCookie().isSecure()) {
          cookie.setSecure(true);
        }
        if (connector.getSecure()) {
          cookie.setSecure(true);
        }

        if (trace_) {
          log_.trace(
              "Setting cookie with session id:"
                  + sessionId
                  + " & name:"
                  + Globals.SESSION_COOKIE_NAME);
        }

        response.addCookie(cookie);
      }
    }
  }

  // ----------------------------------------------------------------- Manager

  /** {@inheritDoc} */
  public void addPropertyChangeListener(PropertyChangeListener listener) {
    support_.addPropertyChangeListener(listener);
  }

  /** {@inheritDoc} */
  public void removePropertyChangeListener(PropertyChangeListener listener) {
    support_.removePropertyChangeListener(listener);
  }

  /** {@inheritDoc} */
  public void propertyChange(PropertyChangeEvent evt) {
    support_.firePropertyChange(evt);
  }

  /** {@inheritDoc} */
  public void backgroundProcess() {
    // Always reset trace_
    trace_ = log_.isTraceEnabled();

    // For other work, only execute every processExpiresFrequency
    backgroundProcessCount = (backgroundProcessCount + 1) % processExpiresFrequency;
    if (backgroundProcessCount != 0) return;

    synchronized (backgroundProcessAllowed) {
      if (backgroundProcessAllowed.get()) {
        long start = System.currentTimeMillis();

        processExpirationPassivation();

        long elapsed = System.currentTimeMillis() - start;

        processingTime_.addAndGet(elapsed);
      }
    }
  }

  /** {@inheritDoc} */
  public int getActiveSessions() {
    return (int) getLocalActiveSessionCount();
  }

  /** {@inheritDoc} */
  public Container getContainer() {
    return container_;
  }

  /** {@inheritDoc} */
  public void setContainer(Container container) {
    // De-register from the old Container (if any)
    if ((this.container_ != null) && (this.container_ instanceof Context))
      this.container_.removePropertyChangeListener(this);

    // Default processing provided by our superclass
    this.container_ = container;

    // Register with the new Container (if any)
    if ((this.container_ != null) && (this.container_ instanceof Context)) {
      setMaxInactiveInterval(((Context) this.container_).getSessionTimeout() * 60);
      this.container_.addPropertyChangeListener(this);
    }
  }

  /** {@inheritDoc} */
  public boolean getDistributable() {
    return distributable_;
  }

  /** {@inheritDoc} */
  public void setDistributable(boolean distributable) {
    this.distributable_ = distributable;
  }

  /** {@inheritDoc} */
  public int getExpiredSessions() {
    return expiredCounter_.get();
  }

  /** No-op */
  public void setExpiredSessions(int expiredSessions) {
    // ignored
  }

  /** {@inheritDoc} */
  public int getMaxActive() {
    return maxActiveAllowed_;
  }

  /** {@inheritDoc} */
  public void setMaxActive(int maxActive) {
    this.maxActiveAllowed_ = maxActive;
  }

  /** {@inheritDoc} */
  public int getMaxInactiveInterval() {
    return maxInactiveInterval_;
  }

  /** {@inheritDoc} */
  public void setMaxInactiveInterval(int interval) {
    this.maxInactiveInterval_ = interval;
  }

  /** {@inheritDoc} */
  public long getProcessingTime() {
    return this.processingTime_.get();
  }

  /** {@inheritDoc} */
  public int getRejectedSessions() {
    return rejectedCounter_.get();
  }

  /** No-op */
  public void setRejectedSessions(int rejectedSessions) {
    // ignored
  }

  /** {@inheritDoc} */
  public int getSessionAverageAliveTime() {
    return averageAliveTime.get();
  }

  /** No-op */
  public void setSessionAverageAliveTime(int sessionAverageAliveTime) {
    // ignored
  }

  /** {@inheritDoc} */
  public int getSessionCounter() {
    return createdCounter_.get();
  }

  /** No-op */
  public void setSessionCounter(int sessionCounter) {
    // ignored
  }

  /** {@inheritDoc} */
  public int getSessionIdLength() {
    return SessionIDGenerator.SESSION_ID_BYTES;
  }

  /** No-op */
  public void setSessionIdLength(int idLength) {
    // ignored
  }

  /** {@inheritDoc} */
  public int getSessionMaxAliveTime() {
    return maxAliveTime.get();
  }

  /** No-op */
  public void setSessionMaxAliveTime(int sessionAliveTime) {
    // ignored
  }

  /** Throws UnsupportedOperationException */
  public void load() throws ClassNotFoundException, IOException {
    throw new UnsupportedOperationException("load() not supported");
  }

  /** Throws UnsupportedOperationException */
  public void unload() throws IOException {
    throw new UnsupportedOperationException("unload() not supported");
  }

  // -------------------------------------------------------------- Lifecycle

  public void addLifecycleListener(LifecycleListener listener) {
    lifecycle_.addLifecycleListener(listener);
  }

  public LifecycleListener[] findLifecycleListeners() {
    return lifecycle_.findLifecycleListeners();
  }

  public void removeLifecycleListener(LifecycleListener listener) {
    lifecycle_.removeLifecycleListener(listener);
  }

  /**
   * Start this Manager
   *
   * @throws org.apache.catalina.LifecycleException
   */
  public void start() throws LifecycleException {
    startManager();
  }

  /**
   * Stop this Manager
   *
   * @throws org.apache.catalina.LifecycleException
   */
  public void stop() throws LifecycleException {
    // Block for any ongoing backgroundProcess, then disable
    synchronized (backgroundProcessAllowed) {
      backgroundProcessAllowed.set(false);
    }

    resetStats();
    stopManager();
  }

  // ------------------------------------------------------- JBossManagerMBean

  /** {@inheritDoc} */
  public long getActiveSessionCount() {
    return calcActiveSessions();
  }

  /** {@inheritDoc} */
  public String getAlgorithm() {
    return SessionIDGenerator.SESSION_ID_HASH_ALGORITHM;
  }

  /** {@inheritDoc} */
  public String getClassName() {
    return getClass().getName();
  }

  /** {@inheritDoc} */
  public long getCreatedSessionCount() {
    return createdCounter_.get();
  }

  /** {@inheritDoc} */
  public long getExpiredSessionCount() {
    return expiredCounter_.get();
  }

  /** {@inheritDoc} */
  public long getLocalActiveSessionCount() {
    return localActiveCounter_.get();
  }

  /** {@inheritDoc} */
  public int getMaxActiveAllowed() {
    return getMaxActive();
  }

  /** {@inheritDoc} */
  public void setMaxActiveAllowed(int maxActive) {
    setMaxActive(maxActive);
  }

  /** {@inheritDoc} */
  public int getMaxActiveSessions() {
    return getMaxActiveAllowed();
  }

  /** {@inheritDoc} */
  public long getMaxActiveSessionCount() {
    return this.maxActiveCounter_.get();
  }

  /** {@inheritDoc} */
  public long getMaxLocalActiveSessionCount() {
    return maxLocalActiveCounter_.get();
  }

  /** {@inheritDoc} */
  public String getName() {
    return getClass().getSimpleName();
  }

  /** {@inheritDoc} */
  public int getProcessExpiresFrequency() {
    return this.processExpiresFrequency;
  }

  /** {@inheritDoc} */
  public void setProcessExpiresFrequency(int frequency) {
    this.processExpiresFrequency = frequency;
  }

  /** {@inheritDoc} */
  public long getRejectedSessionCount() {
    return rejectedCounter_.get();
  }

  /** {@inheritDoc} */
  public ReplicationStatistics getReplicationStatistics() {
    return stats_;
  }

  /** {@inheritDoc} */
  public long getTimeSinceLastReset() {
    return (System.currentTimeMillis() - timeSinceLastReset_) / (1000L);
  }

  /** {@inheritDoc} */
  public String reportReplicationStatistics() {
    StringBuffer tmp = new StringBuffer();
    tmp.append("<table><tr>");
    tmp.append("<th>sessionID</th>");
    tmp.append("<th>replicationCount</th>");
    tmp.append("<th>minPassivationTime</th>");
    tmp.append("<th>maxPassivationTime</th>");
    tmp.append("<th>totalPassivationTime</th>");
    tmp.append("<th>minReplicationTime</th>");
    tmp.append("<th>maxReplicationTime</th>");
    tmp.append("<th>totalReplicationlTime</th>");
    tmp.append("<th>loadCount</th>");
    tmp.append("<th>minLoadTime</th>");
    tmp.append("<th>maxLoadTime</th>");
    tmp.append("<th>totalLoadTime</th>");

    Map<String, ReplicationStatistics.TimeStatistic> copy =
        new HashMap<String, ReplicationStatistics.TimeStatistic>(stats_.getStats());
    for (Map.Entry<String, ReplicationStatistics.TimeStatistic> entry : copy.entrySet()) {
      ReplicationStatistics.TimeStatistic stat =
          (ReplicationStatistics.TimeStatistic) entry.getValue();
      if (stat != null) {
        tmp.append("<tr><td>");
        tmp.append(entry.getKey());
        tmp.append("</td><td>");
        tmp.append(stat.replicationCount);
        tmp.append("</td><td>");
        tmp.append(stat.minPassivationTime);
        tmp.append("</td><td>");
        tmp.append(stat.maxPassivationTime);
        tmp.append("</td><td>");
        tmp.append(stat.totalPassivationTime);
        tmp.append("</td><td>");
        tmp.append(stat.minReplicationTime);
        tmp.append("</td><td>");
        tmp.append(stat.maxReplicationTime);
        tmp.append("</td><td>");
        tmp.append(stat.totalReplicationlTime);
        tmp.append("</td><td>");
        tmp.append(stat.loadCount);
        tmp.append("</td><td>");
        tmp.append(stat.minLoadTime);
        tmp.append("</td><td>");
        tmp.append(stat.maxLoadTime);
        tmp.append("</td><td>");
        tmp.append(stat.totalLoadlTime);
        tmp.append("</td></tr>");
      }
    }
    tmp.append("</table>");
    copy.clear();
    return tmp.toString();
  }

  /** {@inheritDoc} */
  public String reportReplicationStatisticsCSV() {
    StringBuffer tmp = createCSVHeader();
    Map<String, ReplicationStatistics.TimeStatistic> copy =
        new HashMap<String, ReplicationStatistics.TimeStatistic>(stats_.getStats());
    for (Map.Entry<String, ReplicationStatistics.TimeStatistic> entry : copy.entrySet()) {
      ReplicationStatistics.TimeStatistic stat =
          (ReplicationStatistics.TimeStatistic) entry.getValue();
      if (stat != null) {
        tmp.append("\n");
        tmp.append(entry.getKey());
        tmp.append(",");
        tmp.append(stat.replicationCount);
        tmp.append(",");
        tmp.append(stat.minPassivationTime);
        tmp.append(",");
        tmp.append(stat.maxPassivationTime);
        tmp.append(",");
        tmp.append(stat.totalPassivationTime);
        tmp.append(",");
        tmp.append(stat.minReplicationTime);
        tmp.append(",");
        tmp.append(stat.maxReplicationTime);
        tmp.append(",");
        tmp.append(stat.totalReplicationlTime);
        tmp.append(",");
        tmp.append(stat.loadCount);
        tmp.append(",");
        tmp.append(stat.minLoadTime);
        tmp.append(",");
        tmp.append(stat.maxLoadTime);
        tmp.append(",");
        tmp.append(stat.totalLoadlTime);
      }
    }
    copy.clear();
    return tmp.toString();
  }

  /** {@inheritDoc} */
  public String reportReplicationStatisticsCSV(String sessionId) {
    StringBuffer tmp = createCSVHeader();
    Map<String, ReplicationStatistics.TimeStatistic> stats = stats_.getStats();
    ReplicationStatistics.TimeStatistic stat =
        (ReplicationStatistics.TimeStatistic) stats.get(sessionId);
    if (stat != null) {
      tmp.append("\n");
      tmp.append(sessionId);
      tmp.append(",");
      tmp.append(stat.replicationCount);
      tmp.append(",");
      tmp.append(stat.minPassivationTime);
      tmp.append(",");
      tmp.append(stat.maxPassivationTime);
      tmp.append(",");
      tmp.append(stat.totalPassivationTime);
      tmp.append(",");
      tmp.append(stat.minReplicationTime);
      tmp.append(",");
      tmp.append(stat.maxReplicationTime);
      tmp.append(",");
      tmp.append(stat.totalReplicationlTime);
      tmp.append(",");
      tmp.append(stat.loadCount);
      tmp.append(",");
      tmp.append(stat.minLoadTime);
      tmp.append(",");
      tmp.append(stat.maxLoadTime);
      tmp.append(",");
      tmp.append(stat.totalLoadlTime);
    }
    return tmp.toString();
  }

  /** {@inheritDoc} */
  public void resetStats() {
    stats_.resetStats();
    maxActiveCounter_.set(localActiveCounter_.get());
    rejectedCounter_.set(0);
    createdCounter_.set(0);
    expiredCounter_.set(0);
    processingTime_.set(0);
    maxAliveTime.set(0);
    averageAliveTime.set(0);
    duplicates_.set(0);
    timeSinceLastReset_ = System.currentTimeMillis();
  }

  // ------------------------------------------------------------------ Public

  /** Gets the JMX <code>ObjectName</code> under which our <code>TreeCache</code> is registered. */
  public ObjectName getObjectName() {
    return objectName_;
  }

  // ------------------------------------------------------------------ Protected

  /** Go through all sessions and look if they have expired or need to be passivated. */
  protected abstract void processExpirationPassivation();

  /** Get the total number of active sessions */
  protected abstract int getTotalActiveSessions();

  /**
   * Calculates the number of active sessions, and updates the max # of local active sessions and
   * max # of sessions.
   *
   * <p>Call this method when a new session is added or when an accurate count of active sessions is
   * needed.
   *
   * @return the size of the sessions map + the size of the unloaded sessions map - the count of
   *     passivated sessions
   */
  protected int calcActiveSessions() {
    localActiveCounter_.set(sessions_.size());
    int active = localActiveCounter_.get();
    int maxLocal = maxLocalActiveCounter_.get();
    while (active > maxLocal) {
      if (!maxLocalActiveCounter_.compareAndSet(maxLocal, active)) {
        maxLocal = maxLocalActiveCounter_.get();
      }
    }

    int count = getTotalActiveSessions();
    int max = maxActiveCounter_.get();
    while (count > max) {
      if (!maxActiveCounter_.compareAndSet(max, count)) {
        max = maxActiveCounter_.get();
        // Something changed, so reset our count
        count = getTotalActiveSessions();
      }
    }
    return count;
  }

  /**
   * Returns the given session if it is being actively managed by this manager. An actively managed
   * session is on that was either created on this server, brought into local management by a call
   * to {@link #findLocalSession(String)} or brought into local management by a call to {@link
   * #findSessions()}.
   *
   * @param realId the session id, with any trailing jvmRoute removed.
   * @see #getRealId(String)
   */
  protected ClusteredSession<? extends OutgoingDistributableSessionData> findLocalSession(
      String realId) {
    return sessions_.get(realId);
  }

  /**
   * Returns all the sessions that are being actively managed by this manager. This includes those
   * that were created on this server, those that were brought into local management by a call to
   * {@link #findLocalSession(String)} as well as all sessions brought into local management by a
   * call to {@link #findSessions()}.
   */
  protected ClusteredSession<? extends OutgoingDistributableSessionData>[] findLocalSessions() {
    Collection<ClusteredSession<? extends OutgoingDistributableSessionData>> coll =
        sessions_.values();
    @SuppressWarnings("unchecked")
    ClusteredSession<? extends OutgoingDistributableSessionData>[] sess =
        new ClusteredSession[coll.size()];
    return coll.toArray(sess);
  }

  /**
   * Get a new session-id from the distributed store
   *
   * @return new session-id
   */
  protected String getNextId() {
    return sessionIDGenerator_.getSessionId();
  }

  /**
   * Updates statistics to reflect that a session with a given "alive time" has been expired.
   *
   * @param sessionAliveTime number of ms from when the session was created to when it was expired.
   */
  protected void sessionExpired(int sessionAliveTime) {
    int current = maxAliveTime.get();
    while (sessionAliveTime > current) {
      if (maxAliveTime.compareAndSet(current, sessionAliveTime)) break;
      else current = maxAliveTime.get();
    }

    expiredCounter_.incrementAndGet();
    int newAverage;
    do {
      int expCount = expiredCounter_.get();
      current = averageAliveTime.get();
      newAverage = ((current * (expCount - 1)) + sessionAliveTime) / expCount;
    } while (averageAliveTime.compareAndSet(current, newAverage) == false);
  }

  /** Register this Manager with JMX. */
  protected void registerManagerMBean() {
    try {
      MBeanServer server = getMBeanServer();

      String domain;
      if (container_ instanceof ContainerBase) {
        domain = ((ContainerBase) container_).getDomain();
      } else {
        domain = server.getDefaultDomain();
      }
      String hostName = ((Host) container_.getParent()).getName();
      hostName = (hostName == null) ? "localhost" : hostName;
      ObjectName clusterName =
          new ObjectName(
              domain
                  + ":type=Manager,host="
                  + hostName
                  + ",path="
                  + ((Context) container_).getPath());

      if (server.isRegistered(clusterName)) {
        log_.warn("MBean " + clusterName + " already registered");
        return;
      }

      objectName_ = clusterName;
      server.registerMBean(this, clusterName);

    } catch (Exception ex) {
      log_.error("Could not register " + getClass().getSimpleName() + " to MBeanServer", ex);
    }
  }

  /** Unregister this Manager from the JMX server. */
  protected void unregisterManagerMBean() {
    if (mserver_ != null && objectName_ != null) {
      try {
        mserver_.unregisterMBean(objectName_);
      } catch (Exception e) {
        log_.error("Could not unregister " + getClass().getSimpleName() + " from MBeanServer", e);
      }
    }
  }

  /**
   * Get the current MBean Server.
   *
   * @return
   * @throws Exception
   */
  protected MBeanServer getMBeanServer() throws Exception {
    if (mserver_ == null) {
      mserver_ = Registry.getRegistry(null, null).getMBeanServer();
    }
    return mserver_;
  }

  /**
   * Prepare for the beginning of active use of the public methods of this component. This method
   * should be called after <code>configure()</code>, and before any of the public methods of the
   * component are utilized.
   *
   * @throws IllegalStateException if this component has already been started_
   * @throws org.apache.catalina.LifecycleException if this component detects a fatal error that
   *     prevents this component from being used
   */
  protected void startManager() throws LifecycleException {
    log_.debug("Starting JBossManager");

    // Validate and update our current component state
    if (started_) throw new LifecycleException("JBossManager alreadyStarted");

    backgroundProcessAllowed.set(true);

    lifecycle_.fireLifecycleEvent(START_EVENT, null);
    started_ = true;

    // register ClusterManagerMBean to the MBeanServer
    registerManagerMBean();
  }

  /**
   * Gracefully terminate the active use of the public methods of this component. This method should
   * be the last one called on a given instance of this component.
   *
   * @throws IllegalStateException if this component has not been started_
   * @throws org.apache.catalina.LifecycleException if this component detects a fatal error that
   *     needs to be reported
   */
  protected void stopManager() throws LifecycleException {
    log_.debug("Stopping JBossManager");

    // Validate and update our current component state
    if (!started_) throw new LifecycleException("JBossManager notStarted");
    lifecycle_.fireLifecycleEvent(STOP_EVENT, null);
    started_ = false;

    // unregister from the MBeanServer
    unregisterManagerMBean();
  }

  // ----------------------------------------------------------------- Private

  private StringBuffer createCSVHeader() {
    StringBuffer tmp = new StringBuffer();
    tmp.append("sessionID,");
    tmp.append("replicationCount,");
    tmp.append("minPassivationTime,");
    tmp.append("maxPassivationTime,");
    tmp.append("totalPassivationTime,");
    tmp.append("minReplicationTime,");
    tmp.append("maxReplicationTime,");
    tmp.append("totalReplicationlTime,");
    tmp.append("loadCount,");
    tmp.append("minLoadTime,");
    tmp.append("maxLoadTime,");
    tmp.append("totalLoadTime");

    return tmp;
  }

  /**
   * Retrieve the enclosing Engine for this Manager.
   *
   * @return an Engine object (or null).
   */
  private Engine getEngine() {
    Engine e = null;
    for (Container c = getContainer(); e == null && c != null; c = c.getParent()) {
      if (c != null && c instanceof Engine) {
        e = (Engine) c;
      }
    }
    return e;
  }
}