package org.etk.orm.plugins.bean.mapping; import java.util.Collections; import java.util.LinkedList; import java.util.List; import org.etk.orm.api.RelationshipType; import org.etk.orm.plugins.bean.BeanInfo; import org.etk.orm.plugins.bean.BeanValueInfo; import org.etk.orm.plugins.bean.PropertyInfo; import org.etk.orm.plugins.bean.ValueKind; public abstract class RelationshipMapping<P extends PropertyInfo<BeanValueInfo, K>, R extends RelationshipMapping, K extends ValueKind> extends PropertyMapping<P, BeanValueInfo, K> { /** . */ final Class<R> relatedRelationhipType; /** The related property if any. */ private List<R> relatedRelationshipMapping; /** The related bean mapping. */ BeanMapping relatedBeanMapping; public RelationshipMapping(Class<R> relatedRelationhipType, P property) { super(property); // this.relatedRelationhipType = relatedRelationhipType; this.relatedRelationshipMapping = null; this.relatedBeanMapping = null; } public BeanInfo getRelatedBean() { return property.getValue().getBean(); } public BeanMapping getRelatedBeanMapping() { return relatedBeanMapping; } public List<R> getRelatedRelationshipMapping() { return relatedRelationshipMapping; } public boolean isTypeCovariant() { if (parent == null) { return true; } else { RelationshipMapping<?, ?, ?> parentRelationship = (RelationshipMapping<?, ?, ?>)parent; return property.getValue().getBean() != parentRelationship.property.getValue().getBean(); } } /** * The resolution process attempt to find the related relationship for this relationship. */ void resolve() { if (relatedRelationshipMapping != null) { return; } // List<R> found = Collections.emptyList(); // for (PropertyMapping relatedBeanPropertyMapping : relatedBeanMapping.getProperties().values()) { if (relatedBeanPropertyMapping instanceof RelationshipMapping) { RelationshipMapping<?, ?, ?> relatedBeanRelationshipMapping = (RelationshipMapping<?, ?, ?>)relatedBeanPropertyMapping; if (relatedRelationhipType.isInstance(relatedBeanRelationshipMapping)) { R toRelationship = relatedRelationhipType.cast(relatedBeanRelationshipMapping); if (this != toRelationship) { if (matches(toRelationship)) { if (found.isEmpty()) { found = new LinkedList<R>(); } found.add(toRelationship); } } } } } // this.relatedRelationshipMapping = found; } abstract boolean matches(R relationship); public abstract static class OneToOne<R extends OneToOne> extends RelationshipMapping<PropertyInfo<BeanValueInfo, ValueKind.Single>, R, ValueKind.Single> { /** Owner / not owner. */ final boolean owner; protected OneToOne(Class<R> relatedRelationhipType, PropertyInfo<BeanValueInfo, ValueKind.Single> property, boolean owner) { super(relatedRelationhipType, property); // this.owner = owner; } public boolean isOwner() { return owner; } public static class Hierarchic extends OneToOne<Hierarchic> { /** . */ final String declaredPrefix; /** . */ final String prefix; /** . */ final String localName; /** . */ final boolean mandatory; /** . */ final boolean autocreated; public Hierarchic( PropertyInfo<BeanValueInfo, ValueKind.Single> property, boolean owner, String declaredPrefix, String prefix, String localName, boolean mandatory, boolean autocreated) { super(Hierarchic.class, property, owner); // this.declaredPrefix = declaredPrefix; this.prefix = prefix; this.localName = localName; this.mandatory = mandatory; this.autocreated = autocreated; } public boolean getMandatory() { return mandatory; } public boolean getAutocreated() { return autocreated; } public String getDeclaredPrefix() { return declaredPrefix; } public String getPrefix() { return prefix; } public String getLocalName() { return localName; } @Override public void accept(MappingVisitor visitor) { visitor.oneToOneHierarchic(this); } @Override public boolean matches(Hierarchic relationship) { String fromPrefix = prefix == null ? "" : prefix; String toPrefix = relationship.prefix == null ? "" : relationship.prefix; return fromPrefix.equals(toPrefix) && localName.equals(relationship.localName) && owner != relationship.owner; } } public static class Embedded extends OneToOne<Embedded> { public Embedded(PropertyInfo<BeanValueInfo, ValueKind.Single> property, boolean owner) { super(Embedded.class, property, owner); } @Override public void accept(MappingVisitor visitor) { visitor.oneToOneEmbedded(this); } @Override public boolean matches(Embedded relationship) { // For now we don't need this wiring return false; } } } public abstract static class ManyToOne<R extends OneToMany> extends RelationshipMapping<PropertyInfo<BeanValueInfo, ValueKind.Single>, R, ValueKind.Single> { protected ManyToOne(Class<R> relatedRelationhipType, PropertyInfo<BeanValueInfo, ValueKind.Single> property) { super(relatedRelationhipType, property); } public static class Hierarchic extends ManyToOne<OneToMany.Hierarchic> { /** . */ final String declaredPrefix; /** . */ final String prefix; public Hierarchic(PropertyInfo<BeanValueInfo, ValueKind.Single> property, String declaredPrefix, String prefix) { super(OneToMany.Hierarchic.class, property); // this.declaredPrefix = declaredPrefix; this.prefix = prefix; } public String getDeclaredPrefix() { return declaredPrefix; } public String getPrefix() { return prefix; } @Override public void accept(MappingVisitor visitor) { visitor.manyToOneHierarchic(this); } @Override public boolean matches(OneToMany.Hierarchic relationship) { return true; } } public static class Reference extends ManyToOne<OneToMany.Reference> { /** Mapped by value. */ final String mappedBy; /** The relationship type. */ final RelationshipType type; public Reference(PropertyInfo<BeanValueInfo, ValueKind.Single> property, String mappedBy, RelationshipType type) { super(OneToMany.Reference.class, property); // this.mappedBy = mappedBy; this.type = type; } public String getMappedBy() { return mappedBy; } public RelationshipType getType() { return type; } @Override public void accept(MappingVisitor visitor) { visitor.manyToOneReference(this); } @Override public boolean matches(OneToMany.Reference relationship) { return mappedBy.equals(relationship.mappedBy); } } } public abstract static class OneToMany<R extends ManyToOne, K extends ValueKind.Multi> extends RelationshipMapping<PropertyInfo<BeanValueInfo, K>, R, K> { protected OneToMany(Class<R> relatedRelationhipType, PropertyInfo<BeanValueInfo, K> property) { super(relatedRelationhipType, property); } public static class Hierarchic<K extends ValueKind.Multi> extends OneToMany<ManyToOne.Hierarchic, K> { /** . */ final String declaredPrefix; /** . */ final String prefix; public Hierarchic(PropertyInfo<BeanValueInfo, K> property, String declaredPrefix, String prefix) { super(ManyToOne.Hierarchic.class, property); // this.declaredPrefix = declaredPrefix; this.prefix = prefix; } public String getDeclaredPrefix() { return declaredPrefix; } public String getPrefix() { return prefix; } @Override public void accept(MappingVisitor visitor) { visitor.oneToManyHierarchic(this); } @Override public boolean matches(ManyToOne.Hierarchic relationship) { return true; } } public static class Reference<K extends ValueKind.Multi> extends OneToMany<ManyToOne.Reference, K> { /** Mapped by value. */ final String mappedBy; /** The relationship type. */ final RelationshipType type; public Reference(PropertyInfo<BeanValueInfo, K> property, String mappedBy, RelationshipType type) { super(ManyToOne.Reference.class, property); // this.mappedBy = mappedBy; this.type = type; } public String getMappedBy() { return mappedBy; } public RelationshipType getType() { return type; } @Override public void accept(MappingVisitor visitor) { visitor.oneToManyReference(this); } @Override public boolean matches(ManyToOne.Reference relationship) { return mappedBy.equals(relationship.mappedBy); } } } }