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

com.parse.ParseFieldOperations Maven / Gradle / Ivy

package com.parse;

import android.os.Parcel;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Utility methods to deal with {@link ParseFieldOperation} decoding, both from JSON objects and
 * from {@link Parcel}s.
 */
/* package */ final class ParseFieldOperations {
  private ParseFieldOperations() {
  }

  /**
   * A function that creates a ParseFieldOperation from a JSONObject or a Parcel.
   */
  private interface ParseFieldOperationFactory {
    ParseFieldOperation decode(JSONObject object, ParseDecoder decoder) throws JSONException;
    ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder);
  }

  // A map of all known decoders.
  private static Map opDecoderMap = new HashMap<>();

  /**
   * Registers a single factory for a given __op field value.
   */
  private static void registerDecoder(String opName, ParseFieldOperationFactory factory) {
    opDecoderMap.put(opName, factory);
  }

  /**
   * Registers a list of default decoder functions that convert a JSONObject with an __op field,
   * or a Parcel with a op name string, into a ParseFieldOperation.
   */
  static void registerDefaultDecoders() {
    registerDecoder(ParseRelationOperation.OP_NAME_BATCH, new ParseFieldOperationFactory() {
      @Override
      public ParseFieldOperation decode(JSONObject object, ParseDecoder decoder)
          throws JSONException {
        ParseFieldOperation op = null;
        JSONArray ops = object.getJSONArray("ops");
        for (int i = 0; i < ops.length(); ++i) {
          ParseFieldOperation nextOp = ParseFieldOperations.decode(ops.getJSONObject(i), decoder);
          op = nextOp.mergeWithPrevious(op);
        }
        return op;
      }

      @Override
      public ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
        // Decode AddRelation and then RemoveRelation
        ParseFieldOperation add = ParseFieldOperations.decode(source, decoder);
        ParseFieldOperation remove = ParseFieldOperations.decode(source, decoder);
        return remove.mergeWithPrevious(add);
      }
    });

    registerDecoder(ParseDeleteOperation.OP_NAME, new ParseFieldOperationFactory() {
      @Override
      public ParseFieldOperation decode(JSONObject object, ParseDecoder decoder)
          throws JSONException {
        return ParseDeleteOperation.getInstance();
      }

      @Override
      public ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
        return ParseDeleteOperation.getInstance();
      }
    });

    registerDecoder(ParseIncrementOperation.OP_NAME, new ParseFieldOperationFactory() {
      @Override
      public ParseFieldOperation decode(JSONObject object, ParseDecoder decoder)
          throws JSONException {
        return new ParseIncrementOperation((Number) decoder.decode(object.opt("amount")));
      }

      @Override
      public ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
        return new ParseIncrementOperation((Number) decoder.decode(source));
      }
    });

    registerDecoder(ParseAddOperation.OP_NAME, new ParseFieldOperationFactory() {
      @Override
      public ParseFieldOperation decode(JSONObject object, ParseDecoder decoder)
          throws JSONException {
        return new ParseAddOperation((Collection) decoder.decode(object.opt("objects")));
      }

      @Override
      public ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
        int size = source.readInt();
        List list = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
          list.add(i, decoder.decode(source));
        }
        return new ParseAddOperation(list);
      }
    });

    registerDecoder(ParseAddUniqueOperation.OP_NAME, new ParseFieldOperationFactory() {
      @Override
      public ParseFieldOperation decode(JSONObject object, ParseDecoder decoder)
          throws JSONException {
        return new ParseAddUniqueOperation((Collection) decoder.decode(object.opt("objects")));
      }

      @Override
      public ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
        int size = source.readInt();
        List list = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
          list.add(i, decoder.decode(source));
        }
        return new ParseAddUniqueOperation(list);
      }
    });

    registerDecoder(ParseRemoveOperation.OP_NAME, new ParseFieldOperationFactory() {
      @Override
      public ParseFieldOperation decode(JSONObject object, ParseDecoder decoder)
          throws JSONException {
        return new ParseRemoveOperation((Collection) decoder.decode(object.opt("objects")));
      }

      @Override
      public ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
        int size = source.readInt();
        List list = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
          list.add(i, decoder.decode(source));
        }
        return new ParseRemoveOperation(list);
      }
    });

    registerDecoder(ParseRelationOperation.OP_NAME_ADD, new ParseFieldOperationFactory() {
      @Override
      public ParseFieldOperation decode(JSONObject object, ParseDecoder decoder)
          throws JSONException {
        JSONArray objectsArray = object.optJSONArray("objects");
        List objectsList = (List) decoder.decode(objectsArray);
        return new ParseRelationOperation<>(new HashSet<>(objectsList), null);
      }

      @Override
      public ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
        int size = source.readInt();
        Set set = new HashSet<>(size);
        for (int i = 0; i < size; i++) {
          set.add((ParseObject) decoder.decode(source));
        }
        return new ParseRelationOperation<>(set, null);
      }
    });

    registerDecoder(ParseRelationOperation.OP_NAME_REMOVE, new ParseFieldOperationFactory() {
      @Override
      public ParseFieldOperation decode(JSONObject object, ParseDecoder decoder)
          throws JSONException {
        JSONArray objectsArray = object.optJSONArray("objects");
        List objectsList = (List) decoder.decode(objectsArray);
        return new ParseRelationOperation<>(null, new HashSet<>(objectsList));
      }

      @Override
      public ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
        int size = source.readInt();
        Set set = new HashSet<>(size);
        for (int i = 0; i < size; i++) {
          set.add((ParseObject) decoder.decode(source));
        }
        return new ParseRelationOperation<>(null, set);
      }
    });

    registerDecoder(ParseSetOperation.OP_NAME, new ParseFieldOperationFactory() {
      @Override
      public ParseFieldOperation decode(JSONObject object, ParseDecoder decoder) throws JSONException {
        return null; // Not called.
      }

      @Override
      public ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
        return new ParseSetOperation(decoder.decode(source));
      }
    });
  }

  /**
   * Converts a parsed JSON object into a ParseFieldOperation.
   *
   * @param encoded
   *          A JSONObject containing an __op field.
   * @return A ParseFieldOperation.
   */
  static ParseFieldOperation decode(JSONObject encoded, ParseDecoder decoder) throws JSONException {
    String op = encoded.optString("__op");
    ParseFieldOperationFactory factory = opDecoderMap.get(op);
    if (factory == null) {
      throw new RuntimeException("Unable to decode operation of type " + op);
    }
    return factory.decode(encoded, decoder);
  }

  /**
   * Reads a ParseFieldOperation out of the given Parcel.
   *
   * @param source
   *          The source Parcel.
   * @param decoder
   *          The given ParseParcelableDecoder.
   *
   * @return A ParseFieldOperation.
   */
  static ParseFieldOperation decode(Parcel source, ParseParcelDecoder decoder) {
    String op = source.readString();
    ParseFieldOperationFactory factory = opDecoderMap.get(op);
    if (factory == null) {
      throw new RuntimeException("Unable to decode operation of type " + op);
    }
    return factory.decode(source, decoder);
  }

  /**
   * Converts a JSONArray into an ArrayList.
   */
  static ArrayList jsonArrayAsArrayList(JSONArray array) {
    ArrayList result = new ArrayList<>(array.length());
    for (int i = 0; i < array.length(); ++i) {
      try {
        result.add(array.get(i));
      } catch (JSONException e) {
        // This can't actually happen.
        throw new RuntimeException(e);
      }
    }
    return result;
  }
}