// Path: nexusdata/src/main/java/com/github/dkharrat/nexusdata/metamodel/Relationship.java
// public class Relationship extends Property {
//     /**
//      * Represents the type of the relationship
//      */
//     public enum Type {
//         TO_ONE,
//         TO_MANY,
//     }
// 
//     private final Type relationshipType;
//     private final Entity<?> destinationEntity;
//     private Relationship inverse;
// 
//     //TODO: look into deducing the 'type' param based on relationshipType
//     /**
//      * Creates a new Attribute.
//      *
//      * @param entity            the associated entity
//      * @param name              the name of the property
//      * @param type              the relationship instance type. For to-one relationships, it must be the same as
//      *                          {@code destinationEntity} (i.e. type of the related object. For to-many relationships,
//      *                          it must be {@link java.util.Set}.
//      * @param relationshipType  the relationship type (to-one or to-many)
//      * @param destinationEntity the entity of the object(s) this relationship will store
//      * @param inverse           the relationship in the other direction (from the destination entity to this
//      *                          relationship's entity
//      * @param isRequired        if true, property is required to have a value
//      */
//     public Relationship(Entity<?> entity, String name, Class<?> type, Type relationshipType, Entity<?> destinationEntity, Relationship inverse, boolean isRequired) {
//         super(entity, name, type, isRequired);
//         this.relationshipType = relationshipType;
//         this.destinationEntity = destinationEntity;
//         this.inverse = inverse;
//     }
// 
//     /**
//      * Returns the relationship type.
//      *
//      * @return the relationship type
//      */
//     public Type getRelationshipType() {
//         return relationshipType;
//     }
// 
//     /**
//      * Indicates whether this relationship is a to-one relationship or not.
//      *
//      * @return true if this relationship is a to-one relationship, or false otherwise
//      */
//     public boolean isToOne() {
//         return relationshipType == Type.TO_ONE;
//     }
// 
//     /**
//      * Indicates whether this relationship is a to-many relationship or not.
//      *
//      * @return true if this relationship is a to-many relationship, or false otherwise
//      */
//     public boolean isToMany() {
//         return relationshipType == Type.TO_MANY;
//     }
// 
//     /**
//      * Returns the entity to which this relationship is related to.
//      *
//      * @return the entity to which this relationship is related to
//      */
//     public Entity<?> getDestinationEntity() {
//         return destinationEntity;
//     }
// 
//     /**
//      * Returns the inverse relationship (i.e the relationship in the other direction).
//      *
//      * @return the inverse relationship
//      */
//     public Relationship getInverse() {
//         return inverse;
//     }
// 
//     void setInverse(Relationship inverse) {
//         this.inverse = inverse;
//     }
// 
//     @Override
//     public boolean isRelationship() {
//         return true;
//     }
// 
//     @Override
//     public String toString() {
//         return super.toString() + "["
//                 +   "destinationEntity=" + (getDestinationEntity() == null ? "<null>" : getDestinationEntity().getName())
//                 + ", inverseRelationship=" + (getInverse() == null ? "<null>" : getInverse().getName())
//                 + "]";
//     }
// }


import java.io.File;
import java.net.URL;
import java.util.*;
import com.github.dkharrat.nexusdata.metamodel.Property;
import com.github.dkharrat.nexusdata.metamodel.Relationship;
import com.github.dkharrat.nexusdata.utils.ObjectUtil;
package com.github.dkharrat.nexusdata.core;



/**
 * An AtomicStore is a persistence store in which data is loaded and saved all at once. It is useful when the data set
 * is small enough to fit in memory and good performance is needed.
 */
public abstract class AtomicStore extends PersistentStore {

    private final Map<ObjectID, StoreCacheNode> idsToCacheNodes = new HashMap<ObjectID, StoreCacheNode>();

    /**
     * Constructs a new Atomic store
     *
     * @param location  the location in which to save the data persistence file
     */
    public AtomicStore(URL location) {
        super(location);
    }

    public AtomicStore(File location) {
        super(location);
    }

    public abstract void load();
    public abstract void save();
    public abstract Object createReferenceObjectForManagedObject(ManagedObject object);

    @Override
    protected void loadMetadata() {
        setUuid(UUID.randomUUID());
    }

    Set<StoreCacheNode> getCacheNodes() {
        return new HashSet<StoreCacheNode>(idsToCacheNodes.values());
    }

    protected void addCacheNode(StoreCacheNode cacheNode) {
        idsToCacheNodes.put(cacheNode.getID(), cacheNode);
    }

    protected void removeCacheNode(StoreCacheNode cacheNode) {
        idsToCacheNodes.remove(cacheNode.getID());
    }

