diff options
Diffstat (limited to 'plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/relation/impl/RelationManagerImpl.java')
-rw-r--r-- | plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/relation/impl/RelationManagerImpl.java | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/relation/impl/RelationManagerImpl.java b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/relation/impl/RelationManagerImpl.java new file mode 100644 index 00000000000..dc4dccacdac --- /dev/null +++ b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/relation/impl/RelationManagerImpl.java @@ -0,0 +1,444 @@ +/******************************************************************************* + * Copyright (c) 2012 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.orcs.core.internal.relation.impl; + +import static org.eclipse.osee.framework.core.enums.CoreRelationTypes.Default_Hierarchical__Child; +import static org.eclipse.osee.framework.core.enums.CoreRelationTypes.Default_Hierarchical__Parent; +import static org.eclipse.osee.framework.core.enums.DeletionFlag.EXCLUDE_DELETED; +import static org.eclipse.osee.framework.core.enums.DeletionFlag.INCLUDE_DELETED; +import static org.eclipse.osee.framework.core.enums.RelationSide.SIDE_A; +import static org.eclipse.osee.framework.core.enums.RelationSide.SIDE_B; +import static org.eclipse.osee.framework.core.util.Conditions.checkNotNull; +import static org.eclipse.osee.framework.jdk.core.util.Strings.emptyString; +import static org.eclipse.osee.orcs.core.internal.util.OrcsConditions.checkBranch; +import static org.eclipse.osee.orcs.core.internal.util.OrcsConditions.checkOnGraph; +import static org.eclipse.osee.orcs.core.internal.util.OrcsConditions.checkRelateSelf; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.eclipse.osee.framework.core.data.IRelationSorterId; +import org.eclipse.osee.framework.core.data.IRelationType; +import org.eclipse.osee.framework.core.data.IRelationTypeSide; +import org.eclipse.osee.framework.core.data.Identifiable; +import org.eclipse.osee.framework.core.data.ResultSet; +import org.eclipse.osee.framework.core.enums.DeletionFlag; +import org.eclipse.osee.framework.core.enums.RelationOrderBaseTypes; +import org.eclipse.osee.framework.core.enums.RelationSide; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.RelationTypeSide; +import org.eclipse.osee.framework.core.util.Conditions; +import org.eclipse.osee.logger.Log; +import org.eclipse.osee.orcs.OrcsSession; +import org.eclipse.osee.orcs.core.internal.graph.GraphData; +import org.eclipse.osee.orcs.core.internal.relation.Relation; +import org.eclipse.osee.orcs.core.internal.relation.RelationFactory; +import org.eclipse.osee.orcs.core.internal.relation.RelationManager; +import org.eclipse.osee.orcs.core.internal.relation.RelationNode; +import org.eclipse.osee.orcs.core.internal.relation.RelationResolver; +import org.eclipse.osee.orcs.core.internal.relation.RelationTypeValidity; +import org.eclipse.osee.orcs.core.internal.relation.RelationVisitor; +import org.eclipse.osee.orcs.core.internal.relation.order.OrderManager; +import org.eclipse.osee.orcs.core.internal.relation.order.OrderManagerFactory; +import org.eclipse.osee.orcs.core.internal.util.ResultSets; + +/** + * @author Andrew M. Finkbeiner + * @author Roberto E. Escobar + */ +public class RelationManagerImpl implements RelationManager { + + private static final IRelationType DEFAULT_HIERARCHY = Default_Hierarchical__Parent; + private static final RelationSide IS_PARENT = Default_Hierarchical__Parent.getSide(); + private static final RelationSide IS_CHILD = Default_Hierarchical__Child.getSide(); + + private final Log logger; + private final RelationTypeValidity validity; + private final RelationResolver resolver; + private final RelationFactory relationFactory; + private final OrderManagerFactory orderFactory; + + public RelationManagerImpl(Log logger, RelationTypeValidity validity, RelationResolver resolver, RelationFactory relationFactory, OrderManagerFactory orderFactory) { + super(); + this.logger = logger; + this.validity = validity; + this.resolver = resolver; + this.relationFactory = relationFactory; + this.orderFactory = orderFactory; + } + + @Override + public int getMaximumRelationAllowed(OrcsSession session, IRelationType type, RelationNode node, RelationSide side) throws OseeCoreException { + Conditions.checkNotNull(node, "node"); + return validity.getMaximumRelationsAllowed(type, node.getArtifactType(), side); + } + + @Override + public Collection<? extends IRelationType> getValidRelationTypes(OrcsSession session, RelationNode node) throws OseeCoreException { + Conditions.checkNotNull(node, "node"); + return validity.getValidRelationTypes(node.getArtifactType()); + } + + @Override + public void accept(OrcsSession session, GraphData graph, RelationNode node, RelationVisitor visitor) throws OseeCoreException { + checkOnGraph(graph, node); + ensureRelationsInitialized(session, graph, node); + RelationNodeAdjacencies container = graph.getAdjacencies(node); + if (container != null) { + container.accept(visitor); + } else { + logger.warn("Unable to find relation container for [%s]", node.getExceptionString()); + } + } + + @Override + public boolean hasDirtyRelations(OrcsSession session, GraphData graph, RelationNode node) throws OseeCoreException { + checkOnGraph(graph, node); + ensureRelationsInitialized(session, graph, node); + RelationNodeAdjacencies container = graph.getAdjacencies(node); + return container != null ? container.hasDirty() : false; + } + + @Override + public Collection<? extends IRelationType> getExistingRelationTypes(OrcsSession session, GraphData graph, RelationNode node) throws OseeCoreException { + checkOnGraph(graph, node); + ensureRelationsInitialized(session, graph, node); + RelationNodeAdjacencies container = graph.getAdjacencies(node); + Collection<? extends IRelationType> toReturn = null; + if (container != null) { + toReturn = container.getExistingTypes(DeletionFlag.EXCLUDE_DELETED); + } else { + logger.warn("Unable to find relation container for [%s]", node.getExceptionString()); + toReturn = Collections.<IRelationType> emptyList(); + } + return toReturn; + } + + @Override + public int getRelatedCount(OrcsSession session, GraphData graph, IRelationType type, RelationNode node, RelationSide side) throws OseeCoreException { + return getRelatedCount(session, graph, type, node, side, EXCLUDE_DELETED); + } + + @Override + public int getRelatedCount(OrcsSession session, GraphData graph, IRelationType type, RelationNode node, RelationSide side, DeletionFlag includeDeleted) throws OseeCoreException { + return getRelations(session, graph, type, node, side, includeDeleted).size(); + } + + @Override + public boolean areRelated(OrcsSession session, GraphData graph, RelationNode aNode, IRelationType type, RelationNode bNode) throws OseeCoreException { + return getRelation(session, graph, aNode, type, bNode, EXCLUDE_DELETED).size() > 0; + } + + @Override + public <T extends RelationNode> T getParent(OrcsSession session, GraphData graph, RelationNode child) throws OseeCoreException { + ResultSet<T> toReturn = getRelated(session, graph, DEFAULT_HIERARCHY, child, IS_CHILD); + return toReturn.getOneOrNull(); + } + + @Override + public <T extends RelationNode> ResultSet<T> getChildren(OrcsSession session, GraphData graph, RelationNode parent) throws OseeCoreException { + return getRelated(session, graph, DEFAULT_HIERARCHY, parent, IS_PARENT); + } + + @Override + public <T extends RelationNode> ResultSet<T> getRelated(OrcsSession session, GraphData graph, IRelationType type, RelationNode node, RelationSide side) throws OseeCoreException { + List<Relation> links = getRelations(session, graph, type, node, side, EXCLUDE_DELETED); + List<T> result = null; + if (links.isEmpty()) { + result = Collections.emptyList(); + } else { + RelationSide otherSide = side.oppositeSide(); + result = resolver.resolve(session, graph, links, otherSide); + if (result.size() > 1) { + OrderManager orderManager = orderFactory.createOrderManager(node); + IRelationTypeSide key = asTypeSide(type, otherSide); + orderManager.sort(key, result); + } + } + return ResultSets.newResultSet(result); + } + + @Override + public String getRationale(OrcsSession session, GraphData graph, RelationNode aNode, IRelationType type, RelationNode bNode) throws OseeCoreException { + ResultSet<Relation> result = getRelation(session, graph, aNode, type, bNode, EXCLUDE_DELETED); + return result.getExactlyOne().getRationale(); + } + + @Override + public void setRationale(OrcsSession session, GraphData graph, RelationNode aNode, IRelationType type, RelationNode bNode, String rationale) throws OseeCoreException { + ResultSet<Relation> result = getRelation(session, graph, aNode, type, bNode, EXCLUDE_DELETED); + Relation relation = result.getExactlyOne(); + relation.setRationale(rationale); + } + + ///////////////////////// RELATE NODES /////////////////// + @Override + public void addChild(OrcsSession session, GraphData graph, RelationNode parent, RelationNode child) throws OseeCoreException { + unrelateFromAll(session, graph, DEFAULT_HIERARCHY, child, IS_CHILD); + relate(session, graph, parent, DEFAULT_HIERARCHY, child); + } + + @Override + public void addChildren(OrcsSession session, GraphData graph, RelationNode parent, List<? extends RelationNode> children) throws OseeCoreException { + for (RelationNode child : children) { + addChild(session, graph, parent, child); + } + } + + @Override + public void relate(OrcsSession session, GraphData graph, RelationNode aNode, IRelationType type, RelationNode bNode) throws OseeCoreException { + relate(session, graph, aNode, type, bNode, emptyString(), RelationOrderBaseTypes.PREEXISTING); + } + + @Override + public void relate(OrcsSession session, GraphData graph, RelationNode aNode, IRelationType type, RelationNode bNode, String rationale) throws OseeCoreException { + relate(session, graph, aNode, type, bNode, rationale, RelationOrderBaseTypes.PREEXISTING); + } + + @Override + public void relate(OrcsSession session, GraphData graph, RelationNode aNode, IRelationType type, RelationNode bNode, IRelationSorterId sortType) throws OseeCoreException { + relate(session, graph, aNode, type, bNode, emptyString(), sortType); + } + + @Override + public void relate(OrcsSession session, GraphData graph, RelationNode aNode, IRelationType type, RelationNode bNode, String rationale, IRelationSorterId sortType) throws OseeCoreException { + checkOnGraph(graph, aNode, bNode); + checkBranch(aNode, bNode); + checkRelateSelf(aNode, bNode); + + checkTypeAndCanAdd(session, graph, type, aNode, SIDE_A); + checkTypeAndCanAdd(session, graph, type, bNode, SIDE_B); + + Relation relation = getRelation(session, graph, aNode, type, bNode, INCLUDE_DELETED).getOneOrNull(); + boolean updated = false; + if (relation == null) { + relation = relationFactory.createRelation(aNode, type, bNode); + graph.<RelationNodeAdjacencies> getAdjacencies(aNode).add(type.getGuid(), relation); + graph.<RelationNodeAdjacencies> getAdjacencies(bNode).add(type.getGuid(), relation); + updated = true; + } + if (relation.isDeleted()) { + relation.unDelete(); + updated = true; + } + if (updated) { + relation.setDirty(); + order(session, graph, type, aNode, SIDE_A, sortType, OrderOp.ADD_TO_ORDER, Collections.singleton(bNode)); + } + } + + private void checkTypeAndCanAdd(OrcsSession session, GraphData graph, IRelationType type, RelationNode node, RelationSide side) throws OseeCoreException { + validity.checkRelationTypeValid(type, node, side); + checkMultiplicityCanAdd(session, graph, type, node, side); + } + + private void checkMultiplicityCanAdd(OrcsSession session, GraphData graph, IRelationType type, RelationNode node, RelationSide side) throws OseeCoreException { + int currentCount = getRelatedCount(session, graph, type, node, side); + validity.checkRelationTypeMultiplicity(type, node, side, currentCount + 1); + } + + ///////////////////////// UNRELATE NODES /////////////////// + @Override + public void unrelate(OrcsSession session, GraphData graph, RelationNode aNode, IRelationType type, RelationNode bNode) throws OseeCoreException { + Relation relation = getRelation(session, graph, aNode, type, bNode, EXCLUDE_DELETED).getOneOrNull(); + boolean modified = false; + if (relation != null) { + relation.delete(); + modified = true; + } + if (modified) { + order(session, graph, type, aNode, SIDE_A, OrderOp.REMOVE_FROM_ORDER, Collections.singleton(bNode)); + } + } + + @Override + public void unrelateFromAll(OrcsSession session, GraphData graph, IRelationType type, RelationNode node, RelationSide side) throws OseeCoreException { + List<Relation> relations = getRelations(session, graph, type, node, side, EXCLUDE_DELETED); + + RelationSide otherSide = side.oppositeSide(); + resolver.resolve(session, graph, relations, otherSide); + + boolean modified = false; + Set<RelationNode> otherNodes = new LinkedHashSet<RelationNode>(); + for (Relation relation : relations) { + relation.delete(); + Integer artId = relation.getLocalIdForSide(otherSide); + RelationNode otherNode = graph.getNode(artId); + otherNodes.add(otherNode); + modified = true; + } + if (modified) { + order(session, graph, type, node, side, OrderOp.REMOVE_FROM_ORDER, otherNodes); + } + } + + @Override + public void unrelateFromAll(OrcsSession session, GraphData graph, RelationNode node) throws OseeCoreException { + unrelate(session, graph, node, true); + } + + private void unrelate(OrcsSession session, GraphData graph, RelationNode node, boolean reorderRelations) throws OseeCoreException { + checkNotNull(node, "node"); + if (node.isDeleteAllowed()) { + + List<Relation> relations = getRelations(session, graph, node, EXCLUDE_DELETED); + resolver.resolve(session, graph, relations, RelationSide.values()); + + ResultSet<RelationNode> children = getChildren(session, graph, node); + for (RelationNode child : children) { + unrelate(session, graph, child, false); + } + + try { + node.delete(); + + if (relations != null && !relations.isEmpty()) { + Map<IRelationType, RelationSide> typesToRemove = new HashMap<IRelationType, RelationSide>(); + for (Relation relation : relations) { + relation.delete(); + IRelationType type = relation.getRelationType(); + RelationSide otherSide = relation.getLocalIdForSide(SIDE_A) == node.getLocalId() ? SIDE_B : SIDE_A; + typesToRemove.put(type, otherSide); + } + + if (!typesToRemove.isEmpty()) { + OrderManager orderManager = orderFactory.createOrderManager(node); + + for (Entry<IRelationType, RelationSide> entry : typesToRemove.entrySet()) { + IRelationType type = entry.getKey(); + RelationSide side = entry.getValue(); + + List<Relation> sideLinks = getRelations(session, graph, type, node, side, EXCLUDE_DELETED); + List<RelationNode> nodes = resolver.resolve(session, graph, sideLinks, side); + + IRelationTypeSide asTypeSide = asTypeSide(type, side); + orderManager.setOrder(asTypeSide, nodes); + } + } + } + } catch (OseeCoreException ex) { + node.unDelete(); + throw ex; + } + } + } + + ///////////////////////// READ HELPERS /////////////////// + @SuppressWarnings("unused") + private void ensureRelationsInitialized(OrcsSession session, GraphData graph, RelationNode node) throws OseeCoreException { + if (graph.getAdjacencies(node) == null) { + RelationNodeAdjacencies container = relationFactory.createRelationContainer(); + graph.addAdjacencies(node, container); + } + } + + private ResultSet<Relation> getRelation(OrcsSession session, GraphData graph, RelationNode aNode, IRelationType type, RelationNode bNode, DeletionFlag inludeDeleted) throws OseeCoreException { + checkNotNull(session, "session"); + checkOnGraph(graph, aNode, bNode); + checkNotNull(type, "relationType"); + + ensureRelationsInitialized(session, graph, aNode); + ensureRelationsInitialized(session, graph, bNode); + + RelationNodeAdjacencies aAdjacencies = graph.getAdjacencies(aNode); + RelationNodeAdjacencies bAdjacencies = graph.getAdjacencies(bNode); + + Relation relation = aAdjacencies.getRelation(aNode, type, bNode, inludeDeleted); + if (relation != null) { + bAdjacencies.add(type.getGuid(), relation); + } else { + relation = bAdjacencies.getRelation(aNode, type, bNode, inludeDeleted); + if (relation != null) { + aAdjacencies.add(type.getGuid(), relation); + } + } + return ResultSets.singleton(relation); + } + + private List<Relation> getRelations(OrcsSession session, GraphData graph, IRelationType type, RelationNode node, RelationSide side, DeletionFlag includeDeleted) throws OseeCoreException { + checkNotNull(session, "session"); + checkOnGraph(graph, node); + checkNotNull(type, "relationType"); + checkNotNull(side, "relationSide"); + + ensureRelationsInitialized(session, graph, node); + RelationNodeAdjacencies adjacencies = graph.getAdjacencies(node); + return adjacencies.getList(type, includeDeleted, node, side); + } + + private List<Relation> getRelations(OrcsSession session, GraphData graph, RelationNode node, DeletionFlag includeDeleted) throws OseeCoreException { + checkNotNull(session, "session"); + checkOnGraph(graph, node); + ensureRelationsInitialized(session, graph, node); + RelationNodeAdjacencies adjacencies = graph.getAdjacencies(node); + return adjacencies.getList(includeDeleted); + } + + private static enum OrderOp { + ADD_TO_ORDER, + REMOVE_FROM_ORDER; + } + + private void order(OrcsSession session, GraphData graph, IRelationType type, RelationNode node1, RelationSide side, OrderOp op, Collection<? extends RelationNode> node2) throws OseeCoreException { + order(session, graph, type, node1, side, RelationOrderBaseTypes.PREEXISTING, op, node2); + } + + private void order(OrcsSession session, GraphData graph, IRelationType type, RelationNode node1, RelationSide side, IRelationSorterId sorterId, OrderOp op, Collection<? extends RelationNode> node2) throws OseeCoreException { + OrderManager orderManager = orderFactory.createOrderManager(node1); + + RelationSide orderSide = side.oppositeSide(); + IRelationTypeSide key = asTypeSide(type, orderSide); + IRelationSorterId sorterIdToUse = sorterId; + if (sorterIdToUse == RelationOrderBaseTypes.PREEXISTING) { + sorterIdToUse = orderManager.getSorterId(key); + } + List<Identifiable> relatives = Collections.emptyList(); + if (RelationOrderBaseTypes.USER_DEFINED == sorterIdToUse) { + ResultSet<RelationNode> arts = getRelated(session, graph, type, node1, side); + relatives = new LinkedList<Identifiable>(); + for (RelationNode art : arts) { + relatives.add(art); + } + relatives.removeAll(node2); // ensure no duplicates + + if (OrderOp.ADD_TO_ORDER == op) { + relatives.addAll(node2); // always add to the end + } + } + orderManager.setOrder(key, sorterIdToUse, relatives); + } + + @Override + public void cloneRelations(OrcsSession session, RelationNode source, RelationNode destination) throws OseeCoreException { + ensureRelationsInitialized(session, source.getGraph(), source); + RelationNodeAdjacencies adjacencies1 = source.getGraph().getAdjacencies(source); + if (adjacencies1 != null) { + Collection<Relation> all = adjacencies1.getAll(); + if (!all.isEmpty()) { + RelationNodeAdjacencies adjacencies2 = relationFactory.createRelationContainer(); + destination.getGraph().addAdjacencies(destination, adjacencies2); + for (Relation relation : adjacencies1.getAll()) { + Relation newRel = relationFactory.clone(relation); + adjacencies2.add(newRel.getOrcsData().getTypeUuid(), newRel); + } + } + } + } + + private static IRelationTypeSide asTypeSide(IRelationType type, RelationSide side) { + return new RelationTypeSide(type, side); + } +} |