/** {@inheritDoc} */
  public ConfigChangeResult applyConfigurationAdd(LogRotationPolicyCfg config) {
    // Default result code.
    ResultCode resultCode = ResultCode.SUCCESS;
    boolean adminActionRequired = false;
    ArrayList<Message> messages = new ArrayList<Message>();

    try {
      RotationPolicy rotationPolicy = getRotationPolicy(config);

      DirectoryServer.registerRotationPolicy(config.dn(), rotationPolicy);
    } catch (ConfigException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      messages.add(e.getMessageObject());
      resultCode = DirectoryServer.getServerErrorResultCode();
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }

      messages.add(
          ERR_CONFIG_ROTATION_POLICY_CANNOT_CREATE_POLICY.get(
              String.valueOf(config.dn().toString()), stackTraceToSingleLineString(e)));
      resultCode = DirectoryServer.getServerErrorResultCode();
    }

    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
  }
  /** {@inheritDoc} */
  public ConfigChangeResult applyConfigurationAdd(RootDNUserCfg configuration) {
    configuration.addChangeListener(this);

    ResultCode resultCode = ResultCode.SUCCESS;
    boolean adminActionRequired = false;
    ArrayList<Message> messages = new ArrayList<Message>();

    HashSet<DN> altBindDNs = new HashSet<DN>();
    for (DN altBindDN : configuration.getAlternateBindDN()) {
      try {
        DirectoryServer.registerAlternateRootDN(configuration.dn(), altBindDN);
        altBindDNs.add(altBindDN);
      } catch (DirectoryException de) {
        // This shouldn't happen, since the set of DNs should have already been
        // validated.
        resultCode = DirectoryServer.getServerErrorResultCode();
        messages.add(de.getMessageObject());

        for (DN dn : altBindDNs) {
          DirectoryServer.deregisterAlternateRootBindDN(dn);
        }
        break;
      }
    }

    if (resultCode == ResultCode.SUCCESS) {
      DirectoryServer.registerRootDN(configuration.dn());
      alternateBindDNs.put(configuration.dn(), altBindDNs);
    }

    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
  }
  /** {@inheritDoc} */
  public ConfigChangeResult applyConfigurationChange(RootDNUserCfg configuration) {
    ResultCode resultCode = ResultCode.SUCCESS;
    boolean adminActionRequired = false;
    ArrayList<Message> messages = new ArrayList<Message>();

    HashSet<DN> setDNs = new HashSet<DN>();
    HashSet<DN> addDNs = new HashSet<DN>();
    HashSet<DN> delDNs = new HashSet<DN>(alternateBindDNs.get(configuration.dn()));

    for (DN altBindDN : configuration.getAlternateBindDN()) {
      setDNs.add(altBindDN);

      if (!delDNs.remove(altBindDN)) {
        addDNs.add(altBindDN);
      }
    }

    for (DN dn : delDNs) {
      DirectoryServer.deregisterAlternateRootBindDN(dn);
    }

    HashSet<DN> addedDNs = new HashSet<DN>(addDNs.size());
    for (DN dn : addDNs) {
      try {
        DirectoryServer.registerAlternateRootDN(configuration.dn(), dn);
        addedDNs.add(dn);
      } catch (DirectoryException de) {
        // This shouldn't happen, since the set of DNs should have already been
        // validated.
        resultCode = DirectoryServer.getServerErrorResultCode();
        messages.add(de.getMessageObject());

        for (DN addedDN : addedDNs) {
          DirectoryServer.deregisterAlternateRootBindDN(addedDN);
        }

        for (DN deletedDN : delDNs) {
          try {
            DirectoryServer.registerAlternateRootDN(configuration.dn(), deletedDN);
          } catch (Exception e) {
            // This should also never happen.
            alternateBindDNs.get(configuration.dn()).remove(deletedDN);
          }
        }
      }
    }

    if (resultCode == ResultCode.SUCCESS) {
      alternateBindDNs.put(configuration.dn(), setDNs);
    }

    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
  }
  /** {@inheritDoc} */
  public ConfigChangeResult applyConfigurationDelete(LogRotationPolicyCfg config) {
    // Default result code.
    ResultCode resultCode = ResultCode.SUCCESS;
    boolean adminActionRequired = false;
    ArrayList<Message> messages = new ArrayList<Message>();

    RotationPolicy policy = DirectoryServer.getRotationPolicy(config.dn());
    if (policy != null) {
      DirectoryServer.deregisterRotationPolicy(config.dn());
    } else {
      // TODO: Add message and check for usage
      resultCode = DirectoryServer.getServerErrorResultCode();
    }

    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
  }
  private void processSearch(BooleanHolder executePostOpPlugins) throws CanceledOperationException {
    // Process the search base and filter to convert them from their raw forms
    // as provided by the client to the forms required for the rest of the
    // search processing.
    baseDN = getBaseDN();
    filter = getFilter();

    if (baseDN == null || filter == null) {
      return;
    }

    // Check to see if there are any controls in the request. If so, then
    // see if there is any special processing required.
    try {
      handleRequestControls();
    } catch (DirectoryException de) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, de);
      }

      setResponseData(de);
      return;
    }

    // Check to see if the client has permission to perform the
    // search.

    // FIXME: for now assume that this will check all permission
    // pertinent to the operation. This includes proxy authorization
    // and any other controls specified.
    try {
      if (!AccessControlConfigManager.getInstance().getAccessControlHandler().isAllowed(this)) {
        setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
        appendErrorMessage(ERR_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(String.valueOf(baseDN)));
        return;
      }
    } catch (DirectoryException e) {
      setResultCode(e.getResultCode());
      appendErrorMessage(e.getMessageObject());
      return;
    }

    // Check for a request to cancel this operation.
    checkIfCanceled(false);

    // Invoke the pre-operation search plugins.
    executePostOpPlugins.value = true;
    PluginResult.PreOperation preOpResult =
        DirectoryServer.getPluginConfigManager().invokePreOperationSearchPlugins(this);
    if (!preOpResult.continueProcessing()) {
      setResultCode(preOpResult.getResultCode());
      appendErrorMessage(preOpResult.getErrorMessage());
      setMatchedDN(preOpResult.getMatchedDN());
      setReferralURLs(preOpResult.getReferralURLs());
      return;
    }

    // Check for a request to cancel this operation.
    checkIfCanceled(false);

    // Get the backend that should hold the search base. If there is none,
    // then fail.
    if (backend == null) {
      setResultCode(ResultCode.NO_SUCH_OBJECT);
      appendErrorMessage(ERR_SEARCH_BASE_DOESNT_EXIST.get(String.valueOf(baseDN)));
      return;
    }

    // We'll set the result code to "success". If a problem occurs, then it
    // will be overwritten.
    setResultCode(ResultCode.SUCCESS);

    try {
      // If there's a persistent search, then register it with the server.
      boolean processSearchNow = true;
      if (persistentSearch != null) {
        // If we're only interested in changes, then we do not actually want
        // to process the search now.
        processSearchNow = !persistentSearch.isChangesOnly();

        // The Core server maintains the count of concurrent persistent searches
        // so that all the backends (Remote and Local) are aware of it. Verify
        // with the core if we have already reached the threshold.
        if (!DirectoryServer.allowNewPersistentSearch()) {
          setResultCode(ResultCode.ADMIN_LIMIT_EXCEEDED);
          appendErrorMessage(ERR_MAX_PSEARCH_LIMIT_EXCEEDED.get());
          return;
        }
        backend.registerPersistentSearch(persistentSearch);
        persistentSearch.enable();
      }

      if (processSearchNow) {
        // Process the search in the backend and all its subordinates.
        backend.search(this);
      }
    } catch (DirectoryException de) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.VERBOSE, de);
      }

      setResponseData(de);

      if (persistentSearch != null) {
        persistentSearch.cancel();
        setSendResponse(true);
      }

      return;
    } catch (CanceledOperationException coe) {
      if (persistentSearch != null) {
        persistentSearch.cancel();
        setSendResponse(true);
      }

      throw coe;
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }

      setResultCode(DirectoryServer.getServerErrorResultCode());
      appendErrorMessage(ERR_SEARCH_BACKEND_EXCEPTION.get(getExceptionMessage(e)));

      if (persistentSearch != null) {
        persistentSearch.cancel();
        setSendResponse(true);
      }
    }
  }