@Override
        public void completed() {
            final String exchangeId = scope.exchangeId;
            final CachingAsyncDataConsumer cachingDataConsumer = cachingConsumerRef.getAndSet(null);
            if (cachingDataConsumer == null || cachingDataConsumer.writtenThrough.get()) {
                asyncExecCallback.completed();
                return;
            }
            final HttpResponse backendResponse = cachingDataConsumer.backendResponse;
            final ByteArrayBuffer buffer = cachingDataConsumer.bufferRef.getAndSet(null);

            // Handle 304 Not Modified responses
            if (backendResponse.getCode() == HttpStatus.SC_NOT_MODIFIED) {
                responseCache.match(target, request, new FutureCallback<CacheMatch>() {

                    @Override
                    public void completed(final CacheMatch result) {
                        final CacheHit hit = result != null ? result.hit : null;
                        if (hit != null) {
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("{} existing cache entry found, updating cache entry", exchangeId);
                            }
                            responseCache.update(
                                    hit,
                                    target,
                                    request,
                                    backendResponse,
                                    requestDate,
                                    responseDate,
                                    new FutureCallback<CacheHit>() {

                                        @Override
                                        public void completed(final CacheHit updated) {
                                            if (LOG.isDebugEnabled()) {
                                                LOG.debug("{} cache entry updated, generating response from updated entry", exchangeId);
                                            }
                                            triggerCachedResponse(updated.entry);
                                        }
                                        @Override
                                        public void failed(final Exception cause) {
                                            if (LOG.isDebugEnabled()) {
                                                LOG.debug("{} request failed: {}", exchangeId, cause.getMessage());
                                            }
                                            asyncExecCallback.failed(cause);
                                        }

                                        @Override
                                        public void cancelled() {
                                            if (LOG.isDebugEnabled()) {
                                                LOG.debug("{} cache entry updated aborted", exchangeId);
                                            }
                                            asyncExecCallback.failed(new InterruptedIOException());
                                        }

                                    });
                        } else {
                            triggerNewCacheEntryResponse(backendResponse, responseDate, buffer);
                        }
                    }

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

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

                });
            } else {
                if (cacheConfig.isFreshnessCheckEnabled()) {
                    final CancellableDependency operation = scope.cancellableDependency;
                    operation.setDependency(responseCache.match(target, request, new FutureCallback<CacheMatch>() {

                        @Override
                        public void completed(final CacheMatch result) {
                            final CacheHit hit = result != null ? result.hit : null;
                            if (HttpCacheEntry.isNewer(hit != null ? hit.entry : null, backendResponse)) {
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug("{} backend already contains fresher cache entry", exchangeId);
                                }
                                triggerCachedResponse(hit.entry);
                            } else {
                                triggerNewCacheEntryResponse(backendResponse, responseDate, buffer);
                            }
                        }

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

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

                    }));
                } else {
                    triggerNewCacheEntryResponse(backendResponse, responseDate, buffer);
                }
            }
        }
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