void revalidateCacheEntry(
            final ResponseCacheControl responseCacheControl,
            final CacheHit hit,
            final HttpHost target,
            final HttpRequest request,
            final AsyncEntityProducer entityProducer,
            final AsyncExecChain.Scope scope,
            final AsyncExecChain chain,
            final AsyncExecCallback asyncExecCallback) {
        final Instant requestDate = getCurrentDate();
        final HttpRequest conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(
                responseCacheControl,
                BasicRequestBuilder.copy(request).build(),
                hit.entry);
        final HttpCacheContext context = HttpCacheContext.cast(scope.clientContext);
        chainProceed(conditionalRequest, entityProducer, scope, chain, new AsyncExecCallback() {

            final AtomicReference<AsyncExecCallback> callbackRef = new AtomicReference<>();

            void triggerUpdatedCacheEntryResponse(final HttpResponse backendResponse, final Instant responseDate) {
                final CancellableDependency operation = scope.cancellableDependency;
                operation.setDependency(responseCache.update(
                        hit,
                        target,
                        request,
                        backendResponse,
                        requestDate,
                        responseDate,
                        new FutureCallback<CacheHit>() {

                            @Override
                            public void completed(final CacheHit updated) {
                                try {
                                    final SimpleHttpResponse cacheResponse = generateCachedResponse(request, updated.entry, responseDate);
                                    context.setCacheEntry(updated.entry);
                                    triggerResponse(cacheResponse, scope, asyncExecCallback);
                                } catch (final ResourceIOException ex) {
                                    asyncExecCallback.failed(ex);
                                }
                            }

                            @Override
                            public void failed(final Exception ex) {
                                asyncExecCallback.failed(ex);
                            }

                            @Override
                            public void cancelled() {
                                asyncExecCallback.failed(new InterruptedIOException());
                            }

                        }));
            }

            AsyncExecCallback evaluateResponse(final HttpResponse backendResponse, final Instant responseDate) {
                final int statusCode = backendResponse.getCode();
                if (statusCode == HttpStatus.SC_NOT_MODIFIED || statusCode == HttpStatus.SC_OK) {
                    context.setCacheResponseStatus(CacheResponseStatus.VALIDATED);
                    cacheUpdates.getAndIncrement();
                }
                if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
                    return new AsyncExecCallbackWrapper(() -> triggerUpdatedCacheEntryResponse(backendResponse, responseDate), asyncExecCallback::failed);
                }
                return new BackendResponseHandler(target, conditionalRequest, requestDate, responseDate, scope, asyncExecCallback);
            }

            @Override
            public AsyncDataConsumer handleResponse(
                    final HttpResponse backendResponse1,
                    final EntityDetails entityDetails) throws HttpException, IOException {

                final Instant responseDate = getCurrentDate();

                final AsyncExecCallback callback1;
                if (HttpCacheEntry.isNewer(hit.entry, backendResponse1)) {

                    final HttpRequest unconditional = conditionalRequestBuilder.buildUnconditionalRequest(
                            BasicRequestBuilder.copy(scope.originalRequest).build());

                    callback1 = new AsyncExecCallbackWrapper(() -> chainProceed(unconditional, entityProducer, scope, chain, new AsyncExecCallback() {

                        @Override
                        public AsyncDataConsumer handleResponse(
                                final HttpResponse backendResponse2,
                                final EntityDetails entityDetails1) throws HttpException, IOException {
                            final Instant responseDate2 = getCurrentDate();
                            final AsyncExecCallback callback2 = evaluateResponse(backendResponse2, responseDate2);
                            callbackRef.set(callback2);
                            return callback2.handleResponse(backendResponse2, entityDetails1);
                        }

                        @Override
                        public void handleInformationResponse(final HttpResponse response) throws HttpException, IOException {
                            final AsyncExecCallback callback2 = callbackRef.getAndSet(null);
                            if (callback2 != null) {
                                callback2.handleInformationResponse(response);
                            } else {
                                asyncExecCallback.handleInformationResponse(response);
                            }
                        }

                        @Override
                        public void completed() {
                            final AsyncExecCallback callback2 = callbackRef.getAndSet(null);
                            if (callback2 != null) {
                                callback2.completed();
                            } else {
                                asyncExecCallback.completed();
                            }
                        }

                        @Override
                        public void failed(final Exception cause) {
                            final AsyncExecCallback callback2 = callbackRef.getAndSet(null);
                            if (callback2 != null) {
                                callback2.failed(cause);
                            } else {
                                asyncExecCallback.failed(cause);
                            }
                        }

                    }), asyncExecCallback::failed);
                } else {
                    callback1 = evaluateResponse(backendResponse1, responseDate);
                }
                callbackRef.set(callback1);
                return callback1.handleResponse(backendResponse1, entityDetails);
            }

            @Override
            public void handleInformationResponse(final HttpResponse response) throws HttpException, IOException {
                final AsyncExecCallback callback1 = callbackRef.getAndSet(null);
                if (callback1 != null) {
                    callback1.handleInformationResponse(response);
                } else {
                    asyncExecCallback.handleInformationResponse(response);
                }
            }

            @Override
            public void completed() {
                final AsyncExecCallback callback1 = callbackRef.getAndSet(null);
                if (callback1 != null) {
                    callback1.completed();
                } else {
                    asyncExecCallback.completed();
                }
            }

            @Override
            public void failed(final Exception cause) {
                final AsyncExecCallback callback1 = callbackRef.getAndSet(null);
                if (callback1 != null) {
                    callback1.failed(cause);
                } else {
                    asyncExecCallback.failed(cause);
                }
            }

        });

    }
Request executor in the request execution chain that is responsible for
transparent client-side caching.
<p>
The current implementation is conditionally
compliant with HTTP/1.1 (meaning all the MUST and MUST NOTs are obeyed),
although quite a lot, though not all, of the SHOULDs and SHOULD NOTs
are obeyed too.

@since 5.0
httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsyncCachingExec.java