diff options
author | jmisinco | 2015-08-28 17:14:37 +0000 |
---|---|---|
committer | Angel Avila | 2015-09-12 01:05:34 +0000 |
commit | 538384f68f0f14d00c52af1f021984d29a9e51c0 (patch) | |
tree | 800f27b90655bc42d5a07a2ca45bc9987e0ff4c2 | |
parent | 6c68981f8d1ef8cd5e6277dff4ddbf99e5c20eed (diff) | |
download | org.eclipse.osee-538384f68f0f14d00c52af1f021984d29a9e51c0.tar.gz org.eclipse.osee-538384f68f0f14d00c52af1f021984d29a9e51c0.tar.xz org.eclipse.osee-538384f68f0f14d00c52af1f021984d29a9e51c0.zip |
feature[ats_ATS226476]: Enforce attribute and relation multiplicity in transactions
Change-Id: Ia7adf413885f761501712f59c83b71e7f6b271bb
7 files changed, 175 insertions, 57 deletions
diff --git a/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/skynet/core/SkynetTransactionTest.java b/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/skynet/core/SkynetTransactionTest.java index 422f68aaba4..416145493da 100644 --- a/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/skynet/core/SkynetTransactionTest.java +++ b/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/skynet/core/SkynetTransactionTest.java @@ -20,6 +20,9 @@ import org.eclipse.osee.client.test.framework.OseeLogMonitorRule; import org.eclipse.osee.client.test.framework.TestInfo; import org.eclipse.osee.framework.core.data.IOseeBranch; import org.eclipse.osee.framework.core.enums.CoreArtifactTypes; +import org.eclipse.osee.framework.core.enums.CoreAttributeTypes; +import org.eclipse.osee.framework.core.enums.CoreRelationTypes; +import org.eclipse.osee.framework.jdk.core.type.OseeArgumentException; import org.eclipse.osee.framework.jdk.core.type.OseeCoreException; import org.eclipse.osee.framework.jdk.core.type.OseeStateException; import org.eclipse.osee.framework.jdk.core.util.Lib; @@ -133,6 +136,34 @@ public final class SkynetTransactionTest { artifact2.purgeFromBranch(); } + @Test(expected = OseeStateException.class) + public void testAttributeMultiplicity() { + Artifact swReq = ArtifactTypeManager.addArtifact(CoreArtifactTypes.SoftwareRequirement, BRANCH); + swReq.addAttribute(CoreAttributeTypes.ParagraphNumber, "1.1"); + swReq.addAttribute(CoreAttributeTypes.ParagraphNumber, "2.2"); + try { + swReq.persist("testAttributeMultiplicity"); + } finally { + swReq.purgeFromBranch(); + } + } + + @Test(expected = OseeArgumentException.class) + public void testRelationMultiplicity() { + Artifact parent1 = ArtifactTypeManager.addArtifact(CoreArtifactTypes.SoftwareRequirement, BRANCH, "parent1"); + Artifact parent2 = ArtifactTypeManager.addArtifact(CoreArtifactTypes.SoftwareRequirement, BRANCH, "parent2"); + Artifact child = ArtifactTypeManager.addArtifact(CoreArtifactTypes.SoftwareRequirement, BRANCH, "child"); + try { + parent1.addRelation(CoreRelationTypes.Default_Hierarchical__Child, child); + parent2.addRelation(CoreRelationTypes.Default_Hierarchical__Child, child); + child.persist("testRelationMultiplicity"); + } finally { + child.purgeFromBranch(); + parent1.purgeFromBranch(); + parent2.purgeFromBranch(); + } + } + @Test public void test_multiThreadedCoModificationOveralappingTransactions() throws Exception { Object lock = new Object(); diff --git a/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/skynet/core/utils/TestUtil.java b/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/skynet/core/utils/TestUtil.java index 0bf309910cc..d6aa8ad0c83 100644 --- a/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/skynet/core/utils/TestUtil.java +++ b/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/skynet/core/utils/TestUtil.java @@ -53,7 +53,9 @@ public final class TestUtil { public static Artifact createSimpleArtifact(IArtifactType artifactType, String name, IOseeBranch branch) throws OseeCoreException { Artifact softArt = ArtifactTypeManager.addArtifact(artifactType, branch); softArt.setName(name); - softArt.addAttribute(CoreAttributeTypes.Subsystem, "Electrical"); + if (softArt.isAttributeTypeValid(CoreAttributeTypes.Subsystem)) { + softArt.setSoleAttributeFromString(CoreAttributeTypes.Subsystem, "Electrical"); + } Artifact rootArtifact = OseeSystemArtifacts.getDefaultHierarchyRootArtifact(branch); rootArtifact.addRelation(CoreRelationTypes.Default_Hierarchical__Child, softArt); return softArt; diff --git a/plugins/org.eclipse.osee.framework.core/src/org/eclipse/osee/framework/core/enums/CoreRelationTypes.java b/plugins/org.eclipse.osee.framework.core/src/org/eclipse/osee/framework/core/enums/CoreRelationTypes.java index b64f084d3f8..0a7b3d668bf 100644 --- a/plugins/org.eclipse.osee.framework.core/src/org/eclipse/osee/framework/core/enums/CoreRelationTypes.java +++ b/plugins/org.eclipse.osee.framework.core/src/org/eclipse/osee/framework/core/enums/CoreRelationTypes.java @@ -34,51 +34,51 @@ public final class CoreRelationTypes { public static final IRelationTypeSide Executes__Test_Plan_Element = TokenFactory.createRelationTypeSide(SIDE_A, 0x200000000000015EL, "Executes"); public static final IRelationTypeSide Executes__Test_Procedure = Executes__Test_Plan_Element.getOpposite(); - + public static final IRelationTypeSide Related_Feature__Feature = TokenFactory.createRelationTypeSide(SIDE_A, 0x0000000000000058L, "Related Feature"); public static final IRelationTypeSide Related_Feature__Requirement = Related_Feature__Feature.getOpposite(); - + public static final IRelationTypeSide Requirement_Trace__Higher_Level = TokenFactory.createRelationTypeSide(SIDE_A, 0x200000000000015FL, "Requirement Trace"); public static final IRelationTypeSide Requirement_Trace__Lower_Level = Requirement_Trace__Higher_Level.getOpposite(); - + public static final IRelationTypeSide Safety__Safety_Assessment = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000180L, "Safety Assessment"); public static final IRelationTypeSide Safety__System_Function = Safety__Safety_Assessment.getOpposite(); - + public static final IRelationTypeSide Supercedes_Supercedes = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000165L, "Supercedes"); public static final IRelationTypeSide Supercedes_Superceded = Supercedes_Supercedes.getOpposite(); - + public static final IRelationTypeSide SupportingInfo_SupportedBy = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000166L, "Supporting Info"); public static final IRelationTypeSide SupportingInfo_SupportingInfo = SupportingInfo_SupportedBy.getOpposite(); - + public static final IRelationTypeSide SupportingRequirement__Higher_Level = TokenFactory.createRelationTypeSide(SIDE_A, 0x200000000000017CL, "Supporting Requirement"); public static final IRelationTypeSide SupportingRequirement__Lower_Level = SupportingRequirement__Higher_Level.getOpposite(); - + public static final IRelationTypeSide TeamMember_Team = TokenFactory.createRelationTypeSide(SIDE_A, 0x200000000000016AL, "TeamMember"); public static final IRelationTypeSide TeamMember_Member = TeamMember_Team.getOpposite(); - + public static final IRelationTypeSide Test_Unit_Result__Test_Unit = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000168L, "Results Data"); public static final IRelationTypeSide Test_Unit_Result__Test_Result = Test_Unit_Result__Test_Unit.getOpposite(); - + public static final IRelationTypeSide Universal_Grouping__Group = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000156L, "Universal Grouping"); public static final IRelationTypeSide Universal_Grouping__Members = Universal_Grouping__Group.getOpposite(); - - + + public static final IRelationTypeSide User_Grouping__Group = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000163L, "User Grouping"); public static final IRelationTypeSide User_Grouping__Members = User_Grouping__Group.getOpposite(); - - - public static final IRelationTypeSide Users_Artifact = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000164L, "Artifact"); + + + public static final IRelationTypeSide Users_Artifact = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000164L, "Users"); public static final IRelationTypeSide Users_User = Users_Artifact.getOpposite(); - + public static final IRelationTypeSide Uses__Requirement = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000177L, "Uses"); public static final IRelationTypeSide Uses__TestUnit = Uses__Requirement.getOpposite(); - + public static final IRelationTypeSide Validation__Requirement = TokenFactory.createRelationTypeSide(SIDE_A, 0x2000000000000160L, "Validation"); public static final IRelationTypeSide Validation__Validator = Validation__Requirement.getOpposite(); - + public static final IRelationTypeSide Verification__Requirement = TokenFactory.createRelationTypeSide(SIDE_A, 0x200000000000015BL, "Verification"); public static final IRelationTypeSide Verification__Verifier = Verification__Requirement.getOpposite(); - + public static final IRelationTypeSide Verification_Plan__Requirement = TokenFactory.createRelationTypeSide(SIDE_A, 0x200000000000015CL, "Verification Plan"); public static final IRelationTypeSide Verification_Plan__Test_Plan_Element = Verification_Plan__Requirement.getOpposite(); //@formatter:on diff --git a/plugins/org.eclipse.osee.framework.skynet.core/src/org/eclipse/osee/framework/skynet/core/transaction/SkynetTransaction.java b/plugins/org.eclipse.osee.framework.skynet.core/src/org/eclipse/osee/framework/skynet/core/transaction/SkynetTransaction.java index 005eea92874..86ff7755294 100644 --- a/plugins/org.eclipse.osee.framework.skynet.core/src/org/eclipse/osee/framework/skynet/core/transaction/SkynetTransaction.java +++ b/plugins/org.eclipse.osee.framework.skynet.core/src/org/eclipse/osee/framework/skynet/core/transaction/SkynetTransaction.java @@ -25,13 +25,16 @@ import java.util.Set; import java.util.logging.Level; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.osee.framework.core.data.IOseeBranch; +import org.eclipse.osee.framework.core.data.TokenFactory; import org.eclipse.osee.framework.core.enums.ModificationType; import org.eclipse.osee.framework.core.enums.PermissionEnum; import org.eclipse.osee.framework.core.enums.RelationSide; +import org.eclipse.osee.framework.core.enums.RelationTypeMultiplicity; import org.eclipse.osee.framework.core.model.Branch; import org.eclipse.osee.framework.core.model.RelationTypeSide; import org.eclipse.osee.framework.core.model.TransactionRecord; import org.eclipse.osee.framework.core.model.access.PermissionStatus; +import org.eclipse.osee.framework.core.model.type.RelationType; import org.eclipse.osee.framework.core.operation.IOperation; import org.eclipse.osee.framework.core.operation.Operations; import org.eclipse.osee.framework.jdk.core.type.CompositeKeyHashMap; @@ -107,9 +110,8 @@ public final class SkynetTransaction extends TransactionOperation<Branch> { } Branch txBranch = getBranch(); if (!artifact.getBranch().equals(txBranch)) { - String msg = - String.format("The artifact [%s] is on branch [%s] but this transaction is for branch [%s]", - artifact.getGuid(), artifact.getBranch(), txBranch); + String msg = String.format("The artifact [%s] is on branch [%s] but this transaction is for branch [%s]", + artifact.getGuid(), artifact.getBranch(), txBranch); throw new OseeStateException(msg); } @@ -143,8 +145,8 @@ public final class SkynetTransaction extends TransactionOperation<Branch> { boolean toReturn = true; if (!UserManager.duringMainUserCreation()) { Branch fullBranch = BranchManager.getBranch(branch); - toReturn = - getAccess().hasBranchPermission(branch, PermissionEnum.WRITE, Level.FINE).matched() && fullBranch.isEditable(); + toReturn = getAccess().hasBranchPermission(branch, PermissionEnum.WRITE, + Level.FINE).matched() && fullBranch.isEditable(); } return toReturn; } @@ -156,16 +158,14 @@ public final class SkynetTransaction extends TransactionOperation<Branch> { checkBranch(link); Branch txBranch = getBranch(); if (!link.getBranch().equals(txBranch)) { - String msg = - String.format("The relation link [%s] is on branch [%s] but this transaction is for branch [%s]", - link.getId(), link.getBranch(), txBranch); + String msg = String.format("The relation link [%s] is on branch [%s] but this transaction is for branch [%s]", + link.getId(), link.getBranch(), txBranch); throw new OseeStateException(msg); } RelationSide sideToCheck = link.getSide(artifact).oppositeSide(); - PermissionStatus status = - getAccess().canRelationBeModified(artifact, null, new RelationTypeSide(link.getRelationType(), sideToCheck), - Level.FINE); + PermissionStatus status = getAccess().canRelationBeModified(artifact, null, + new RelationTypeSide(link.getRelationType(), sideToCheck), Level.FINE); if (!status.matched()) { throw new OseeCoreException( @@ -253,10 +253,36 @@ public final class SkynetTransaction extends TransactionOperation<Branch> { } } + private void checkMultiplicity(Artifact artifact, Attribute<?> attr) { + if (attr.getAttributeType().getMaxOccurrences() == 1 && artifact.getAttributeCount(attr.getAttributeType()) > 1) { + throw new OseeStateException("Artifact [%s] can only have 1 [%s] attribute but has %d", artifact.getName(), + attr.getAttributeType().getName(), artifact.getAttributeCount(attr.getAttributeType())); + } + } + + private void checkMultiplicity(Artifact art, RelationLink link) { + RelationType relationType = link.getRelationType(); + RelationTypeMultiplicity multiplicity = relationType.getMultiplicity(); + + RelationSide sideToCheck = link.getOppositeSide(art); + int limitToCheck = sideToCheck.isSideA() ? multiplicity.getSideALimit() : multiplicity.getSideBLimit(); + if (limitToCheck == 1) { + int count = art.getRelatedArtifactsCount( + TokenFactory.createRelationTypeSide(sideToCheck, relationType.getGuid(), relationType.getName())); + if (count > 1) { + throw new OseeStateException("Artifact [%s] can only have 1 [%s] on [%s] but has %d", art.getName(), + link.getSideNameFor(art), sideToCheck.name(), count); + } + } + } + private void addAttribute(Artifact artifact, Attribute<?> attribute) throws OseeCoreException { if (attribute.isDeleted() && !attribute.isInDb()) { return; } + + checkMultiplicity(artifact, attribute); + if (attribute.getId() == 0) { attribute.internalSetAttributeId(getNewAttributeId(artifact, attribute)); } @@ -317,6 +343,7 @@ public final class SkynetTransaction extends TransactionOperation<Branch> { if (link.isDeleted()) { return; } + checkMultiplicity(artifact, link); link.internalSetRelationId(getNewRelationId()); modificationType = NEW; relationEventType = RelationEventType.Added; diff --git a/plugins/org.eclipse.osee.orcs.core.test/src/org/eclipse/osee/orcs/core/internal/relation/impl/RelationManagerImplTest.java b/plugins/org.eclipse.osee.orcs.core.test/src/org/eclipse/osee/orcs/core/internal/relation/impl/RelationManagerImplTest.java index d8ff599ae9e..85756734aff 100644 --- a/plugins/org.eclipse.osee.orcs.core.test/src/org/eclipse/osee/orcs/core/internal/relation/impl/RelationManagerImplTest.java +++ b/plugins/org.eclipse.osee.orcs.core.test/src/org/eclipse/osee/orcs/core/internal/relation/impl/RelationManagerImplTest.java @@ -50,6 +50,7 @@ import org.eclipse.osee.framework.core.model.DefaultBasicArtifact; import org.eclipse.osee.framework.jdk.core.type.Identifiable; import org.eclipse.osee.framework.jdk.core.type.OseeArgumentException; import org.eclipse.osee.framework.jdk.core.type.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.type.OseeStateException; import org.eclipse.osee.framework.jdk.core.type.ResultSet; import org.eclipse.osee.framework.jdk.core.util.GUID; import org.eclipse.osee.logger.Log; @@ -81,7 +82,7 @@ import org.mockito.stubbing.Answer; /** * Test Case for {@link RelationManagerImpl} - * + * * @author Roberto E. Escobar */ public class RelationManagerImplTest { @@ -96,40 +97,40 @@ public class RelationManagerImplTest { @Mock private RelationTypeValidity validity; @Mock private RelationResolver resolver; @Mock private OrderManagerFactory orderFactory; - + @Mock private RelationFactory relationFactory; @Mock private OrcsSession session; @Mock private QueryModuleProvider provider; @Mock private ProxyProvider proxy; - + @Mock private GraphData graph; - + @Mock private RelationNode node1; @Mock private RelationNode node2; @Mock private RelationNode node3; @Mock private RelationNode node4; @Mock private RelationNode node5; @Mock private RelationNode node6; - + @Mock private RelationNodeAdjacencies container1; @Mock private RelationNodeAdjacencies container2; - + @Mock private IArtifactType artifactType1; @Mock private IArtifactType artifactType2; - + @Mock private Relation relation1; @Mock private Relation relation2; @Mock private Relation relation3; @Mock private Relation relation4; - + @Mock private IRelationType relType1; @Mock private IRelationType relType2; - + @Mock private IRelationTypeSide typeAndSide1; - + @Mock private ResultSet<Relation> rSet1; @Mock private ResultSet<Relation> rSet2; - + @Mock private OrderManager orderManager1; @Captor private ArgumentCaptor<List<? extends Identifiable<String>>> sortedListCaptor; // @formatter:on @@ -489,12 +490,12 @@ public class RelationManagerImplTest { when(node1.getBranch()).thenReturn(COMMON); when(node2.getBranch()).thenReturn(COMMON); - OseeCoreException myException = new OseeCoreException("Test Multiplicity Exception"); + thrown.expect(OseeStateException.class); - doThrow(myException).when(validity).checkRelationTypeMultiplicity(TYPE_1, node1, SIDE_B, 1); + when(node1.getArtifactType()).thenReturn(artifactType1); + when(node2.getArtifactType()).thenReturn(artifactType2); + when(validity.getMaximumRelationsAllowed(Default_Hierarchical__Child, artifactType1, SIDE_A)).thenReturn(1); - thrown.expect(OseeCoreException.class); - thrown.expectMessage("Test Multiplicity Exception"); manager.relate(session, node1, TYPE_1, node2); verify(validity).checkRelationTypeValid(TYPE_1, node1, SIDE_A); @@ -511,12 +512,7 @@ public class RelationManagerImplTest { when(container1.getResultSet(TYPE_1, INCLUDE_DELETED, node1, SIDE_A)).thenReturn(rSet1); when(rSet1.getOneOrNull()).thenReturn(relation1); - OseeCoreException myException = new OseeCoreException("Test Multiplicity Exception"); - - doThrow(myException).when(validity).checkRelationTypeMultiplicity(TYPE_1, node2, SIDE_A, 1); - - thrown.expect(OseeCoreException.class); - thrown.expectMessage("Test Multiplicity Exception"); + thrown.expect(OseeStateException.class); manager.relate(session, node1, TYPE_1, node2); verify(validity).checkRelationTypeValid(TYPE_1, node1, SIDE_A); @@ -549,6 +545,11 @@ public class RelationManagerImplTest { when(relationFactory.createRelation(node1, TYPE_1, node2)).thenReturn(relation1); when(orderFactory.createOrderManager(node1)).thenReturn(orderManager1); + when(node1.getArtifactType()).thenReturn(artifactType1); + when(node2.getArtifactType()).thenReturn(artifactType2); + when(validity.getMaximumRelationsAllowed(TYPE_1, artifactType1, SIDE_A)).thenReturn(10); + when(validity.getMaximumRelationsAllowed(TYPE_1, artifactType2, SIDE_B)).thenReturn(10); + manager.relate(session, node1, TYPE_1, node2, LEXICOGRAPHICAL_ASC); IRelationTypeSide typeSide = RelationUtil.asTypeSide(TYPE_1, SIDE_B); @@ -576,6 +577,11 @@ public class RelationManagerImplTest { IRelationTypeSide typeSide = RelationUtil.asTypeSide(TYPE_1, SIDE_B); when(orderManager1.getSorterId(typeSide)).thenReturn(UNORDERED); + when(node1.getArtifactType()).thenReturn(artifactType1); + when(node2.getArtifactType()).thenReturn(artifactType2); + when(validity.getMaximumRelationsAllowed(TYPE_1, artifactType1, SIDE_A)).thenReturn(10); + when(validity.getMaximumRelationsAllowed(TYPE_1, artifactType2, SIDE_B)).thenReturn(10); + manager.relate(session, node1, TYPE_1, node2); verify(container1).getRelation(node1, TYPE_1, node2, INCLUDE_DELETED); @@ -604,6 +610,11 @@ public class RelationManagerImplTest { List<RelationNode> nodesToOrder = Arrays.asList(node3, node4, node5, node6); when(resolver.resolve(session, graph, toOrder, SIDE_B)).thenReturn(nodesToOrder); + when(node1.getArtifactType()).thenReturn(artifactType1); + when(node2.getArtifactType()).thenReturn(artifactType2); + when(validity.getMaximumRelationsAllowed(TYPE_1, artifactType1, SIDE_A)).thenReturn(10); + when(validity.getMaximumRelationsAllowed(TYPE_1, artifactType2, SIDE_B)).thenReturn(10); + manager.relate(session, node1, TYPE_1, node2, USER_DEFINED); verify(container1).getRelation(node1, TYPE_1, node2, INCLUDE_DELETED); @@ -639,6 +650,11 @@ public class RelationManagerImplTest { when(orderFactory.createOrderManager(node1)).thenReturn(orderManager1); when(orderManager1.getSorterId(Default_Hierarchical__Child)).thenReturn(UNORDERED); + when(node1.getArtifactType()).thenReturn(artifactType1); + when(node2.getArtifactType()).thenReturn(artifactType2); + when(validity.getMaximumRelationsAllowed(Default_Hierarchical__Child, artifactType1, SIDE_A)).thenReturn(10); + when(validity.getMaximumRelationsAllowed(Default_Hierarchical__Child, artifactType2, SIDE_B)).thenReturn(10); + manager.addChild(session, node1, node2); verify(container1).getRelation(node1, DEFAULT_HIERARCHY, node2, INCLUDE_DELETED); @@ -661,6 +677,11 @@ public class RelationManagerImplTest { when(orderFactory.createOrderManager(node1)).thenReturn(orderManager1); when(orderManager1.getSorterId(Default_Hierarchical__Child)).thenReturn(UNORDERED); + when(node1.getArtifactType()).thenReturn(artifactType1); + when(node2.getArtifactType()).thenReturn(artifactType2); + when(validity.getMaximumRelationsAllowed(Default_Hierarchical__Child, artifactType1, SIDE_A)).thenReturn(10); + when(validity.getMaximumRelationsAllowed(Default_Hierarchical__Child, artifactType2, SIDE_B)).thenReturn(10); + List<? extends RelationNode> children = Arrays.asList(node2); manager.addChildren(session, node1, children); @@ -686,6 +707,11 @@ public class RelationManagerImplTest { when(orderFactory.createOrderManager(node1)).thenReturn(orderManager1); when(orderManager1.getSorterId(Default_Hierarchical__Child)).thenReturn(UNORDERED); + when(node1.getArtifactType()).thenReturn(artifactType1); + when(node2.getArtifactType()).thenReturn(artifactType2); + when(validity.getMaximumRelationsAllowed(Default_Hierarchical__Child, artifactType1, SIDE_A)).thenReturn(10); + when(validity.getMaximumRelationsAllowed(Default_Hierarchical__Child, artifactType2, SIDE_B)).thenReturn(10); + manager.addChild(session, node1, node2); verify(orderManager1).getSorterId(Default_Hierarchical__Child); 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 index 4f5732a1750..c673fb10eba 100644 --- 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 @@ -41,6 +41,7 @@ import org.eclipse.osee.framework.core.enums.RelationOrderBaseTypes; import org.eclipse.osee.framework.core.enums.RelationSide; import org.eclipse.osee.framework.jdk.core.type.Identifiable; import org.eclipse.osee.framework.jdk.core.type.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.type.OseeStateException; import org.eclipse.osee.framework.jdk.core.type.ResultSet; import org.eclipse.osee.framework.jdk.core.type.ResultSets; import org.eclipse.osee.framework.jdk.core.util.Conditions; @@ -231,8 +232,7 @@ public class RelationManagerImpl implements RelationManager { validity.checkRelationTypeValid(type, bNode, SIDE_B); // Check we can create the type on other side of each node - checkMultiplicityCanAdd(session, type, aNode, SIDE_B); - checkMultiplicityCanAdd(session, type, bNode, SIDE_A); + checkMultiplicityCanAdd(session, type, aNode, bNode); Relation relation = getRelation(session, aNode, type, bNode, INCLUDE_DELETED).getOneOrNull(); boolean updated = false; @@ -257,9 +257,22 @@ public class RelationManagerImpl implements RelationManager { return aNode.getGraph().getTransaction() > bNode.getGraph().getTransaction() ? aNode.getGraph() : bNode.getGraph(); } - private void checkMultiplicityCanAdd(OrcsSession session, IRelationType type, RelationNode node, RelationSide side) throws OseeCoreException { - int currentCount = getRelatedCount(session, type, node, side); - validity.checkRelationTypeMultiplicity(type, node, side, currentCount + 1); + private void checkMultiplicityCanAdd(OrcsSession session, IRelationType type, RelationNode aNode, RelationNode bNode) { + int bSideCount = getRelations(session, type, aNode, SIDE_A, EXCLUDE_DELETED).size(); + int bSideMax = validity.getMaximumRelationsAllowed(type, bNode.getArtifactType(), SIDE_B); + + if (bSideCount >= bSideMax) { + throw new OseeStateException("Relation type [%s] on [%s] exceeds max occurrence rule on [%s]", type.getName(), + SIDE_B, aNode.getExceptionString()); + } + + int aSideCount = getRelations(session, type, bNode, SIDE_B, EXCLUDE_DELETED).size(); + int aSideMax = validity.getMaximumRelationsAllowed(type, aNode.getArtifactType(), SIDE_A); + + if (aSideCount >= aSideMax) { + throw new OseeStateException("Relation type [%s] on [%s] exceeds max occurrence rule on [%s]", type.getName(), + SIDE_A, bNode.getExceptionString()); + } } ///////////////////////// UNRELATE NODES /////////////////// @@ -490,7 +503,7 @@ public class RelationManagerImpl implements RelationManager { int artIdA = rel.getOrcsData().getArtIdA(); int artIdB = rel.getOrcsData().getArtIdB(); int checkArtId = destination.getLocalId() == artIdA ? artIdB : artIdA; - // need to check if artifact to relate to exists + // need to check if artifact to relate to exists ArtifactReadable readable = provider.getQueryFactory(session).fromBranch(branch).andUuid(checkArtId).getResults().getOneOrNull(); return readable; diff --git a/plugins/org.eclipse.osee.orcs.test/src/org/eclipse/osee/orcs/api/OrcsTransactionTest.java b/plugins/org.eclipse.osee.orcs.test/src/org/eclipse/osee/orcs/api/OrcsTransactionTest.java index e94d2b8b11e..75326178a9e 100644 --- a/plugins/org.eclipse.osee.orcs.test/src/org/eclipse/osee/orcs/api/OrcsTransactionTest.java +++ b/plugins/org.eclipse.osee.orcs.test/src/org/eclipse/osee/orcs/api/OrcsTransactionTest.java @@ -41,6 +41,7 @@ import org.eclipse.osee.framework.core.enums.SystemUser; import org.eclipse.osee.framework.core.enums.TransactionDetailsType; import org.eclipse.osee.framework.jdk.core.type.OseeArgumentException; import org.eclipse.osee.framework.jdk.core.type.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.type.OseeStateException; import org.eclipse.osee.framework.jdk.core.type.ResultSet; import org.eclipse.osee.framework.jdk.core.util.Lib; import org.eclipse.osee.orcs.OrcsApi; @@ -1075,6 +1076,24 @@ public class OrcsTransactionTest { assertEquals(expectedComment, actual.getComment()); } + @Test(expected = OseeStateException.class) + public void testAttributeMultiplicity() { + TransactionBuilder tx = createTx(); + ArtifactId art1 = tx.createArtifact(CoreArtifactTypes.SoftwareRequirement, "SwReq"); + tx.createAttribute(art1, CoreAttributeTypes.ParagraphNumber, "1.1"); + tx.createAttribute(art1, CoreAttributeTypes.ParagraphNumber, "2.2"); + } + + @Test(expected = OseeStateException.class) + public void testRelationMultiplicity() { + TransactionBuilder tx = createTx(); + ArtifactId child = tx.createArtifact(CoreArtifactTypes.SoftwareRequirement, "Child"); + ArtifactId parent1 = tx.createArtifact(CoreArtifactTypes.SoftwareRequirement, "Parent1"); + ArtifactId parent2 = tx.createArtifact(CoreArtifactTypes.SoftwareRequirement, "Parent2"); + tx.relate(parent1, Default_Hierarchical__Parent, child); + tx.relate(parent2, Default_Hierarchical__Parent, child); + } + private TransactionBuilder createTx() throws OseeCoreException { return txFactory.createTransaction(COMMON, userArtifact, testName.getMethodName()); } |