    protected void updateCacheNode(StoreCacheNode cacheNode, ManagedObject object) {
        for(Property property : object.getEntity().getProperties()) {
            Object value = object.getValue(property.getName());
            if (property.isRelationship()) {
// Path: nexusdata/src/main/java/com/github/dkharrat/nexusdata/metamodel/Relationship.java
// public class Relationship extends Property {
//     /**
//      * Represents the type of the relationship
//      */
//     public enum Type {
//         TO_ONE,
//         TO_MANY,
//     }
// 
//     private final Type relationshipType;
//     private final Entity<?> destinationEntity;
//     private Relationship inverse;
// 
//     //TODO: look into deducing the 'type' param based on relationshipType
//     /**
//      * Creates a new Attribute.
//      *
//      * @param entity            the associated entity
//      * @param name              the name of the property
//      * @param type              the relationship instance type. For to-one relationships, it must be the same as
//      *                          {@code destinationEntity} (i.e. type of the related object. For to-many relationships,
//      *                          it must be {@link java.util.Set}.
//      * @param relationshipType  the relationship type (to-one or to-many)
//      * @param destinationEntity the entity of the object(s) this relationship will store
//      * @param inverse           the relationship in the other direction (from the destination entity to this
//      *                          relationship's entity
//      * @param isRequired        if true, property is required to have a value
//      */
//     public Relationship(Entity<?> entity, String name, Class<?> type, Type relationshipType, Entity<?> destinationEntity, Relationship inverse, boolean isRequired) {
//         super(entity, name, type, isRequired);
//         this.relationshipType = relationshipType;
//         this.destinationEntity = destinationEntity;
//         this.inverse = inverse;
//     }
// 
//     /**
//      * Returns the relationship type.
//      *
//      * @return the relationship type
//      */
//     public Type getRelationshipType() {
//         return relationshipType;
//     }
// 
//     /**
//      * Indicates whether this relationship is a to-one relationship or not.
//      *
//      * @return true if this relationship is a to-one relationship, or false otherwise
//      */
//     public boolean isToOne() {
//         return relationshipType == Type.TO_ONE;
//     }
// 
//     /**
//      * Indicates whether this relationship is a to-many relationship or not.
//      *
//      * @return true if this relationship is a to-many relationship, or false otherwise
//      */
//     public boolean isToMany() {
//         return relationshipType == Type.TO_MANY;
//     }
// 
//     /**
//      * Returns the entity to which this relationship is related to.
//      *
//      * @return the entity to which this relationship is related to
//      */
//     public Entity<?> getDestinationEntity() {
//         return destinationEntity;
//     }
// 
//     /**
//      * Returns the inverse relationship (i.e the relationship in the other direction).
//      *
//      * @return the inverse relationship
//      */
//     public Relationship getInverse() {
//         return inverse;
//     }
// 
//     void setInverse(Relationship inverse) {
//         this.inverse = inverse;
//     }
// 
//     @Override
//     public boolean isRelationship() {
//         return true;
//     }
// 
//     @Override
//     public String toString() {
//         return super.toString() + "["
//                 +   "destinationEntity=" + (getDestinationEntity() == null ? "<null>" : getDestinationEntity().getName())
//                 + ", inverseRelationship=" + (getInverse() == null ? "<null>" : getInverse().getName())
//                 + "]";
//     }
// }


// Path: nexusdata/src/main/java/com/github/dkharrat/nexusdata/core/AtomicStore.java
import java.io.File;
import java.net.URL;
import java.util.*;
import com.github.dkharrat.nexusdata.metamodel.Property;
import com.github.dkharrat.nexusdata.metamodel.Relationship;
import com.github.dkharrat.nexusdata.utils.ObjectUtil;

package com.github.dkharrat.nexusdata.core;



/**
 * An AtomicStore is a persistence store in which data is loaded and saved all at once. It is useful when the data set
 * is small enough to fit in memory and good performance is needed.
 */
public abstract class AtomicStore extends PersistentStore {

    private final Map<ObjectID, StoreCacheNode> idsToCacheNodes = new HashMap<ObjectID, StoreCacheNode>();

    /**
     * Constructs a new Atomic store
     *
     * @param location  the location in which to save the data persistence file
     */
    public AtomicStore(URL location) {
        super(location);
    }

    public AtomicStore(File location) {
        super(location);
    }

    public abstract void load();
    public abstract void save();
    public abstract Object createReferenceObjectForManagedObject(ManagedObject object);

    @Override
    protected void loadMetadata() {
        setUuid(UUID.randomUUID());
    }

    Set<StoreCacheNode> getCacheNodes() {
        return new HashSet<StoreCacheNode>(idsToCacheNodes.values());
    }

    protected void addCacheNode(StoreCacheNode cacheNode) {
        idsToCacheNodes.put(cacheNode.getID(), cacheNode);
    }

    protected void removeCacheNode(StoreCacheNode cacheNode) {
        idsToCacheNodes.remove(cacheNode.getID());
    }

    protected void updateCacheNode(StoreCacheNode cacheNode, ManagedObject object) {
        for(Property property : object.getEntity().getProperties()) {
            Object value = object.getValue(property.getName());
            if (property.isRelationship()) {
                Relationship relationship = (Relationship) property;