package er.neo4jadaptor.ersatz.neo4j; import java.util.HashMap; import java.util.Map; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.Relationship; import com.webobjects.eoaccess.EOAttribute; import com.webobjects.eoaccess.EOEntity; import com.webobjects.eoaccess.EORelationship; import er.neo4jadaptor.ersatz.Ersatz; /** * Ersatz stored using Neo4J {@link PropertyContainer}. * * @author Jedrzej Sobanski */ public abstract class Neo4JErsatz extends Ersatz { protected final EOEntity entity; private final PropertyContainer pc; // source attribute name -> relationship private final Map<String, EORelationship> foreignKeys = new HashMap<>(); /** * Create ersatz using values stored in the given property container. * * @param entity entity that the property container contains record for * @param pc property container to read record values from * @return ersatz for a record stored in property container */ public static Neo4JErsatz create(EOEntity entity, PropertyContainer pc) { if (pc instanceof Node) { return new Neo4JNodeErsatz(entity, (Node) pc); } else if (pc instanceof Relationship) { return new Neo4JRelationshipErsatz(entity, (Relationship) pc); } else { throw new IllegalArgumentException("Property container " + pc + " is not supported/known"); } } protected Neo4JErsatz(EOEntity entity, PropertyContainer pc) { this.entity = entity; this.pc = pc; for (EORelationship rel : entity.relationships()) { if (! rel.isCompound() && ! rel.isToMany()) { if (rel.sourceAttributes().size() != 1) { throw new IllegalArgumentException(); } else { EOAttribute att = rel.sourceAttributes().get(0); foreignKeys.put(att.name(), rel); } } } } public PropertyContainer getPropertyContainer() { return pc; } @Override public Iterable<EOAttribute> attributes() { return entity.attributes(); } private boolean isForeignKey(EOAttribute att) { return foreignKeys.containsKey(att.name()); } /** * Gets ID of an object referenced by the given foreign key * * @param rel foreign key attribute * @return referenced object ID */ protected abstract Number getForeignKeyValue(EORelationship rel); /** * Sets relationship value. * * @param rel relationship to set value for * @param val ID of an object referenced by the relationship */ protected abstract void setForeignKeyValue(EORelationship rel, Number val); @Override public Object get(EOAttribute att) { if (isForeignKey(att)) { EORelationship rel = foreignKeys.get(att.name()); return getForeignKeyValue(rel); } else { return getAttribute(pc, att); } } @Override public void put(EOAttribute att, Object value) { if (isForeignKey(att)) { EORelationship rel = foreignKeys.get(att.name()); setForeignKeyValue(rel, (Number) value); } else { setAttribute(pc, att, value); } } /** * Gets EO attribute value from a property container. * * @param container * @param att * @return EO attribute value */ public static Object getAttribute(PropertyContainer container, EOAttribute att) { Object libraryValue = container.getProperty(att.name(), null); // if property is not set then use null as default return Neo4JTranslator.instance.toNeutralValue(libraryValue, att); } protected static void setAttribute(PropertyContainer pc, EOAttribute att, Object value ) { Object libraryValue = Neo4JTranslator.instance.fromNeutralValue(value, att); if (libraryValue != null) { pc.setProperty(att.name(), libraryValue); } else { pc.removeProperty(att.name()); } } @Override public void remove(EOAttribute att) { pc.removeProperty(att.name()); } }