@Override
  public void run() {
    setName(handlerName);

    boolean lastIterationFailed = false;
    boolean starting = true;

    while (!shutdownRequested) {
      // If this connection handler is not enabled, then just sleep for a bit and check again.
      if (!this.enabled) {
        if (isListening()) {
          stopHttpServer();
        }

        if (starting) {
          // This may happen if there was an initialisation error which led to disable the
          // connector.
          // The main thread is waiting for the connector to listen on its port, which will not
          // occur yet,
          // so notify here to allow the server startup to complete.
          synchronized (waitListen) {
            starting = false;
            waitListen.notify();
          }
        }

        StaticUtils.sleep(1000);
        continue;
      }

      if (isListening()) {
        // If already listening, then sleep for a bit and check again.
        StaticUtils.sleep(1000);
        continue;
      }

      try {
        // At this point, the connection Handler either started correctly or failed
        // to start but the start process should be notified and resume its work in any cases.
        synchronized (waitListen) {
          waitListen.notify();
        }

        // If we have gotten here, then we are about to start listening
        // for the first time since startup or since we were previously disabled.
        // Start the embedded HTTP server
        startHttpServer();
        lastIterationFailed = false;
      } catch (Exception e) {
        // Clean up the messed up HTTP server
        cleanUpHttpServer();

        // Error + alert about the horked config
        logger.traceException(e);
        logger.error(
            ERR_CONNHANDLER_CANNOT_ACCEPT_CONNECTION,
            friendlyName,
            currentConfig.dn(),
            getExceptionMessage(e));

        if (lastIterationFailed) {
          // The last time through the accept loop we also encountered a failure.
          // Rather than enter a potential infinite loop of failures,
          // disable this acceptor and log an error.
          LocalizableMessage message =
              ERR_CONNHANDLER_CONSECUTIVE_ACCEPT_FAILURES.get(
                  friendlyName, currentConfig.dn(), stackTraceToSingleLineString(e));
          logger.error(message);

          DirectoryServer.sendAlertNotification(
              this, ALERT_TYPE_HTTP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES, message);
          this.enabled = false;
        } else {
          lastIterationFailed = true;
        }
      }
    }

    // Initiate shutdown
    stopHttpServer();
  }
  /**
   * Operates in a loop, accepting new connections and ensuring that requests on those connections
   * are handled properly.
   */
  @Override
  public void run() {
    setName(handlerName);
    boolean listening = false;
    boolean starting = true;

    while (!shutdownRequested) {
      // If this connection handler is not enabled, then just sleep
      // for a bit and check again.
      if (!enabled) {
        if (listening) {
          cleanUpSelector();
          listening = false;

          logger.info(NOTE_CONNHANDLER_STOPPED_LISTENING, handlerName);
        }

        if (starting) {
          // This may happen if there was an initialisation error
          // which led to disable the connector.
          // The main thread is waiting for the connector to listen
          // on its port, which will not occur yet,
          // so notify here to allow the server startup to complete.
          synchronized (waitListen) {
            starting = false;
            waitListen.notify();
          }
        }

        StaticUtils.sleep(1000);
        continue;
      }

      // If we have gotten here, then we are about to start listening
      // for the first time since startup or since we were previously
      // disabled. Make sure to start with a clean selector and then
      // create all the listeners.
      try {
        cleanUpSelector();

        int numRegistered = registerChannels();

        // At this point, the connection Handler either started
        // correctly or failed to start but the start process
        // should be notified and resume its work in any cases.
        synchronized (waitListen) {
          waitListen.notify();
        }

        // If none of the listeners were created successfully, then
        // consider the connection handler disabled and require
        // administrative action before trying again.
        if (numRegistered == 0) {
          logger.error(ERR_LDAP_CONNHANDLER_NO_ACCEPTORS, currentConfig.dn());

          enabled = false;
          continue;
        }

        listening = true;

        // Enter a loop, waiting for new connections to arrive and
        // then accepting them as they come in.
        boolean lastIterationFailed = false;
        while (enabled && !shutdownRequested) {
          try {
            serveIncomingConnections();

            lastIterationFailed = false;
          } catch (Exception e) {
            logger.traceException(e);
            logger.error(
                ERR_CONNHANDLER_CANNOT_ACCEPT_CONNECTION,
                friendlyName,
                currentConfig.dn(),
                getExceptionMessage(e));

            if (lastIterationFailed) {
              // The last time through the accept loop we also
              // encountered a failure. Rather than enter a potential
              // infinite loop of failures, disable this acceptor and
              // log an error.
              LocalizableMessage message =
                  ERR_CONNHANDLER_CONSECUTIVE_ACCEPT_FAILURES.get(
                      friendlyName, currentConfig.dn(), stackTraceToSingleLineString(e));
              logger.error(message);

              DirectoryServer.sendAlertNotification(
                  this, ALERT_TYPE_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES, message);

              cleanUpSelector();
              enabled = false;
            } else {
              lastIterationFailed = true;
            }
          }
        }

        if (shutdownRequested) {
          cleanUpSelector();
          selector.close();
          listening = false;
          enabled = false;
        }

      } catch (Exception e) {
        logger.traceException(e);

        // This is very bad because we failed outside the loop. The
        // only thing we can do here is log a message, send an alert,
        // and disable the selector until an administrator can figure
        // out what's going on.
        LocalizableMessage message =
            ERR_LDAP_CONNHANDLER_UNCAUGHT_ERROR.get(
                currentConfig.dn(), stackTraceToSingleLineString(e));
        logger.error(message);

        DirectoryServer.sendAlertNotification(
            this, ALERT_TYPE_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR, message);

        cleanUpSelector();
        enabled = false;
      }
    }
  }