Skip to content
This repository was archived by the owner on Mar 28, 2026. It is now read-only.

Commit bac064e

Browse files
Adds support for "deployment groups", providing a way to scope how software system/container instance relationships are replicated when added to deployment nodes.
1 parent 8d57131 commit bac064e

9 files changed

Lines changed: 102 additions & 47 deletions

File tree

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ subprojects { proj ->
1414

1515
description = 'Structurizr'
1616
group = 'com.structurizr'
17-
version = '1.8.1'
17+
version = '1.9.0'
1818

1919
repositories {
2020
mavenCentral()

docs/changelog.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# Changelog
22

3-
## 1.8.1 (unreleased)
3+
## 1.9.0 (unreleased)
44

55
- Adds support for adding individual infrastructure nodes, software system instances, and container instances to a deployment view.
66
- Adds support for removing software system instances from deployment views.
77
- Improved support for themes (e.g. when exporting to PlantUML), which now works the same as described at [Structurizr - Themes](https://structurizr.com/help/themes).
8+
- Adds support for "deployment groups", providing a way to scope how software system/container instance relationships are replicated when added to deployment nodes. __breaking change__
89

910
## 1.8.0 (20th February 2021)
1011

structurizr-core/src/com/structurizr/model/ContainerInstance.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ public final class ContainerInstance extends StaticStructureElementInstance {
1313
ContainerInstance() {
1414
}
1515

16-
ContainerInstance(Container container, int instanceId, String environment) {
17-
super(instanceId, environment);
16+
ContainerInstance(Container container, int instanceId, String environment, String deploymentGroup) {
17+
super(instanceId, environment, deploymentGroup);
1818

1919
setContainer(container);
2020
addTags(Tags.CONTAINER_INSTANCE);

structurizr-core/src/com/structurizr/model/DeploymentElement.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
public abstract class DeploymentElement extends Element {
99

1010
public static final String DEFAULT_DEPLOYMENT_ENVIRONMENT = "Default";
11+
public static final String DEFAULT_DEPLOYMENT_GROUP = "Default";
1112

1213
private DeploymentNode parent;
1314
private String environment = DEFAULT_DEPLOYMENT_ENVIRONMENT;

structurizr-core/src/com/structurizr/model/DeploymentNode.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ public final class DeploymentNode extends DeploymentElement {
3636
* @return a SoftwareSystemInstance object
3737
*/
3838
public SoftwareSystemInstance add(SoftwareSystem softwareSystem) {
39-
return add(softwareSystem, true);
39+
return add(softwareSystem, DEFAULT_DEPLOYMENT_GROUP);
4040
}
4141

4242
/**
43-
* Adds a software system instance to this deployment node, optionally replicating relationships.
43+
* Adds a software system instance to this deployment node, replicating relationships.
4444
*
45-
* @param softwareSystem the SoftwareSystem to add an instance of
46-
* @param replicateRelationships true if relationships should be replicated between the element instances in the same deployment environment, false otherwise
45+
* @param softwareSystem the SoftwareSystem to add an instance of
46+
* @param deploymentGroup the deployment group
4747
* @return a SoftwareSystemInstance object
4848
*/
49-
public SoftwareSystemInstance add(SoftwareSystem softwareSystem, boolean replicateRelationships) {
50-
SoftwareSystemInstance softwareSystemInstance = getModel().addSoftwareSystemInstance(this, softwareSystem, replicateRelationships);
49+
public SoftwareSystemInstance add(SoftwareSystem softwareSystem, String deploymentGroup) {
50+
SoftwareSystemInstance softwareSystemInstance = getModel().addSoftwareSystemInstance(this, softwareSystem, deploymentGroup);
5151
this.softwareSystemInstances.add(softwareSystemInstance);
5252

5353
return softwareSystemInstance;
@@ -60,18 +60,18 @@ public SoftwareSystemInstance add(SoftwareSystem softwareSystem, boolean replica
6060
* @return a ContainerInstance object
6161
*/
6262
public ContainerInstance add(Container container) {
63-
return add(container, true);
63+
return add(container, DEFAULT_DEPLOYMENT_GROUP);
6464
}
6565

6666
/**
6767
* Adds a container instance to this deployment node, optionally replicating relationships.
6868
*
6969
* @param container the Container to add an instance of
70-
* @param replicateRelationships true if relationships should be replicated between the element instances in the same deployment environment, false otherwise
70+
* @param deploymentGroup the deployment group
7171
* @return a ContainerInstance object
7272
*/
73-
public ContainerInstance add(Container container, boolean replicateRelationships) {
74-
ContainerInstance containerInstance = getModel().addContainerInstance(this, container, replicateRelationships);
73+
public ContainerInstance add(Container container, String deploymentGroup) {
74+
ContainerInstance containerInstance = getModel().addContainerInstance(this, container, deploymentGroup);
7575
this.containerInstances.add(containerInstance);
7676

7777
return containerInstance;

structurizr-core/src/com/structurizr/model/Model.java

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -982,56 +982,54 @@ public DeploymentNode getDeploymentNodeWithName(String name, String environment)
982982
return null;
983983
}
984984

985-
SoftwareSystemInstance addSoftwareSystemInstance(DeploymentNode deploymentNode, SoftwareSystem softwareSystem, boolean replicateRelationships) {
985+
SoftwareSystemInstance addSoftwareSystemInstance(DeploymentNode deploymentNode, SoftwareSystem softwareSystem, String deploymentGroup) {
986986
if (softwareSystem == null) {
987987
throw new IllegalArgumentException("A software system must be specified.");
988988
}
989989

990990
long instanceNumber = deploymentNode.getSoftwareSystemInstances().stream().filter(ssi -> ssi.getSoftwareSystem().equals(softwareSystem)).count();
991991
instanceNumber++;
992-
SoftwareSystemInstance softwareSystemInstance = new SoftwareSystemInstance(softwareSystem, (int)instanceNumber, deploymentNode.getEnvironment());
992+
SoftwareSystemInstance softwareSystemInstance = new SoftwareSystemInstance(softwareSystem, (int)instanceNumber, deploymentNode.getEnvironment(), deploymentGroup);
993993
softwareSystemInstance.setParent(deploymentNode);
994994
softwareSystemInstance.setId(idGenerator.generateId(softwareSystemInstance));
995995

996-
if (replicateRelationships) {
997-
replicateElementRelationships(deploymentNode.getEnvironment(), softwareSystemInstance);
998-
}
996+
replicateElementRelationships(softwareSystemInstance);
999997

1000998
addElementToInternalStructures(softwareSystemInstance);
1001999

10021000
return softwareSystemInstance;
10031001
}
10041002

1005-
ContainerInstance addContainerInstance(DeploymentNode deploymentNode, Container container, boolean replicateRelationships) {
1003+
ContainerInstance addContainerInstance(DeploymentNode deploymentNode, Container container, String deploymentGroup) {
10061004
if (container == null) {
10071005
throw new IllegalArgumentException("A container must be specified.");
10081006
}
10091007

10101008
long instanceNumber = deploymentNode.getContainerInstances().stream().filter(ci -> ci.getContainer().equals(container)).count();
10111009
instanceNumber++;
1012-
ContainerInstance containerInstance = new ContainerInstance(container, (int)instanceNumber, deploymentNode.getEnvironment());
1010+
ContainerInstance containerInstance = new ContainerInstance(container, (int)instanceNumber, deploymentNode.getEnvironment(), deploymentGroup);
10131011
containerInstance.setParent(deploymentNode);
10141012
containerInstance.setId(idGenerator.generateId(containerInstance));
10151013

1016-
if (replicateRelationships) {
1017-
replicateElementRelationships(deploymentNode.getEnvironment(), containerInstance);
1018-
}
1014+
replicateElementRelationships(containerInstance);
10191015

10201016
addElementToInternalStructures(containerInstance);
10211017

10221018
return containerInstance;
10231019
}
10241020

1025-
private void replicateElementRelationships(String deploymentEnvironment, StaticStructureElementInstance elementInstance) {
1021+
private void replicateElementRelationships(StaticStructureElementInstance elementInstance) {
10261022
StaticStructureElement element = elementInstance.getElement();
10271023

1028-
// find all StaticStructureElementInstance objects in the same deployment environment
1024+
// find all StaticStructureElementInstance objects in the same deployment environment and deployment group
10291025
Set<StaticStructureElementInstance> elementInstances = getElements().stream()
1030-
.filter(e -> e instanceof StaticStructureElementInstance && ((StaticStructureElementInstance)e).getEnvironment().equals(deploymentEnvironment))
1026+
.filter(e -> e instanceof StaticStructureElementInstance)
10311027
.map(e -> (StaticStructureElementInstance)e)
1028+
.filter(ssei -> ssei.getEnvironment().equals(elementInstance.getEnvironment()))
1029+
.filter(ssei -> ssei.getDeploymentGroup().equals(elementInstance.getDeploymentGroup()))
10321030
.collect(Collectors.toSet());
10331031

1034-
// and replicate the relationships within the same deployment environment
1032+
// and replicate the relationships to/from the element instance
10351033
for (StaticStructureElementInstance ssei : elementInstances) {
10361034
StaticStructureElement sse = ssei.getElement();
10371035

structurizr-core/src/com/structurizr/model/SoftwareSystemInstance.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ public final class SoftwareSystemInstance extends StaticStructureElementInstance
1313
SoftwareSystemInstance() {
1414
}
1515

16-
SoftwareSystemInstance(SoftwareSystem softwareSystem, int instanceId, String environment) {
17-
super(instanceId, environment);
16+
SoftwareSystemInstance(SoftwareSystem softwareSystem, int instanceId, String environment, String deploymentGroup) {
17+
super(instanceId, environment, deploymentGroup);
1818

1919
setSoftwareSystem(softwareSystem);
2020
addTags(Tags.SOFTWARE_SYSTEM_INSTANCE);

structurizr-core/src/com/structurizr/model/StaticStructureElementInstance.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,37 @@ public abstract class StaticStructureElementInstance extends DeploymentElement {
1616
private static final int DEFAULT_HEALTH_CHECK_INTERVAL_IN_SECONDS = 60;
1717
private static final long DEFAULT_HEALTH_CHECK_TIMEOUT_IN_MILLISECONDS = 0;
1818

19+
private String deploymentGroup = DEFAULT_DEPLOYMENT_GROUP;
1920
private int instanceId;
2021
private Set<HttpHealthCheck> healthChecks = new HashSet<>();
2122

2223
StaticStructureElementInstance() {
2324
}
2425

25-
StaticStructureElementInstance(int instanceId, String environment) {
26+
StaticStructureElementInstance(int instanceId, String environment, String deploymentGroup) {
2627
setInstanceId(instanceId);
2728
setEnvironment(environment);
29+
setDeploymentGroup(deploymentGroup);
2830
}
2931

3032
@JsonIgnore
3133
public abstract StaticStructureElement getElement();
3234

3335
/**
34-
* Gets the instance ID of this container.
36+
* Gets the deployment group of this element instance.
37+
*
38+
* @return a deployment group name
39+
*/
40+
public String getDeploymentGroup() {
41+
return deploymentGroup;
42+
}
43+
44+
void setDeploymentGroup(String deploymentGroup) {
45+
this.deploymentGroup = deploymentGroup;
46+
}
47+
48+
/**
49+
* Gets the instance ID of this element instance.
3550
*
3651
* @return the instance ID, an integer greater than zero
3752
*/

structurizr-core/test/unit/com/structurizr/model/ModelTests.java

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -686,26 +686,66 @@ public void test_addElementInstance_AddsElementInstancesAndReplicatesRelationshi
686686
}
687687

688688
@Test
689-
public void test_addContainerInstance_AddsAContainerInstanceAndDoesNotReplicateRelationships() {
690-
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System 1", "Description");
691-
Container container1 = softwareSystem1.addContainer("Container 1", "Description", "Technology");
689+
public void test_addElementInstance_AddsElementInstancesAndReplicatesRelationshipsWithinTheDeploymentEnvironmentAndDefaultGroup() {
690+
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System");
691+
Container api = softwareSystem1.addContainer("API");
692+
Container database = softwareSystem1.addContainer("Database");
693+
api.uses(database, "Uses");
692694

693-
SoftwareSystem softwareSystem2 = model.addSoftwareSystem("Software System 2", "Description");
694-
Container container2 = softwareSystem2.addContainer("Container 2", "Description", "Technology");
695+
DeploymentNode liveDeploymentNode = model.addDeploymentNode("Live", "Deployment Node", "Description", "Technology");
696+
ContainerInstance apiInstance1 = liveDeploymentNode.add(api);
697+
ContainerInstance databaseInstance1 = liveDeploymentNode.add(database);
695698

696-
SoftwareSystem softwareSystem3 = model.addSoftwareSystem("Software System 3", "Description");
697-
Container container3 = softwareSystem3.addContainer("Container 3", "Description", "Technology");
699+
ContainerInstance apiInstance2 = liveDeploymentNode.add(api);
700+
ContainerInstance databaseInstance2 = liveDeploymentNode.add(database);
698701

699-
container1.uses(container2, "Uses 1", "Technology 1", InteractionStyle.Synchronous);
700-
container2.uses(container3, "Uses 2", "Technology 2", InteractionStyle.Asynchronous);
702+
assertEquals(2, apiInstance1.getRelationships().size());
703+
assertEquals(2, apiInstance2.getRelationships().size());
701704

702-
DeploymentNode deploymentNode = model.addDeploymentNode("Deployment Node", "Description", "Technology");
703-
ContainerInstance containerInstance1 = deploymentNode.add(container1, false);
704-
ContainerInstance containerInstance2 = deploymentNode.add(container2, false);
705-
ContainerInstance containerInstance3 = deploymentNode.add(container3, false);
705+
// apiInstance1 -> databaseInstance1
706+
Relationship relationship = apiInstance1.getEfferentRelationshipWith(databaseInstance1);
707+
assertEquals("Uses", relationship.getDescription());
708+
709+
// apiInstance1 -> databaseInstance2
710+
relationship = apiInstance1.getEfferentRelationshipWith(databaseInstance2);
711+
assertEquals("Uses", relationship.getDescription());
712+
713+
// apiInstance2 -> databaseInstance1
714+
relationship = apiInstance2.getEfferentRelationshipWith(databaseInstance1);
715+
assertEquals("Uses", relationship.getDescription());
716+
717+
// apiInstance2 -> databaseInstance2
718+
relationship = apiInstance2.getEfferentRelationshipWith(databaseInstance2);
719+
assertEquals("Uses", relationship.getDescription());
720+
}
721+
722+
@Test
723+
public void test_addElementInstance_AddsElementInstancesAndReplicatesRelationshipsWithinTheDeploymentEnvironmentAndSpecifiedGroup() {
724+
// in this test, container instances are added to two deployment groups: "Service 1" and "Service 2"
725+
// relationships are not replicated between element instances in other groups
726+
727+
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System");
728+
Container api = softwareSystem1.addContainer("API");
729+
Container database = softwareSystem1.addContainer("Database");
730+
api.uses(database, "Uses");
706731

707-
assertEquals(0, containerInstance1.getRelationships().size());
708-
assertEquals(0, containerInstance2.getRelationships().size());
732+
DeploymentNode liveDeploymentNode = model.addDeploymentNode("Live", "Deployment Node", "Description", "Technology");
733+
ContainerInstance apiInstance1 = liveDeploymentNode.add(api, "Service 1");
734+
ContainerInstance databaseInstance1 = liveDeploymentNode.add(database, "Service 1");
735+
736+
ContainerInstance apiInstance2 = liveDeploymentNode.add(api, "Service 2");
737+
ContainerInstance databaseInstance2 = liveDeploymentNode.add(database, "Service 2");
738+
739+
assertEquals(1, apiInstance1.getRelationships().size());
740+
assertEquals(1, apiInstance2.getRelationships().size());
741+
742+
// apiInstance1 -> databaseInstance1
743+
Relationship relationship = apiInstance1.getEfferentRelationshipWith(databaseInstance1);
744+
assertEquals("Uses", relationship.getDescription());
745+
746+
// apiInstance2 -> databaseInstance2
747+
relationship = apiInstance2.getEfferentRelationshipWith(databaseInstance2);
748+
assertEquals("Uses", relationship.getDescription());
709749
}
710750

711751
@Test

0 commit comments

Comments
 (0)