| /******************************************************************************* |
| * Copyright (c) 2004, 2007 Boeing. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Boeing - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.osee.framework.skynet.core.relation; |
| |
| import static org.eclipse.osee.framework.core.enums.RelationOrderBaseTypes.USER_DEFINED; |
| import java.util.logging.Level; |
| import org.eclipse.osee.framework.core.data.IOseeBranch; |
| import org.eclipse.osee.framework.core.data.IRelationSorterId; |
| import org.eclipse.osee.framework.core.data.IRelationType; |
| import org.eclipse.osee.framework.core.enums.CoreAttributeTypes; |
| import org.eclipse.osee.framework.core.enums.ModificationType; |
| import org.eclipse.osee.framework.core.enums.RelationOrderBaseTypes; |
| import org.eclipse.osee.framework.core.enums.RelationSide; |
| import org.eclipse.osee.framework.core.exception.OseeArgumentException; |
| import org.eclipse.osee.framework.core.exception.OseeCoreException; |
| import org.eclipse.osee.framework.core.model.type.RelationType; |
| import org.eclipse.osee.framework.logging.OseeLog; |
| import org.eclipse.osee.framework.skynet.core.artifact.Artifact; |
| import org.eclipse.osee.framework.skynet.core.artifact.search.ArtifactQuery; |
| import org.eclipse.osee.framework.skynet.core.internal.Activator; |
| import org.eclipse.osee.framework.skynet.core.relation.order.RelationOrderData; |
| import org.eclipse.osee.framework.skynet.core.relation.order.RelationOrderFactory; |
| import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; |
| |
| /** |
| * @author Jeff C. Phillips |
| * @author Ryan D. Brooks |
| */ |
| public class RelationLink { |
| |
| public static interface ArtifactLinker { |
| |
| public void updateCachedArtifact(int artId, IOseeBranch branch); |
| |
| public Artifact getArtifact(int ArtId, IOseeBranch branch) throws OseeCoreException; |
| |
| public String getLazyArtifactName(int aArtifactId, IOseeBranch branch); |
| |
| public void deleteFromRelationOrder(Artifact aArtifact, Artifact bArtifact, IRelationType relationType) throws OseeCoreException; |
| } |
| |
| private int relationId; |
| private int gammaId; |
| private String rationale; |
| private final RelationType relationType; |
| private boolean dirty; |
| private final int aArtifactId; |
| private final int bArtifactId; |
| private final IOseeBranch branch; |
| private ModificationType modificationType; |
| |
| private static final boolean SET_DIRTY = true; |
| private static final boolean SET_NOT_DIRTY = false; |
| |
| private final ArtifactLinker artifactLinker; |
| |
| public RelationLink(ArtifactLinker artifactLinker, int aArtifactId, int bArtifactId, IOseeBranch branch, RelationType relationType, int relationId, int gammaId, String rationale, ModificationType modificationType) { |
| this.artifactLinker = artifactLinker; |
| this.relationType = relationType; |
| this.relationId = relationId; |
| this.gammaId = gammaId; |
| this.rationale = rationale == null ? "" : rationale; |
| this.dirty = false; |
| this.aArtifactId = aArtifactId; |
| this.bArtifactId = bArtifactId; |
| this.branch = branch; |
| this.modificationType = modificationType; |
| } |
| |
| public void internalSetModificationType(ModificationType modificationType) { |
| this.modificationType = modificationType; |
| } |
| |
| public RelationSide getSide(Artifact artifact) { |
| if (aArtifactId == artifact.getArtId()) { |
| return RelationSide.SIDE_A; |
| } |
| if (bArtifactId == artifact.getArtId()) { |
| return RelationSide.SIDE_B; |
| } |
| throw new IllegalArgumentException("The artifact " + artifact + " is on neither side of " + this); |
| } |
| |
| public RelationSide getOppositeSide(Artifact artifact) { |
| return getSide(artifact).oppositeSide(); |
| } |
| |
| /** |
| * artifact.persist(); artifact.reloadAttributesAndRelations(); Will need to be called afterwards to see replaced |
| * data in memory |
| */ |
| public void replaceWithVersion(int gammaId) { |
| modificationType = ModificationType.REPLACED_WITH_VERSION; |
| this.gammaId = gammaId; |
| setDirtyFlag(true); |
| } |
| |
| public int getAArtifactId() { |
| return aArtifactId; |
| } |
| |
| public int getBArtifactId() { |
| return bArtifactId; |
| } |
| |
| public int getArtifactId(RelationSide relationSide) { |
| return relationSide == RelationSide.SIDE_A ? aArtifactId : bArtifactId; |
| } |
| |
| public boolean isDeleted() { |
| return modificationType.isDeleted(); |
| } |
| |
| public boolean isUnDeleted() { |
| return modificationType.isUnDeleted(); |
| } |
| |
| public boolean isDirty() { |
| return dirty; |
| } |
| |
| public void delete(boolean reorderRelations) { |
| delete(reorderRelations, null); |
| |
| } |
| |
| public void delete(boolean reorderRelations, SkynetTransaction transaction) { |
| internalDelete(reorderRelations, true); |
| |
| deleteEmptyRelationOrder(transaction); |
| } |
| |
| private void deleteEmptyRelationOrder(SkynetTransaction transaction) { |
| try { |
| Artifact aArtifact = ArtifactQuery.getArtifactFromId(aArtifactId, branch); |
| |
| if (aArtifact.getAttributeCount(CoreAttributeTypes.RelationOrder) == 1) { |
| RelationOrderData relationOrderData = new RelationOrderFactory().createRelationOrderData(aArtifact); |
| if (!relationOrderData.hasEntries()) { |
| aArtifact.getSoleAttribute(CoreAttributeTypes.RelationOrder).delete(); |
| if (transaction == null) { |
| aArtifact.persist("Delete empty relation order attribute for artifact: " + aArtifact.getGuid()); |
| } else { |
| aArtifact.persist(transaction); |
| } |
| } |
| } |
| |
| } catch (OseeCoreException ex) { |
| OseeLog.log(this.getClass(), Level.INFO, ex.toString(), ex); |
| } |
| } |
| |
| public void undelete() { |
| internalUnDelete(); |
| } |
| |
| public void internalUnDelete() { |
| markedAsChanged(ModificationType.UNDELETED, true); |
| } |
| |
| public void internalRemoteEventDelete() { |
| internalDelete(true, false); |
| } |
| |
| private void internalDelete(boolean reorderRelations, boolean setDirty) { |
| if (!isDeleted()) { |
| if (reorderRelations) { |
| try { |
| artifactLinker.deleteFromRelationOrder(getArtifactA(), getArtifactB(), getRelationType()); |
| } catch (OseeCoreException e) { |
| OseeLog.log(Activator.class, Level.SEVERE, e.getMessage()); |
| } |
| } |
| |
| markAsDeleted(setDirty); |
| } |
| } |
| |
| private void markAsDeleted(boolean setDirty) { |
| markedAsChanged(ModificationType.DELETED, setDirty); |
| } |
| |
| public void markAsPurged() { |
| markAsDeleted(SET_NOT_DIRTY); |
| } |
| |
| public Artifact getArtifact(RelationSide relationSide) throws OseeCoreException { |
| return artifactLinker.getArtifact(getArtifactId(relationSide), getBranch()); |
| } |
| |
| public Artifact getArtifactOnOtherSide(Artifact artifact) throws OseeCoreException { |
| return getArtifact(getOppositeSide(artifact)); |
| } |
| |
| public Artifact getArtifactA() throws OseeCoreException { |
| return getArtifact(RelationSide.SIDE_A); |
| } |
| |
| public Artifact getArtifactB() throws OseeCoreException { |
| return getArtifact(RelationSide.SIDE_B); |
| } |
| |
| public String getRationale() { |
| return rationale; |
| } |
| |
| public void setRationale(String rationale) { |
| if (rationale == null) { |
| rationale = ""; |
| } |
| if (this.rationale.equals(rationale)) { |
| return; |
| } |
| internalSetRationale(rationale); |
| markedAsChanged(ModificationType.MODIFIED, SET_DIRTY); |
| |
| } |
| |
| public void internalSetRationale(String rationale) { |
| if (rationale == null) { |
| rationale = ""; |
| } |
| if (this.rationale.equals(rationale)) { |
| return; |
| } |
| this.rationale = rationale; |
| } |
| |
| public boolean isOfType(IRelationType oseeType) { |
| return relationType.equals(oseeType); |
| } |
| |
| public RelationType getRelationType() { |
| return relationType; |
| } |
| |
| public String getSideNameFor(Artifact artifact) { |
| return relationType.getSideName(getSide(artifact)); |
| } |
| |
| public String getSidePhrasingFor(Artifact artifact) throws OseeCoreException { |
| return getSidePhrasingFor(artifact, false); |
| } |
| |
| public String getSidePhrasingForOtherArtifact(Artifact artifact) throws OseeCoreException { |
| return getSidePhrasingFor(artifact, true); |
| } |
| |
| private String getSidePhrasingFor(Artifact artifact, boolean isOtherArtifact) throws OseeCoreException { |
| RelationSide side; |
| if (artifact == getArtifact(RelationSide.SIDE_A)) { |
| side = RelationSide.SIDE_A; |
| } else if (artifact == getArtifact(RelationSide.SIDE_B)) { |
| side = RelationSide.SIDE_B; |
| } else { |
| throw new OseeArgumentException("Link does not contain the artifact."); |
| } |
| if (isOtherArtifact) { |
| side = side.oppositeSide(); |
| } |
| return "has (" + getRelationType().getMultiplicity().asLimitLabel(side) + ")"; |
| } |
| |
| @Override |
| public String toString() { |
| String artAName = artifactLinker.getLazyArtifactName(getAArtifactId(), getBranch()); |
| String artBName = artifactLinker.getLazyArtifactName(getBArtifactId(), getBranch()); |
| return String.format("type[%s] id[%d] modType[%s] [%s]: aName[%s] aId[%d] <--> bName[%s] bId[%s]", |
| relationType.getName(), relationId, getModificationType(), (isDirty() ? "dirty" : "not dirty"), artAName, |
| aArtifactId, artBName, bArtifactId); |
| } |
| |
| public void setNotDirty() { |
| setDirtyFlag(false); |
| } |
| |
| public void setDirty() { |
| setDirtyFlag(true); |
| } |
| |
| private void setDirtyFlag(boolean dirty) { |
| this.dirty = dirty; |
| artifactLinker.updateCachedArtifact(aArtifactId, getBranch()); |
| artifactLinker.updateCachedArtifact(bArtifactId, getBranch()); |
| } |
| |
| public void internalSetRelationId(int relationId) { |
| this.relationId = relationId; |
| } |
| |
| public int getId() { |
| return relationId; |
| } |
| |
| public int getGammaId() { |
| return gammaId; |
| } |
| |
| public boolean isInDb() { |
| return getId() > 0; |
| } |
| |
| void internalSetGammaId(int gammaId) { |
| this.gammaId = gammaId; |
| } |
| |
| public IOseeBranch getBranch() { |
| return branch; |
| } |
| |
| private void markedAsChanged(ModificationType modificationType, boolean setDirty) { |
| //Because deletes can reorder links and we want the final mod type to be the delete and not the modify. |
| if (modificationType != ModificationType.DELETED || modificationType != ModificationType.ARTIFACT_DELETED) { |
| this.modificationType = modificationType; |
| } |
| |
| if (setDirty) { |
| setDirty(); |
| } else { |
| setNotDirty(); |
| } |
| } |
| |
| public ModificationType getModificationType() { |
| return modificationType; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof RelationLink) { |
| RelationLink other = (RelationLink) obj; |
| //@formatter:off |
| boolean result = aArtifactId == other.aArtifactId && |
| branch.equals(other.branch) && |
| bArtifactId == other.bArtifactId && |
| other.modificationType == modificationType && |
| relationType.equals(other.relationType); |
| //@formatter:on |
| |
| // This should eventually be removed once DB cleanup occurs |
| return result && relationId == other.relationId; |
| } |
| return false; |
| } |
| |
| /** |
| * Same as equals except don't check relationIds. This is what equals should become once database is cleaned |
| * (permanently) of duplicate "conceptual" relations. ex same artA, artB and relationType |
| */ |
| public boolean equalsConceptually(Object obj) { |
| if (obj instanceof RelationLink) { |
| RelationLink other = (RelationLink) obj; |
| //@formatter:off |
| return aArtifactId == other.aArtifactId && |
| branch.equals(other.branch) && |
| bArtifactId == other.bArtifactId && |
| other.modificationType == modificationType && |
| relationType.equals(other.relationType); |
| //@formatter:on |
| } |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + branch.hashCode(); |
| result = prime * result + aArtifactId; |
| result = prime * result + bArtifactId; |
| result = prime * result + relationType.hashCode(); |
| result = prime * result + modificationType.hashCode(); |
| return result; |
| } |
| |
| public boolean isUserDefined() throws OseeCoreException { |
| RelationOrderFactory factory = new RelationOrderFactory(); |
| Artifact aArtifact = ArtifactQuery.getArtifactFromId(getAArtifactId(), branch); |
| Artifact bArtifact = ArtifactQuery.getArtifactFromId(getBArtifactId(), branch); |
| |
| RelationOrderData leftData = factory.createRelationOrderData(aArtifact); |
| RelationOrderData rightData = factory.createRelationOrderData(bArtifact); |
| |
| IRelationSorterId leftSorter = |
| RelationOrderBaseTypes.getFromGuid(leftData.getCurrentSorterGuid(getRelationType(), getSide(aArtifact))); |
| IRelationSorterId rightSorter = |
| RelationOrderBaseTypes.getFromGuid(rightData.getCurrentSorterGuid(getRelationType(), getSide(bArtifact))); |
| |
| return (rightSorter.equals(USER_DEFINED) && leftSorter.equals(USER_DEFINED)); |
| } |
| } |