/**
   * Performs the work of actually processing this operation. This should include all processing for
   * the operation, including invoking plugins, logging messages, performing access control,
   * managing synchronization, and any other work that might need to be done in the course of
   * processing.
   */
  public final void run() {
    setResultCode(ResultCode.UNDEFINED);

    // Start the processing timer.
    setProcessingStartTime();

    // Log the abandon request message.
    logAbandonRequest(this);

    // Get the plugin config manager that will be used for invoking plugins.
    PluginConfigManager pluginConfigManager = DirectoryServer.getPluginConfigManager();

    // Create a labeled block of code that we can break out of if a problem is
    // detected.
    abandonProcessing:
    {
      // Invoke the pre-parse abandon plugins.
      PluginResult.PreParse preParseResult = pluginConfigManager.invokePreParseAbandonPlugins(this);
      if (!preParseResult.continueProcessing()) {
        setResultCode(preParseResult.getResultCode());
        appendErrorMessage(preParseResult.getErrorMessage());
        setMatchedDN(preParseResult.getMatchedDN());
        setReferralURLs(preParseResult.getReferralURLs());
        break abandonProcessing;
      }

      // Actually perform the abandon operation.  Make sure to set the result
      // code to reflect whether the abandon was successful and an error message
      // if it was not.  Even though there is no response, the result should
      // still be logged.
      //
      // Even though it is technically illegal to send a response for
      // operations that have been abandoned, it may be a good idea to do so
      // to ensure that the requestor isn't left hanging.  This will be a
      // configurable option in the server.
      boolean notifyRequestor = DirectoryServer.notifyAbandonedOperations();

      Message cancelReason = INFO_CANCELED_BY_ABANDON_REQUEST.get(messageID);

      CancelRequest _cancelRequest = new CancelRequest(notifyRequestor, cancelReason);

      CancelResult result = clientConnection.cancelOperation(idToAbandon, _cancelRequest);

      setResultCode(result.getResultCode());
      appendErrorMessage(result.getResponseMessage());

      PluginResult.PostOperation postOpResult =
          pluginConfigManager.invokePostOperationAbandonPlugins(this);
      if (!postOpResult.continueProcessing()) {
        setResultCode(preParseResult.getResultCode());
        appendErrorMessage(preParseResult.getErrorMessage());
        setMatchedDN(preParseResult.getMatchedDN());
        setReferralURLs(preParseResult.getReferralURLs());
        break abandonProcessing;
      }
    }

    // Stop the processing timer.
    setProcessingStopTime();

    // Log the result of the abandon operation.
    logAbandonResult(this);
  }