com.parse.ParseRelationOperation.java Source code

Java tutorial

Introduction

Here is the source code for com.parse.ParseRelationOperation.java

Source

/*
 * 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 java.util.Collection;
import java.util.HashSet;
import java.util.Set;

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

/**
 * An operation where a ParseRelation's value is modified.
 */
/** package */
class ParseRelationOperation<T extends ParseObject> implements ParseFieldOperation {
    // The className of the target objects.
    private final String targetClass;

    // A set of objects to add to this relation.
    private final Set<ParseObject> relationsToAdd;
    // A set of objects to remove from this relation.
    private final Set<ParseObject> relationsToRemove;

    ParseRelationOperation(Set<T> newRelationsToAdd, Set<T> newRelationsToRemove) {
        String targetClass = null;
        relationsToAdd = new HashSet<>();
        relationsToRemove = new HashSet<>();

        if (newRelationsToAdd != null) {
            for (T object : newRelationsToAdd) {
                addParseObjectToSet(object, relationsToAdd);

                if (targetClass == null) {
                    targetClass = object.getClassName();
                } else {
                    if (!targetClass.equals(object.getClassName())) {
                        throw new IllegalArgumentException("All objects in a relation must be of the same class.");
                    }
                }
            }
        }

        if (newRelationsToRemove != null) {
            for (T object : newRelationsToRemove) {
                addParseObjectToSet(object, relationsToRemove);

                if (targetClass == null) {
                    targetClass = object.getClassName();
                } else {
                    if (!targetClass.equals(object.getClassName())) {
                        throw new IllegalArgumentException("All objects in a relation must be of the same class.");
                    }
                }
            }
        }

        if (targetClass == null) {
            throw new IllegalArgumentException("Cannot create a ParseRelationOperation with no objects.");
        }
        this.targetClass = targetClass;
    }

    private ParseRelationOperation(String newTargetClass, Set<ParseObject> newRelationsToAdd,
            Set<ParseObject> newRelationsToRemove) {
        targetClass = newTargetClass;
        relationsToAdd = new HashSet<>(newRelationsToAdd);
        relationsToRemove = new HashSet<>(newRelationsToRemove);
    }

    /*
     * Adds a ParseObject to a set, replacing any existing instance of the same object.
     */
    private void addParseObjectToSet(ParseObject obj, Set<ParseObject> set) {
        if (Parse.getLocalDatastore() != null || obj.getObjectId() == null) {
            // There's no way there could be duplicate instances.
            set.add(obj);
            return;
        }

        // We have to do this the hard way.
        for (ParseObject existingObject : set) {
            if (obj.getObjectId().equals(existingObject.getObjectId())) {
                set.remove(existingObject);
            }
        }
        set.add(obj);
    }

    /*
     * Adds a list of ParseObject to a set, replacing any existing instance of the same object.
     */
    private void addAllParseObjectsToSet(Collection<ParseObject> list, Set<ParseObject> set) {
        for (ParseObject obj : list) {
            addParseObjectToSet(obj, set);
        }
    }

    /*
     * Removes an object (and any duplicate instances of that object) from the set.
     */
    private void removeParseObjectFromSet(ParseObject obj, Set<ParseObject> set) {
        if (Parse.getLocalDatastore() != null || obj.getObjectId() == null) {
            // There's no way there could be duplicate instances.
            set.remove(obj);
            return;
        }

        // We have to do this the hard way.
        for (ParseObject existingObject : set) {
            if (obj.getObjectId().equals(existingObject.getObjectId())) {
                set.remove(existingObject);
            }
        }
    }

    /*
     * Removes all objects (and any duplicate instances of those objects) from the set.
     */
    private void removeAllParseObjectsFromSet(Collection<ParseObject> list, Set<ParseObject> set) {
        for (ParseObject obj : list) {
            removeParseObjectFromSet(obj, set);
        }
    }

