/** {@inheritDoc} */
    @Override
    public <R extends ExtendedResult> void handleExtendedRequest(
        final Integer messageID,
        final ExtendedRequest<R> request,
        final IntermediateResponseHandler intermediateResponseHandler,
        final LdapResultHandler<R> resultHandler) {
      if (request.getOID().equals(CancelExtendedRequest.OID)) {
        // Decode the request as a cancel request.
        CancelExtendedRequest cancelRequest;
        try {
          cancelRequest =
              CancelExtendedRequest.DECODER.decodeExtendedRequest(request, new DecodeOptions());
        } catch (final DecodeException e) {
          // Couldn't decode a cancel request.
          resultHandler.handleException(
              newLdapException(ResultCode.PROTOCOL_ERROR, e.getLocalizedMessage()));
          return;
        }

        /*
         * Register the request in the pending requests table. Even
         * though this request cannot be cancelled, it is important to
         * do this in order to monitor the number of pending operations.
         */
        final RequestContextImpl<R, LdapResultHandler<R>> requestContext =
            new RequestContextImpl<>(this, resultHandler, messageID, false);
        if (addPendingRequest(requestContext)) {
          // Find and cancel the request.
          final RequestContextImpl<?, ?> cancelledRequest =
              getPendingRequest(cancelRequest.getRequestID());
          if (cancelledRequest != null) {
            final LocalizableMessage cancelReason = INFO_CANCELED_BY_CANCEL_REQUEST.get(messageID);
            cancelledRequest.cancel(cancelReason, request, requestContext, true);
          } else {
            /*
             * Couldn't find the request. Invoke on context in order
             * to remove pending request.
             */
            requestContext.handleException(newLdapException(ResultCode.NO_SUCH_OPERATION));
          }
        }
      } else {
        // StartTLS requests cannot be cancelled.
        boolean isCancelSupported = !request.getOID().equals(StartTLSExtendedRequest.OID);
        final RequestContextImpl<R, LdapResultHandler<R>> requestContext =
            new RequestContextImpl<>(this, resultHandler, messageID, isCancelSupported);

        if (addPendingRequest(requestContext)) {
          requestHandler.handleExtendedRequest(
              requestContext, request, intermediateResponseHandler, requestContext);
        }
      }
    }
 private void handleTooLate() {
   final R cancelResult =
       request.getResultDecoder().newExtendedErrorResult(ResultCode.TOO_LATE, "", "");
   resultHandler.handleException(newLdapException(cancelResult));
 }
 private void handleSuccess() {
   final R cancelResult =
       request.getResultDecoder().newExtendedErrorResult(ResultCode.SUCCESS, "", "");
   resultHandler.handleResult(cancelResult);
 }
    private <R extends ExtendedResult> void cancel(
        final LocalizableMessage reason,
        final ExtendedRequest<R> cancelRequest,
        final LdapResultHandler<R> cancelResultHandler,
        final boolean sendResult) {
      Reject.ifNull(reason);

      if (!isCancelSupported) {
        if (cancelResultHandler != null) {
          final Result result = Responses.newGenericExtendedResult(ResultCode.CANNOT_CANCEL);
          cancelResultHandler.handleException(newLdapException(result));
        }
        return;
      }

      List<CancelRequestListener> tmpListeners = null;
      boolean invokeResultHandler = false;
      boolean resultHandlerIsSuccess = false;

      synchronized (stateLock) {
        switch (state) {
          case PENDING:
            /* Switch to CANCEL_REQUESTED state. */
            cancelRequestReason = reason;
            if (cancelResultHandler != null) {
              cancelResultHandlers = new LinkedList<>();
              cancelResultHandlers.add(
                  new ExtendedResultHandlerHolder<R>(cancelRequest, cancelResultHandler));
            }
            tmpListeners = cancelRequestListeners;
            cancelRequestListeners = null;
            state = RequestState.CANCEL_REQUESTED;
            this.sendResult &= sendResult;
            break;
          case CANCEL_REQUESTED:
            /*
             * Cancel already request so listeners already invoked.
             */
            if (cancelResultHandler != null) {
              if (cancelResultHandlers == null) {
                cancelResultHandlers = new LinkedList<>();
              }
              cancelResultHandlers.add(
                  new ExtendedResultHandlerHolder<R>(cancelRequest, cancelResultHandler));
            }
            break;
          case TOO_LATE:
          case RESULT_SENT:
            /*
             * Cannot cancel, so invoke result handler immediately
             * outside of lock.
             */
            if (cancelResultHandler != null) {
              invokeResultHandler = true;
              resultHandlerIsSuccess = false;
            }
            break;
          case CANCELLED:
            /*
             * Multiple cancellation attempts. Clients should not do
             * this, but the cancel will effectively succeed
             * immediately, so invoke result handler immediately outside
             * of lock.
             */
            if (cancelResultHandler != null) {
              invokeResultHandler = true;
              resultHandlerIsSuccess = true;
            }
            break;
        }
      }

      /* Invoke listeners outside of lock. */
      if (tmpListeners != null) {
        for (final CancelRequestListener listener : tmpListeners) {
          listener.handleCancelRequest(reason);
        }
      }

      if (invokeResultHandler) {
        if (resultHandlerIsSuccess) {
          final R result =
              cancelRequest.getResultDecoder().newExtendedErrorResult(ResultCode.SUCCESS, "", "");
          cancelResultHandler.handleResult(result);
        } else {
          final Result result = Responses.newGenericExtendedResult(ResultCode.TOO_LATE);
          cancelResultHandler.handleException(newLdapException(result));
        }
      }
    }