private boolean addPendingRequest(final RequestContextImpl<?, ?> requestContext) {
      final Integer messageID = requestContext.getMessageID();

      if (isClosed.get()) {
        final LocalizableMessage message = INFO_CLIENT_CONNECTION_CLOSING.get();
        requestContext.handleException(
            newLdapException(ResultCode.UNWILLING_TO_PERFORM, message.toString()));
        return false;
      } else if (pendingRequests.putIfAbsent(messageID, requestContext) != null) {
        final LocalizableMessage message =
            WARN_CLIENT_DUPLICATE_MESSAGE_ID.get(requestContext.getMessageID());
        requestContext.handleException(
            newLdapException(ResultCode.PROTOCOL_ERROR, message.toString()));
        return false;
      } else if (isClosed.get()) {
        /*
         * A concurrent close may have already removed the pending
         * request but it will have only been notified for cancellation.
         */
        pendingRequests.remove(messageID);

        final LocalizableMessage message = INFO_CLIENT_CONNECTION_CLOSING.get();
        requestContext.handleException(
            newLdapException(ResultCode.UNWILLING_TO_PERFORM, message.toString()));
        return false;
      } else {
        /*
         * If the connection is closed now then we just have to pay the
         * cost of invoking the request in the request handler.
         */
        return true;
      }
    }
 /** {@inheritDoc} */
 @Override
 public void handleAbandon(final Integer messageID, final AbandonRequest request) {
   final RequestContextImpl<?, ?> abandonedRequest = getPendingRequest(request.getRequestID());
   if (abandonedRequest != null) {
     final LocalizableMessage abandonReason = INFO_CANCELED_BY_ABANDON_REQUEST.get(messageID);
     abandonedRequest.cancel(abandonReason, null, null, false);
   }
 }
    /** {@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 doClose(final LocalizableMessage cancelReason) {
   if (!isClosed.getAndSet(true)) {
     /*
      * At this point if any pending requests are added then we may
      * end up cancelling them, but this does not matter since
      * addPendingRequest will fail the request immediately.
      */
     final Iterator<RequestContextImpl<?, ?>> iterator = pendingRequests.values().iterator();
     while (iterator.hasNext()) {
       final RequestContextImpl<?, ?> pendingRequest = iterator.next();
       pendingRequest.cancel(cancelReason, null, null, false);
       iterator.remove();
     }
   }
 }
 /**
  * Deregister a request context once it has completed.
  *
  * @param requestContext The request context.
  * @return {@code true} if the request context was found and removed.
  */
 private boolean removePendingRequest(final RequestContextImpl<?, ?> requestContext) {
   return pendingRequests.remove(requestContext.getMessageID()) != null;
 }