/*
* ====================================================================
*
* The ObjectStyle Group Software License, Version 1.0
*
* Copyright (c) 2006 The ObjectStyle Group and individual authors of the
* software. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowlegement: "This product includes software
* developed by the ObjectStyle Group (http://objectstyle.org/)." Alternately,
* this acknowlegement may appear in the software itself, if and wherever such
* third-party acknowlegements normally appear.
*
* 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse or
* promote products derived from this software without prior written permission.
* For written permission, please contact andrus@objectstyle.org.
*
* 5. Products derived from this software may not be called "ObjectStyle" nor
* may "ObjectStyle" appear in their names without prior written permission of
* the ObjectStyle Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* OBJECTSTYLE GROUP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals on
* behalf of the ObjectStyle Group. For more information on the ObjectStyle
* Group, please see <http://objectstyle.org/>.
*
*/
package org.objectstyle.wolips.eomodeler.core.model;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.objectstyle.wolips.baseforplugins.util.ComparisonUtils;
import org.objectstyle.wolips.baseforplugins.util.StringUtils;
import org.objectstyle.wolips.eomodeler.core.Messages;
import org.objectstyle.wolips.eomodeler.core.utils.BooleanUtils;
public class EORelationship extends UserInfoableEOModelObject<EOEntity> implements IEOAttribute, ISortableEOModelObject {
public static final String TO_MANY = "toMany";
public static final String TO_ONE = "toOne";
public static final String CLASS_PROPERTY = "classProperty";
public static final String CLIENT_CLASS_PROPERTY = "clientClassProperty";
public static final String COMMON_CLASS_PROPERTY = "commonClassProperty";
public static final String NAME = "name";
public static final String DESTINATION = "destination";
public static final String DEFINITION = "definition";
public static final String DELETE_RULE = "deleteRule";
public static final String JOIN_SEMANTIC = "joinSemantic";
public static final String OPTIONAL = "optional";
public static final String MANDATORY = "mandatory";
public static final String OWNS_DESTINATION = "ownsDestination";
public static final String PROPAGATES_PRIMARY_KEY = "propagatesPrimaryKey";
public static final String NUMBER_OF_TO_MANY_FAULTS_TO_BATCH_FETCH = "numberOfToManyFaultsToBatchFetch";
public static final String JOINS = "joins";
public static final String JOIN = "join";
private EOEntity myEntity;
private EOEntity myDestination;
private String myName;
private String myDefinition;
private EORelationshipPath myDefinitionPath;
private Boolean myMandatory;
private Boolean myToMany;
private Boolean myOwnsDestination;
private Boolean myPropagatesPrimaryKey;
private Boolean myClassProperty;
private Boolean myClientClassProperty;
private Boolean _commonClassProperty;
private Integer myNumberOfToManyFaultsToBatchFetch;
private EODeleteRule myDeleteRule;
private EOJoinSemantic myJoinSemantic;
private List<EOJoin> myJoins;
private EOModelMap myRelationshipMap;
private EOEntity myEntityBeforeCloning;
public EORelationship() {
myJoins = new LinkedList<EOJoin>();
myRelationshipMap = new EOModelMap();
myDeleteRule = EODeleteRule.getDeleteRuleByID(null);
myJoinSemantic = EOJoinSemantic.getJoinSemanticByID(null);
}
public EORelationship(String _name) {
this();
myName = _name;
}
public EORelationship(String _name, String _definition) {
this(_name);
myDefinition = _definition;
}
public Set<EOModelReferenceFailure> getReferenceFailures() {
Set<EOModelReferenceFailure> referenceFailures = new HashSet<EOModelReferenceFailure>();
for (EORelationship referencingRelationship : getReferencingFlattenedRelationships()) {
referenceFailures.add(new EOFlattenedRelationshipRelationshipReferenceFailure(referencingRelationship, this));
}
for (EOAttribute referencingAttributes : getReferencingFlattenedAttributes()) {
referenceFailures.add(new EOFlattenedAttributeRelationshipReferenceFailure(referencingAttributes, this));
}
return referenceFailures;
}
public List<EOAttribute> getReferencingFlattenedAttributes() {
List<EOAttribute> referencingFlattenedAttributes = new LinkedList<EOAttribute>();
if (myEntity != null) {
for (EOModel model : getEntity().getModel().getModelGroup().getModels()) {
for (EOEntity entity : model.getEntities()) {
for (EOAttribute attribute : entity.getAttributes()) {
if (attribute.isFlattened()) {
EOAttributePath attributePath = attribute.getDefinitionPath();
if (attributePath != null && attributePath.isRelatedTo(this)) {
referencingFlattenedAttributes.add(attribute);
}
}
}
}
}
}
return referencingFlattenedAttributes;
}
public List<EORelationship> getReferencingFlattenedRelationships() {
List<EORelationship> referencingFlattenedRelationships = new LinkedList<EORelationship>();
if (myEntity != null) {
for (EOModel model : getEntity().getModel().getModelGroup().getModels()) {
for (EOEntity entity : model.getEntities()) {
for (EORelationship relationship : entity.getRelationships()) {
if (relationship.isFlattened()) {
EORelationshipPath relationshipPath = relationship.getDefinitionPath();
if (relationshipPath != null && relationshipPath.isRelatedTo(this)) {
referencingFlattenedRelationships.add(relationship);
}
}
}
}
}
}
return referencingFlattenedRelationships;
}
public void pasted() throws DuplicateNameException {
if (myEntityBeforeCloning != null) {
if (myDestination == myEntityBeforeCloning) {
myDestination = myEntity;
} else {
if (myDestination != null) {
EOModel model = myEntity.getModel();
EOModelGroup modelGroup = model.getModelGroup();
myDestination = modelGroup.getEntityNamed(myDestination.getName());
}
}
for (EOJoin join : myJoins) {
join.pasted();
}
myEntityBeforeCloning = null;
}
}
@SuppressWarnings("unused")
protected void _joinChanged(EOJoin _join, String _propertyName, Object _oldValue, Object _newValue) {
firePropertyChange(EORelationship.JOIN, null, _join);
}
protected void _propertyChanged(String _propertyName, Object _oldValue, Object _newValue) {
if (myEntity != null) {
myEntity._relationshipChanged(this, _propertyName, _oldValue, _newValue);
}
}
// public int hashCode() {
// return ((myEntity == null) ? 1 : myEntity.hashCode()) * ((myName == null) ? 1 : myName.hashCode());
// }
//
// public boolean equals(Object _obj) {
// boolean equals = false;
// if (_obj instanceof EORelationship) {
// EORelationship relationship = (EORelationship) _obj;
// equals = (relationship == this) || (ComparisonUtils.equals(relationship.myEntity, myEntity) && ComparisonUtils.equals(relationship.myName, myName));
// if (equals && _obj != this) {
// throw new IllegalStateException("RUH ROH!");
// }
// }
// return equals;
// }
public boolean isInverseRelationship(EORelationship _relationship) {
boolean isInverse;
if (_relationship == null) {
isInverse = false;
} else {
List<EOJoin> inverseJoins = new LinkedList<EOJoin>(_relationship.getJoins());
if (inverseJoins.size() != myJoins.size()) {
isInverse = false;
} else {
Iterator<EOJoin> joinsIter = myJoins.iterator();
isInverse = true;
while (isInverse && joinsIter.hasNext()) {
EOJoin join = joinsIter.next();
EOJoin inverseJoin = null;
int inverseJoinsSize = inverseJoins.size();
for (int inverseJoinNum = 0; inverseJoin == null && inverseJoinNum < inverseJoinsSize; inverseJoinNum++) {
EOJoin potentialInverseJoin = inverseJoins.get(inverseJoinNum);
if (potentialInverseJoin.isInverseJoin(join)) {
inverseJoin = potentialInverseJoin;
}
}
if (inverseJoin == null) {
isInverse = false;
}
}
}
}
return isInverse;
}
public EORelationship getInverseRelationship() {
EORelationship inverseRelationship = null;
if (myDestination != null) {
Iterator<EORelationship> relationshipsIter = myDestination.getRelationships().iterator();
while (inverseRelationship == null && relationshipsIter.hasNext()) {
EORelationship potentialInverseRelationship = relationshipsIter.next();
if (potentialInverseRelationship.isInverseRelationship(this)) {
inverseRelationship = potentialInverseRelationship;
}
}
}
return inverseRelationship;
}
public EORelationship createInverseRelationshipNamed(String _name, boolean _toMany) {
EORelationship inverseRelationship = new EORelationship(myDestination.findUnusedRelationshipName(_name));
inverseRelationship.setClassProperty(getClassProperty());
inverseRelationship.setToMany(Boolean.valueOf(_toMany));
inverseRelationship.setDestination(myEntity);
for (EOJoin join : getJoins()) {
join.addInverseJoinInto(inverseRelationship, false);
}
inverseRelationship._setEntity(myDestination);
return inverseRelationship;
}
public boolean isRelatedTo(EOEntity _entity) {
return _entity.equals(myDestination);
}
public boolean isRelatedTo(EOAttribute _attribute) {
boolean isRelated = false;
Iterator<EOJoin> joinsIter = myJoins.iterator();
while (!isRelated && joinsIter.hasNext()) {
EOJoin join = joinsIter.next();
isRelated = join.isRelatedTo(_attribute);
}
return isRelated;
}
public Set<EOAttribute> getRelatedAttributes() {
Set<EOAttribute> relatedAttributes = new HashSet<EOAttribute>();
Iterator<EOJoin> joinsIter = myJoins.iterator();
while (joinsIter.hasNext()) {
EOJoin join = joinsIter.next();
EOAttribute sourceAttribute = join.getSourceAttribute();
if (sourceAttribute != null) {
relatedAttributes.add(sourceAttribute);
}
EOAttribute destinationAttribute = join.getDestinationAttribute();
if (destinationAttribute != null) {
relatedAttributes.add(destinationAttribute);
}
}
return relatedAttributes;
}
public void setDefinition(String _definition) {
String oldDefinition = myDefinition;
myDefinition = _definition;
updateDefinitionPath();
firePropertyChange(EORelationship.DEFINITION, oldDefinition, myDefinition);
}
public String getDefinition() {
String definition;
if (isFlattened() && myDefinitionPath != null) {
definition = myDefinitionPath.toKeyPath();
} else {
definition = _getDefinition();
}
return definition;
}
public EORelationshipPath getDefinitionPath() {
if (myDefinitionPath == null) {
updateDefinitionPath();
}
return myDefinitionPath;
}
public String _getDefinition() {
return myDefinition;
}
public void updateDefinitionBecauseRelationshipNameChanged(EORelationship relationship) {
if (isFlattened()) {
EORelationshipPath definitionPath = getDefinitionPath();
if (definitionPath != null && definitionPath.isRelatedTo(relationship)) {
setDefinition(definitionPath.toKeyPath());
}
}
}
protected void updateDefinitionPath() {
if (isFlattened()) {
EOEntity entity = getEntity();
if (entity != null) {
AbstractEOAttributePath definitionPath = entity.resolveKeyPath(_getDefinition());
if (definitionPath instanceof EORelationshipPath && definitionPath.isValid()) {
myDefinitionPath = (EORelationshipPath) definitionPath;
} else {
myDefinitionPath = null;
}
}
else {
myDefinition = null;
}
} else {
myDefinitionPath = null;
}
}
public void setClassProperty(Boolean _classProperty) {
setClassProperty(_classProperty, true);
}
public void setClassProperty(Boolean _classProperty, boolean _fireEvents) {
Boolean oldClassProperty = myClassProperty;
myClassProperty = _classProperty;
if (_fireEvents) {
firePropertyChange(EORelationship.CLASS_PROPERTY, oldClassProperty, myClassProperty);
}
}
public Boolean isClassProperty() {
return myClassProperty;
}
public Boolean getClassProperty() {
return isClassProperty();
}
public void setCommonClassProperty(Boolean commonClassProperty) {
setCommonClassProperty(commonClassProperty, true);
}
public void setCommonClassProperty(Boolean commonClassProperty, boolean fireEvents) {
Boolean oldCommonClassProperty = _commonClassProperty;
_commonClassProperty = commonClassProperty;
if (fireEvents) {
firePropertyChange(EORelationship.COMMON_CLASS_PROPERTY, oldCommonClassProperty, _commonClassProperty);
}
}
public Boolean isCommonClassProperty() {
return _commonClassProperty;
}
public Boolean getCommonClassProperty() {
return isCommonClassProperty();
}
public void setClientClassProperty(Boolean _clientClassProperty) {
setClientClassProperty(_clientClassProperty, true);
}
public void setClientClassProperty(Boolean _clientClassProperty, boolean _fireEvents) {
Boolean oldClientClassProperty = myClientClassProperty;
myClientClassProperty = _clientClassProperty;
if (_fireEvents) {
firePropertyChange(EORelationship.CLIENT_CLASS_PROPERTY, oldClientClassProperty, myClientClassProperty);
}
}
public Boolean isClientClassProperty() {
return myClientClassProperty;
}
public Boolean getClientClassProperty() {
return isClientClassProperty();
}
public boolean isFlattened() {
return StringUtils.isKeyPath(_getDefinition());
}
public EORelationship getParentRelationship() {
EORelationship parentRelationship = null;
EOEntity parent = myEntity.getParent();
if (parent != null) {
parentRelationship = parent.getRelationshipNamed(myName);
}
return parentRelationship;
}
public boolean isInherited() {
return getParentRelationship() != null;
}
public void _setEntity(EOEntity _entity) {
myEntity = _entity;
}
public EOEntity getEntity() {
return myEntity;
}
public void setName(String _name) throws DuplicateNameException {
setName(_name, true);
}
public void setName(String _name, boolean _fireEvents) throws DuplicateNameException {
if (_name == null) {
throw new NullPointerException(Messages.getString("EORelationship.noBlankRelationshipNames"));
}
String oldName = myName;
if (myEntity != null) {
myEntity._checkForDuplicateRelationshipName(this, _name, null);
}
myName = _name;
if (myEntity != null && myEntity.getModel() != null) {
EOModelGroup modelGroup = myEntity.getModel().getModelGroup();
for (EOEntity entity : modelGroup.getEntities()) {
for (EOAttribute attribute : entity.getAttributes()) {
attribute.updateDefinitionBecauseRelationshipNameChanged(this);
}
for (EORelationship relationship : entity.getRelationships()) {
relationship.updateDefinitionBecauseRelationshipNameChanged(this);
}
}
}
if (_fireEvents) {
firePropertyChange(EORelationship.NAME, oldName, myName);
}
}
public String getName() {
return myName;
}
public String getUppercaseName() {
return getName().toUpperCase();
}
public String getUppercaseUnderscoreName() {
return StringUtils.camelCaseToUnderscore(getName()).toUpperCase();
}
public String getCapitalizedName() {
String name = getName();
if (name != null) {
name = StringUtils.toUppercaseFirstLetter(name);
}
return name;
}
public EODeleteRule getDeleteRule() {
return myDeleteRule;
}
public void setDeleteRule(EODeleteRule _deleteRule) {
EODeleteRule oldDeleteRule = myDeleteRule;
myDeleteRule = _deleteRule;
firePropertyChange(EORelationship.DELETE_RULE, oldDeleteRule, myDeleteRule);
}
public EOEntity getActualDestination() {
EOEntity destination = getDestination();
if (destination != null && destination.isPartialEntitySet()) {
destination = destination.getPartialEntity();
}
return destination;
}
public EOEntity getDestination() {
EOEntity destination;
if (isFlattened()) {
AbstractEOAttributePath targetAttributePath = myEntity.resolveKeyPath(getDefinition());
if (targetAttributePath != null && targetAttributePath.getChildIEOAttribute() != null) {
destination = ((EORelationshipPath) targetAttributePath).getChildRelationship().getDestination();
} else {
destination = null;
}
} else {
destination = myDestination;
}
return destination;
}
public void setDestination(EOEntity _destination) {
setDestination(_destination, true);
}
public void setDestination(EOEntity _destination, boolean _fireEvents) {
EOEntity oldDestination = myDestination;
myDestination = _destination;
if (_fireEvents) {
firePropertyChange(EORelationship.DESTINATION, oldDestination, myDestination);
}
}
public EOJoinSemantic getJoinSemantic() {
return myJoinSemantic;
}
public void setJoinSemantic(EOJoinSemantic _joinSemantic) {
EOJoinSemantic oldJoinSemantic = myJoinSemantic;
myJoinSemantic = _joinSemantic;
firePropertyChange(EORelationship.JOIN_SEMANTIC, oldJoinSemantic, myJoinSemantic);
}
public Boolean getMandatory() {
return isMandatory();
}
public Boolean isMandatory() {
return myMandatory;
}
public void setMandatory(Boolean _mandatory) {
_setMandatory(_mandatory);
if (BooleanUtils.isTrue(isToOne())) {
EOEntity entity = getEntity();
if (entity != null && !entity.isSingleTableInheritance()) {
Iterator<EOJoin> joinsIter = getJoins().iterator();
while (joinsIter.hasNext()) {
EOJoin join = joinsIter.next();
EOAttribute sourceAttribute = join.getSourceAttribute();
if (sourceAttribute != null) {
sourceAttribute._setAllowsNull(BooleanUtils.negate(_mandatory), true);
}
}
}
}
}
public void _setMandatory(Boolean _mandatory) {
Boolean oldMandatory = myMandatory;
myMandatory = _mandatory;
firePropertyChange(EORelationship.MANDATORY, oldMandatory, myMandatory);
firePropertyChange(EORelationship.OPTIONAL, BooleanUtils.negate(oldMandatory), BooleanUtils.negate(myMandatory));
}
public void setMandatoryIfNecessary() {
boolean mandatory = false;
if (BooleanUtils.isTrue(isToOne())) {
Iterator<EOJoin> joinsIter = getJoins().iterator();
while (!mandatory && joinsIter.hasNext()) {
EOJoin join = joinsIter.next();
EOAttribute sourceAttribute = join.getSourceAttribute();
if (sourceAttribute != null) {
mandatory = BooleanUtils.isFalse(sourceAttribute.isAllowsNull());
}
}
}
setMandatory(Boolean.valueOf(mandatory));
}
public Boolean getOptional() {
return isOptional();
}
public Boolean isOptional() {
return BooleanUtils.negate(isMandatory());
}
public void setOptional(Boolean _optional) {
setMandatory(BooleanUtils.negate(_optional));
}
public Boolean getOwnsDestination() {
return isOwnsDestination();
}
public Boolean isOwnsDestination() {
return myOwnsDestination;
}
public void setOwnsDestination(Boolean _ownsDestination) {
Boolean oldOwnsDestination = myOwnsDestination;
myOwnsDestination = _ownsDestination;
firePropertyChange(EORelationship.OWNS_DESTINATION, oldOwnsDestination, myOwnsDestination);
}
public Boolean getPropagatesPrimaryKey() {
return isPropagatesPrimaryKey();
}
public Boolean isPropagatesPrimaryKey() {
return myPropagatesPrimaryKey;
}
public void setPropagatesPrimaryKey(Boolean _propagatesPrimaryKey) {
Boolean oldPropagatesPrimaryKey = myPropagatesPrimaryKey;
myPropagatesPrimaryKey = _propagatesPrimaryKey;
firePropertyChange(EORelationship.PROPAGATES_PRIMARY_KEY, oldPropagatesPrimaryKey, myPropagatesPrimaryKey);
}
public Boolean getToMany() {
return isToMany();
}
public Boolean isToMany() {
Boolean toMany = null;
if (isFlattened() && myEntity != null) {
AbstractEOAttributePath targetAttributePath = myEntity.resolveKeyPath(getDefinition());
if (targetAttributePath != null && targetAttributePath.getChildIEOAttribute() != this) {
toMany = targetAttributePath.isToMany();
}
} else {
toMany = myToMany;
}
return toMany;
}
public void setToMany(Boolean _toMany) {
if (!isFlattened()) {
Boolean oldToMany = myToMany;
myToMany = _toMany;
firePropertyChange(EORelationship.TO_MANY, oldToMany, myToMany);
firePropertyChange(EORelationship.TO_ONE, BooleanUtils.negate(oldToMany), BooleanUtils.negate(myToMany));
}
}
public Boolean getToOne() {
return isToOne();
}
public Boolean isToOne() {
return BooleanUtils.negate(isToMany());
}
public void setToOne(Boolean _toOne) {
setToMany(BooleanUtils.negate(_toOne));
}
public void setNumberOfToManyFaultsToBatchFetch(Integer _numberOfToManyFaultsToBatchFetch) {
Integer oldNumberOfToManyFaultsToBatchFetch = myNumberOfToManyFaultsToBatchFetch;
myNumberOfToManyFaultsToBatchFetch = _numberOfToManyFaultsToBatchFetch;
firePropertyChange(EORelationship.NUMBER_OF_TO_MANY_FAULTS_TO_BATCH_FETCH, oldNumberOfToManyFaultsToBatchFetch, myNumberOfToManyFaultsToBatchFetch);
}
public Integer getNumberOfToManyFaultsToBatchFetch() {
return myNumberOfToManyFaultsToBatchFetch;
}
public void clearJoins() {
myJoins.clear();
firePropertyChange(EORelationship.JOINS, null, null);
}
public void setJoins(List<EOJoin> _joins) {
myJoins.clear();
myJoins.addAll(_joins);
firePropertyChange(EORelationship.JOINS, null, null);
}
public void addJoin(EOJoin _join) {
addJoin(_join, true);
}
public void addJoin(EOJoin _join, boolean _fireEvents) {
// TODO: Check duplicates?
_join._setRelationship(this);
List<EOJoin> oldJoins = null;
if (_fireEvents) {
oldJoins = myJoins;
List<EOJoin> newJoins = new LinkedList<EOJoin>();
newJoins.addAll(myJoins);
newJoins.add(_join);
myJoins = newJoins;
firePropertyChange(EORelationship.JOINS, oldJoins, myJoins);
} else {
myJoins.add(_join);
}
}
public void removeAllJoins() {
List<EOJoin> oldJoins = myJoins;
List<EOJoin> newJoins = new LinkedList<EOJoin>();
myJoins = newJoins;
firePropertyChange(EORelationship.JOINS, oldJoins, newJoins);
for (EOJoin join : oldJoins) {
join._setRelationship(null);
}
}
public void removeJoin(EOJoin _join) {
List<EOJoin> oldJoins = myJoins;
List<EOJoin> newJoins = new LinkedList<EOJoin>();
newJoins.addAll(myJoins);
newJoins.remove(_join);
myJoins = newJoins;
firePropertyChange(EORelationship.JOINS, oldJoins, newJoins);
_join._setRelationship(null);
}
public List<EOJoin> getJoins() {
return myJoins;
}
public EOJoin getFirstJoin() {
EOJoin join = null;
Iterator<EOJoin> joinsIter = myJoins.iterator();
if (joinsIter.hasNext()) {
join = joinsIter.next();
}
return join;
}
public void loadFromMap(EOModelMap _relationshipMap, Set<EOModelVerificationFailure> _failures) {
myRelationshipMap = _relationshipMap;
if (_relationshipMap.containsKey("dataPath")) {
myDefinition = _relationshipMap.getString("dataPath", true);
} else {
myDefinition = _relationshipMap.getString("definition", true);
}
myMandatory = _relationshipMap.getBoolean("isMandatory");
myToMany = _relationshipMap.getBoolean("isToMany");
String joinSemanticID = _relationshipMap.getString("joinSemantic", true);
myJoinSemantic = EOJoinSemantic.getJoinSemanticByID(joinSemanticID);
myName = _relationshipMap.getString("name", true);
String deleteRuleID = _relationshipMap.getString("deleteRule", true);
myDeleteRule = EODeleteRule.getDeleteRuleByID(deleteRuleID);
myOwnsDestination = _relationshipMap.getBoolean("ownsDestination");
myNumberOfToManyFaultsToBatchFetch = _relationshipMap.getInteger("numberOfToManyFaultsToBatchFetch");
myPropagatesPrimaryKey = _relationshipMap.getBoolean("propagatesPrimaryKey");
Set<Map> joins = _relationshipMap.getSet("joins");
if (joins != null) {
for (Map originalJoinMap : joins) {
EOModelMap joinMap = new EOModelMap(originalJoinMap);
EOJoin join = new EOJoin();
join.loadFromMap(joinMap, _failures);
addJoin(join, false);
}
}
loadUserInfo(_relationshipMap);
}
public EOModelMap toMap() {
EOModelMap relationshipMap = myRelationshipMap.cloneModelMap();
if (myDestination != null) {
relationshipMap.setString("destination", myDestination.getName(), true);
} else {
relationshipMap.remove("destination");
}
relationshipMap.setString("definition", getDefinition(), true);
relationshipMap.remove("dataPath");
relationshipMap.setBoolean("isMandatory", myMandatory, EOModelMap.YNOptionalDefaultNo);
relationshipMap.setBoolean("isToMany", myToMany, EOModelMap.YN);
if (!isFlattened() && myJoinSemantic != null) {
relationshipMap.setString("joinSemantic", myJoinSemantic.getID(), true);
} else if (isFlattened() && myRelationshipMap.get("joinSemantic") != null) {
relationshipMap.setString("joinSemantic", (String) myRelationshipMap.get("joinSemantic"), true);
} else {
relationshipMap.remove("joinSemantic");
}
relationshipMap.setString("name", myName, true);
if (myDeleteRule != null && myDeleteRule != EODeleteRule.NULLIFY) {
relationshipMap.setString("deleteRule", myDeleteRule.getID(), true);
} else {
relationshipMap.remove("deleteRule");
}
relationshipMap.setBoolean("ownsDestination", myOwnsDestination, EOModelMap.YNOptionalDefaultNo);
relationshipMap.setBoolean("propagatesPrimaryKey", myPropagatesPrimaryKey, EOModelMap.YNOptionalDefaultNo);
relationshipMap.setInteger("numberOfToManyFaultsToBatchFetch", myNumberOfToManyFaultsToBatchFetch);
Set<Map> joins = new PropertyListSet<Map>();
for (EOJoin join : myJoins) {
EOModelMap joinMap = join.toMap();
joins.add(joinMap);
}
relationshipMap.setSet("joins", joins, true);
writeUserInfo(relationshipMap);
// remove join semantic for flattened if anything else is changing
if (isFlattened()) {
if (!ComparisonUtils.deepEquals(relationshipMap, myRelationshipMap)) {
relationshipMap.remove("joinSemantic");
}
}
return relationshipMap;
}
public void resolve(Set<EOModelVerificationFailure> _failures) {
if (!isFlattened()) {
String destinationName = myRelationshipMap.getString("destination", true);
if (destinationName == null) {
_failures.add(new EOModelVerificationFailure(myEntity.getModel(), this, "The relationship " + getName() + " has no destination entity.", false));
} else {
myDestination = myEntity.getModel().getModelGroup().getEntityNamed(destinationName);
if (myDestination == null) {
_failures.add(new MissingEntityFailure(myEntity.getModel(), destinationName));
}
}
} else {
updateDefinitionPath();
}
for (EOJoin join : myJoins) {
join.resolve(_failures);
}
}
public void verify(Set<EOModelVerificationFailure> _failures) {
String name = getName();
if (name == null || name.trim().length() == 0) {
_failures.add(new EOModelVerificationFailure(myEntity.getModel(), this, "The relationship " + getName() + " has an empty name.", false));
} else {
if (name.indexOf(' ') != -1) {
_failures.add(new EOModelVerificationFailure(myEntity.getModel(), this, "The relationship " + getName() + "'s name has a space in it.", false));
}
if (!StringUtils.isLowercaseFirstLetter(name)) {
_failures.add(new EOModelVerificationFailure(myEntity.getModel(), this, "The relationship " + getName() + "'s name is capitalized, but should not be.", true));
}
}
if (isFlattened()) {
if (myEntity.resolveKeyPath(getDefinition()) == null) {
_failures.add(new EOModelVerificationFailure(myEntity.getModel(), this, "The relationship " + getName() + " is flattened and either creates a loop or points to a non-existent target.", false));
}
} else {
if (myDestination == null) {
_failures.add(new EOModelVerificationFailure(myEntity.getModel(), this, "The relationship " + getName() + " has no destination entity.", false));
}
}
// Q: EOF supports this for some specific cases - disabling until I work out a more concise check
//if (BooleanUtils.isTrue(isPropagatesPrimaryKey()) && BooleanUtils.isTrue(isToMany())) {
// EOEntity destination = getDestination();
// if (destination != null && destination.getPrimaryKeyAttributes().size() == 1) {
// _failures.add(new EOModelVerificationFailure(myEntity.getModel(), this, "The relationship " + getName() + " is a to-many but also propagates its primary key.", false));
// }
//}
EOEntity entity = getEntity();
boolean singleTableInheritance = entity != null && entity.isSingleTableInheritance();
boolean mandatory = BooleanUtils.isTrue(isMandatory());
boolean toOne = BooleanUtils.isTrue(isToOne());
Iterator<EOJoin> joinsIter = myJoins.iterator();
if (!joinsIter.hasNext() && !isFlattened()) {
_failures.add(new EOModelVerificationFailure(myEntity.getModel(), this, "The relationship " + getName() + " does not have any joins.", false));
}
while (joinsIter.hasNext()) {
EOJoin join = joinsIter.next();
join.verify(_failures);
EOAttribute sourceAttribute = join.getSourceAttribute();
if (toOne && mandatory && !singleTableInheritance && sourceAttribute != null && BooleanUtils.isTrue(sourceAttribute.isAllowsNull())) {
_failures.add(new EORelationshipOptionalityMismatchFailure(myEntity.getModel(), this, "The relationship " + getName() + " is mandatory but the attribute " + sourceAttribute.getName() + " allows nulls.", true));
} else if (toOne && !mandatory && sourceAttribute != null && !BooleanUtils.isTrue(sourceAttribute.isAllowsNull())) {
_failures.add(new EORelationshipOptionalityMismatchFailure(myEntity.getModel(), this, "The relationship " + getName() + " is optional but the attribute " + sourceAttribute.getName() + " does not allow nulls.", true));
}
}
}
public String getFullyQualifiedName() {
return ((myEntity == null) ? "?" : myEntity.getFullyQualifiedName()) + "/rel: " + getName();
}
@Override
public EORelationship _cloneModelObject() {
EORelationship relationship = new EORelationship(myName);
if (myEntity == null) {
relationship.myEntityBeforeCloning = myEntityBeforeCloning;
} else {
relationship.myEntityBeforeCloning = myEntity;
}
relationship.myDestination = myDestination;
relationship.myDefinition = myDefinition;
relationship.myMandatory = myMandatory;
relationship.myToMany = myToMany;
relationship.myOwnsDestination = myOwnsDestination;
relationship.myPropagatesPrimaryKey = myPropagatesPrimaryKey;
relationship.myClassProperty = myClassProperty;
relationship.myClientClassProperty = myClientClassProperty;
relationship.myNumberOfToManyFaultsToBatchFetch = myNumberOfToManyFaultsToBatchFetch;
relationship.myDeleteRule = myDeleteRule;
relationship.myJoinSemantic = myJoinSemantic;
for (EOJoin join : myJoins) {
EOJoin newJoin = join._cloneModelObject();
relationship.addJoin(newJoin, false);
}
_cloneUserInfoInto(relationship);
return relationship;
}
@Override
public Class<EOEntity> _getModelParentType() {
return EOEntity.class;
}
public EOEntity _getModelParent() {
return getEntity();
}
public void _removeFromModelParent(Set<EOModelVerificationFailure> failures) {
if (getEntity() != null) {
getEntity().removeRelationship(this, true);
}
}
public void _addToModelParent(EOEntity modelParent, boolean findUniqueName, Set<EOModelVerificationFailure> failures) throws EOModelException {
if (findUniqueName) {
setName(modelParent.findUnusedRelationshipName(getName()));
}
modelParent.addRelationship(this);
}
public boolean getSqlGenerationCreateProperty() {
return !isInherited() || getEntity().getSqlGenerationCreateInheritedProperties();
}
public String toString() {
return "[EORelationship: name = " + myName + "; destination = " + ((myDestination == null) ? "null" : myDestination.getName()) + "; joins = " + myJoins + "]"; //$NON-NLS-4$ //$NON-NLS-5$
}
}