com.apollographql.apollo.internal.fetcher.CacheAndNetworkFetcher Maven / Gradle / Ivy
/**
* Copyright 2018-2019 Amazon.com,
* Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package com.apollographql.apollo.internal.fetcher;
import com.apollographql.apollo.interceptor.ApolloInterceptor;
import com.apollographql.apollo.api.internal.Optional;
import com.apollographql.apollo.exception.ApolloException;
import com.apollographql.apollo.fetcher.ResponseFetcher;
import com.apollographql.apollo.interceptor.ApolloInterceptorChain;
import com.apollographql.apollo.internal.ApolloLogger;
import java.util.concurrent.Executor;
import javax.annotation.Nonnull;
/**
* Signal the apollo client to fetch the data from both the network and the cache. If cached data is not present, only
* network data will be returned. If cached data is available, but network experiences an error, cached data is
* returned. If cache data is not available, and network data is not available, the error of the network request will be
* propagated. If both network and cache are available, both will be returned. Cache data is guaranteed to be returned
* first.
*/
public final class CacheAndNetworkFetcher implements ResponseFetcher {
@Override public ApolloInterceptor provideInterceptor(ApolloLogger apolloLogger) {
return new CacheAndNetworkInterceptor();
}
private static final class CacheAndNetworkInterceptor implements ApolloInterceptor {
private Optional cacheResponse = Optional.absent();
private Optional networkResponse = Optional.absent();
private Optional cacheException = Optional.absent();
private Optional networkException = Optional.absent();
private boolean dispatchedCacheResult;
private ApolloInterceptor.CallBack originalCallback;
private volatile boolean disposed;
@Override
public void interceptAsync(@Nonnull InterceptorRequest request, @Nonnull ApolloInterceptorChain chain,
@Nonnull Executor dispatcher, @Nonnull final CallBack callBack) {
if (disposed) return;
originalCallback = callBack;
InterceptorRequest cacheRequest = request.toBuilder().fetchFromCache(true).build();
chain.proceedAsync(cacheRequest, dispatcher, new CallBack() {
@Override public void onResponse(@Nonnull InterceptorResponse response) {
handleCacheResponse(response);
}
@Override public void onFailure(@Nonnull ApolloException e) {
handleCacheError(e);
}
@Override public void onCompleted() {
}
@Override public void onFetch(FetchSourceType sourceType) {
callBack.onFetch(sourceType);
}
});
InterceptorRequest networkRequest = request.toBuilder().fetchFromCache(false).build();
chain.proceedAsync(networkRequest, dispatcher, new CallBack() {
@Override public void onResponse(@Nonnull InterceptorResponse response) {
handleNetworkResponse(response);
}
@Override public void onFailure(@Nonnull ApolloException e) {
handleNetworkError(e);
}
@Override public void onCompleted() {
}
@Override public void onFetch(FetchSourceType sourceType) {
callBack.onFetch(sourceType);
}
});
}
@Override public void dispose() {
disposed = true;
}
private synchronized void handleNetworkResponse(ApolloInterceptor.InterceptorResponse response) {
networkResponse = Optional.of(response);
dispatch();
}
private synchronized void handleNetworkError(ApolloException exception) {
networkException = Optional.of(exception);
dispatch();
}
private synchronized void handleCacheResponse(ApolloInterceptor.InterceptorResponse response) {
cacheResponse = Optional.of(response);
dispatch();
}
private synchronized void handleCacheError(ApolloException exception) {
cacheException = Optional.of(exception);
dispatch();
}
private synchronized void dispatch() {
if (disposed) {
return;
}
if (!dispatchedCacheResult) {
if (cacheResponse.isPresent()) {
originalCallback.onResponse(cacheResponse.get());
dispatchedCacheResult = true;
} else if (cacheException.isPresent()) {
dispatchedCacheResult = true;
}
}
// Only send the network result after the cache result has been dispatched
if (dispatchedCacheResult) {
if (networkResponse.isPresent()) {
originalCallback.onResponse(networkResponse.get());
originalCallback.onCompleted();
} else if (networkException.isPresent()) {
if (cacheException.isPresent()) {
// Both cache and network errored out
originalCallback.onFailure(networkException.get());
} else {
// Cache was successful. Just terminate.
originalCallback.onCompleted();
}
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy