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; }