/**
     * Run the maintenance thread. Every REFRESH seconds, re-register this app server as alive in
     * the cluster. Then check for any cluster entries that are more than EXPIRED seconds old,
     * indicating a failed app server, and remove that record, that server's sessions, generating
     * appropriate session events so the other app servers know what's going on. The "then" checks
     * need not be done each iteration - run them on 1 of n randomly choosen iterations. In a
     * clustered environment, this also distributes the work over the cluster better.
     */
    public void run() {
      // wait till things are rolling
      ComponentManager.waitTillConfigured();

      if (M_log.isDebugEnabled()) M_log.debug("run()");

      while (!m_maintenanceCheckerStop) {
        try {
          final String serverIdInstance = m_serverConfigurationService.getServerIdInstance();

          if (M_log.isDebugEnabled()) M_log.debug("checking...");

          // if we have been closed, reopen!
          String statement = clusterServiceSql.getReadServerSql();
          Object[] fields = new Object[1];
          fields[0] = serverIdInstance;
          List results = m_sqlService.dbRead(statement, fields, null);
          if (results.isEmpty()) {
            M_log.warn(
                "run(): server has been closed in cluster table, reopened: " + serverIdInstance);

            statement = clusterServiceSql.getInsertServerSql();
            fields[0] = serverIdInstance;
            boolean ok = m_sqlService.dbWrite(statement, fields);
            if (!ok) {
              M_log.warn("start(): dbWrite failed");
            }
          }

          // update our alive and well status
          else {
            // register that this app server is alive and well
            statement = clusterServiceSql.getUpdateServerSql();
            fields[0] = serverIdInstance;
            boolean ok = m_sqlService.dbWrite(statement, fields);
            if (!ok) {
              M_log.warn("run(): dbWrite failed: " + statement);
            }
          }

          // pick a random number, 0..99, to see if we want to do the full ghosting / cleanup
          // activities now
          int rand = (int) (Math.random() * 100.0);
          if (rand < m_ghostingPercent) {
            // get all expired open app servers not me
            statement = clusterServiceSql.getListExpiredServers(m_expired);
            // setup the fields to skip reading me!
            fields[0] = serverIdInstance;

            List instances = m_sqlService.dbRead(statement, fields, null);

            // close any severs found to be expired
            for (Iterator iInstances = instances.iterator(); iInstances.hasNext(); ) {
              String serverId = (String) iInstances.next();

              // close the server - delete the record
              statement = clusterServiceSql.getDeleteServerSql();
              fields[0] = serverId;
              boolean ok = m_sqlService.dbWrite(statement, fields);
              if (!ok) {
                M_log.warn("run(): dbWrite failed: " + statement);
              }

              M_log.warn(
                  "run(): ghost-busting server: " + serverId + " from : " + serverIdInstance);
            }

            // Close all sessions left over from deleted servers.
            int nbrClosed = m_usageSessionService.closeSessionsOnInvalidServers(getServers());
            if ((nbrClosed > 0) && M_log.isInfoEnabled())
              M_log.info("Closed " + nbrClosed + " orphaned usage session records");

            // Delete any orphaned locks from closed or missing sessions.
            statement = clusterServiceSql.getOrphanedLockSessionsSql();
            List sessions = m_sqlService.dbRead(statement);
            if (sessions.size() > 0) {
              if (M_log.isInfoEnabled())
                M_log.info(
                    "Found " + sessions.size() + " closed or deleted sessions in lock table");
              statement = clusterServiceSql.getDeleteLocksSql();
              for (Iterator iSessions = sessions.iterator(); iSessions.hasNext(); ) {
                fields[0] = (String) iSessions.next();
                boolean ok = m_sqlService.dbWrite(statement, fields);
                if (!ok) {
                  M_log.warn("run(): dbWrite failed: " + statement);
                }
              }
            }
          }
        } catch (Throwable e) {
          M_log.warn("exception: ", e);
        } finally {
          // clear out any current access bindings
          m_threadLocalManager.clear();
        }

        // cycle every REFRESH seconds
        if (!m_maintenanceCheckerStop) {
          try {
            Thread.sleep(m_refresh * 1000L);
          } catch (Exception ignore) {
          }
        }
      }

      if (M_log.isDebugEnabled()) M_log.debug("done");
    }