package com.apollographql.apollo.internal;
import com.apollographql.apollo.ApolloCall;
import com.apollographql.apollo.ApolloQueryWatcher;
import com.apollographql.apollo.api.Response;
import com.apollographql.apollo.api.internal.Utils;
import com.apollographql.apollo.cache.normalized.ApolloStore;
import com.apollographql.apollo.cache.normalized.CacheControl;
import com.apollographql.apollo.exception.ApolloCanceledException;
import com.apollographql.apollo.exception.ApolloException;
import com.apollographql.apollo.exception.ApolloHttpException;
import com.apollographql.apollo.exception.ApolloNetworkException;
import com.apollographql.apollo.exception.ApolloParseException;
import java.util.Collections;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
final class RealApolloQueryWatcher<T> implements ApolloQueryWatcher<T> {
private RealApolloCall<T> activeCall;
@Nullable private ApolloCall.Callback<T> callback = null;
private CacheControl refetchCacheControl = CacheControl.CACHE_FIRST;
private volatile boolean canceled;
private boolean executed = false;
private final ApolloStore apolloStore;
private Set<String> dependentKeys = Collections.emptySet();
private final ApolloStore.RecordChangeSubscriber recordChangeSubscriber = new ApolloStore.RecordChangeSubscriber() {
@Override public void onCacheRecordsChanged(Set<String> changedRecordKeys) {
if (!Utils.areDisjoint(dependentKeys, changedRecordKeys)) {
refetch();
}
}
};
RealApolloQueryWatcher(RealApolloCall<T> originalCall, ApolloStore apolloStore) {
activeCall = originalCall;
this.apolloStore = apolloStore;
}
@Override public void enqueueAndWatch(@Nullable final ApolloCall.Callback<T> callback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed.");
executed = true;
}
this.callback = callback;
activeCall.enqueue(callbackProxy(this.callback));
}
@Nonnull @Override public RealApolloQueryWatcher<T> refetchCacheControl(@Nonnull CacheControl cacheControl) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
}
Utils.checkNotNull(cacheControl, "httpCacheControl == null");
this.refetchCacheControl = cacheControl;
return this;
}
@Override public void cancel() {
canceled = true;
activeCall.cancel();
apolloStore.unsubscribe(recordChangeSubscriber);
}
@Override public boolean isCanceled() {
return canceled;
}
private void refetch() {
apolloStore.unsubscribe(recordChangeSubscriber);
activeCall.cancel();
activeCall = activeCall.clone().cacheControl(refetchCacheControl);
activeCall.enqueue(callbackProxy(this.callback));
}
private ApolloCall.Callback<T> callbackProxy(final ApolloCall.Callback<T> sourceCallback) {
return new ApolloCall.Callback<T>() {
@Override public void onResponse(@Nonnull Response<T> response) {
if (canceled) return;
dependentKeys = response.dependentKeys();
apolloStore.subscribe(recordChangeSubscriber);
sourceCallback.onResponse(response);
}
@Override public void onHttpError(@Nonnull ApolloHttpException e) {
if (canceled) return;
sourceCallback.onHttpError(e);
}
@Override public void onNetworkError(@Nonnull ApolloNetworkException e) {
if (canceled) return;
sourceCallback.onNetworkError(e);
}
@Override public void onParseError(@Nonnull ApolloParseException e) {
if (canceled) return;
sourceCallback.onParseError(e);
}
@Override public void onCanceledError(@Nonnull ApolloCanceledException e) {
if (canceled) return;
sourceCallback.onCanceledError(e);
}
@Override public void onFailure(@Nonnull ApolloException e) {
if (canceled) return;
sourceCallback.onFailure(e);
}
};
}
}