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

co.easimart.EasimartRelationOperation Maven / Gradle / Ivy

package co.easimart;

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 EasimartRelation's value is modified.
 */
/** package */ class EasimartRelationOperation implements EasimartFieldOperation {
  // The className of the target objects.
  private final String targetClass;

  // A set of objects to add to this relation.
  private final Set relationsToAdd;
  // A set of objects to remove from this relation.
  private final Set relationsToRemove;
  
  EasimartRelationOperation(Set newRelationsToAdd, Set newRelationsToRemove) {
    String targetClass = null;
    relationsToAdd = new HashSet<>();
    relationsToRemove = new HashSet<>();

    if (newRelationsToAdd != null) {
      for (T object : newRelationsToAdd) {
        addEasimartObjectToSet(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) {
        addEasimartObjectToSet(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 EasimartRelationOperation with no objects.");
    }
    this.targetClass = targetClass;
  }

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

  /*
   * Adds a EasimartObject to a set, replacing any existing instance of the same object.
   */
  private void addEasimartObjectToSet(EasimartObject obj, Set set) {
    if (Easimart.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 (EasimartObject existingObject : set) {
      if (obj.getObjectId().equals(existingObject.getObjectId())) {
        set.remove(existingObject);
      }
    }
    set.add(obj);
  }

  /*
   * Adds a list of EasimartObject to a set, replacing any existing instance of the same object.
   */
  private void addAllEasimartObjectsToSet(Collection list, Set set) {
    for (EasimartObject obj : list) {
      addEasimartObjectToSet(obj, set);
    }
  }
  
  /*
   * Removes an object (and any duplicate instances of that object) from the set.
   */
  private void removeEasimartObjectFromSet(EasimartObject obj, Set set) {
    if (Easimart.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 (EasimartObject 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 removeAllEasimartObjectsFromSet(Collection list, Set set) {
    for (EasimartObject obj : list) {
      removeEasimartObjectFromSet(obj, set);
    }
  }

  String getTargetClass() {
    return targetClass;
  }

  /*
   * Converts a set of objects into a JSONArray of Easimart pointers.
   */
  JSONArray convertSetToArray(Set set, EasimartEncoder objectEncoder)
      throws JSONException {
    JSONArray array = new JSONArray();
    for (EasimartObject 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(EasimartEncoder 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 EasimartRelationOperation was created without any data.");
  }

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

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

    } else if (previous instanceof EasimartRelationOperation) {
      @SuppressWarnings("unchecked")
      EasimartRelationOperation previousOperation = (EasimartRelationOperation) 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 newRelationsToAdd = new HashSet<>(previousOperation.relationsToAdd);
      Set newRelationsToRemove = new HashSet<>(previousOperation.relationsToRemove);
      if (relationsToAdd != null) {
        addAllEasimartObjectsToSet(relationsToAdd, newRelationsToAdd);
        removeAllEasimartObjectsFromSet(relationsToAdd, newRelationsToRemove);
      }
      if (relationsToRemove != null) {
        removeAllEasimartObjectsFromSet(relationsToRemove, newRelationsToAdd);
        addAllEasimartObjectsToSet(relationsToRemove, newRelationsToRemove);
      }
      return new EasimartRelationOperation(targetClass, newRelationsToAdd, newRelationsToRemove);

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

  @Override
  @SuppressWarnings("unchecked")
  public Object apply(Object oldValue, String key) {
    EasimartRelation relation;

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

    } else if (oldValue instanceof EasimartRelation) {
      relation = (EasimartRelation) 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 (EasimartObject relationToAdd : relationsToAdd) {
      relation.addKnownObject(relationToAdd);
    }
    for (EasimartObject relationToRemove : relationsToRemove) {
      relation.removeKnownObject(relationToRemove);
    }
    return relation;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy