Skip to content

Commit

Permalink
Closes #336.
Browse files Browse the repository at this point in the history
  • Loading branch information
simonbrowndotje committed Sep 19, 2024
1 parent 12ddd83 commit 24c5cf6
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 17 deletions.
26 changes: 24 additions & 2 deletions structurizr-core/src/main/java/com/structurizr/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.structurizr.PropertyHolder;
import com.structurizr.WorkspaceValidationException;
import com.structurizr.util.StringUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -937,12 +938,12 @@ private void replicateElementRelationships(StaticStructureElementInstance elemen
/**
* Gets the element with the specified canonical name.
*
* @param canonicalName the canonical name (e.g. /SoftwareSystem/Container)
* @param canonicalName the canonical name
* @return the Element with the given canonical name, or null if one doesn't exist
* @throws IllegalArgumentException if the canonical name is null or empty
*/
public Element getElementWithCanonicalName(String canonicalName) {
if (canonicalName == null || canonicalName.trim().length() == 0) {
if (StringUtils.isNullOrEmpty(canonicalName)) {
throw new IllegalArgumentException("A canonical name must be specified.");
}

Expand All @@ -955,6 +956,27 @@ public Element getElementWithCanonicalName(String canonicalName) {
return null;
}

/**
* Gets the relationship with the specified canonical name.
*
* @param canonicalName the canonical name
* @return the Relationship with the given canonical name, or null if one doesn't exist
* @throws IllegalArgumentException if the canonical name is null or empty
*/
public Relationship getRelationshipWithCanonicalName(String canonicalName) {
if (StringUtils.isNullOrEmpty(canonicalName)) {
throw new IllegalArgumentException("A canonical name must be specified.");
}

for (Relationship relationship : getRelationships()) {
if (relationship.getCanonicalName().equals(canonicalName)) {
return relationship;
}
}

return null;
}

/**
* Sets the ID generator associated with this model.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,16 +583,48 @@ void getElementWithCanonicalName_ThrowsAnException_WhenAnEmptyCanonicalNameIsSpe

@Test
void getElementWithCanonicalName_ReturnsNull_WhenAnElementWithTheSpecifiedCanonicalNameDoesNotExist() {
assertNull(model.getElementWithCanonicalName("Software System"));
assertNull(model.getElementWithCanonicalName("SoftwareSystem://A"));
}

@Test
void getElementWithCanonicalName_ReturnsTheElement_WhenAnElementWithTheSpecifiedCanonicalNameExists() {
SoftwareSystem softwareSystem = model.addSoftwareSystem("Software System", "Description");
Container container = softwareSystem.addContainer("Web Application", "Description", "Technology");
SoftwareSystem a = model.addSoftwareSystem("A");
Container b = a.addContainer("B");

assertSame(softwareSystem, model.getElementWithCanonicalName("SoftwareSystem://Software System"));
assertSame(container, model.getElementWithCanonicalName("Container://Software System.Web Application"));
assertSame(a, model.getElementWithCanonicalName("SoftwareSystem://A"));
assertSame(b, model.getElementWithCanonicalName("Container://A.B"));
}

@Test
void getRelationshipWithCanonicalName_ThrowsAnException_WhenANullCanonicalNameIsSpecified() {
try {
model.getRelationshipWithCanonicalName(null);
} catch (IllegalArgumentException iae) {
assertEquals("A canonical name must be specified.", iae.getMessage());
}
}

@Test
void getRelationshipWithCanonicalName_ThrowsAnException_WhenAnEmptyCanonicalNameIsSpecified() {
try {
model.getRelationshipWithCanonicalName(" ");
} catch (IllegalArgumentException iae) {
assertEquals("A canonical name must be specified.", iae.getMessage());
}
}

@Test
void getRelationshipWithCanonicalName_ReturnsNull_WhenARelationshipWithTheSpecifiedCanonicalNameDoesNotExist() {
assertNull(model.getRelationshipWithCanonicalName("Relationship://SoftwareSystem://A -> SoftwareSystem://B (Uses)"));
}

@Test
void getRelationshipWithCanonicalName_ReturnsTheRelationship_WhenARelationshipWithTheSpecifiedCanonicalNameExists() {
SoftwareSystem a = model.addSoftwareSystem("A");
SoftwareSystem b = model.addSoftwareSystem("B");
Relationship r = a.uses(b, "Uses");

assertSame(r, model.getRelationshipWithCanonicalName("Relationship://SoftwareSystem://A -> SoftwareSystem://B (Uses)"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ Element parse(DslContext context, Tokens tokens) {
throw new RuntimeException("Expected: " + GRAMMAR);
}

String s = tokens.get(IDENTIFIER_INDEX);

Element element;

String s = tokens.get(IDENTIFIER_INDEX);
if (s.contains("://")) {
element = context.getWorkspace().getModel().getElementWithCanonicalName(s);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.structurizr.dsl;

import com.structurizr.model.Element;
import com.structurizr.model.Relationship;

final class FindRelationshipParser extends AbstractParser {

private static final String GRAMMAR = "!relationship <identifier>";
private static final String GRAMMAR = "!relationship <identifier|canonical name>";

private final static int IDENTIFIER_INDEX = 1;

Expand All @@ -19,9 +20,14 @@ Relationship parse(DslContext context, Tokens tokens) {
throw new RuntimeException("Expected: " + GRAMMAR);
}

String s = tokens.get(IDENTIFIER_INDEX);
Relationship relationship;

Relationship relationship = context.getRelationship(s);
String s = tokens.get(IDENTIFIER_INDEX);
if (s.startsWith("Relationship://")) {
relationship = context.getWorkspace().getModel().getRelationshipWithCanonicalName(s);
} else {
relationship = context.getRelationship(s);
}

if (relationship == null) {
throw new RuntimeException("A relationship identified by \"" + s + "\" could not be found");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.structurizr.model.ModelItem;
import com.structurizr.model.Person;
import com.structurizr.model.Relationship;
import com.structurizr.model.SoftwareSystem;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;
Expand All @@ -17,17 +18,17 @@ void test_parse_ThrowsAnException_WhenThereAreTooManyTokens() {
parser.parse(context(), tokens("!relationship", "name", "tokens"));
fail();
} catch (Exception e) {
assertEquals("Too many tokens, expected: !relationship <identifier>", e.getMessage());
assertEquals("Too many tokens, expected: !relationship <identifier|canonical name>", e.getMessage());
}
}

@Test
void test_parse_ThrowsAnException_WhenTheIdentifierIsNotSpecified() {
void test_parse_ThrowsAnException_WhenTheIdentifierOrCanonicalNameIsNotSpecified() {
try {
parser.parse(context(), tokens("!relationship"));
fail();
} catch (Exception e) {
assertEquals("Expected: !relationship <identifier>", e.getMessage());
assertEquals("Expected: !relationship <identifier|canonical name>", e.getMessage());
}
}

Expand All @@ -41,10 +42,23 @@ void test_parse_ThrowsAnException_WhenTheReferencedRelationshipCannotBeFound() {
}
}

@Test
void test_parse_FindsARelationshipByCanonicalName() {
SoftwareSystem a = model.addSoftwareSystem("A");
SoftwareSystem b = model.addSoftwareSystem("B");
Relationship relationship = a.uses(b, "Description");

ModelDslContext context = context();

ModelItem modelItem = parser.parse(context, tokens("!relationship", "Relationship://SoftwareSystem://A -> SoftwareSystem://B (Description)"));
assertSame(modelItem, relationship);
}

@Test
void test_parse_FindsARelationshipByIdentifier() {
Person user = workspace.getModel().addPerson("User");
Relationship relationship = user.interactsWith(user, "Description");
SoftwareSystem a = model.addSoftwareSystem("A");
SoftwareSystem b = model.addSoftwareSystem("B");
Relationship relationship = a.uses(b, "Description");

ModelDslContext context = context();
IdentifiersRegister register = new IdentifiersRegister();
Expand Down

0 comments on commit 24c5cf6

Please sign in to comment.