All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.parse.CacheQueryController Maven / Gradle / Ivy

Go to download

A library that gives you access to the powerful Parse cloud platform from your Android app.

There is a newer version: 1.17.3
Show newest version
/*
 * 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();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy