com.parse.CacheQueryController Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parse-android Show documentation
Show all versions of parse-android Show documentation
A library that gives you access to the powerful Parse cloud platform from your Android app.
/*
* Copyright (c) 2015-present, Parse, LLC.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.parse;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
import java.util.concurrent.Callable;
import bolts.Continuation;
import bolts.Task;
/** package */ class CacheQueryController extends AbstractQueryController {
private final NetworkQueryController networkController;
public CacheQueryController(NetworkQueryController network) {
networkController = network;
}
@Override
public Task> findAsync(
final ParseQuery.State state,
final ParseUser user,
final Task cancellationToken) {
final String sessionToken = user != null ? user.getSessionToken() : null;
CommandDelegate> callbacks = new CommandDelegate>() {
@Override
public Task> runOnNetworkAsync(boolean retry) {
return networkController.findAsync(state, sessionToken, retry, cancellationToken);
}
@Override
public Task> runFromCacheAsync() {
return findFromCacheAsync(state, sessionToken);
}
};
return runCommandWithPolicyAsync(callbacks, state.cachePolicy());
}
@Override
public Task countAsync(
final ParseQuery.State state,
final ParseUser user,
final Task cancellationToken) {
final String sessionToken = user != null ? user.getSessionToken() : null;
CommandDelegate callbacks = new CommandDelegate() {
@Override
public Task runOnNetworkAsync(boolean retry) {
return networkController.countAsync(state, sessionToken, retry, cancellationToken);
}
@Override
public Task runFromCacheAsync() {
return countFromCacheAsync(state, sessionToken);
}
};
return runCommandWithPolicyAsync(callbacks, state.cachePolicy());
}
/**
* Retrieves the results of the last time {@link ParseQuery#find()} was called on a query
* identical to this one.
*
* @param sessionToken The user requesting access.
* @return A list of {@link ParseObject}s corresponding to this query. Returns null if there is no
* cache for this query.
*/
private Task> findFromCacheAsync(
final ParseQuery.State state, String sessionToken) {
final String cacheKey = ParseRESTQueryCommand.findCommand(state, sessionToken).getCacheKey();
return Task.call(new Callable>() {
@Override
public List call() throws Exception {
JSONObject cached = ParseKeyValueCache.jsonFromKeyValueCache(cacheKey, state.maxCacheAge());
if (cached == null) {
throw new ParseException(ParseException.CACHE_MISS, "results not cached");
}
try {
return networkController.convertFindResponse(state, cached);
} catch (JSONException e) {
throw new ParseException(ParseException.CACHE_MISS, "the cache contains corrupted json");
}
}
}, Task.BACKGROUND_EXECUTOR);
}
/**
* Retrieves the results of the last time {@link ParseQuery#count()} was called on a query
* identical to this one.
*
* @param sessionToken The user requesting access.
* @return A list of {@link ParseObject}s corresponding to this query. Returns null if there is no
* cache for this query.
*/
private Task countFromCacheAsync(
final ParseQuery.State state, String sessionToken) {
final String cacheKey = ParseRESTQueryCommand.countCommand(state, sessionToken).getCacheKey();
return Task.call(new Callable() {
@Override
public Integer call() throws Exception {
JSONObject cached = ParseKeyValueCache.jsonFromKeyValueCache(cacheKey, state.maxCacheAge());
if (cached == null) {
throw new ParseException(ParseException.CACHE_MISS, "results not cached");
}
try {
return cached.getInt("count");
} catch (JSONException e) {
throw new ParseException(ParseException.CACHE_MISS, "the cache contains corrupted json");
}
}
}, Task.BACKGROUND_EXECUTOR);
}
private Task runCommandWithPolicyAsync(final CommandDelegate c,
ParseQuery.CachePolicy policy) {
switch (policy) {
case IGNORE_CACHE:
case NETWORK_ONLY:
return c.runOnNetworkAsync(true);
case CACHE_ONLY:
return c.runFromCacheAsync();
case CACHE_ELSE_NETWORK:
return c.runFromCacheAsync().continueWithTask(new Continuation>() {
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
@Override
public Task then(Task task) throws Exception {
if (task.getError() instanceof ParseException) {
return c.runOnNetworkAsync(true);
}
return task;
}
});
case NETWORK_ELSE_CACHE:
return c.runOnNetworkAsync(false).continueWithTask(new Continuation>() {
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
@Override
public Task then(Task task) throws Exception {
Exception error = task.getError();
if (error instanceof ParseException &&
((ParseException) error).getCode() == ParseException.CONNECTION_FAILED) {
return c.runFromCacheAsync();
}
// Either the query succeeded, or there was an an error with the query, not the
// network
return task;
}
});
case CACHE_THEN_NETWORK:
throw new RuntimeException(
"You cannot use the cache policy CACHE_THEN_NETWORK with find()");
default:
throw new RuntimeException("Unknown cache policy: " + policy);
}
}
/**
* A callback that will be used to tell runCommandWithPolicy how to perform the command on the
* network and form the cache.
*/
private interface CommandDelegate {
// Fetches data from the network.
Task runOnNetworkAsync(boolean retry);
// Fetches data from the cache.
Task runFromCacheAsync();
}
}