    String getTargetClass() {
        return targetClass;
    }

    /*
     * Converts a set of objects into a JSONArray of Parse pointers.
     */
    JSONArray convertSetToArray(Set<ParseObject> set, ParseEncoder objectEncoder) throws JSONException {
        JSONArray array = new JSONArray();
        for (ParseObject obj : set) {
            array.put(objectEncoder.encode(obj));
        }
        return array;
    }

    // Encodes any add/removes ops to JSON to send to the server.
    @Override
    public JSONObject encode(ParseEncoder objectEncoder) throws JSONException {
        JSONObject adds = null;
        JSONObject removes = null;

        if (relationsToAdd.size() > 0) {
            adds = new JSONObject();
            adds.put("__op", "AddRelation");
            adds.put("objects", convertSetToArray(relationsToAdd, objectEncoder));
        }

        if (relationsToRemove.size() > 0) {
            removes = new JSONObject();
            removes.put("__op", "RemoveRelation");
            removes.put("objects", convertSetToArray(relationsToRemove, objectEncoder));
        }

        if (adds != null && removes != null) {
            JSONObject result = new JSONObject();
            result.put("__op", "Batch");
            JSONArray ops = new JSONArray();
            ops.put(adds);
            ops.put(removes);
            result.put("ops", ops);
            return result;
        }

        if (adds != null) {
            return adds;
        }

        if (removes != null) {
            return removes;
        }

        throw new IllegalArgumentException("A ParseRelationOperation was created without any data.");
    }

    @Override
    public ParseFieldOperation mergeWithPrevious(ParseFieldOperation previous) {
        if (previous == null) {
            return this;

        } else if (previous instanceof ParseDeleteOperation) {
            throw new IllegalArgumentException("You can't modify a relation after deleting it.");

        } else if (previous instanceof ParseRelationOperation) {
            @SuppressWarnings("unchecked")
            ParseRelationOperation<T> previousOperation = (ParseRelationOperation<T>) previous;

            if (previousOperation.targetClass != null && !previousOperation.targetClass.equals(targetClass)) {
                throw new IllegalArgumentException("Related object object must be of class "
                        + previousOperation.targetClass + ", but " + targetClass + " was passed in.");
            }

            Set<ParseObject> newRelationsToAdd = new HashSet<>(previousOperation.relationsToAdd);
            Set<ParseObject> newRelationsToRemove = new HashSet<>(previousOperation.relationsToRemove);
            if (relationsToAdd != null) {
                addAllParseObjectsToSet(relationsToAdd, newRelationsToAdd);
                removeAllParseObjectsFromSet(relationsToAdd, newRelationsToRemove);
            }
            if (relationsToRemove != null) {
                removeAllParseObjectsFromSet(relationsToRemove, newRelationsToAdd);
                addAllParseObjectsToSet(relationsToRemove, newRelationsToRemove);
            }
            return new ParseRelationOperation<T>(targetClass, newRelationsToAdd, newRelationsToRemove);

        } else {
            throw new IllegalArgumentException("Operation is invalid after previous operation.");
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object apply(Object oldValue, String key) {
        ParseRelation<T> relation;

        if (oldValue == null) {
            relation = new ParseRelation<>(targetClass);

        } else if (oldValue instanceof ParseRelation) {
            relation = (ParseRelation<T>) oldValue;
            if (targetClass != null && !targetClass.equals(relation.getTargetClass())) {
                throw new IllegalArgumentException("Related object object must be of class "
                        + relation.getTargetClass() + ", but " + targetClass + " was passed in.");
            }
        } else {
            throw new IllegalArgumentException("Operation is invalid after previous operation.");
        }

        for (ParseObject relationToAdd : relationsToAdd) {
            relation.addKnownObject(relationToAdd);
        }
        for (ParseObject relationToRemove : relationsToRemove) {
            relation.removeKnownObject(relationToRemove);
        }
        return relation;
    }
}