diff --git a/changelog.md b/changelog.md index 96cdedfe..2975057d 100644 --- a/changelog.md +++ b/changelog.md @@ -12,6 +12,7 @@ - structurizr-dsl: Adds a way to configure whether the DSL source is retained via a workspace property named `structurizr.dsl.source` - `true` (default) or `false`. - structurizr-dsl: Adds the ability to define a PlantUML/Mermaid image view that is an export of a workspace view. - structurizr-dsl: Adds support for `url`, `properties`, and `perspectives` nested inside `!elements` and `!relationships`. +- structurizr-dsl: Fixes https://github.com/structurizr/java/issues/347 (`->container->` expression does not work as expected in deployment view). ## 3.0.0 (19th September 2024) diff --git a/structurizr-dsl/src/main/java/com/structurizr/dsl/DeploymentViewExpressionParser.java b/structurizr-dsl/src/main/java/com/structurizr/dsl/DeploymentViewExpressionParser.java index 33e9a5b3..ea6266d8 100644 --- a/structurizr-dsl/src/main/java/com/structurizr/dsl/DeploymentViewExpressionParser.java +++ b/structurizr-dsl/src/main/java/com/structurizr/dsl/DeploymentViewExpressionParser.java @@ -4,6 +4,7 @@ import java.util.LinkedHashSet; import java.util.Set; +import java.util.stream.Collectors; import static com.structurizr.dsl.StructurizrDslExpressions.ELEMENT_TYPE_EQUALS_EXPRESSION; @@ -43,6 +44,24 @@ protected Set evaluateElementTypeExpression(String expr, DslContext con return elements; } + @Override + protected Set getElements(String identifier, DslContext context) { + Set elements = new LinkedHashSet<>(); + for (Element element : super.getElements(identifier, context)) { + if (element instanceof SoftwareSystem) { + Set elementInstances = context.getWorkspace().getModel().getElements().stream().filter(e -> e instanceof SoftwareSystemInstance).map(e -> (SoftwareSystemInstance) e).filter(ssi -> ssi.getSoftwareSystem().equals(element)).collect(Collectors.toSet()); + elements.addAll(elementInstances); + } else if (element instanceof Container) { + Set elementInstances = context.getWorkspace().getModel().getElements().stream().filter(e -> e instanceof ContainerInstance).map(e -> (ContainerInstance)e).filter(ci -> ci.getContainer().equals(element)).collect(Collectors.toSet()); + elements.addAll(elementInstances); + } else { + elements.add(element); + } + } + + return elements; + } + protected Set findAfferentCouplings(Element element) { Set elements = new LinkedHashSet<>(); diff --git a/structurizr-dsl/src/main/java/com/structurizr/dsl/ExpressionParser.java b/structurizr-dsl/src/main/java/com/structurizr/dsl/ExpressionParser.java index 9599c79f..8ee65bbc 100644 --- a/structurizr-dsl/src/main/java/com/structurizr/dsl/ExpressionParser.java +++ b/structurizr-dsl/src/main/java/com/structurizr/dsl/ExpressionParser.java @@ -419,7 +419,7 @@ protected Set parseIdentifier(String identifier, DslContext context) } } - private Set getElements(String identifier, DslContext context) { + protected Set getElements(String identifier, DslContext context) { Set elements = new HashSet<>(); Element element = context.getElement(identifier); diff --git a/structurizr-dsl/src/test/java/com/structurizr/dsl/DeploymentViewExpressionParserTests.java b/structurizr-dsl/src/test/java/com/structurizr/dsl/DeploymentViewExpressionParserTests.java index bf4a417a..95eef0d0 100644 --- a/structurizr-dsl/src/test/java/com/structurizr/dsl/DeploymentViewExpressionParserTests.java +++ b/structurizr-dsl/src/test/java/com/structurizr/dsl/DeploymentViewExpressionParserTests.java @@ -217,4 +217,57 @@ void test_parseExpression_ReturnsElements_WhenBooleanOrUsed() { assertTrue(elements.contains(containerInstance)); } + @Test + void test_parseExpression_ReturnsSoftwareSystemInstanceDependencies_WhenASoftwareSystemExpressionIsUsed() { + SoftwareSystem a = model.addSoftwareSystem("A"); + SoftwareSystem b = model.addSoftwareSystem("B"); + a.uses(b, ""); + + DeploymentNode deploymentNode = model.addDeploymentNode("Live", "Deployment Node", "Description", "Technology"); + InfrastructureNode infrastructureNode = deploymentNode.addInfrastructureNode("Infrastructure Node"); + SoftwareSystemInstance softwareSystemInstanceA = deploymentNode.add(a); + SoftwareSystemInstance softwareSystemInstanceB = deploymentNode.add(b); + infrastructureNode.uses(softwareSystemInstanceA, "", ""); + + DeploymentViewDslContext context = new DeploymentViewDslContext(null); + context.setWorkspace(workspace); + + IdentifiersRegister identifiersRegister = new IdentifiersRegister(); + identifiersRegister.register("a", a); + context.setIdentifierRegister(identifiersRegister); + + Set elements = parser.parseExpression("->a->", context); + assertEquals(3, elements.size()); + assertTrue(elements.contains(infrastructureNode)); + assertTrue(elements.contains(softwareSystemInstanceA)); + assertTrue(elements.contains(softwareSystemInstanceB)); + } + + @Test + void test_parseExpression_ReturnsContainerInstanceDependencies_WhenAContainerExpressionIsUsed() { + SoftwareSystem softwareSystem = model.addSoftwareSystem("Software System"); + Container container1 = softwareSystem.addContainer("Container 1"); + Container container2 = softwareSystem.addContainer("Container 2"); + container1.uses(container2, ""); + + DeploymentNode deploymentNode = model.addDeploymentNode("Live", "Deployment Node", "Description", "Technology"); + InfrastructureNode infrastructureNode = deploymentNode.addInfrastructureNode("Infrastructure Node"); + ContainerInstance containerInstance1 = deploymentNode.add(container1); + ContainerInstance containerInstance2 = deploymentNode.add(container2); + infrastructureNode.uses(containerInstance1, "", ""); + + DeploymentViewDslContext context = new DeploymentViewDslContext(null); + context.setWorkspace(workspace); + + IdentifiersRegister identifiersRegister = new IdentifiersRegister(); + identifiersRegister.register("c1", container1); + context.setIdentifierRegister(identifiersRegister); + + Set elements = parser.parseExpression("->c1->", context); + assertEquals(3, elements.size()); + assertTrue(elements.contains(infrastructureNode)); + assertTrue(elements.contains(containerInstance1)); + assertTrue(elements.contains(containerInstance2)); + } + } \ No newline at end of file