diff --git a/Structurizr.ActiveDirectory/Structurizr.ActiveDirectory.csproj b/Structurizr.ActiveDirectory/Structurizr.ActiveDirectory.csproj
index 1d7b98d..581ff58 100644
--- a/Structurizr.ActiveDirectory/Structurizr.ActiveDirectory.csproj
+++ b/Structurizr.ActiveDirectory/Structurizr.ActiveDirectory.csproj
@@ -8,12 +8,12 @@
Exe
- netcoreapp1.1
+ netcoreapp2.1
-
+
\ No newline at end of file
diff --git a/Structurizr.AdrTools.Tests/AdrTools/AdrToolsImporterTests.cs b/Structurizr.AdrTools.Tests/AdrTools/AdrToolsImporterTests.cs
index b0122bf..f3849c7 100644
--- a/Structurizr.AdrTools.Tests/AdrTools/AdrToolsImporterTests.cs
+++ b/Structurizr.AdrTools.Tests/AdrTools/AdrToolsImporterTests.cs
@@ -106,7 +106,8 @@ public void Test_ImportArchitectureDecisionRecords_RewritesLinksBetweenADRsWhenT
importer.ImportArchitectureDecisionRecords();
Decision decision5 = _documentation.Decisions.Where(d => d.Id == "5").First();
- Assert.True(decision5.Content.Contains("Amended by [9. Help scripts](#/:9)"));
+ // sync with java impl %2F instead of /
+ Assert.True(decision5.Content.Contains("Amended by [9. Help scripts](#%2F:9)"));
}
[Fact]
@@ -127,7 +128,8 @@ public void Test_ImportArchitectureDecisionRecords_SupportsTheIncorrectSpellingO
Decision decision4 = _documentation.Decisions.Where(d => d.Id == "4").First();
Assert.Equal(DecisionStatus.Superseded, decision4.Status);
- Assert.True(decision4.Content.Contains("Superceded by [10. AsciiDoc format](#/:10)"));
+ // sync with java impl %2F instead of /
+ Assert.True(decision4.Content.Contains("Superceded by [10. AsciiDoc format](#%2F:10)"));
}
}
diff --git a/Structurizr.AdrTools.Tests/Structurizr.AdrTools.Tests.csproj b/Structurizr.AdrTools.Tests/Structurizr.AdrTools.Tests.csproj
index 9f13f19..e939dbb 100644
--- a/Structurizr.AdrTools.Tests/Structurizr.AdrTools.Tests.csproj
+++ b/Structurizr.AdrTools.Tests/Structurizr.AdrTools.Tests.csproj
@@ -1,6 +1,6 @@
- netcoreapp1.1
+ netcoreapp2.1
false
diff --git a/Structurizr.AdrTools/AdrTools/AdrToolsImporter.cs b/Structurizr.AdrTools/AdrTools/AdrToolsImporter.cs
index 0bfa2db..81676fb 100644
--- a/Structurizr.AdrTools/AdrTools/AdrToolsImporter.cs
+++ b/Structurizr.AdrTools/AdrTools/AdrToolsImporter.cs
@@ -90,11 +90,15 @@ public ISet ImportArchitectureDecisionRecords(SoftwareSystem softwareS
private string CalculateUrl(SoftwareSystem softwareSystem, string id)
{
if (softwareSystem == null) {
- return "#/:" + UrlEncode(id);
+ // sync with java impl
+ return "#" + UrlEncode("/") + ":" + UrlEncode(id);
}
else
{
- return "#" + UrlEncode(softwareSystem.CanonicalName) + ":" + UrlEncode(id);
+ //CanonicalName impl changed: old "/", new "SoftwareSystem://" (CanonicalNameGenerator.SoftwareSystemType)
+ var name = softwareSystem.CanonicalName;
+ name = name.Substring("SoftwareSystem:/".Length); // last "/" is reused
+ return "#" + UrlEncode(name) + ":" + UrlEncode(id);
}
}
diff --git a/Structurizr.AdrTools/Structurizr.AdrTools.csproj b/Structurizr.AdrTools/Structurizr.AdrTools.csproj
index 38c9414..c9c8733 100644
--- a/Structurizr.AdrTools/Structurizr.AdrTools.csproj
+++ b/Structurizr.AdrTools/Structurizr.AdrTools.csproj
@@ -7,11 +7,11 @@
- netstandard1.3;net45
+ netstandard2.0;net45
-
+
diff --git a/Structurizr.Analysis/Structurizr.Analysis.csproj b/Structurizr.Analysis/Structurizr.Analysis.csproj
index 3bfbc40..f536c8b 100644
--- a/Structurizr.Analysis/Structurizr.Analysis.csproj
+++ b/Structurizr.Analysis/Structurizr.Analysis.csproj
@@ -7,11 +7,11 @@
- netstandard1.3;net45
+ netstandard2.0;net45
-
+
\ No newline at end of file
diff --git a/Structurizr.Annotations/Structurizr.Annotations.csproj b/Structurizr.Annotations/Structurizr.Annotations.csproj
index 2395b0c..b0aab59 100644
--- a/Structurizr.Annotations/Structurizr.Annotations.csproj
+++ b/Structurizr.Annotations/Structurizr.Annotations.csproj
@@ -17,7 +17,12 @@
+
+ netstandard2.0;net20
bin\$(Configuration)\$(TargetFramework)\Structurizr.Annotations.xml
1.6.0
@@ -48,4 +53,11 @@
4.1.0
+
+
+
+ 4.1.0
+
+
+
diff --git a/Structurizr.Cecil.Examples/Structurizr.Cecil.Examples.csproj b/Structurizr.Cecil.Examples/Structurizr.Cecil.Examples.csproj
index 9d7a008..2a94992 100644
--- a/Structurizr.Cecil.Examples/Structurizr.Cecil.Examples.csproj
+++ b/Structurizr.Cecil.Examples/Structurizr.Cecil.Examples.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/Structurizr.Cecil/Structurizr.Cecil.csproj b/Structurizr.Cecil/Structurizr.Cecil.csproj
index ffa5ec8..4a98d97 100644
--- a/Structurizr.Cecil/Structurizr.Cecil.csproj
+++ b/Structurizr.Cecil/Structurizr.Cecil.csproj
@@ -16,12 +16,12 @@
- netstandard1.3;net45
+ netstandard2.0;net45
-
+
diff --git a/Structurizr.Examples/BigBankPlc.cs b/Structurizr.Examples/BigBankPlc.cs
index 005e661..b9e7d32 100644
--- a/Structurizr.Examples/BigBankPlc.cs
+++ b/Structurizr.Examples/BigBankPlc.cs
@@ -5,7 +5,7 @@
namespace Structurizr.Examples
{
-
+
///
/// This is an example workspace to illustrate the key features of Structurizr,
/// based around a fictional Internet Banking System for Big Bank plc.
@@ -28,238 +28,270 @@ public class BigBankPlc
public static Workspace Create()
{
- Workspace workspace = new Workspace("Big Bank plc", "This is an example workspace to illustrate the key features of Structurizr, based around a fictional online banking system.");
- Model model = workspace.Model;
- ViewSet views = workspace.Views;
-
- model.Enterprise = new Enterprise("Big Bank plc");
-
- // people and software systems
- Person customer = model.AddPerson(Location.External, "Personal Banking Customer", "A customer of the bank, with personal bank accounts.");
-
- SoftwareSystem internetBankingSystem = model.AddSoftwareSystem(Location.Internal, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.");
- customer.Uses(internetBankingSystem, "Uses");
-
- SoftwareSystem mainframeBankingSystem = model.AddSoftwareSystem(Location.Internal, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.");
- mainframeBankingSystem.AddTags(ExistingSystemTag);
- internetBankingSystem.Uses(mainframeBankingSystem, "Uses");
-
- SoftwareSystem emailSystem = model.AddSoftwareSystem(Location.Internal, "E-mail System", "The internal Microsoft Exchange e-mail system.");
- internetBankingSystem.Uses(emailSystem, "Sends e-mail using");
- emailSystem.AddTags(ExistingSystemTag);
- emailSystem.Delivers(customer, "Sends e-mails to");
-
- SoftwareSystem atm = model.AddSoftwareSystem(Location.Internal, "ATM", "Allows customers to withdraw cash.");
- atm.AddTags(ExistingSystemTag);
- atm.Uses(mainframeBankingSystem, "Uses");
- customer.Uses(atm, "Withdraws cash using");
-
- Person customerServiceStaff = model.AddPerson(Location.Internal, "Customer Service Staff", "Customer service staff within the bank.");
- customerServiceStaff.AddTags(BankStaffTag);
- customerServiceStaff.Uses(mainframeBankingSystem, "Uses");
- customer.InteractsWith(customerServiceStaff, "Asks questions to", "Telephone");
-
- Person backOfficeStaff = model.AddPerson(Location.Internal, "Back Office Staff", "Administration and support staff within the bank.");
- backOfficeStaff.AddTags(BankStaffTag);
- backOfficeStaff.Uses(mainframeBankingSystem, "Uses");
-
- // containers
- Container singlePageApplication = internetBankingSystem.AddContainer("Single-Page Application", "Provides all of the Internet banking functionality to customers via their web browser.", "JavaScript and Angular");
- singlePageApplication.AddTags(WebBrowserTag);
- Container mobileApp = internetBankingSystem.AddContainer("Mobile App", "Provides a limited subset of the Internet banking functionality to customers via their mobile device.", "Xamarin");
- mobileApp.AddTags(MobileAppTag);
- Container webApplication = internetBankingSystem.AddContainer("Web Application", "Delivers the static content and the Internet banking single page application.", "Java and Spring MVC");
- Container apiApplication = internetBankingSystem.AddContainer("API Application", "Provides Internet banking functionality via a JSON/HTTPS API.", "Java and Spring MVC");
- Container database = internetBankingSystem.AddContainer("Database", "Stores user registration information, hashed authentication credentials, access logs, etc.", "Relational Database Schema");
- database.AddTags(DatabaseTag);
-
- customer.Uses(webApplication, "Uses", "HTTPS");
- customer.Uses(singlePageApplication, "Uses", "");
- customer.Uses(mobileApp, "Uses", "");
- webApplication.Uses(singlePageApplication, "Delivers to the customer's web browser", "");
- apiApplication.Uses(database, "Reads from and writes to", "JDBC");
- apiApplication.Uses(mainframeBankingSystem, "Uses", "XML/HTTPS");
- apiApplication.Uses(emailSystem, "Sends e-mail using", "SMTP");
-
- // components
- // - for a real-world software system, you would probably want to extract the components using
- // - static analysis/reflection rather than manually specifying them all
- Component signinController = apiApplication.AddComponent("Sign In Controller", "Allows users to sign in to the Internet Banking System.", "Spring MVC Rest Controller");
- Component accountsSummaryController = apiApplication.AddComponent("Accounts Summary Controller", "Provides customers with a summary of their bank accounts.", "Spring MVC Rest Controller");
- Component resetPasswordController = apiApplication.AddComponent("Reset Password Controller", "Allows users to reset their passwords with a single use URL.", "Spring MVC Rest Controller");
- Component securityComponent = apiApplication.AddComponent("Security Component", "Provides functionality related to signing in, changing passwords, etc.", "Spring Bean");
- Component mainframeBankingSystemFacade = apiApplication.AddComponent("Mainframe Banking System Facade", "A facade onto the mainframe banking system.", "Spring Bean");
- Component emailComponent = apiApplication.AddComponent("E-mail Component", "Sends e-mails to users.", "Spring Bean");
-
- apiApplication.Components.Where(c => "Spring MVC Rest Controller".Equals(c.Technology)).ToList().ForEach(c => singlePageApplication.Uses(c, "Makes API calls to", "JSON/HTTPS"));
- apiApplication.Components.Where(c => "Spring MVC Rest Controller".Equals(c.Technology)).ToList().ForEach(c => mobileApp.Uses(c, "Makes API calls to", "JSON/HTTPS"));
- signinController.Uses(securityComponent, "Uses");
- accountsSummaryController.Uses(mainframeBankingSystemFacade, "Uses");
- resetPasswordController.Uses(securityComponent, "Uses");
- resetPasswordController.Uses(emailComponent, "Uses");
- securityComponent.Uses(database, "Reads from and writes to", "JDBC");
- mainframeBankingSystemFacade.Uses(mainframeBankingSystem, "Uses", "XML/HTTPS");
- emailComponent.Uses(emailSystem, "Sends e-mail using");
-
- model.AddImplicitRelationships();
-
- // deployment nodes and container instances
- DeploymentNode developerLaptop = model.AddDeploymentNode("Development", "Developer Laptop", "A developer laptop.", "Microsoft Windows 10 or Apple macOS");
- DeploymentNode apacheTomcat = developerLaptop.AddDeploymentNode("Docker Container - Web Server", "A Docker container.", "Docker")
- .AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8"));
- apacheTomcat.Add(webApplication);
- apacheTomcat.Add(apiApplication);
-
- developerLaptop.AddDeploymentNode("Docker Container - Database Server", "A Docker container.", "Docker")
- .AddDeploymentNode("Database Server", "A development database.", "Oracle 12c")
- .Add(database);
-
- developerLaptop.AddDeploymentNode("Web Browser", "", "Google Chrome, Mozilla Firefox, Apple Safari or Microsoft Edge").Add(singlePageApplication);
-
- DeploymentNode customerMobileDevice = model.AddDeploymentNode("Live", "Customer's mobile device", "", "Apple iOS or Android");
- customerMobileDevice.Add(mobileApp);
-
- DeploymentNode customerComputer = model.AddDeploymentNode("Live", "Customer's computer", "", "Microsoft Windows or Apple macOS");
- customerComputer.AddDeploymentNode("Web Browser", "", "Google Chrome, Mozilla Firefox, Apple Safari or Microsoft Edge").Add(singlePageApplication);
-
- DeploymentNode bigBankDataCenter = model.AddDeploymentNode("Live", "Big Bank plc", "", "Big Bank plc data center");
-
- DeploymentNode liveWebServer = bigBankDataCenter.AddDeploymentNode("bigbank-web***", "A web server residing in the web server farm, accessed via F5 BIG-IP LTMs.", "Ubuntu 16.04 LTS", 4, DictionaryUtils.Create("Location=London and Reading"));
- liveWebServer.AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8"))
- .Add(webApplication);
-
- DeploymentNode liveApiServer = bigBankDataCenter.AddDeploymentNode("bigbank-api***", "A web server residing in the web server farm, accessed via F5 BIG-IP LTMs.", "Ubuntu 16.04 LTS", 8, DictionaryUtils.Create("Location=London and Reading"));
- liveApiServer.AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8"))
- .Add(apiApplication);
-
- DeploymentNode primaryDatabaseServer = bigBankDataCenter.AddDeploymentNode("bigbank-db01", "The primary database server.", "Ubuntu 16.04 LTS", 1, DictionaryUtils.Create("Location=London"))
- .AddDeploymentNode("Oracle - Primary", "The primary, live database server.", "Oracle 12c");
- primaryDatabaseServer.Add(database);
-
- DeploymentNode secondaryDatabaseServer = bigBankDataCenter.AddDeploymentNode("bigbank-db02", "The secondary database server.", "Ubuntu 16.04 LTS", 1, DictionaryUtils.Create("Location=Reading"))
- .AddDeploymentNode("Oracle - Secondary", "A secondary, standby database server, used for failover purposes only.", "Oracle 12c");
- ContainerInstance secondaryDatabase = secondaryDatabaseServer.Add(database);
-
- model.Relationships.Where(r=>r.Destination.Equals(secondaryDatabase)).ToList().ForEach(r=>r.AddTags(FailoverTag));
- Relationship dataReplicationRelationship = primaryDatabaseServer.Uses(secondaryDatabaseServer, "Replicates data to", "");
- secondaryDatabase.AddTags(FailoverTag);
-
- // views/diagrams
- SystemLandscapeView systemLandscapeView = views.CreateSystemLandscapeView("SystemLandscape", "The system landscape diagram for Big Bank plc.");
- systemLandscapeView.AddAllElements();
- systemLandscapeView.PaperSize = PaperSize.A5_Landscape;
-
- SystemContextView systemContextView = views.CreateSystemContextView(internetBankingSystem, "SystemContext", "The system context diagram for the Internet Banking System.");
- systemContextView.EnterpriseBoundaryVisible = false;
- systemContextView.AddNearestNeighbours(internetBankingSystem);
- systemContextView.PaperSize = PaperSize.A5_Landscape;
-
- ContainerView containerView = views.CreateContainerView(internetBankingSystem, "Containers", "The container diagram for the Internet Banking System.");
- containerView.Add(customer);
- containerView.AddAllContainers();
- containerView.Add(mainframeBankingSystem);
- containerView.Add(emailSystem);
- containerView.PaperSize = PaperSize.A5_Landscape;
-
- ComponentView componentView = views.CreateComponentView(apiApplication, "Components", "The component diagram for the API Application.");
- componentView.Add(mobileApp);
- componentView.Add(singlePageApplication);
- componentView.Add(database);
- componentView.AddAllComponents();
- componentView.Add(mainframeBankingSystem);
- componentView.Add(emailSystem);
- componentView.PaperSize = PaperSize.A5_Landscape;
-
- systemLandscapeView.AddAnimation(internetBankingSystem, customer, mainframeBankingSystem, emailSystem);
- systemLandscapeView.AddAnimation(atm);
- systemLandscapeView.AddAnimation(customerServiceStaff, backOfficeStaff);
-
- systemContextView.AddAnimation(internetBankingSystem);
- systemContextView.AddAnimation(customer);
- systemContextView.AddAnimation(mainframeBankingSystem);
- systemContextView.AddAnimation(emailSystem);
-
- containerView.AddAnimation(customer, mainframeBankingSystem, emailSystem);
- containerView.AddAnimation(webApplication);
- containerView.AddAnimation(singlePageApplication);
- containerView.AddAnimation(mobileApp);
- containerView.AddAnimation(apiApplication);
- containerView.AddAnimation(database);
-
- componentView.AddAnimation(singlePageApplication, mobileApp);
- componentView.AddAnimation(signinController, securityComponent, database);
- componentView.AddAnimation(accountsSummaryController, mainframeBankingSystemFacade, mainframeBankingSystem);
- componentView.AddAnimation(resetPasswordController, emailComponent, database);
-
- // dynamic diagrams and deployment diagrams are not available with the Free Plan
- DynamicView dynamicView = views.CreateDynamicView(apiApplication, "SignIn", "Summarises how the sign in feature works in the single-page application.");
- dynamicView.Add(singlePageApplication, "Submits credentials to", signinController);
- dynamicView.Add(signinController, "Calls isAuthenticated() on", securityComponent);
- dynamicView.Add(securityComponent, "select * from users where username = ?", database);
- dynamicView.PaperSize = PaperSize.A5_Landscape;
-
- DeploymentView developmentDeploymentView = views.CreateDeploymentView(internetBankingSystem, "DevelopmentDeployment", "An example development deployment scenario for the Internet Banking System.");
- developmentDeploymentView.Environment = "Development";
- developmentDeploymentView.Add(developerLaptop);
- developmentDeploymentView.PaperSize = PaperSize.A5_Landscape;
-
- DeploymentView liveDeploymentView = views.CreateDeploymentView(internetBankingSystem, "LiveDeployment", "An example live deployment scenario for the Internet Banking System.");
- liveDeploymentView.Environment = "Live";
- liveDeploymentView.Add(bigBankDataCenter);
- liveDeploymentView.Add(customerMobileDevice);
- liveDeploymentView.Add(customerComputer);
- liveDeploymentView.Add(dataReplicationRelationship);
- liveDeploymentView.PaperSize = PaperSize.A5_Landscape;
-
- // colours, shapes and other diagram styling
- Styles styles = views.Configuration.Styles;
- styles.Add(new ElementStyle(Tags.Element) { Color = "#ffffff" });
- styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#1168bd" });
- styles.Add(new ElementStyle(Tags.Container) { Background = "#438dd5" });
- styles.Add(new ElementStyle(Tags.Component) { Background = "#85bbf0", Color = "#000000" });
- styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Shape = Shape.Person, FontSize = 22});
- styles.Add(new ElementStyle(ExistingSystemTag) { Background = "#999999"});
- styles.Add(new ElementStyle(BankStaffTag) { Background = "#999999" });
- styles.Add(new ElementStyle(WebBrowserTag) { Shape = Shape.WebBrowser });
- styles.Add(new ElementStyle(MobileAppTag) { Shape = Shape.MobileDeviceLandscape });
- styles.Add(new ElementStyle(DatabaseTag) { Shape = Shape.Cylinder });
- styles.Add(new ElementStyle(FailoverTag) { Opacity = 25 });
- styles.Add(new RelationshipStyle(FailoverTag) { Opacity = 25, Position = 70});
-
- // documentation
- // - usually the documentation would be included from separate Markdown/AsciiDoc files, but this is just an example
- StructurizrDocumentationTemplate template = new StructurizrDocumentationTemplate(workspace);
- template.AddContextSection(internetBankingSystem, Format.Markdown,
- "Here is some context about the Internet Banking System...\n" +
- "\n" +
- "\n" +
- "### Internet Banking System\n...\n" +
- "### Mainframe Banking System\n...\n");
- template.AddContainersSection(internetBankingSystem, Format.Markdown,
- "Here is some information about the containers within the Internet Banking System...\n" +
- "\n" +
- "### Web Application\n...\n" +
- "### Database\n...\n");
- template.AddComponentsSection(webApplication, Format.Markdown,
- "Here is some information about the API Application...\n" +
- "\n" +
- "### Sign in process\n" +
- "Here is some information about the Sign In Controller, including how the sign in process works...\n" +
- "");
- template.AddDevelopmentEnvironmentSection(internetBankingSystem, Format.AsciiDoc,
- "Here is some information about how to set up a development environment for the Internet Banking System...\n" +
- "image::embed:DevelopmentDeployment[]");
- template.AddDeploymentSection(internetBankingSystem, Format.AsciiDoc,
- "Here is some information about the live deployment environment for the Internet Banking System...\n" +
- "image::embed:LiveDeployment[]");
-
- return workspace;
+ Workspace workspace = new Workspace("Big Bank plc", "This is an example workspace to illustrate the key features of Structurizr, based around a fictional online banking system.");
+ Model model = workspace.Model;
+ model.ImpliedRelationshipsStrategy = new CreateImpliedRelationshipsUnlessAnyRelationshipExistsStrategy();
+ ViewSet views = workspace.Views;
+
+ model.Enterprise = new Enterprise("Big Bank plc");
+
+ // people and software systems
+ SoftwareSystem internetBankingSystem = model.AddSoftwareSystem(Location.Internal, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.");
+ Person customer = model.AddPerson(Location.External, "Personal Banking Customer", "A customer of the bank, with personal bank accounts.");
+
+ customer.Uses(internetBankingSystem, "Views account balances, and makes payments using");
+
+ SoftwareSystem mainframeBankingSystem = model.AddSoftwareSystem(Location.Internal, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.");
+ mainframeBankingSystem.AddTags(ExistingSystemTag);
+ internetBankingSystem.Uses(mainframeBankingSystem, "Gets account information from, and makes payments using");
+
+ SoftwareSystem emailSystem = model.AddSoftwareSystem(Location.Internal, "E-mail System", "The internal Microsoft Exchange e-mail system.");
+ internetBankingSystem.Uses(emailSystem, "Sends e-mail using");
+ emailSystem.AddTags(ExistingSystemTag);
+ emailSystem.Delivers(customer, "Sends e-mails to");
+
+ SoftwareSystem atm = model.AddSoftwareSystem(Location.Internal, "ATM", "Allows customers to withdraw cash.");
+ atm.AddTags(ExistingSystemTag);
+ atm.Uses(mainframeBankingSystem, "Uses");
+ customer.Uses(atm, "Withdraws cash using");
+
+ Person customerServiceStaff = model.AddPerson(Location.Internal, "Customer Service Staff", "Customer service staff within the bank.");
+ customerServiceStaff.AddTags(BankStaffTag);
+ customerServiceStaff.Uses(mainframeBankingSystem, "Uses");
+ customer.InteractsWith(customerServiceStaff, "Asks questions to", "Telephone");
+
+ Person backOfficeStaff = model.AddPerson(Location.Internal, "Back Office Staff", "Administration and support staff within the bank.");
+ backOfficeStaff.AddTags(BankStaffTag);
+ backOfficeStaff.Uses(mainframeBankingSystem, "Uses");
+
+ // containers
+ Container singlePageApplication = internetBankingSystem.AddContainer("Single-Page Application", "Provides all of the Internet banking functionality to customers via their web browser.", "JavaScript and Angular");
+ singlePageApplication.AddTags(WebBrowserTag);
+ Container mobileApp = internetBankingSystem.AddContainer("Mobile App", "Provides a limited subset of the Internet banking functionality to customers via their mobile device.", "Xamarin");
+ mobileApp.AddTags(MobileAppTag);
+ Container webApplication = internetBankingSystem.AddContainer("Web Application", "Delivers the static content and the Internet banking single page application.", "Java and Spring MVC");
+ Container apiApplication = internetBankingSystem.AddContainer("API Application", "Provides Internet banking functionality via a JSON/HTTPS API.", "Java and Spring MVC");
+ Container database = internetBankingSystem.AddContainer("Database", "Stores user registration information, hashed authentication credentials, access logs, etc.", "Relational Database Schema");
+ database.AddTags(DatabaseTag);
+
+ customer.Uses(webApplication, "Visits bigbank.com/ib using", "HTTPS");
+ customer.Uses(singlePageApplication, "Views account balances, and makes payments using", "");
+ customer.Uses(mobileApp, "Views account balances, and makes payments using", "");
+ webApplication.Uses(singlePageApplication, "Delivers to the customer's web browser", "");
+ apiApplication.Uses(database, "Reads from and writes to", "JDBC");
+ apiApplication.Uses(mainframeBankingSystem, "Makes API calls to", "XML/HTTPS");
+ apiApplication.Uses(emailSystem, "Sends e-mail using", "SMTP");
+
+ // components
+ // - for a real-world software system, you would probably want to extract the components using
+ // - static analysis/reflection rather than manually specifying them all
+ Component signinController = apiApplication.AddComponent("Sign In Controller", "Allows users to sign in to the Internet Banking System.", "Spring MVC Rest Controller");
+ Component accountsSummaryController = apiApplication.AddComponent("Accounts Summary Controller", "Provides customers with a summary of their bank accounts.", "Spring MVC Rest Controller");
+ Component resetPasswordController = apiApplication.AddComponent("Reset Password Controller", "Allows users to reset their passwords with a single use URL.", "Spring MVC Rest Controller");
+ Component securityComponent = apiApplication.AddComponent("Security Component", "Provides functionality related to signing in, changing passwords, etc.", "Spring Bean");
+ Component mainframeBankingSystemFacade = apiApplication.AddComponent("Mainframe Banking System Facade", "A facade onto the mainframe banking system.", "Spring Bean");
+ Component emailComponent = apiApplication.AddComponent("E-mail Component", "Sends e-mails to users.", "Spring Bean");
+
+ apiApplication.Components.Where(c => "Spring MVC Rest Controller".Equals(c.Technology)).ToList().ForEach(c => singlePageApplication.Uses(c, "Makes API calls to", "JSON/HTTPS"));
+ apiApplication.Components.Where(c => "Spring MVC Rest Controller".Equals(c.Technology)).ToList().ForEach(c => mobileApp.Uses(c, "Makes API calls to", "JSON/HTTPS"));
+ signinController.Uses(securityComponent, "Uses");
+ accountsSummaryController.Uses(mainframeBankingSystemFacade, "Uses");
+ resetPasswordController.Uses(securityComponent, "Uses");
+ resetPasswordController.Uses(emailComponent, "Uses");
+ securityComponent.Uses(database, "Reads from and writes to", "JDBC");
+ mainframeBankingSystemFacade.Uses(mainframeBankingSystem, "Uses", "XML/HTTPS");
+ emailComponent.Uses(emailSystem, "Sends e-mail using");
+
+ // deployment nodes and container instances
+ DeploymentNode developerLaptop = model.AddDeploymentNode("Development", "Developer Laptop", "A developer laptop.", "Microsoft Windows 10 or Apple macOS");
+ DeploymentNode apacheTomcat = developerLaptop
+ .AddDeploymentNode("Docker Container - Web Server", "A Docker container.", "Docker")
+ .AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8"));
+ ContainerInstance developmentWebApplication = apacheTomcat.Add(webApplication);
+ ContainerInstance developmentApiApplication = apacheTomcat.Add(apiApplication);
+
+ DeploymentNode bigBankDataCenterForDevelopment = model.AddDeploymentNode("Development", "Big Bank plc", "", "Big Bank plc data center");
+ SoftwareSystemInstance developmentMainframeBankingSystem = bigBankDataCenterForDevelopment
+ .AddDeploymentNode("bigbank-dev001").Add(mainframeBankingSystem);
+
+ ContainerInstance developmentDatabase = developerLaptop
+ .AddDeploymentNode("Docker Container - Database Server", "A Docker container.", "Docker")
+ .AddDeploymentNode("Database Server", "A development database.", "Oracle 12c")
+ .Add(database);
+
+ ContainerInstance developmentSinglePageApplication = developerLaptop
+ .AddDeploymentNode("Web Browser", "", "Chrome, Firefox, Safari, or Edge")
+ .Add(singlePageApplication);
+
+ DeploymentNode customerMobileDevice = model.AddDeploymentNode("Live", "Customer's mobile device", "", "Apple iOS or Android");
+ ContainerInstance liveMobileApp = customerMobileDevice.Add(mobileApp);
+
+ DeploymentNode customerComputer = model.AddDeploymentNode("Live", "Customer's computer", "", "Microsoft Windows or Apple macOS");
+ ContainerInstance liveSinglePageApplication = customerComputer
+ .AddDeploymentNode("Web Browser", "", "Chrome, Firefox, Safari, or Edge")
+ .Add(singlePageApplication);
+
+ DeploymentNode bigBankDataCenterForLive =
+ model.AddDeploymentNode("Live", "Big Bank plc", "", "Big Bank plc data center");
+ SoftwareSystemInstance liveMainframeBankingSystem = bigBankDataCenterForLive
+ .AddDeploymentNode("bigbank-prod001").Add(mainframeBankingSystem);
+
+ DeploymentNode liveWebServer = bigBankDataCenterForLive.AddDeploymentNode("bigbank-web***", "A web server residing in the web server farm, accessed via F5 BIG-IP LTMs.", "Ubuntu 16.04 LTS", 4, DictionaryUtils.Create("Location=London and Reading"));
+ ContainerInstance liveWebApplication = liveWebServer.AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8"))
+ .Add(webApplication);
+
+ DeploymentNode liveApiServer = bigBankDataCenterForLive.AddDeploymentNode("bigbank-api***", "A web server residing in the web server farm, accessed via F5 BIG-IP LTMs.", "Ubuntu 16.04 LTS", 8, DictionaryUtils.Create("Location=London and Reading"));
+ ContainerInstance liveApiApplication = liveApiServer.AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8"))
+ .Add(apiApplication);
+
+ DeploymentNode primaryDatabaseServer = bigBankDataCenterForLive
+ .AddDeploymentNode("bigbank-db01", "The primary database server.", "Ubuntu 16.04 LTS", 1, DictionaryUtils.Create("Location=London"))
+ .AddDeploymentNode("Oracle - Primary", "The primary, live database server.", "Oracle 12c");
+ ContainerInstance livePrimaryDatabase = primaryDatabaseServer.Add(database);
+
+ DeploymentNode bigBankdb02 = bigBankDataCenterForLive.AddDeploymentNode("bigbank-db02", "The secondary database server.", "Ubuntu 16.04 LTS", 1, DictionaryUtils.Create("Location=Reading"));
+ bigBankdb02.AddTags(FailoverTag);
+ DeploymentNode secondaryDatabaseServer = bigBankdb02.AddDeploymentNode("Oracle - Secondary", "A secondary, standby database server, used for failover purposes only.", "Oracle 12c");
+ secondaryDatabaseServer.AddTags(FailoverTag);
+ ContainerInstance liveSecondaryDatabase = secondaryDatabaseServer.Add(database);
+
+ model.Relationships.Where(r => r.Destination.Equals(liveSecondaryDatabase)).ToList().ForEach(r => r.AddTags(FailoverTag));
+ Relationship dataReplicationRelationship = primaryDatabaseServer.Uses(secondaryDatabaseServer, "Replicates data to", "");
+ liveSecondaryDatabase.AddTags(FailoverTag);
+
+ // views/diagrams
+ SystemLandscapeView systemLandscapeView = views.CreateSystemLandscapeView("SystemLandscape", "The system landscape diagram for Big Bank plc.");
+ systemLandscapeView.AddAllElements();
+ systemLandscapeView.PaperSize = PaperSize.A5_Landscape;
+
+ SystemContextView systemContextView = views.CreateSystemContextView(internetBankingSystem, "SystemContext", "The system context diagram for the Internet Banking System.");
+ systemContextView.EnterpriseBoundaryVisible = false;
+ systemContextView.AddNearestNeighbours(internetBankingSystem);
+ systemContextView.PaperSize = PaperSize.A5_Landscape;
+
+ ContainerView containerView = views.CreateContainerView(internetBankingSystem, "Containers", "The container diagram for the Internet Banking System.");
+ containerView.Add(customer);
+ containerView.AddAllContainers();
+ containerView.Add(mainframeBankingSystem);
+ containerView.Add(emailSystem);
+ containerView.PaperSize = PaperSize.A5_Landscape;
+
+ ComponentView componentView = views.CreateComponentView(apiApplication, "Components", "The component diagram for the API Application.");
+ componentView.Add(mobileApp);
+ componentView.Add(singlePageApplication);
+ componentView.Add(database);
+ componentView.AddAllComponents();
+ componentView.Add(mainframeBankingSystem);
+ componentView.Add(emailSystem);
+ componentView.PaperSize = PaperSize.A5_Landscape;
+
+ systemLandscapeView.AddAnimation(internetBankingSystem, customer, mainframeBankingSystem, emailSystem);
+ systemLandscapeView.AddAnimation(atm);
+ systemLandscapeView.AddAnimation(customerServiceStaff, backOfficeStaff);
+
+ systemContextView.AddAnimation(internetBankingSystem);
+ systemContextView.AddAnimation(customer);
+ systemContextView.AddAnimation(mainframeBankingSystem);
+ systemContextView.AddAnimation(emailSystem);
+
+ containerView.AddAnimation(customer, mainframeBankingSystem, emailSystem);
+ containerView.AddAnimation(webApplication);
+ containerView.AddAnimation(singlePageApplication);
+ containerView.AddAnimation(mobileApp);
+ containerView.AddAnimation(apiApplication);
+ containerView.AddAnimation(database);
+
+ componentView.AddAnimation(singlePageApplication, mobileApp);
+ componentView.AddAnimation(signinController, securityComponent, database);
+ componentView.AddAnimation(accountsSummaryController, mainframeBankingSystemFacade, mainframeBankingSystem);
+ componentView.AddAnimation(resetPasswordController, emailComponent, database);
+
+ // dynamic diagrams and deployment diagrams are not available with the Free Plan
+ DynamicView dynamicView = views.CreateDynamicView(apiApplication, "SignIn", "Summarises how the sign in feature works in the single-page application.");
+ dynamicView.Add(singlePageApplication, "Submits credentials to", signinController);
+ dynamicView.Add(signinController, "Validates credentials using", securityComponent);
+ dynamicView.Add(securityComponent, "select * from users where username = ?", database);
+ dynamicView.Add(database, "Returns user data to", securityComponent);
+ dynamicView.Add(securityComponent, "Returns true if the hashed password matches", signinController);
+ dynamicView.Add(signinController, "Sends back an authentication token to", singlePageApplication);
+ dynamicView.PaperSize = PaperSize.A5_Landscape;
+
+ DeploymentView developmentDeploymentView = views.CreateDeploymentView(internetBankingSystem, "DevelopmentDeployment", "An example development deployment scenario for the Internet Banking System.");
+ developmentDeploymentView.Environment = "Development";
+ developmentDeploymentView.Add(developerLaptop);
+ developmentDeploymentView.Add(bigBankDataCenterForDevelopment);
+ developmentDeploymentView.PaperSize = PaperSize.A5_Landscape;
+
+ developmentDeploymentView.AddAnimation(developmentSinglePageApplication);
+ developmentDeploymentView.AddAnimation(developmentWebApplication, developmentApiApplication);
+ developmentDeploymentView.AddAnimation(developmentDatabase);
+ developmentDeploymentView.AddAnimation(developmentMainframeBankingSystem);
+
+ DeploymentView liveDeploymentView = views.CreateDeploymentView(internetBankingSystem, "LiveDeployment", "An example live deployment scenario for the Internet Banking System.");
+ liveDeploymentView.Environment = "Live";
+ liveDeploymentView.Add(bigBankDataCenterForLive);
+ liveDeploymentView.Add(customerMobileDevice);
+ liveDeploymentView.Add(customerComputer);
+ liveDeploymentView.Add(dataReplicationRelationship);
+ liveDeploymentView.PaperSize = PaperSize.A5_Landscape;
+
+ liveDeploymentView.AddAnimation(liveSinglePageApplication);
+ liveDeploymentView.AddAnimation(liveMobileApp);
+ liveDeploymentView.AddAnimation(liveWebApplication, liveApiApplication);
+ liveDeploymentView.AddAnimation(livePrimaryDatabase);
+ liveDeploymentView.AddAnimation(liveSecondaryDatabase);
+ liveDeploymentView.AddAnimation(liveMainframeBankingSystem);
+
+ // colours, shapes and other diagram styling
+ Styles styles = views.Configuration.Styles;
+ styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#1168bd", Color = "#ffffff" });
+ styles.Add(new ElementStyle(Tags.Container) { Background = "#438dd5", Color = "#ffffff" });
+ styles.Add(new ElementStyle(Tags.Component) { Background = "#85bbf0", Color = "#000000" });
+ styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Color = "#ffffff", Shape = Shape.Person, FontSize = 22 });
+ styles.Add(new ElementStyle(ExistingSystemTag) { Background = "#999999", Color = "#ffffff" });
+ styles.Add(new ElementStyle(BankStaffTag) { Background = "#999999", Color = "#ffffff" });
+ styles.Add(new ElementStyle(WebBrowserTag) { Shape = Shape.WebBrowser });
+ styles.Add(new ElementStyle(MobileAppTag) { Shape = Shape.MobileDeviceLandscape });
+ styles.Add(new ElementStyle(DatabaseTag) { Shape = Shape.Cylinder });
+ styles.Add(new ElementStyle(FailoverTag) { Opacity = 25 });
+ styles.Add(new RelationshipStyle(FailoverTag) {Opacity = 25, Position = 70 });
+
+ // documentation
+ // - usually the documentation would be included from separate Markdown/AsciiDoc files, but this is just an example
+ StructurizrDocumentationTemplate template = new StructurizrDocumentationTemplate(workspace);
+ template.AddContextSection(internetBankingSystem, Format.Markdown,
+ "Here is some context about the Internet Banking System...\n" +
+ "\n" +
+ "\n" +
+ "### Internet Banking System\n...\n" +
+ "### Mainframe Banking System\n...\n");
+ template.AddContainersSection(internetBankingSystem, Format.Markdown,
+ "Here is some information about the containers within the Internet Banking System...\n" +
+ "\n" +
+ "### Web Application\n...\n" +
+ "### Database\n...\n");
+ template.AddComponentsSection(webApplication, Format.Markdown,
+ "Here is some information about the API Application...\n" +
+ "\n" +
+ "### Sign in process\n" +
+ "Here is some information about the Sign In Controller, including how the sign in process works...\n" +
+ "");
+ template.AddDevelopmentEnvironmentSection(internetBankingSystem, Format.AsciiDoc,
+ "Here is some information about how to set up a development environment for the Internet Banking System...\n" +
+ "image::embed:DevelopmentDeployment[]");
+ template.AddDeploymentSection(internetBankingSystem, Format.AsciiDoc,
+ "Here is some information about the live deployment environment for the Internet Banking System...\n" +
+ "image::embed:LiveDeployment[]");
+
+ return workspace;
}
-
+
static void Main()
{
StructurizrClient structurizrClient = new StructurizrClient(ApiKey, ApiSecret);
structurizrClient.PutWorkspace(WorkspaceId, Create());
}
+
}
+
}
\ No newline at end of file
diff --git a/Structurizr.Examples/C4PlantUML.cs b/Structurizr.Examples/C4PlantUML.cs
index 44fdfc3..7ea8656 100644
--- a/Structurizr.Examples/C4PlantUML.cs
+++ b/Structurizr.Examples/C4PlantUML.cs
@@ -42,21 +42,48 @@ static void Main()
Console.WriteLine(stringWriter.ToString());
}
-
+ //
+ // Mark containers or components as database or via tags
+ //
Container webApplication = softwareSystem.AddContainer("Web Application", "Delivers content", "Java and spring MVC");
+ // Additional tag element
+ webApplication.Tags = "Single Page App";
+
Container database = softwareSystem.AddContainer("Database", "Stores information", "Relational Database Schema");
// Additional mark it as database
database.SetIsDatabase(true);
- user.Uses(webApplication, "uses", "HTTP");
+
+ var httpCall = user.Uses(webApplication, "uses", "HTTP");
+ // Additional tag relationship
+ httpCall.Tags = "via firewall";
+
webApplication.Uses(database, "Reads from and writes to", "JDBC").SetDirection(DirectionValues.Right);
+ // add corresponding styles
+ var styles = views.Configuration.Styles;
+ styles.Add(new ElementStyle("Single Page App") {Background = "#5F9061", Stroke = "#2E4F2E", Color = "#FFFFFF", Shape = Shape.RoundedBox }); // rounded box is supported with next version see below
+ styles.Add(new RelationshipStyle("via firewall") {Color = "#B40404", Dashed = true }); // dashed is supported with next version see below
+
var containerView = views.CreateContainerView(softwareSystem, "containers", "");
containerView.AddAllElements();
using (var stringWriter = new StringWriter())
{
var plantUmlWriter = new C4PlantUmlWriter();
- plantUmlWriter.Write(containerView, stringWriter);
+ plantUmlWriter.Write(containerView, workspace.Views.Configuration, stringWriter);
+ Console.WriteLine(stringWriter.ToString());
+ }
+
+ //
+ // Use features of the next planned C4-PlantUML version (v2.3.0 ?)
+ //
+ using (var stringWriter = new StringWriter())
+ {
+ var plantUmlWriter = new C4PlantUmlWriter();
+ plantUmlWriter.EnableNextFeatures = true;
+ plantUmlWriter.CustomBaseUrl = "https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/";
+
+ plantUmlWriter.Write(containerView, workspace.Views.Configuration, stringWriter);
Console.WriteLine(stringWriter.ToString());
}
}
diff --git a/Structurizr.Examples/Structurizr.Examples.csproj b/Structurizr.Examples/Structurizr.Examples.csproj
index 6de67c5..29b95ca 100644
--- a/Structurizr.Examples/Structurizr.Examples.csproj
+++ b/Structurizr.Examples/Structurizr.Examples.csproj
@@ -1,12 +1,12 @@
Exe
- netcoreapp1.1
+ netcoreapp2.1
Structurizr.Examples.PlantUML
false
-
+
diff --git a/Structurizr.PlantUML.Tests/IO/C4PlantUML/C4PlantUmlWriterTests.cs b/Structurizr.PlantUML.Tests/IO/C4PlantUML/C4PlantUmlWriterTests.cs
index 36fc4f1..e595fc4 100644
--- a/Structurizr.PlantUML.Tests/IO/C4PlantUML/C4PlantUmlWriterTests.cs
+++ b/Structurizr.PlantUML.Tests/IO/C4PlantUML/C4PlantUmlWriterTests.cs
@@ -29,14 +29,14 @@ public void test_writeBigBankPlcWorkspace()
_workspace = BigBankPlc.Create();
AddLayoutDetails(_workspace);
-/*
- using (var writer = new StringWriter())
- {
- new Structurizr.IO.Json.JsonWriter(true).Write(_workspace, writer);
- var json = writer.GetStringBuilder().ToString();
- json = json;
- }
-*/
+ /*
+ using (var writer = new StringWriter())
+ {
+ new Structurizr.IO.Json.JsonWriter(true).Write(_workspace, writer);
+ var json = writer.GetStringBuilder().ToString();
+ json = json;
+ }
+ */
_plantUMLWriter.Write(_workspace, _stringWriter);
Assert.Equal(
@@ -46,26 +46,33 @@ public void test_writeBigBankPlcWorkspace()
' Structurizr.SystemLandscapeView: SystemLandscape
title System Landscape for Big Bank plc
-LAYOUT_WITH_LEGEND()
+UpdateElementStyle(system, $bgColor = ""#1168bd"", $fontColor = ""#ffffff"", $borderColor = ""#1168bd"")
+UpdateElementStyle(container, $bgColor = ""#438dd5"", $fontColor = ""#ffffff"", $borderColor = ""#438dd5"")
+UpdateElementStyle(component, $bgColor = ""#85bbf0"", $fontColor = ""#000000"", $borderColor = ""#85bbf0"")
+UpdateElementStyle(person, $bgColor = ""#08427b"", $fontColor = ""#ffffff"", $borderColor = ""#08427b"")
+AddElementTag(Existing System, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+AddElementTag(Bank Staff, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
-Person_Ext(PersonalBankingCustomer__9bc576, ""Personal Banking Customer"", ""A customer of the bank, with personal bank accounts."")
+Person_Ext(PersonalBankingCustomer__HASH0, ""Personal Banking Customer"", ""A customer of the bank, with personal bank accounts."")
Enterprise_Boundary(BigBankplc, ""Big Bank plc"") {
- Person(BackOfficeStaff__5f761d, ""Back Office Staff"", ""Administration and support staff within the bank."")
- Person(CustomerServiceStaff__a35be5, ""Customer Service Staff"", ""Customer service staff within the bank."")
- System(ATM__22fc739, ""ATM"", ""Allows customers to withdraw cash."")
- System(EmailSystem__2908eb9, ""E-mail System"", ""The internal Microsoft Exchange e-mail system."")
- System(InternetBankingSystem__2aef74c, ""Internet Banking System"", ""Allows customers to view information about their bank accounts, and make payments."")
- System(MainframeBankingSystem__f50ffa, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."")
+ Person(BackOfficeStaff__HASH1, ""Back Office Staff"", ""Administration and support staff within the bank."", $tags=""Bank Staff"")
+ Person(CustomerServiceStaff__HASH2, ""Customer Service Staff"", ""Customer service staff within the bank."", $tags=""Bank Staff"")
+ System(ATM__HASH3, ""ATM"", ""Allows customers to withdraw cash."", $tags=""Existing System"")
+ System(EmailSystem__HASH4, ""E-mail System"", ""The internal Microsoft Exchange e-mail system."", $tags=""Existing System"")
+ System(InternetBankingSystem__HASH5, ""Internet Banking System"", ""Allows customers to view information about their bank accounts, and make payments."")
+ System(MainframeBankingSystem__HASH6, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."", $tags=""Existing System"")
}
-Rel_Down(ATM__22fc739, MainframeBankingSystem__f50ffa, ""Uses"")
-Rel_Down(BackOfficeStaff__5f761d, MainframeBankingSystem__f50ffa, ""Uses"")
-Rel_Down(CustomerServiceStaff__a35be5, MainframeBankingSystem__f50ffa, ""Uses"")
-Rel_Up(EmailSystem__2908eb9, PersonalBankingCustomer__9bc576, ""Sends e-mails to"")
-Rel_Down(InternetBankingSystem__2aef74c, EmailSystem__2908eb9, ""Sends e-mail using"")
-Rel_Down(InternetBankingSystem__2aef74c, MainframeBankingSystem__f50ffa, ""Uses"")
-Rel(PersonalBankingCustomer__9bc576, ATM__22fc739, ""Withdraws cash using"")
-Rel(PersonalBankingCustomer__9bc576, CustomerServiceStaff__a35be5, ""Asks questions to"", ""Telephone"")
-Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__2aef74c, ""Uses"")
+Rel_Down(ATM__HASH3, MainframeBankingSystem__HASH6, ""Uses"")
+Rel_Down(BackOfficeStaff__HASH1, MainframeBankingSystem__HASH6, ""Uses"")
+Rel_Down(CustomerServiceStaff__HASH2, MainframeBankingSystem__HASH6, ""Uses"")
+Rel_Up(EmailSystem__HASH4, PersonalBankingCustomer__HASH0, ""Sends e-mails to"")
+Rel_Down(InternetBankingSystem__HASH5, EmailSystem__HASH4, ""Sends e-mail using"")
+Rel_Down(InternetBankingSystem__HASH5, MainframeBankingSystem__HASH6, ""Gets account information from, and makes payments using"")
+Rel(PersonalBankingCustomer__HASH0, ATM__HASH3, ""Withdraws cash using"")
+Rel(PersonalBankingCustomer__HASH0, CustomerServiceStaff__HASH2, ""Asks questions to"", ""Telephone"")
+Rel(PersonalBankingCustomer__HASH0, InternetBankingSystem__HASH5, ""Views account balances, and makes payments using"")
+
+SHOW_LEGEND()
@enduml
@startuml
@@ -74,16 +81,23 @@ public void test_writeBigBankPlcWorkspace()
' Structurizr.SystemContextView: SystemContext
title Internet Banking System - System Context
-LAYOUT_WITH_LEGEND()
-
-System(EmailSystem__2908eb9, ""E-mail System"", ""The internal Microsoft Exchange e-mail system."")
-System(InternetBankingSystem__2aef74c, ""Internet Banking System"", ""Allows customers to view information about their bank accounts, and make payments."")
-System(MainframeBankingSystem__f50ffa, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."")
-Person_Ext(PersonalBankingCustomer__9bc576, ""Personal Banking Customer"", ""A customer of the bank, with personal bank accounts."")
-Rel_Up(EmailSystem__2908eb9, PersonalBankingCustomer__9bc576, ""Sends e-mails to"")
-Rel_Right(InternetBankingSystem__2aef74c, EmailSystem__2908eb9, ""Sends e-mail using"")
-Rel(InternetBankingSystem__2aef74c, MainframeBankingSystem__f50ffa, ""Uses"")
-Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__2aef74c, ""Uses"")
+UpdateElementStyle(system, $bgColor = ""#1168bd"", $fontColor = ""#ffffff"", $borderColor = ""#1168bd"")
+UpdateElementStyle(container, $bgColor = ""#438dd5"", $fontColor = ""#ffffff"", $borderColor = ""#438dd5"")
+UpdateElementStyle(component, $bgColor = ""#85bbf0"", $fontColor = ""#000000"", $borderColor = ""#85bbf0"")
+UpdateElementStyle(person, $bgColor = ""#08427b"", $fontColor = ""#ffffff"", $borderColor = ""#08427b"")
+AddElementTag(Existing System, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+AddElementTag(Bank Staff, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+
+System(EmailSystem__HASH4, ""E-mail System"", ""The internal Microsoft Exchange e-mail system."", $tags=""Existing System"")
+System(InternetBankingSystem__HASH5, ""Internet Banking System"", ""Allows customers to view information about their bank accounts, and make payments."")
+System(MainframeBankingSystem__HASH6, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."", $tags=""Existing System"")
+Person_Ext(PersonalBankingCustomer__HASH0, ""Personal Banking Customer"", ""A customer of the bank, with personal bank accounts."")
+Rel_Up(EmailSystem__HASH4, PersonalBankingCustomer__HASH0, ""Sends e-mails to"")
+Rel_Right(InternetBankingSystem__HASH5, EmailSystem__HASH4, ""Sends e-mail using"")
+Rel(InternetBankingSystem__HASH5, MainframeBankingSystem__HASH6, ""Gets account information from, and makes payments using"")
+Rel(PersonalBankingCustomer__HASH0, InternetBankingSystem__HASH5, ""Views account balances, and makes payments using"")
+
+SHOW_LEGEND()
@enduml
@startuml
@@ -92,28 +106,35 @@ title Internet Banking System - System Context
' Structurizr.ContainerView: Containers
title Internet Banking System - Containers
-LAYOUT_WITH_LEGEND()
-
-System(EmailSystem__2908eb9, ""E-mail System"", ""The internal Microsoft Exchange e-mail system."")
-System(MainframeBankingSystem__f50ffa, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."")
-Person_Ext(PersonalBankingCustomer__9bc576, ""Personal Banking Customer"", ""A customer of the bank, with personal bank accounts."")
-System_Boundary(InternetBankingSystem__2aef74c, ""Internet Banking System"") {
- Container(InternetBankingSystem__APIApplication__2c36bed, ""API Application"", ""Java and Spring MVC"", ""Provides Internet banking functionality via a JSON/HTTPS API."")
- ContainerDb(InternetBankingSystem__Database__18307f7, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."")
- Container(InternetBankingSystem__MobileApp__38a070b, ""Mobile App"", ""Xamarin"", ""Provides a limited subset of the Internet banking functionality to customers via their mobile device."")
- Container(InternetBankingSystem__SinglePageApplication__1414c79, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."")
- Container(InternetBankingSystem__WebApplication__1bb919c, ""Web Application"", ""Java and Spring MVC"", ""Delivers the static content and the Internet banking single page application."")
+UpdateElementStyle(system, $bgColor = ""#1168bd"", $fontColor = ""#ffffff"", $borderColor = ""#1168bd"")
+UpdateElementStyle(container, $bgColor = ""#438dd5"", $fontColor = ""#ffffff"", $borderColor = ""#438dd5"")
+UpdateElementStyle(component, $bgColor = ""#85bbf0"", $fontColor = ""#000000"", $borderColor = ""#85bbf0"")
+UpdateElementStyle(person, $bgColor = ""#08427b"", $fontColor = ""#ffffff"", $borderColor = ""#08427b"")
+AddElementTag(Existing System, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+AddElementTag(Bank Staff, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+
+System(EmailSystem__HASH4, ""E-mail System"", ""The internal Microsoft Exchange e-mail system."", $tags=""Existing System"")
+System(MainframeBankingSystem__HASH6, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."", $tags=""Existing System"")
+Person_Ext(PersonalBankingCustomer__HASH0, ""Personal Banking Customer"", ""A customer of the bank, with personal bank accounts."")
+System_Boundary(InternetBankingSystem__HASH5, ""Internet Banking System"") {
+ Container(InternetBankingSystem__APIApplication__HASH7, ""API Application"", ""Java and Spring MVC"", ""Provides Internet banking functionality via a JSON/HTTPS API."")
+ ContainerDb(InternetBankingSystem__Database__HASH8, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."", $tags=""Database"")
+ Container(InternetBankingSystem__MobileApp__HASH9, ""Mobile App"", ""Xamarin"", ""Provides a limited subset of the Internet banking functionality to customers via their mobile device."", $tags=""Mobile App"")
+ Container(InternetBankingSystem__SinglePageApplication__HASH10, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."", $tags=""Web Browser"")
+ Container(InternetBankingSystem__WebApplication__HASH11, ""Web Application"", ""Java and Spring MVC"", ""Delivers the static content and the Internet banking single page application."")
}
-Rel_Left(InternetBankingSystem__APIApplication__2c36bed, InternetBankingSystem__Database__18307f7, ""Reads from and writes to"", ""JDBC"")
-Rel_Up(InternetBankingSystem__APIApplication__2c36bed, EmailSystem__2908eb9, ""Sends e-mail using"", ""SMTP"")
-Rel_Left(InternetBankingSystem__APIApplication__2c36bed, MainframeBankingSystem__f50ffa, ""Uses"", ""XML/HTTPS"")
-Rel_Up(EmailSystem__2908eb9, PersonalBankingCustomer__9bc576, ""Sends e-mails to"")
-Rel(InternetBankingSystem__MobileApp__38a070b, InternetBankingSystem__APIApplication__2c36bed, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__MobileApp__38a070b, ""Uses"")
-Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__SinglePageApplication__1414c79, ""Uses"")
-Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__WebApplication__1bb919c, ""Uses"", ""HTTPS"")
-Rel(InternetBankingSystem__SinglePageApplication__1414c79, InternetBankingSystem__APIApplication__2c36bed, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel_Right(InternetBankingSystem__WebApplication__1bb919c, InternetBankingSystem__SinglePageApplication__1414c79, ""Delivers to the customer's web browser"")
+Rel_Left(InternetBankingSystem__APIApplication__HASH7, InternetBankingSystem__Database__HASH8, ""Reads from and writes to"", ""JDBC"")
+Rel_Up(InternetBankingSystem__APIApplication__HASH7, EmailSystem__HASH4, ""Sends e-mail using"", ""SMTP"")
+Rel_Left(InternetBankingSystem__APIApplication__HASH7, MainframeBankingSystem__HASH6, ""Makes API calls to"", ""XML/HTTPS"")
+Rel_Up(EmailSystem__HASH4, PersonalBankingCustomer__HASH0, ""Sends e-mails to"")
+Rel(InternetBankingSystem__MobileApp__HASH9, InternetBankingSystem__APIApplication__HASH7, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel(PersonalBankingCustomer__HASH0, InternetBankingSystem__MobileApp__HASH9, ""Views account balances, and makes payments using"")
+Rel(PersonalBankingCustomer__HASH0, InternetBankingSystem__SinglePageApplication__HASH10, ""Views account balances, and makes payments using"")
+Rel(PersonalBankingCustomer__HASH0, InternetBankingSystem__WebApplication__HASH11, ""Visits bigbank.com/ib using"", ""HTTPS"")
+Rel(InternetBankingSystem__SinglePageApplication__HASH10, InternetBankingSystem__APIApplication__HASH7, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel_Right(InternetBankingSystem__WebApplication__HASH11, InternetBankingSystem__SinglePageApplication__HASH10, ""Delivers to the customer's web browser"")
+
+SHOW_LEGEND()
@enduml
@startuml
@@ -122,374 +143,169 @@ title Internet Banking System - Containers
' Structurizr.ComponentView: Components
title Internet Banking System - API Application - Components
-LAYOUT_WITH_LEGEND()
-
-ContainerDb(InternetBankingSystem__Database__18307f7, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."")
-System(EmailSystem__2908eb9, ""E-mail System"", ""The internal Microsoft Exchange e-mail system."")
-System(MainframeBankingSystem__f50ffa, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."")
-Container(InternetBankingSystem__MobileApp__38a070b, ""Mobile App"", ""Xamarin"", ""Provides a limited subset of the Internet banking functionality to customers via their mobile device."")
-Container(InternetBankingSystem__SinglePageApplication__1414c79, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."")
-Container_Boundary(InternetBankingSystem__APIApplication__2c36bed, ""API Application"") {
- Component(InternetBankingSystem__APIApplication__AccountsSummaryController__3f81fb2, ""Accounts Summary Controller"", ""Spring MVC Rest Controller"", ""Provides customers with a summary of their bank accounts."")
- Component(InternetBankingSystem__APIApplication__EmailComponent__24ec565, ""E-mail Component"", ""Spring Bean"", ""Sends e-mails to users."")
- Component(InternetBankingSystem__APIApplication__MainframeBankingSystemFacade__2493dd9, ""Mainframe Banking System Facade"", ""Spring Bean"", ""A facade onto the mainframe banking system."")
- Component(InternetBankingSystem__APIApplication__ResetPasswordController__23f0eac, ""Reset Password Controller"", ""Spring MVC Rest Controller"", ""Allows users to reset their passwords with a single use URL."")
- Component(InternetBankingSystem__APIApplication__SecurityComponent__a4474, ""Security Component"", ""Spring Bean"", ""Provides functionality related to signing in, changing passwords, etc."")
- Component(InternetBankingSystem__APIApplication__SignInController__22cc62b, ""Sign In Controller"", ""Spring MVC Rest Controller"", ""Allows users to sign in to the Internet Banking System."")
+UpdateElementStyle(system, $bgColor = ""#1168bd"", $fontColor = ""#ffffff"", $borderColor = ""#1168bd"")
+UpdateElementStyle(container, $bgColor = ""#438dd5"", $fontColor = ""#ffffff"", $borderColor = ""#438dd5"")
+UpdateElementStyle(component, $bgColor = ""#85bbf0"", $fontColor = ""#000000"", $borderColor = ""#85bbf0"")
+UpdateElementStyle(person, $bgColor = ""#08427b"", $fontColor = ""#ffffff"", $borderColor = ""#08427b"")
+AddElementTag(Existing System, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+AddElementTag(Bank Staff, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+
+ContainerDb(InternetBankingSystem__Database__HASH8, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."", $tags=""Database"")
+System(EmailSystem__HASH4, ""E-mail System"", ""The internal Microsoft Exchange e-mail system."", $tags=""Existing System"")
+System(MainframeBankingSystem__HASH6, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."", $tags=""Existing System"")
+Container(InternetBankingSystem__MobileApp__HASH9, ""Mobile App"", ""Xamarin"", ""Provides a limited subset of the Internet banking functionality to customers via their mobile device."", $tags=""Mobile App"")
+Container(InternetBankingSystem__SinglePageApplication__HASH10, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."", $tags=""Web Browser"")
+Container_Boundary(InternetBankingSystem__APIApplication__HASH7, ""API Application"") {
+ Component(InternetBankingSystem__APIApplication__AccountsSummaryController__HASH12, ""Accounts Summary Controller"", ""Spring MVC Rest Controller"", ""Provides customers with a summary of their bank accounts."")
+ Component(InternetBankingSystem__APIApplication__EmailComponent__HASH13, ""E-mail Component"", ""Spring Bean"", ""Sends e-mails to users."")
+ Component(InternetBankingSystem__APIApplication__MainframeBankingSystemFacade__HASH14, ""Mainframe Banking System Facade"", ""Spring Bean"", ""A facade onto the mainframe banking system."")
+ Component(InternetBankingSystem__APIApplication__ResetPasswordController__HASH15, ""Reset Password Controller"", ""Spring MVC Rest Controller"", ""Allows users to reset their passwords with a single use URL."")
+ Component(InternetBankingSystem__APIApplication__SecurityComponent__HASH16, ""Security Component"", ""Spring Bean"", ""Provides functionality related to signing in, changing passwords, etc."")
+ Component(InternetBankingSystem__APIApplication__SignInController__HASH17, ""Sign In Controller"", ""Spring MVC Rest Controller"", ""Allows users to sign in to the Internet Banking System."")
}
-Rel(InternetBankingSystem__APIApplication__AccountsSummaryController__3f81fb2, InternetBankingSystem__APIApplication__MainframeBankingSystemFacade__2493dd9, ""Uses"")
-Rel(InternetBankingSystem__APIApplication__EmailComponent__24ec565, EmailSystem__2908eb9, ""Sends e-mail using"")
-Rel(InternetBankingSystem__APIApplication__MainframeBankingSystemFacade__2493dd9, MainframeBankingSystem__f50ffa, ""Uses"", ""XML/HTTPS"")
-Rel(InternetBankingSystem__MobileApp__38a070b, InternetBankingSystem__APIApplication__AccountsSummaryController__3f81fb2, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel(InternetBankingSystem__MobileApp__38a070b, InternetBankingSystem__APIApplication__ResetPasswordController__23f0eac, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel(InternetBankingSystem__MobileApp__38a070b, InternetBankingSystem__APIApplication__SignInController__22cc62b, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel(InternetBankingSystem__APIApplication__ResetPasswordController__23f0eac, InternetBankingSystem__APIApplication__EmailComponent__24ec565, ""Uses"")
-Rel(InternetBankingSystem__APIApplication__ResetPasswordController__23f0eac, InternetBankingSystem__APIApplication__SecurityComponent__a4474, ""Uses"")
-Rel(InternetBankingSystem__APIApplication__SecurityComponent__a4474, InternetBankingSystem__Database__18307f7, ""Reads from and writes to"", ""JDBC"")
-Rel(InternetBankingSystem__APIApplication__SignInController__22cc62b, InternetBankingSystem__APIApplication__SecurityComponent__a4474, ""Uses"")
-Rel(InternetBankingSystem__SinglePageApplication__1414c79, InternetBankingSystem__APIApplication__AccountsSummaryController__3f81fb2, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel(InternetBankingSystem__SinglePageApplication__1414c79, InternetBankingSystem__APIApplication__ResetPasswordController__23f0eac, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel(InternetBankingSystem__SinglePageApplication__1414c79, InternetBankingSystem__APIApplication__SignInController__22cc62b, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel(InternetBankingSystem__APIApplication__AccountsSummaryController__HASH12, InternetBankingSystem__APIApplication__MainframeBankingSystemFacade__HASH14, ""Uses"")
+Rel(InternetBankingSystem__APIApplication__EmailComponent__HASH13, EmailSystem__HASH4, ""Sends e-mail using"")
+Rel(InternetBankingSystem__APIApplication__MainframeBankingSystemFacade__HASH14, MainframeBankingSystem__HASH6, ""Uses"", ""XML/HTTPS"")
+Rel(InternetBankingSystem__MobileApp__HASH9, InternetBankingSystem__APIApplication__AccountsSummaryController__HASH12, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel(InternetBankingSystem__MobileApp__HASH9, InternetBankingSystem__APIApplication__ResetPasswordController__HASH15, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel(InternetBankingSystem__MobileApp__HASH9, InternetBankingSystem__APIApplication__SignInController__HASH17, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel(InternetBankingSystem__APIApplication__ResetPasswordController__HASH15, InternetBankingSystem__APIApplication__EmailComponent__HASH13, ""Uses"")
+Rel(InternetBankingSystem__APIApplication__ResetPasswordController__HASH15, InternetBankingSystem__APIApplication__SecurityComponent__HASH16, ""Uses"")
+Rel(InternetBankingSystem__APIApplication__SecurityComponent__HASH16, InternetBankingSystem__Database__HASH8, ""Reads from and writes to"", ""JDBC"")
+Rel(InternetBankingSystem__APIApplication__SignInController__HASH17, InternetBankingSystem__APIApplication__SecurityComponent__HASH16, ""Uses"")
+Rel(InternetBankingSystem__SinglePageApplication__HASH10, InternetBankingSystem__APIApplication__AccountsSummaryController__HASH12, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel(InternetBankingSystem__SinglePageApplication__HASH10, InternetBankingSystem__APIApplication__ResetPasswordController__HASH15, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel(InternetBankingSystem__SinglePageApplication__HASH10, InternetBankingSystem__APIApplication__SignInController__HASH17, ""Makes API calls to"", ""JSON/HTTPS"")
+
+SHOW_LEGEND()
@enduml
@startuml
-!include
-' C4_Dynamic.puml is missing, simulate it with following definitions
-' Scope: Interactions in an enterprise, software system or container.
-' Primary and supporting elements: Depends on the diagram scope -
-' enterprise - people and software systems related to the enterprise in scope
-' software system - see system context or container diagrams,
-' container - see component diagram.
-' Intended audience: Technical and non-technical people, inside and outside of the software development team.
-
-' Dynamic diagram introduces (automatically) numbered interactions:
-' Interact(): used automatic calculated index,
-' Interact2(): index can be explicit defined,
-' SetIndex(): set the next index,
-' GetIndex(): get the index and automatically increase index
-
-' Index
-' ##################################
-
-!function $inc_($value, $step=1)
- !return $value + $step
-!endfunction
-
-!$index=1
-
-!function SetIndex($new_index)
- !$index=$new_index
-!endfunction
-
-!function GetIndex($auto_increase=1)
- !$old = $index
- !$index=$inc_($index, $auto_increase)
- !return $old
-!endfunction
-
-' Interact
-' ##################################
-!define Interact2(e_index, e_from, e_to, e_label) Rel(e_from, e_to, ""e_index: e_label"")
-!define Interact2(e_index, e_from, e_to, e_label, e_techn) Rel(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_Back(e_index, e_from, e_to, e_label) Rel_Back(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Back(e_index, e_from, e_to, e_label, e_techn) Rel_Back(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_Neighbor(e_index, e_from, e_to, e_label) Rel_Neighbor(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Neighbor(e_index, e_from, e_to, e_label, e_techn) Rel_Neighbor(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_Back_Neighbor(e_index, e_from, e_to, e_label) Rel_Back_Neighbor(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Back_Neighbor(e_index, e_from, e_to, e_label, e_techn) Rel_Back_Neighbor(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_D(e_index, e_from, e_to, e_label) Rel_D(e_from, e_to, ""e_index: e_label"")
-!define Interact2_D(e_index, e_from, e_to, e_label, e_techn) Rel_D(e_from, e_to, ""e_index: e_label"", e_techn)
-!define Interact2_Down(e_index, e_from, e_to, e_label) Rel_Down(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Down(e_index, e_from, e_to, e_label, e_techn) Rel_Down(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_U(e_index, e_from, e_to, e_label) Rel_U(e_from, e_to, ""e_index: e_label"")
-!define Interact2_U(e_index, e_from, e_to, e_label, e_techn) Rel_U(e_from, e_to, ""e_index: e_label"", e_techn)
-!define Interact2_Up(e_index, e_from, e_to, e_label) Rel_Up(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Up(e_index, e_from, e_to, e_label, e_techn) Rel_Up(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_L(e_index, e_from, e_to, e_label) Rel_L(e_from, e_to, ""e_index: e_label"")
-!define Interact2_L(e_index, e_from, e_to, e_label, e_techn) Rel_L(e_from, e_to, ""e_index: e_label"", e_techn)
-!define Interact2_Left(e_index, e_from, e_to, e_label) Rel_Left(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Left(e_index, e_from, e_to, e_label, e_techn) Rel_Left(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_R(e_index, e_from, e_to, e_label) Rel_R(e_from, e_to, ""e_index: e_label"")
-!define Interact2_R(e_index, e_from, e_to, e_label, e_techn) Rel_R(e_from, e_to, ""e_index: e_label"", e_techn)
-!define Interact2_Right(e_index, e_from, e_to, e_label) Rel_Right(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Right(e_index, e_from, e_to, e_label, e_techn) Rel_Right(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!unquoted function Interact($e_from, $e_to, $e_label)
- Interact2($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact($e_from, $e_to, $e_label, $e_techn)
- Interact2($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_Back($e_from, $e_to, $e_label)
- Interact2_Back($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Back($e_from, $e_to, $e_label, $e_techn)
- Interact2_Back($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_Neighbor($e_from, $e_to, $e_label)
- Interact2_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Neighbor($e_from, $e_to, $e_label, $e_techn)
- Interact2_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_Back_Neighbor($e_from, $e_to, $e_label)
- Interact2_Back_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Back_Neighbor($e_from, $e_to, $e_label, $e_techn)
- Interact2_Back_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_D($e_from, $e_to, $e_label)
- Interact2_D($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_D($e_from, $e_to, $e_label, $e_techn)
- Interact2_D($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Down($e_from, $e_to, $e_label)
- Interact2_Down($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Down($e_from, $e_to, $e_label, $e_techn)
- Interact2_Down($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_U($e_from, $e_to, $e_label)
- Interact2_U($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_U($e_from, $e_to, $e_label, $e_techn)
- Interact2_U($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Up($e_from, $e_to, $e_label)
- Interact2_Up($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Up($e_from, $e_to, $e_label, $e_techn)
- Interact2_Up($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_L($e_from, $e_to, $e_label)
- Interact2_L($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_L($e_from, $e_to, $e_label, $e_techn)
- Interact2_L($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Left($e_from, $e_to, $e_label)
- Interact2_Left($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Left($e_from, $e_to, $e_label, $e_techn)
- Interact2_Left($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_R($e_from, $e_to, $e_label)
- Interact2_R($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_R($e_from, $e_to, $e_label, $e_techn)
- Interact2_R($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Right($e_from, $e_to, $e_label)
- Interact2_Right($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Right($e_from, $e_to, $e_label, $e_techn)
- Interact2_Right($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
+!include
' Structurizr.DynamicView: SignIn
title API Application - Dynamic
-LAYOUT_WITH_LEGEND()
-
-ContainerDb(InternetBankingSystem__Database__18307f7, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."")
-Container(InternetBankingSystem__SinglePageApplication__1414c79, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."")
-Container_Boundary(InternetBankingSystem__APIApplication__2c36bed, ""API Application"") {
- Component(InternetBankingSystem__APIApplication__SecurityComponent__a4474, ""Security Component"", ""Spring Bean"", ""Provides functionality related to signing in, changing passwords, etc."")
- Component(InternetBankingSystem__APIApplication__SignInController__22cc62b, ""Sign In Controller"", ""Spring MVC Rest Controller"", ""Allows users to sign in to the Internet Banking System."")
+UpdateElementStyle(system, $bgColor = ""#1168bd"", $fontColor = ""#ffffff"", $borderColor = ""#1168bd"")
+UpdateElementStyle(container, $bgColor = ""#438dd5"", $fontColor = ""#ffffff"", $borderColor = ""#438dd5"")
+UpdateElementStyle(component, $bgColor = ""#85bbf0"", $fontColor = ""#000000"", $borderColor = ""#85bbf0"")
+UpdateElementStyle(person, $bgColor = ""#08427b"", $fontColor = ""#ffffff"", $borderColor = ""#08427b"")
+AddElementTag(Existing System, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+AddElementTag(Bank Staff, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+
+ContainerDb(InternetBankingSystem__Database__HASH8, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."", $tags=""Database"")
+Container(InternetBankingSystem__SinglePageApplication__HASH10, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."", $tags=""Web Browser"")
+Container_Boundary(InternetBankingSystem__APIApplication__HASH7, ""API Application"") {
+ Component(InternetBankingSystem__APIApplication__SecurityComponent__HASH16, ""Security Component"", ""Spring Bean"", ""Provides functionality related to signing in, changing passwords, etc."")
+ Component(InternetBankingSystem__APIApplication__SignInController__HASH17, ""Sign In Controller"", ""Spring MVC Rest Controller"", ""Allows users to sign in to the Internet Banking System."")
}
-Interact2_Right(""1"", InternetBankingSystem__SinglePageApplication__1414c79, InternetBankingSystem__APIApplication__SignInController__22cc62b, ""Submits credentials to"", ""JSON/HTTPS"")
-Interact2(""2"", InternetBankingSystem__APIApplication__SignInController__22cc62b, InternetBankingSystem__APIApplication__SecurityComponent__a4474, ""Calls isAuthenticated() on"")
-Interact2_Right(""3"", InternetBankingSystem__APIApplication__SecurityComponent__a4474, InternetBankingSystem__Database__18307f7, ""select * from users where username = ?"", ""JDBC"")
+RelIndex_Right(""1"", InternetBankingSystem__SinglePageApplication__HASH10, InternetBankingSystem__APIApplication__SignInController__HASH17, ""Submits credentials to"", ""JSON/HTTPS"")
+RelIndex(""2"", InternetBankingSystem__APIApplication__SignInController__HASH17, InternetBankingSystem__APIApplication__SecurityComponent__HASH16, ""Validates credentials using"")
+RelIndex_Right(""3"", InternetBankingSystem__APIApplication__SecurityComponent__HASH16, InternetBankingSystem__Database__HASH8, ""select * from users where username = ?"", ""JDBC"")
+RelIndex_Left(""4"", InternetBankingSystem__Database__HASH8, InternetBankingSystem__APIApplication__SecurityComponent__HASH16, ""Returns user data to"", ""JDBC"", $tags=""Back"")
+RelIndex(""5"", InternetBankingSystem__APIApplication__SecurityComponent__HASH16, InternetBankingSystem__APIApplication__SignInController__HASH17, ""Returns true if the hashed password matches"", $tags=""Back"")
+RelIndex_Left(""6"", InternetBankingSystem__APIApplication__SignInController__HASH17, InternetBankingSystem__SinglePageApplication__HASH10, ""Sends back an authentication token to"", ""JSON/HTTPS"", $tags=""Back"")
+
+SHOW_LEGEND()
@enduml
@startuml
-!include
-' C4_Deployment.puml is missing, simulate it with following definitions
-' Scope: A single software system.
-' Primary elements: Deployment nodes and containers within the software system in scope.
-' Intended audience: Technical people inside and outside of the software development team; including software architects, developers and operations/support staff.
-
-' Colors
-' ##################################
-!define NODE_FONT_COLOR #444444
-!define NODE_BG_COLOR #FFFFFF
-
-' Styling
-' ##################################
-
-skinparam rectangle<> {
- Shadowing false
- StereotypeFontSize 0
- FontColor NODE_FONT_COLOR
- BackgroundColor NODE_BG_COLOR
- BorderColor #444444
-}
-
-' Layout
-' ##################################
-
-!definelong LAYOUT_WITH_LEGEND
-hide stereotype
-legend right
-|= |= Type |
-| | deployment node |
-| | deployment container |
-endlegend
-!enddefinelong
-
-' Nodes
-' ##################################
-' PlantUML does not support automatic line breaks of container, if e_techn is very long insert line breaks with
-' ""\n""
-!define Node(e_alias, e_label, e_techn) rectangle ""==e_label\n[e_techn]"" <> as e_alias
+!include
' Structurizr.DeploymentView: DevelopmentDeployment
-title Internet Banking System - Deployment
-
-LAYOUT_WITH_LEGEND()
-
-Node(Deployment__Development__DeveloperLaptop__389f399, ""Developer Laptop"", ""Microsoft Windows 10 or Apple \nmacOS"") {
- Node(Deployment__Development__DeveloperLaptop__DockerContainerWebServer__1b73d2e, ""Docker Container - Web Server"", ""Docker"") {
- Node(Deployment__Development__DeveloperLaptop__DockerContainerWebServer__ApacheTomcat__1cc9f55, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
- Container(InternetBankingSystem__WebApplication1__28f79f6, ""Web Application"", ""Java and Spring MVC"", ""Delivers the static content and the Internet banking single page application."")
- Container(InternetBankingSystem__APIApplication1__1f227f4, ""API Application"", ""Java and Spring MVC"", ""Provides Internet banking functionality via a JSON/HTTPS API."")
+title Internet Banking System - Deployment - Development
+
+UpdateElementStyle(system, $bgColor = ""#1168bd"", $fontColor = ""#ffffff"", $borderColor = ""#1168bd"")
+UpdateElementStyle(container, $bgColor = ""#438dd5"", $fontColor = ""#ffffff"", $borderColor = ""#438dd5"")
+UpdateElementStyle(component, $bgColor = ""#85bbf0"", $fontColor = ""#000000"", $borderColor = ""#85bbf0"")
+UpdateElementStyle(person, $bgColor = ""#08427b"", $fontColor = ""#ffffff"", $borderColor = ""#08427b"")
+AddElementTag(Existing System, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+AddElementTag(Bank Staff, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+
+Node(BigBankplc__HASH18, ""Big Bank plc"", ""Big Bank plc data center"") {
+ Node(bigbankdev001__HASH19, ""bigbank-dev001"") {
+ System(MainframeBankingSystem1__HASH20, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."", $tags=""Software System Instance"")
+ }
+}
+Node(DeveloperLaptop__HASH21, ""Developer Laptop"", ""Microsoft Windows 10 or Apple macOS"") {
+ Node(DockerContainerWebServer__HASH22, ""Docker Container - Web Server"", ""Docker"") {
+ Node(ApacheTomcat__HASH23, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+ Container(InternetBankingSystem__WebApplication1__HASH24, ""Web Application"", ""Java and Spring MVC"", ""Delivers the static content and the Internet banking single page application."", $tags=""Container Instance"")
+ Container(InternetBankingSystem__APIApplication1__HASH25, ""API Application"", ""Java and Spring MVC"", ""Provides Internet banking functionality via a JSON/HTTPS API."", $tags=""Container Instance"")
}
}
- Node(Deployment__Development__DeveloperLaptop__DockerContainerDatabaseServer__2eae566, ""Docker Container - Database Server"", ""Docker"") {
- Node(Deployment__Development__DeveloperLaptop__DockerContainerDatabaseServer__DatabaseServer__24d13de, ""Database Server"", ""Oracle 12c"") {
- ContainerDb(InternetBankingSystem__Database1__3296ca6, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."")
+ Node(DockerContainerDatabaseServer__HASH26, ""Docker Container - Database Server"", ""Docker"") {
+ Node(DatabaseServer__HASH27, ""Database Server"", ""Oracle 12c"") {
+ ContainerDb(InternetBankingSystem__Database1__HASH28, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."", $tags=""Container Instance"")
}
}
- Node(Deployment__Development__DeveloperLaptop__WebBrowser__3930fd, ""Web Browser"", ""Google Chrome, Mozilla \nFirefox, Apple Safari or \nMicrosoft Edge"") {
- Container(InternetBankingSystem__SinglePageApplication1__bbe85d, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."")
+ Node(WebBrowser__HASH29, ""Web Browser"", ""Chrome, Firefox, Safari, or Edge"") {
+ Container(InternetBankingSystem__SinglePageApplication1__HASH30, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."", $tags=""Container Instance"")
}
}
-Rel(InternetBankingSystem__APIApplication1__1f227f4, InternetBankingSystem__Database1__3296ca6, ""Reads from and writes to"", ""JDBC"")
-Rel(InternetBankingSystem__SinglePageApplication1__bbe85d, InternetBankingSystem__APIApplication1__1f227f4, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel_Up(InternetBankingSystem__WebApplication1__28f79f6, InternetBankingSystem__SinglePageApplication1__bbe85d, ""Delivers to the customer's web browser"")
+Rel(InternetBankingSystem__APIApplication1__HASH25, InternetBankingSystem__Database1__HASH28, ""Reads from and writes to"", ""JDBC"")
+Rel(InternetBankingSystem__APIApplication1__HASH25, MainframeBankingSystem1__HASH20, ""Makes API calls to"", ""XML/HTTPS"")
+Rel(InternetBankingSystem__SinglePageApplication1__HASH30, InternetBankingSystem__APIApplication1__HASH25, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel_Up(InternetBankingSystem__WebApplication1__HASH24, InternetBankingSystem__SinglePageApplication1__HASH30, ""Delivers to the customer's web browser"")
+
+SHOW_LEGEND()
@enduml
@startuml
-!include
-' C4_Deployment.puml is missing, simulate it with following definitions
-' Scope: A single software system.
-' Primary elements: Deployment nodes and containers within the software system in scope.
-' Intended audience: Technical people inside and outside of the software development team; including software architects, developers and operations/support staff.
-
-' Colors
-' ##################################
-!define NODE_FONT_COLOR #444444
-!define NODE_BG_COLOR #FFFFFF
-
-' Styling
-' ##################################
-
-skinparam rectangle<> {
- Shadowing false
- StereotypeFontSize 0
- FontColor NODE_FONT_COLOR
- BackgroundColor NODE_BG_COLOR
- BorderColor #444444
-}
-
-' Layout
-' ##################################
-
-!definelong LAYOUT_WITH_LEGEND
-hide stereotype
-legend right
-|= |= Type |
-| | deployment node |
-| | deployment container |
-endlegend
-!enddefinelong
-
-' Nodes
-' ##################################
-' PlantUML does not support automatic line breaks of container, if e_techn is very long insert line breaks with
-' ""\n""
-!define Node(e_alias, e_label, e_techn) rectangle ""==e_label\n[e_techn]"" <> as e_alias
+!include
' Structurizr.DeploymentView: LiveDeployment
-title Internet Banking System - Deployment
-
-LAYOUT_WITH_LEGEND()
-
-Node(Deployment__Live__BigBankplc__3ffe15e, ""Big Bank plc"", ""Big Bank plc data center"") {
- Node(Deployment__Live__BigBankplc__bigbankweb***__3f92e18, ""bigbank-web*** (x4)"", ""Ubuntu 16.04 LTS"") {
- Node(Deployment__Live__BigBankplc__bigbankweb***__ApacheTomcat__27b4383, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
- Container(InternetBankingSystem__WebApplication2__1720850, ""Web Application"", ""Java and Spring MVC"", ""Delivers the static content and the Internet banking single page application."")
+title Internet Banking System - Deployment - Live
+
+UpdateElementStyle(system, $bgColor = ""#1168bd"", $fontColor = ""#ffffff"", $borderColor = ""#1168bd"")
+UpdateElementStyle(container, $bgColor = ""#438dd5"", $fontColor = ""#ffffff"", $borderColor = ""#438dd5"")
+UpdateElementStyle(component, $bgColor = ""#85bbf0"", $fontColor = ""#000000"", $borderColor = ""#85bbf0"")
+UpdateElementStyle(person, $bgColor = ""#08427b"", $fontColor = ""#ffffff"", $borderColor = ""#08427b"")
+AddElementTag(Existing System, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+AddElementTag(Bank Staff, $bgColor = ""#999999"", $fontColor = ""#ffffff"", $borderColor = ""#999999"")
+
+Node(BigBankplc__HASH31, ""Big Bank plc"", ""Big Bank plc data center"") {
+ Node(bigbankprod001__HASH32, ""bigbank-prod001"") {
+ System(MainframeBankingSystem1__HASH33, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."", $tags=""Software System Instance"")
+ }
+ Node(bigbankweb***__HASH34, ""bigbank-web*** (x4)"", ""Ubuntu 16.04 LTS"") {
+ Node(ApacheTomcat__HASH35, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+ Container(InternetBankingSystem__WebApplication1__HASH36, ""Web Application"", ""Java and Spring MVC"", ""Delivers the static content and the Internet banking single page application."", $tags=""Container Instance"")
}
}
- Node(Deployment__Live__BigBankplc__bigbankapi***__263d9e8, ""bigbank-api*** (x8)"", ""Ubuntu 16.04 LTS"") {
- Node(Deployment__Live__BigBankplc__bigbankapi***__ApacheTomcat__3b84ab, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
- Container(InternetBankingSystem__APIApplication2__1408a33, ""API Application"", ""Java and Spring MVC"", ""Provides Internet banking functionality via a JSON/HTTPS API."")
+ Node(bigbankapi***__HASH37, ""bigbank-api*** (x8)"", ""Ubuntu 16.04 LTS"") {
+ Node(ApacheTomcat__HASH38, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+ Container(InternetBankingSystem__APIApplication1__HASH39, ""API Application"", ""Java and Spring MVC"", ""Provides Internet banking functionality via a JSON/HTTPS API."", $tags=""Container Instance"")
}
}
- Node(Deployment__Live__BigBankplc__bigbankdb01__35ec592, ""bigbank-db01"", ""Ubuntu 16.04 LTS"") {
- Node(Deployment__Live__BigBankplc__bigbankdb01__OraclePrimary__19fd8f, ""Oracle - Primary"", ""Oracle 12c"") {
- ContainerDb(InternetBankingSystem__Database2__1c974ec, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."")
+ Node(bigbankdb01__HASH40, ""bigbank-db01"", ""Ubuntu 16.04 LTS"") {
+ Node(OraclePrimary__HASH41, ""Oracle - Primary"", ""Oracle 12c"") {
+ ContainerDb(InternetBankingSystem__Database1__HASH42, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."", $tags=""Container Instance"")
}
}
- Node(Deployment__Live__BigBankplc__bigbankdb02__1db08a2, ""bigbank-db02"", ""Ubuntu 16.04 LTS"") {
- Node(Deployment__Live__BigBankplc__bigbankdb02__OracleSecondary__1c4ec22, ""Oracle - Secondary"", ""Oracle 12c"") {
- ContainerDb(InternetBankingSystem__Database3__d89394, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."")
+ Node(bigbankdb02__HASH43, ""bigbank-db02"", ""Ubuntu 16.04 LTS"") {
+ Node(OracleSecondary__HASH44, ""Oracle - Secondary"", ""Oracle 12c"") {
+ ContainerDb(InternetBankingSystem__Database1__HASH45, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."", $tags=""Failover+Container Instance"")
}
}
}
-Node(Deployment__Live__Customer'scomputer__2510bf3, ""Customer's computer"", ""Microsoft Windows or Apple \nmacOS"") {
- Node(Deployment__Live__Customer'scomputer__WebBrowser__ba951, ""Web Browser"", ""Google Chrome, Mozilla \nFirefox, Apple Safari or \nMicrosoft Edge"") {
- Container(InternetBankingSystem__SinglePageApplication2__298b31c, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."")
+Node(Customer'scomputer__HASH46, ""Customer's computer"", ""Microsoft Windows or Apple macOS"") {
+ Node(WebBrowser__HASH47, ""Web Browser"", ""Chrome, Firefox, Safari, or Edge"") {
+ Container(InternetBankingSystem__SinglePageApplication1__HASH48, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."", $tags=""Container Instance"")
}
}
-Node(Deployment__Live__Customer'smobiledevice__1d6bcb6, ""Customer's mobile device"", ""Apple iOS or Android"") {
- Container(InternetBankingSystem__MobileApp1__d004b3, ""Mobile App"", ""Xamarin"", ""Provides a limited subset of the Internet banking functionality to customers via their mobile device."")
+Node(Customer'smobiledevice__HASH49, ""Customer's mobile device"", ""Apple iOS or Android"") {
+ Container(InternetBankingSystem__MobileApp1__HASH50, ""Mobile App"", ""Xamarin"", ""Provides a limited subset of the Internet banking functionality to customers via their mobile device."", $tags=""Container Instance"")
}
-Rel(InternetBankingSystem__APIApplication2__1408a33, InternetBankingSystem__Database2__1c974ec, ""Reads from and writes to"", ""JDBC"")
-Rel(InternetBankingSystem__APIApplication2__1408a33, InternetBankingSystem__Database3__d89394, ""Reads from and writes to"", ""JDBC"")
-Rel(InternetBankingSystem__MobileApp1__d004b3, InternetBankingSystem__APIApplication2__1408a33, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel(InternetBankingSystem__SinglePageApplication2__298b31c, InternetBankingSystem__APIApplication2__1408a33, ""Makes API calls to"", ""JSON/HTTPS"")
-Rel_Up(InternetBankingSystem__WebApplication2__1720850, InternetBankingSystem__SinglePageApplication2__298b31c, ""Delivers to the customer's web browser"")
-Rel_Left(Deployment__Live__BigBankplc__bigbankdb01__OraclePrimary__19fd8f, Deployment__Live__BigBankplc__bigbankdb02__OracleSecondary__1c4ec22, ""Replicates data to"")
+Rel(InternetBankingSystem__APIApplication1__HASH39, InternetBankingSystem__Database1__HASH42, ""Reads from and writes to"", ""JDBC"")
+Rel(InternetBankingSystem__APIApplication1__HASH39, InternetBankingSystem__Database1__HASH45, ""Reads from and writes to"", ""JDBC"", $tags=""Failover"")
+Rel(InternetBankingSystem__APIApplication1__HASH39, MainframeBankingSystem1__HASH33, ""Makes API calls to"", ""XML/HTTPS"")
+Rel(InternetBankingSystem__MobileApp1__HASH50, InternetBankingSystem__APIApplication1__HASH39, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel_Left(OraclePrimary__HASH41, OracleSecondary__HASH44, ""Replicates data to"")
+Rel(InternetBankingSystem__SinglePageApplication1__HASH48, InternetBankingSystem__APIApplication1__HASH39, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel_Up(InternetBankingSystem__WebApplication1__HASH36, InternetBankingSystem__SinglePageApplication1__HASH48, ""Delivers to the customer's web browser"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -504,9 +320,9 @@ private void AddLayoutDetails(Workspace workspace)
// all SystemLandscapeView, SystemContext, ... (update relation):
// Rel_Up(EmailSystem, PersonalBankingCustomer, ""Sends e-mails to"")
// Rel_Right(InternetBankingSystem, EmailSystem, ""Sends e-mail using"")
- var emailSystem = workspace.Model.GetElementWithCanonicalName("/E-mail System");
- var personalBankingCustomer = workspace.Model.GetElementWithCanonicalName("/Personal Banking Customer");
- var internetBankingSystem = workspace.Model.GetElementWithCanonicalName("/Internet Banking System");
+ var emailSystem = workspace.Model.GetElementWithCanonicalOrStaticalName("SoftwareSystem://E-mail System");
+ var personalBankingCustomer = workspace.Model.GetElementWithCanonicalOrStaticalName("Person://Personal Banking Customer");
+ var internetBankingSystem = workspace.Model.GetElementWithCanonicalOrStaticalName("SoftwareSystem://Internet Banking System");
var systemLandscapeView = workspace.Views.SystemLandscapeViews.First();
systemLandscapeView.Relationships
@@ -519,7 +335,7 @@ private void AddLayoutDetails(Workspace workspace)
.SetDirection(DirectionValues.Right);
// but only SystemLandscapeView should use Down relations, therefore add the tags relation view specific (via AddViewTags)
- var mainframeBankingSystem = workspace.Model.GetElementWithCanonicalName("/Mainframe Banking System");
+ var mainframeBankingSystem = workspace.Model.GetElementWithCanonicalOrStaticalName("SoftwareSystem://Mainframe Banking System");
foreach (var relationshipView in systemLandscapeView.Relationships
.Where(rv => rv.Relationship.DestinationId == mainframeBankingSystem.Id))
{
@@ -534,31 +350,41 @@ private void AddLayoutDetails(Workspace workspace)
.SetDirection(DirectionValues.Down);
// DynamicView
- // Rel_Right(InternetBankingSystem__SinglePageApplication, InternetBankingSystem__APIApplication__SignInController, ...)
- // Rel_Right(InternetBankingSystem__APIApplication__SecurityComponent, InternetBankingSystem__Database, ...)
+ // RelIndex_Right(""1"", InternetBankingSystem__SinglePageApplication__1414c79, InternetBankingSystem__APIApplication__SignInController__22cc62b, ""Submits credentials to"", ""JSON/HTTPS"")
+ // RelIndex_Right(""3"", InternetBankingSystem__APIApplication__SecurityComponent__a4474, InternetBankingSystem__Database__18307f7, ""select * from users where username = ?"", ""JDBC"")
+ // Response switch displayed order - RelIndex_Left(""4"", InternetBankingSystem__Database__18307f7, InternetBankingSystem__APIApplication__SecurityComponent__a4474, ""Returns user data to"", ""JDBC"")
+ // Response switch displayed order - RelIndex_Left(""6"", InternetBankingSystem__APIApplication__SignInController__22cc62b, InternetBankingSystem__SinglePageApplication__1414c79, ""Sends back an authentication token to"", ""JSON/HTTPS"")
var singlePageApplication =
- workspace.Model.GetElementWithCanonicalName("/Internet Banking System/Single-Page Application");
+ workspace.Model.GetElementWithCanonicalOrStaticalName("Container://Internet Banking System.Single-Page Application");
var signInController =
- workspace.Model.GetElementWithCanonicalName("/Internet Banking System/API Application/Sign In Controller");
+ workspace.Model.GetElementWithCanonicalOrStaticalName("Component://Internet Banking System.API Application.Sign In Controller");
var securityComponent =
- workspace.Model.GetElementWithCanonicalName("/Internet Banking System/API Application/Security Component");
- var database = workspace.Model.GetElementWithCanonicalName("/Internet Banking System/Database") as Container;
+ workspace.Model.GetElementWithCanonicalOrStaticalName("Component://Internet Banking System.API Application.Security Component");
+ var database = workspace.Model.GetElementWithCanonicalOrStaticalName("Container://Internet Banking System.Database") as Container;
database.SetIsDatabase(true);
var dynamicView = workspace.Views.DynamicViews.First();
dynamicView.Relationships
- .First(r => r.Relationship.SourceId == singlePageApplication.Id &&
- r.Relationship.DestinationId == signInController.Id)
+ .First(r =>
+ !(r.Response ?? false) && r.Relationship.SourceId == securityComponent.Id && r.Relationship.DestinationId == database.Id)
.SetDirection(DirectionValues.Right);
dynamicView.Relationships
- .First(r => r.Relationship.SourceId == securityComponent.Id && r.Relationship.DestinationId == database.Id)
+ .First(r =>
+ !(r.Response ?? false) && r.Relationship.SourceId == singlePageApplication.Id && r.Relationship.DestinationId == signInController.Id)
.SetDirection(DirectionValues.Right);
+ // response swaps display order
+ dynamicView.Relationships
+ .First(r =>
+ (r.Response ?? false) && r.Relationship.SourceId == securityComponent.Id && r.Relationship.DestinationId == database.Id)
+ .SetDirection(DirectionValues.Left);
+ dynamicView.Relationships
+ .First(r =>
+ (r.Response ?? false) && r.Relationship.SourceId == singlePageApplication.Id && r.Relationship.DestinationId == signInController.Id)
+ .SetDirection(DirectionValues.Left);
// ContainerView
// Rel_Up(InternetBankingSystem__WebApplication, InternetBankingSystem__SinglePageApplication, "Delivers to the customer's web browser")
- var apiApplication = workspace.Model.GetElementWithCanonicalName("/Internet Banking System/API Application");
- var webApplication = workspace.Model.GetElementWithCanonicalName("/Internet Banking System/Web Application");
-
-
+ var apiApplication = workspace.Model.GetElementWithCanonicalOrStaticalName("Container://Internet Banking System.API Application");
+ var webApplication = workspace.Model.GetElementWithCanonicalOrStaticalName("Container://Internet Banking System.Web Application");
var containerView = workspace.Views.ContainerViews.First();
containerView.Relationships
.First(r => r.Relationship.SourceId == apiApplication.Id &&
@@ -584,47 +410,69 @@ private void AddLayoutDetails(Workspace workspace)
// DeploymentView´(with already copied relations): DevelopmentDeployment, LiveDeployment
// Rel_Up(InternetBankingSystem__WebApplication1, InternetBankingSystem__SinglePageApplication1, "Delivers to the customer's web browser")
// Rel_Up(InternetBankingSystem__WebApplication2, InternetBankingSystem__SinglePageApplication2, "Delivers to the customer's web browser")
- // Rel_Left(Deployment__Live__BigBankplc__bigbankdb01__OraclePrimary, Deployment__Live__BigBankplc__bigbankdb02__OracleSecondary, "Replicates data to")
- var webApplication1 = workspace.Model.GetElementWithCanonicalName("/Internet Banking System/Web Application[1]");
- var webApplication2 = workspace.Model.GetElementWithCanonicalName("/Internet Banking System/Web Application[2]");
- var singlePageApplication1 =
- workspace.Model.GetElementWithCanonicalName("/Internet Banking System/Single-Page Application[1]");
- var singlePageApplication2 =
- workspace.Model.GetElementWithCanonicalName("/Internet Banking System/Single-Page Application[2]");
- var oraclePrimary =
- workspace.Model.GetElementWithCanonicalName("/Deployment/Live/Big Bank plc/bigbank-db01/Oracle - Primary");
- var oracleSecondary =
- workspace.Model.GetElementWithCanonicalName("/Deployment/Live/Big Bank plc/bigbank-db02/Oracle - Secondary");
+ // Rel_Left(Live__BigBankplc__bigbankdb01__OraclePrimary, Live__BigBankplc__bigbankdb02__OracleSecondary, "Replicates data to")
+
+ // Model is changed that instances are counted per parent orig ...[2] cannot be used anymore, separate per view, full names have to be used
+ var developmentWebApplication =
+ workspace.Model.GetElementWithCanonicalOrStaticalName("ContainerInstance://Development/Developer Laptop/Docker Container - Web Server/Apache Tomcat/Internet Banking System.Web Application[1]");
+ var developmentSinglePageApplication =
+ workspace.Model.GetElementWithCanonicalOrStaticalName("ContainerInstance://Development/Developer Laptop/Web Browser/Internet Banking System.Single-Page Application[1]");
var developmentDeploymentView = workspace.Views.DeploymentViews.First();
- var liveDeploymentView = workspace.Views.DeploymentViews.Last();
developmentDeploymentView.Relationships
- .First(r => r.Relationship.SourceId == webApplication1.Id &&
- r.Relationship.DestinationId == singlePageApplication1.Id)
+ .First(r => r.Relationship.SourceId == developmentWebApplication.Id &&
+ r.Relationship.DestinationId == developmentSinglePageApplication.Id)
.SetDirection(DirectionValues.Up);
+
+ var liveWebApplication =
+ workspace.Model.GetElementWithCanonicalOrStaticalName("ContainerInstance://Live/Big Bank plc/bigbank-web***/Apache Tomcat/Internet Banking System.Web Application[1]");
+ var liveSinglePageApplication =
+ workspace.Model.GetElementWithCanonicalOrStaticalName("ContainerInstance://Live/Customer's computer/Web Browser/Internet Banking System.Single-Page Application[1]");
+ var liveOraclePrimary =
+ workspace.Model.GetElementWithCanonicalOrStaticalName("DeploymentNode://Live/Big Bank plc/bigbank-db01/Oracle - Primary");
+ var liveOracleSecondary =
+ workspace.Model.GetElementWithCanonicalOrStaticalName("DeploymentNode://Live/Big Bank plc/bigbank-db02/Oracle - Secondary");
+ var liveDeploymentView = workspace.Views.DeploymentViews.Last();
liveDeploymentView.Relationships
- .First(r => r.Relationship.SourceId == webApplication2.Id &&
- r.Relationship.DestinationId == singlePageApplication2.Id)
+ .First(r => r.Relationship.SourceId == liveWebApplication.Id &&
+ r.Relationship.DestinationId == liveSinglePageApplication.Id)
.SetDirection(DirectionValues.Up);
liveDeploymentView.Relationships
- .First(r => r.Relationship.SourceId == oraclePrimary.Id && r.Relationship.DestinationId == oracleSecondary.Id)
+ .First(r => r.Relationship.SourceId == liveOraclePrimary.Id && r.Relationship.DestinationId == liveOracleSecondary.Id)
.SetDirection(DirectionValues.Left);
+
+ // !!! structrizr has another border color calculation (if no value is set) details unclear; set explicit border color too
+ workspace.Views.Configuration.Styles.Elements
+ .Where(e=>!string.IsNullOrWhiteSpace(e.Background) && string.IsNullOrWhiteSpace(e.Stroke)).ToList()
+ .ForEach(e=>e.Stroke = e.Background);
+
+ /* add/update other styles
+ workspace.Views.Configuration.Styles.Add(new ElementStyle("Container Instance"){ Background = "#E0E0C0", Stroke= "#E0E0C0", Color = "#000000"});
+ workspace.Views.Configuration.Styles.Elements.Where(e=>e.Tag=="Failover").ToList()
+ .ForEach(e=> { e.Background = "#808080"; e.Stroke="#808080"; e.Color = "#FFFFFF"; });
+
+ workspace.Views.Configuration.Styles.Add(new RelationshipStyle("Relationship"){ Color = "#000000" });
+ workspace.Views.Configuration.Styles.Relationships.Where(r=>r.Tag=="Failover").ToList()
+ .ForEach(r=> { r.Color = "#808080"; r.Dashed = true; });
+ */
}
[Fact]
- public void test_writeWorkspace_WithCustomBaseUrl()
+ public void test_writeWorkspace_WithNextFeaturesCustomBaseUrl()
{
PopulateWorkspace();
- _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/";
+ _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/";
+ _plantUMLWriter.EnableNextFeatures = true;
_plantUMLWriter.Write(_workspace, _stringWriter);
Assert.Equal(
@"@startuml
-!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/C4_Context.puml
+!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/C4_Context.puml
' Structurizr.SystemLandscapeView: enterpriseContext
title System Landscape for Some Enterprise
-LAYOUT_WITH_LEGEND()
+SHOW_PERSON_OUTLINE()
+AddRelTag(""Back"", $textColor=$ARROW_COLOR, $lineColor=$ARROW_COLOR, $lineStyle = DottedLine())
System_Ext(EmailSystem__1127701, ""E-mail System"")
Enterprise_Boundary(SomeEnterprise, ""Some Enterprise"") {
@@ -634,15 +482,18 @@ public void test_writeWorkspace_WithCustomBaseUrl()
Rel(EmailSystem__1127701, User__387cc75, ""Delivers e-mails to"")
Rel(SoftwareSystem__31d545b, EmailSystem__1127701, ""Sends e-mail using"")
Rel(User__387cc75, SoftwareSystem__31d545b, ""Uses"")
+
+SHOW_LEGEND()
@enduml
@startuml
-!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/C4_Context.puml
+!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/C4_Context.puml
' Structurizr.SystemContextView: systemContext
title Software System - System Context
-LAYOUT_WITH_LEGEND()
+SHOW_PERSON_OUTLINE()
+AddRelTag(""Back"", $textColor=$ARROW_COLOR, $lineColor=$ARROW_COLOR, $lineStyle = DottedLine())
Enterprise_Boundary(SomeEnterprise, ""Some Enterprise"") {
System_Ext(EmailSystem__1127701, ""E-mail System"")
@@ -652,15 +503,18 @@ title Software System - System Context
Rel(SoftwareSystem__31d545b, EmailSystem__1127701, ""Sends e-mail using"")
Rel(User__387cc75, SoftwareSystem__31d545b, ""Uses"")
}
+
+SHOW_LEGEND()
@enduml
@startuml
-!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/C4_Container.puml
+!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/C4_Container.puml
' Structurizr.ContainerView: containers
title Software System - Containers
-LAYOUT_WITH_LEGEND()
+SHOW_PERSON_OUTLINE()
+AddRelTag(""Back"", $textColor=$ARROW_COLOR, $lineColor=$ARROW_COLOR, $lineStyle = DottedLine())
System_Ext(EmailSystem__1127701, ""E-mail System"")
Person(User__387cc75, ""User"")
@@ -672,15 +526,18 @@ title Software System - Containers
Rel(User__387cc75, SoftwareSystem__WebApplication__d2a342, """", ""HTTP"")
Rel(SoftwareSystem__WebApplication__d2a342, SoftwareSystem__Database__39bccb8, ""Reads from and writes to"", ""JDBC"")
Rel(SoftwareSystem__WebApplication__d2a342, EmailSystem__1127701, ""Sends e-mail using"")
+
+SHOW_LEGEND()
@enduml
@startuml
-!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/C4_Component.puml
+!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/C4_Component.puml
' Structurizr.ComponentView: components
title Software System - Web Application - Components
-LAYOUT_WITH_LEGEND()
+SHOW_PERSON_OUTLINE()
+AddRelTag(""Back"", $textColor=$ARROW_COLOR, $lineColor=$ARROW_COLOR, $lineStyle = DottedLine())
ContainerDb(SoftwareSystem__Database__39bccb8, ""Database"", ""Relational Database Schema"", ""Stores information"")
System_Ext(EmailSystem__1127701, ""E-mail System"")
@@ -696,15 +553,18 @@ title Software System - Web Application - Components
Rel(SoftwareSystem__WebApplication__SomeController__341621c, SoftwareSystem__WebApplication__SomeRepository__6d9009, ""Uses"")
Rel(SoftwareSystem__WebApplication__SomeRepository__6d9009, SoftwareSystem__Database__39bccb8, ""Reads from and writes to"", ""JDBC"")
Rel(User__387cc75, SoftwareSystem__WebApplication__SomeController__341621c, ""Uses"", ""HTTP"")
+
+SHOW_LEGEND()
@enduml
@startuml
-!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/C4_Dynamic.puml
+!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/C4_Dynamic.puml
' Structurizr.DynamicView: dynamic
title Web Application - Dynamic
-LAYOUT_WITH_LEGEND()
+SHOW_PERSON_OUTLINE()
+AddRelTag(""Back"", $textColor=$ARROW_COLOR, $lineColor=$ARROW_COLOR, $lineStyle = DottedLine())
ContainerDb(SoftwareSystem__Database__39bccb8, ""Database"", ""Relational Database Schema"", ""Stores information"")
Person(User__387cc75, ""User"")
@@ -712,30 +572,35 @@ title Web Application - Dynamic
Component(SoftwareSystem__WebApplication__SomeController__341621c, ""SomeController"", ""Spring MVC Controller"")
Component(SoftwareSystem__WebApplication__SomeRepository__6d9009, ""SomeRepository"", ""Spring Data"")
}
-Interact2(""1"", User__387cc75, SoftwareSystem__WebApplication__SomeController__341621c, ""Requests /something"", ""HTTP"")
-Interact2(""2"", SoftwareSystem__WebApplication__SomeController__341621c, SoftwareSystem__WebApplication__SomeRepository__6d9009, """")
-Interact2(""3"", SoftwareSystem__WebApplication__SomeRepository__6d9009, SoftwareSystem__Database__39bccb8, ""select * from something"", ""JDBC"")
+RelIndex(""1"", User__387cc75, SoftwareSystem__WebApplication__SomeController__341621c, ""Requests /something"", ""HTTP"")
+RelIndex(""2"", SoftwareSystem__WebApplication__SomeController__341621c, SoftwareSystem__WebApplication__SomeRepository__6d9009, """")
+RelIndex(""3"", SoftwareSystem__WebApplication__SomeRepository__6d9009, SoftwareSystem__Database__39bccb8, ""select * from something"", ""JDBC"")
+
+SHOW_LEGEND()
@enduml
@startuml
-!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/C4_Deployment.puml
+!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/C4_Deployment.puml
' Structurizr.DeploymentView: deployment
-title Software System - Deployment
+title Software System - Deployment - Default
-LAYOUT_WITH_LEGEND()
+SHOW_PERSON_OUTLINE()
+AddRelTag(""Back"", $textColor=$ARROW_COLOR, $lineColor=$ARROW_COLOR, $lineStyle = DottedLine())
-Node(Deployment__Default__DatabaseServer__1edef6c, ""Database Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__DatabaseServer__MySQL__1fa4f18, ""MySQL"", ""MySQL 5.5.x"") {
- ContainerDb(SoftwareSystem__Database1__bb9c73, ""Database"", ""Relational Database Schema"", ""Stores information"")
+Node(DatabaseServer__1edef6c, ""Database Server"", ""Ubuntu 12.04 LTS"") {
+ Node(MySQL__1fa4f18, ""MySQL"", ""MySQL 5.5.x"") {
+ ContainerDb(SoftwareSystem__Database1__bb9c73, ""Database"", ""Relational Database Schema"", ""Stores information"", $tags=""Container Instance"")
}
}
-Node(Deployment__Default__WebServer__1e2ffe, ""Web Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__WebServer__ApacheTomcat__2b8afb4, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
- Container(SoftwareSystem__WebApplication1__31f1f25, ""Web Application"", ""Java and spring MVC"", ""Delivers content"")
+Node(WebServer__1e2ffe, ""Web Server"", ""Ubuntu 12.04 LTS"") {
+ Node(ApacheTomcat__2b8afb4, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+ Container(SoftwareSystem__WebApplication1__31f1f25, ""Web Application"", ""Java and spring MVC"", ""Delivers content"", $tags=""Container Instance"")
}
}
Rel(SoftwareSystem__WebApplication1__31f1f25, SoftwareSystem__Database1__bb9c73, ""Reads from and writes to"", ""JDBC"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -747,7 +612,7 @@ public void test_writeEnterpriseContextView()
PopulateWorkspace();
SystemLandscapeView systemLandscapeView = _workspace.Views.SystemLandscapeViews.First();
- _plantUMLWriter.Write(systemLandscapeView, _stringWriter);
+ _plantUMLWriter.Write(systemLandscapeView, _workspace.Views.Configuration, _stringWriter);
Assert.Equal(
@"@startuml
@@ -756,8 +621,6 @@ public void test_writeEnterpriseContextView()
' Structurizr.SystemLandscapeView: enterpriseContext
title System Landscape for Some Enterprise
-LAYOUT_WITH_LEGEND()
-
System_Ext(EmailSystem__1934cbe, ""E-mail System"")
Enterprise_Boundary(SomeEnterprise, ""Some Enterprise"") {
Person(User__3b843b5, ""User"")
@@ -766,6 +629,8 @@ public void test_writeEnterpriseContextView()
Rel(EmailSystem__1934cbe, User__3b843b5, ""Delivers e-mails to"")
Rel(SoftwareSystem__7134f, EmailSystem__1934cbe, ""Sends e-mail using"")
Rel(User__3b843b5, SoftwareSystem__7134f, ""Uses"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -778,18 +643,16 @@ public void test_writeEnterpriseContextView_WithCustomBaseUrl()
PopulateWorkspace();
SystemLandscapeView systemLandscapeView = _workspace.Views.SystemLandscapeViews.First();
- _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/";
- _plantUMLWriter.Write(systemLandscapeView, _stringWriter);
+ _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/";
+ _plantUMLWriter.Write(systemLandscapeView, _workspace.Views.Configuration, _stringWriter);
Assert.Equal(
@"@startuml
-!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/C4_Context.puml
+!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/C4_Context.puml
' Structurizr.SystemLandscapeView: enterpriseContext
title System Landscape for Some Enterprise
-LAYOUT_WITH_LEGEND()
-
System_Ext(EmailSystem__1934cbe, ""E-mail System"")
Enterprise_Boundary(SomeEnterprise, ""Some Enterprise"") {
Person(User__3b843b5, ""User"")
@@ -798,6 +661,8 @@ public void test_writeEnterpriseContextView_WithCustomBaseUrl()
Rel(EmailSystem__1934cbe, User__3b843b5, ""Delivers e-mails to"")
Rel(SoftwareSystem__7134f, EmailSystem__1934cbe, ""Sends e-mail using"")
Rel(User__3b843b5, SoftwareSystem__7134f, ""Uses"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -810,7 +675,7 @@ public void test_writeSystemContextView()
PopulateWorkspace();
SystemContextView systemContextView = _workspace.Views.SystemContextViews.First();
- _plantUMLWriter.Write(systemContextView, _stringWriter);
+ _plantUMLWriter.Write(systemContextView, _workspace.Views.Configuration, _stringWriter);
Assert.Equal(
@"@startuml
@@ -819,8 +684,6 @@ public void test_writeSystemContextView()
' Structurizr.SystemContextView: systemContext
title Software System - System Context
-LAYOUT_WITH_LEGEND()
-
Enterprise_Boundary(SomeEnterprise, ""Some Enterprise"") {
System_Ext(EmailSystem__1127701, ""E-mail System"")
System(SoftwareSystem__31d545b, ""Software System"")
@@ -829,6 +692,8 @@ title Software System - System Context
Rel(SoftwareSystem__31d545b, EmailSystem__1127701, ""Sends e-mail using"")
Rel(User__387cc75, SoftwareSystem__31d545b, ""Uses"")
}
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -840,7 +705,7 @@ public void test_writeContainerView()
PopulateWorkspace();
ContainerView containerView = _workspace.Views.ContainerViews.First();
- _plantUMLWriter.Write(containerView, _stringWriter);
+ _plantUMLWriter.Write(containerView, _workspace.Views.Configuration, _stringWriter);
Assert.Equal(
@"@startuml
@@ -849,8 +714,6 @@ public void test_writeContainerView()
' Structurizr.ContainerView: containers
title Software System - Containers
-LAYOUT_WITH_LEGEND()
-
System_Ext(EmailSystem__1934cbe, ""E-mail System"")
Person(User__3b843b5, ""User"")
System_Boundary(SoftwareSystem__7134f, ""Software System"") {
@@ -861,6 +724,8 @@ title Software System - Containers
Rel(User__3b843b5, SoftwareSystem__WebApplication__1cc1659, """", ""HTTP"")
Rel(SoftwareSystem__WebApplication__1cc1659, SoftwareSystem__Database__270f9f2, ""Reads from and writes to"", ""JDBC"")
Rel(SoftwareSystem__WebApplication__1cc1659, EmailSystem__1934cbe, ""Sends e-mail using"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -872,7 +737,7 @@ public void test_writeComponentsView()
PopulateWorkspace();
ComponentView componentView = _workspace.Views.ComponentViews.First();
- _plantUMLWriter.Write(componentView, _stringWriter);
+ _plantUMLWriter.Write(componentView, _workspace.Views.Configuration, _stringWriter);
Assert.Equal(
@"@startuml
@@ -881,8 +746,6 @@ public void test_writeComponentsView()
' Structurizr.ComponentView: components
title Software System - Web Application - Components
-LAYOUT_WITH_LEGEND()
-
ContainerDb(SoftwareSystem__Database__270f9f2, ""Database"", ""Relational Database Schema"", ""Stores information"")
System_Ext(EmailSystem__1934cbe, ""E-mail System"")
Person(User__3b843b5, ""User"")
@@ -897,6 +760,8 @@ title Software System - Web Application - Components
Rel(SoftwareSystem__WebApplication__SomeController__327a713, SoftwareSystem__WebApplication__SomeRepository__23f6823, ""Uses"")
Rel(SoftwareSystem__WebApplication__SomeRepository__23f6823, SoftwareSystem__Database__270f9f2, ""Reads from and writes to"", ""JDBC"")
Rel(User__3b843b5, SoftwareSystem__WebApplication__SomeController__327a713, ""Uses"", ""HTTP"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -908,197 +773,27 @@ public void test_writeDynamicView()
PopulateWorkspace();
DynamicView dynamicView = _workspace.Views.DynamicViews.First();
- _plantUMLWriter.Write(dynamicView, _stringWriter);
+ _plantUMLWriter.Write(dynamicView, _workspace.Views.Configuration, _stringWriter);
// Dynamic diagrams can be drawn with Components
Assert.Equal(
@"@startuml
-!include
-' C4_Dynamic.puml is missing, simulate it with following definitions
-' Scope: Interactions in an enterprise, software system or container.
-' Primary and supporting elements: Depends on the diagram scope -
-' enterprise - people and software systems related to the enterprise in scope
-' software system - see system context or container diagrams,
-' container - see component diagram.
-' Intended audience: Technical and non-technical people, inside and outside of the software development team.
-
-' Dynamic diagram introduces (automatically) numbered interactions:
-' Interact(): used automatic calculated index,
-' Interact2(): index can be explicit defined,
-' SetIndex(): set the next index,
-' GetIndex(): get the index and automatically increase index
-
-' Index
-' ##################################
-
-!function $inc_($value, $step=1)
- !return $value + $step
-!endfunction
-
-!$index=1
-
-!function SetIndex($new_index)
- !$index=$new_index
-!endfunction
-
-!function GetIndex($auto_increase=1)
- !$old = $index
- !$index=$inc_($index, $auto_increase)
- !return $old
-!endfunction
-
-' Interact
-' ##################################
-!define Interact2(e_index, e_from, e_to, e_label) Rel(e_from, e_to, ""e_index: e_label"")
-!define Interact2(e_index, e_from, e_to, e_label, e_techn) Rel(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_Back(e_index, e_from, e_to, e_label) Rel_Back(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Back(e_index, e_from, e_to, e_label, e_techn) Rel_Back(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_Neighbor(e_index, e_from, e_to, e_label) Rel_Neighbor(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Neighbor(e_index, e_from, e_to, e_label, e_techn) Rel_Neighbor(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_Back_Neighbor(e_index, e_from, e_to, e_label) Rel_Back_Neighbor(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Back_Neighbor(e_index, e_from, e_to, e_label, e_techn) Rel_Back_Neighbor(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_D(e_index, e_from, e_to, e_label) Rel_D(e_from, e_to, ""e_index: e_label"")
-!define Interact2_D(e_index, e_from, e_to, e_label, e_techn) Rel_D(e_from, e_to, ""e_index: e_label"", e_techn)
-!define Interact2_Down(e_index, e_from, e_to, e_label) Rel_Down(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Down(e_index, e_from, e_to, e_label, e_techn) Rel_Down(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_U(e_index, e_from, e_to, e_label) Rel_U(e_from, e_to, ""e_index: e_label"")
-!define Interact2_U(e_index, e_from, e_to, e_label, e_techn) Rel_U(e_from, e_to, ""e_index: e_label"", e_techn)
-!define Interact2_Up(e_index, e_from, e_to, e_label) Rel_Up(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Up(e_index, e_from, e_to, e_label, e_techn) Rel_Up(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_L(e_index, e_from, e_to, e_label) Rel_L(e_from, e_to, ""e_index: e_label"")
-!define Interact2_L(e_index, e_from, e_to, e_label, e_techn) Rel_L(e_from, e_to, ""e_index: e_label"", e_techn)
-!define Interact2_Left(e_index, e_from, e_to, e_label) Rel_Left(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Left(e_index, e_from, e_to, e_label, e_techn) Rel_Left(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!define Interact2_R(e_index, e_from, e_to, e_label) Rel_R(e_from, e_to, ""e_index: e_label"")
-!define Interact2_R(e_index, e_from, e_to, e_label, e_techn) Rel_R(e_from, e_to, ""e_index: e_label"", e_techn)
-!define Interact2_Right(e_index, e_from, e_to, e_label) Rel_Right(e_from, e_to, ""e_index: e_label"")
-!define Interact2_Right(e_index, e_from, e_to, e_label, e_techn) Rel_Right(e_from, e_to, ""e_index: e_label"", e_techn)
-
-!unquoted function Interact($e_from, $e_to, $e_label)
- Interact2($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact($e_from, $e_to, $e_label, $e_techn)
- Interact2($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_Back($e_from, $e_to, $e_label)
- Interact2_Back($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Back($e_from, $e_to, $e_label, $e_techn)
- Interact2_Back($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_Neighbor($e_from, $e_to, $e_label)
- Interact2_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Neighbor($e_from, $e_to, $e_label, $e_techn)
- Interact2_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_Back_Neighbor($e_from, $e_to, $e_label)
- Interact2_Back_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Back_Neighbor($e_from, $e_to, $e_label, $e_techn)
- Interact2_Back_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_D($e_from, $e_to, $e_label)
- Interact2_D($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_D($e_from, $e_to, $e_label, $e_techn)
- Interact2_D($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Down($e_from, $e_to, $e_label)
- Interact2_Down($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Down($e_from, $e_to, $e_label, $e_techn)
- Interact2_Down($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_U($e_from, $e_to, $e_label)
- Interact2_U($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_U($e_from, $e_to, $e_label, $e_techn)
- Interact2_U($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Up($e_from, $e_to, $e_label)
- Interact2_Up($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Up($e_from, $e_to, $e_label, $e_techn)
- Interact2_Up($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_L($e_from, $e_to, $e_label)
- Interact2_L($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_L($e_from, $e_to, $e_label, $e_techn)
- Interact2_L($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Left($e_from, $e_to, $e_label)
- Interact2_Left($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Left($e_from, $e_to, $e_label, $e_techn)
- Interact2_Left($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-
-!unquoted function Interact_R($e_from, $e_to, $e_label)
- Interact2_R($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_R($e_from, $e_to, $e_label, $e_techn)
- Interact2_R($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Right($e_from, $e_to, $e_label)
- Interact2_Right($index, ""$e_from"", ""$e_to"", ""$e_label"")
- !$index=$inc_($index)
-!endfunction
-!unquoted function Interact_Right($e_from, $e_to, $e_label, $e_techn)
- Interact2_Right($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)
- !$index=$inc_($index)
-!endfunction
+!include
' Structurizr.DynamicView: dynamic
title Web Application - Dynamic
-LAYOUT_WITH_LEGEND()
-
ContainerDb(SoftwareSystem__Database__39bccb8, ""Database"", ""Relational Database Schema"", ""Stores information"")
Person(User__387cc75, ""User"")
Container_Boundary(SoftwareSystem__WebApplication__d2a342, ""Web Application"") {
Component(SoftwareSystem__WebApplication__SomeController__341621c, ""SomeController"", ""Spring MVC Controller"")
Component(SoftwareSystem__WebApplication__SomeRepository__6d9009, ""SomeRepository"", ""Spring Data"")
}
-Interact2(""1"", User__387cc75, SoftwareSystem__WebApplication__SomeController__341621c, ""Requests /something"", ""HTTP"")
-Interact2(""2"", SoftwareSystem__WebApplication__SomeController__341621c, SoftwareSystem__WebApplication__SomeRepository__6d9009, """")
-Interact2(""3"", SoftwareSystem__WebApplication__SomeRepository__6d9009, SoftwareSystem__Database__39bccb8, ""select * from something"", ""JDBC"")
+RelIndex(""1"", User__387cc75, SoftwareSystem__WebApplication__SomeController__341621c, ""Requests /something"", ""HTTP"")
+RelIndex(""2"", SoftwareSystem__WebApplication__SomeController__341621c, SoftwareSystem__WebApplication__SomeRepository__6d9009, """")
+RelIndex(""3"", SoftwareSystem__WebApplication__SomeRepository__6d9009, SoftwareSystem__Database__39bccb8, ""select * from something"", ""JDBC"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -1110,106 +805,33 @@ public void test_writeDeploymentView()
PopulateWorkspace();
DeploymentView deploymentView = _workspace.Views.DeploymentViews.First();
- _plantUMLWriter.Write(deploymentView, _stringWriter);
+ _plantUMLWriter.Write(deploymentView, _workspace.Views.Configuration, _stringWriter);
Assert.Equal(
@"@startuml
-!include
-' C4_Deployment.puml is missing, simulate it with following definitions
-' Scope: A single software system.
-' Primary elements: Deployment nodes and containers within the software system in scope.
-' Intended audience: Technical people inside and outside of the software development team; including software architects, developers and operations/support staff.
-
-' Colors
-' ##################################
-!define NODE_FONT_COLOR #444444
-!define NODE_BG_COLOR #FFFFFF
-
-' Styling
-' ##################################
-
-skinparam rectangle<> {
- Shadowing false
- StereotypeFontSize 0
- FontColor NODE_FONT_COLOR
- BackgroundColor NODE_BG_COLOR
- BorderColor #444444
-}
-
-' Layout
-' ##################################
-
-!definelong LAYOUT_WITH_LEGEND
-hide stereotype
-legend right
-|= |= Type |
-| | deployment node |
-| | deployment container |
-endlegend
-!enddefinelong
-
-' Nodes
-' ##################################
-' PlantUML does not support automatic line breaks of container, if e_techn is very long insert line breaks with
-' ""\n""
-!define Node(e_alias, e_label, e_techn) rectangle ""==e_label\n[e_techn]"" <> as e_alias
+!include
' Structurizr.DeploymentView: deployment
-title Software System - Deployment
-
-LAYOUT_WITH_LEGEND()
+title Software System - Deployment - Default
-Node(Deployment__Default__DatabaseServer__1edef6c, ""Database Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__DatabaseServer__MySQL__1fa4f18, ""MySQL"", ""MySQL 5.5.x"") {
- ContainerDb(SoftwareSystem__Database1__bb9c73, ""Database"", ""Relational Database Schema"", ""Stores information"")
+Node(DatabaseServer__1edef6c, ""Database Server"", ""Ubuntu 12.04 LTS"") {
+ Node(MySQL__1fa4f18, ""MySQL"", ""MySQL 5.5.x"") {
+ ContainerDb(SoftwareSystem__Database1__bb9c73, ""Database"", ""Relational Database Schema"", ""Stores information"", $tags=""Container Instance"")
}
}
-Node(Deployment__Default__WebServer__1e2ffe, ""Web Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__WebServer__ApacheTomcat__2b8afb4, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
- Container(SoftwareSystem__WebApplication1__31f1f25, ""Web Application"", ""Java and spring MVC"", ""Delivers content"")
+Node(WebServer__1e2ffe, ""Web Server"", ""Ubuntu 12.04 LTS"") {
+ Node(ApacheTomcat__2b8afb4, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+ Container(SoftwareSystem__WebApplication1__31f1f25, ""Web Application"", ""Java and spring MVC"", ""Delivers content"", $tags=""Container Instance"")
}
}
Rel(SoftwareSystem__WebApplication1__31f1f25, SoftwareSystem__Database1__bb9c73, ""Reads from and writes to"", ""JDBC"")
-@enduml
-".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
- }
-
- [Fact]
- public void test_writeDeploymentView_WithCustomBaseUrl()
- {
- PopulateWorkspace();
- DeploymentView deploymentView = _workspace.Views.DeploymentViews.First();
-
- _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/";
- _plantUMLWriter.Write(deploymentView, _stringWriter);
-
- Assert.Equal(
-@"@startuml
-!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/C4_Deployment.puml
-
-' Structurizr.DeploymentView: deployment
-title Software System - Deployment
-
-LAYOUT_WITH_LEGEND()
-
-Node(Deployment__Default__DatabaseServer__1edef6c, ""Database Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__DatabaseServer__MySQL__1fa4f18, ""MySQL"", ""MySQL 5.5.x"") {
- ContainerDb(SoftwareSystem__Database1__bb9c73, ""Database"", ""Relational Database Schema"", ""Stores information"")
- }
-}
-Node(Deployment__Default__WebServer__1e2ffe, ""Web Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__WebServer__ApacheTomcat__2b8afb4, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
- Container(SoftwareSystem__WebApplication1__31f1f25, ""Web Application"", ""Java and spring MVC"", ""Delivers content"")
- }
-}
-Rel(SoftwareSystem__WebApplication1__31f1f25, SoftwareSystem__Database1__bb9c73, ""Reads from and writes to"", ""JDBC"")
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
}
-
private void PopulateWorkspace()
{
Model model = _workspace.Model;
diff --git a/Structurizr.PlantUML.Tests/IO/PlantUML/PlantUMLWriterTests.cs b/Structurizr.PlantUML.Tests/IO/PlantUML/PlantUMLWriterTests.cs
index 3d5e4c7..754debe 100644
--- a/Structurizr.PlantUML.Tests/IO/PlantUML/PlantUMLWriterTests.cs
+++ b/Structurizr.PlantUML.Tests/IO/PlantUML/PlantUMLWriterTests.cs
@@ -101,7 +101,7 @@ title Web Application - Dynamic
@enduml
@startuml
-title Software System - Deployment
+title Software System - Deployment - Default
node ""Database Server"" <> as 23 {
node ""MySQL"" <> as 24 {
artifact ""Database"" <> as 25
@@ -254,7 +254,7 @@ public void test_writeDeploymentView()
Assert.Equal(
@"@startuml
-title Software System - Deployment
+title Software System - Deployment - Default
node ""Database Server"" <> as 23 {
node ""MySQL"" <> as 24 {
artifact ""Database"" <> as 25
diff --git a/Structurizr.PlantUML.Tests/Structurizr.PlantUML.Tests.csproj b/Structurizr.PlantUML.Tests/Structurizr.PlantUML.Tests.csproj
index 1152688..99d79e0 100644
--- a/Structurizr.PlantUML.Tests/Structurizr.PlantUML.Tests.csproj
+++ b/Structurizr.PlantUML.Tests/Structurizr.PlantUML.Tests.csproj
@@ -1,6 +1,6 @@
- netcoreapp1.1
+ netcoreapp2.1
false
diff --git a/Structurizr.PlantUML/IO/C4PlantUML/C4PlantUmlException.cs b/Structurizr.PlantUML/IO/C4PlantUML/C4PlantUmlException.cs
new file mode 100644
index 0000000..71ba6d4
--- /dev/null
+++ b/Structurizr.PlantUML/IO/C4PlantUML/C4PlantUmlException.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Structurizr.PlantUML.IO.C4PlantUML
+{
+ public class C4PlantUmlException : Exception
+ {
+ public C4PlantUmlException(string message) : base(message) { }
+ }
+}
diff --git a/Structurizr.PlantUML/IO/C4PlantUML/C4PlantUmlWriter.cs b/Structurizr.PlantUML/IO/C4PlantUML/C4PlantUmlWriter.cs
index 186f336..51cadb9 100644
--- a/Structurizr.PlantUML/IO/C4PlantUML/C4PlantUmlWriter.cs
+++ b/Structurizr.PlantUML/IO/C4PlantUML/C4PlantUmlWriter.cs
@@ -2,10 +2,14 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text;
using Structurizr.IO.C4PlantUML.ModelExtensions;
// Source base version copied from https://gist.github.com/coldacid/465fa8f3a4cd3fdd7b640a65ad5b86f4 (https://github.com/structurizr/dotnet/issues/47)
// kirchsth: Extended with dynamic and deployment view
+// kirchsth: updated to update generated source to new C4PlantUml stdlib v2.2.0 (no additional dynamic and deployment view macros are required anymore, calls updated)
+// kirchsth: Support ViewConfiguration, tags and styles
+// kirchsth: next planed C4PlantUml stdlib v2.3.0 features can be used with CustomBaseUrl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/
namespace Structurizr.IO.C4PlantUML
{
public class C4PlantUmlWriter : PlantUMLWriterBase
@@ -23,18 +27,22 @@ public enum LayoutDirection
public LayoutDirection? Layout { get; set; }
///
- /// PlantUML-stdlib or https://raw.githubusercontent.com/RicardoNiepel/C4-PlantUML/release/1-0/ does not support
- /// dynamic or deployment diagrams. They can be used via the PlantUML-stdlib and in the diagram added definitions
- /// or use a pull-request version which is available at https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/
+ /// C4PlantUml stdlib v2.2.0 () supports dynamic or deployment diagrams. They can be used via the PlantUML-stdlib and no
+ /// special CustomBaseUrl is required.
+ /// Only next stdlib features (like Person shapes) has to be defined via CustomBaseUrl=https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/
/// (if the value is empty/null then PlantUML-stdlib with added definitions is used)
///
- public string CustomBaseUrl { get; set; } = ""; // @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/";
+ public string CustomBaseUrl { get; set; } =""; // @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/";
+ public bool EnableNextFeatures { get; set; } = false; // true;
- protected override void Write(SystemLandscapeView view, TextWriter writer)
+ public string AdditionalProlog { get; set; }
+ public string AdditionalEpilog { get; set; }
+
+ protected override void Write(SystemLandscapeView view, ViewConfiguration viewConfiguration, TextWriter writer)
{
var showBoundary = view.EnterpriseBoundaryVisible ?? true;
- WriteProlog(view, writer);
+ WriteProlog(view, viewConfiguration, writer);
view.Elements
.Select(ev => ev.Element)
@@ -71,14 +79,14 @@ protected override void Write(SystemLandscapeView view, TextWriter writer)
Write(view.Relationships, writer);
- WriteEpilog(view, writer);
+ WriteEpilog(view, viewConfiguration, writer);
}
- protected override void Write(SystemContextView view, TextWriter writer)
+ protected override void Write(SystemContextView view, ViewConfiguration viewConfiguration, TextWriter writer)
{
var showBoundary = view.EnterpriseBoundaryVisible ?? true;
- WriteProlog(view, writer);
+ WriteProlog(view, viewConfiguration, writer);
if (showBoundary)
{
@@ -95,17 +103,17 @@ protected override void Write(SystemContextView view, TextWriter writer)
if (showBoundary)
writer.WriteLine("}");
- WriteEpilog(view, writer);
+ WriteEpilog(view, viewConfiguration, writer);
}
- protected override void Write(ContainerView view, TextWriter writer)
+ protected override void Write(ContainerView view, ViewConfiguration viewConfiguration, TextWriter writer)
{
var externals = view.Elements
.Select(ev => ev.Element)
.Where(e => !(e is Container));
var showBoundary = externals.Any();
- WriteProlog(view, writer);
+ WriteProlog(view, viewConfiguration, writer);
externals
.OrderBy(e => e.Name).ToList()
@@ -125,10 +133,10 @@ protected override void Write(ContainerView view, TextWriter writer)
Write(view.Relationships, writer);
- WriteEpilog(view, writer);
+ WriteEpilog(view, viewConfiguration, writer);
}
- protected override void Write(ComponentView view, TextWriter writer)
+ protected override void Write(ComponentView view, ViewConfiguration viewConfiguration, TextWriter writer)
{
var nonComponents = view.Elements
.Select(ev => ev.Element)
@@ -140,7 +148,7 @@ from ev in view.Elements
group e by e.Parent;
var showBoundary = nonComponents.Any() || nonContainedComponents.Any();
- WriteProlog(view, writer);
+ WriteProlog(view, viewConfiguration, writer);
nonComponents
.OrderBy(e => e.Name).ToList()
@@ -171,12 +179,12 @@ from ev in view.Elements
Write(view.Relationships, writer);
- WriteEpilog(view, writer);
+ WriteEpilog(view, viewConfiguration, writer);
}
- protected override void Write(DynamicView view, TextWriter writer)
+ protected override void Write(DynamicView view, ViewConfiguration viewConfiguration, TextWriter writer)
{
- WriteProlog(view, writer);
+ WriteProlog(view, viewConfiguration, writer);
IList innerElements = new List();
IList outerElements = new List();
@@ -224,12 +232,12 @@ protected override void Write(DynamicView view, TextWriter writer)
WriteDynamicInteractions(view.Relationships, writer);
- WriteEpilog(view, writer);
+ WriteEpilog(view, viewConfiguration, writer);
}
- protected override void Write(DeploymentView view, TextWriter writer)
+ protected override void Write(DeploymentView view, ViewConfiguration viewConfiguration, TextWriter writer)
{
- WriteProlog(view, writer);
+ WriteProlog(view, viewConfiguration, writer);
view.Elements
.Where(ev => ev.Element is DeploymentNode && ev.Element.Parent == null)
@@ -239,7 +247,7 @@ protected override void Write(DeploymentView view, TextWriter writer)
Write(view.Relationships, writer);
- WriteEpilog(view, writer);
+ WriteEpilog(view, viewConfiguration, writer);
}
private void Write(DeploymentNode deploymentNode, TextWriter writer, int indentLevel)
@@ -258,6 +266,11 @@ private void Write(DeploymentNode deploymentNode, TextWriter writer, int indentL
Write(containerInstance, writer, indentLevel + 1);
}
+ foreach (SoftwareSystemInstance systemInstance in deploymentNode.SoftwareSystemInstances)
+ {
+ Write(systemInstance, writer, indentLevel + 1);
+ }
+
writer.WriteLine($"{indent}}}");
}
@@ -296,6 +309,11 @@ private string TypeOf(Element e)
return "Container";
}
+ if (e is SoftwareSystemInstance)
+ {
+ return "Software System";
+ }
+
return "";
}
@@ -305,275 +323,60 @@ private bool HasValue(string s)
return s != null && s.Trim().Length > 0;
}
- protected override void WriteProlog(View view, TextWriter writer)
+ protected override void WriteProlog(View view, ViewConfiguration viewConfiguration, TextWriter writer)
{
+ if (view == null) throw new ArgumentNullException(nameof(view));
+ if (writer == null) throw new ArgumentNullException(nameof(writer));
+
writer.WriteLine("@startuml");
+ string diagramType;
+ HashSet existingLegendTags; // (already mapped) tags (styles) which have to be overwritten not added
+
switch (view)
{
case SystemLandscapeView _:
case SystemContextView _:
- writer.WriteLine(!string.IsNullOrWhiteSpace(CustomBaseUrl)
- ? $"!includeurl {CustomBaseUrl}C4_Context.puml"
- : $"!include ");
+ diagramType = "Context";
+ existingLegendTags = new HashSet { "person", "system", "external_person", "external_system" };
break;
- case ComponentView _:
- writer.WriteLine(!string.IsNullOrWhiteSpace(CustomBaseUrl)
- ? $"!includeurl {CustomBaseUrl}C4_Component.puml"
- : $"!include ");
+ case ContainerView _:
+ diagramType = "Container";
+ existingLegendTags = new HashSet { "person", "system", "container", "external_person", "external_system", "external_container" };
break;
case DynamicView _:
- if (!string.IsNullOrWhiteSpace(CustomBaseUrl))
- {
- writer.WriteLine($"!includeurl {CustomBaseUrl}C4_Dynamic.puml");
- }
- else
- {
- writer.WriteLine(@"!include ");
- // Add missing deployment nodes (until they are part of the plantuml macros)
- writer.WriteLine(@"' C4_Dynamic.puml is missing, simulate it with following definitions");
-
- writer.WriteLine(@"' Scope: Interactions in an enterprise, software system or container.");
- writer.WriteLine(@"' Primary and supporting elements: Depends on the diagram scope - ");
- writer.WriteLine(@"' enterprise - people and software systems related to the enterprise in scope ");
- writer.WriteLine(@"' software system - see system context or container diagrams, ");
- writer.WriteLine(@"' container - see component diagram.");
- writer.WriteLine(@"' Intended audience: Technical and non-technical people, inside and outside of the software development team.");
- writer.WriteLine(@"");
- writer.WriteLine(@"' Dynamic diagram introduces (automatically) numbered interactions: ");
- writer.WriteLine(@"' Interact(): used automatic calculated index, ");
- writer.WriteLine(@"' Interact2(): index can be explicit defined,");
- writer.WriteLine(@"' SetIndex(): set the next index, ");
- writer.WriteLine(@"' GetIndex(): get the index and automatically increase index");
- writer.WriteLine(@"");
- writer.WriteLine(@"' Index");
- writer.WriteLine(@"' ##################################");
- writer.WriteLine(@"");
- writer.WriteLine(@"!function $inc_($value, $step=1)");
- writer.WriteLine(@" !return $value + $step");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"!$index=1");
- writer.WriteLine(@"");
- writer.WriteLine(@"!function SetIndex($new_index)");
- writer.WriteLine(@" !$index=$new_index");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"!function GetIndex($auto_increase=1)");
- writer.WriteLine(@" !$old = $index");
- writer.WriteLine(@" !$index=$inc_($index, $auto_increase)");
- writer.WriteLine(@" !return $old");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"' Interact");
- writer.WriteLine(@"' ##################################");
- writer.WriteLine(@"!define Interact2(e_index, e_from, e_to, e_label) Rel(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2(e_index, e_from, e_to, e_label, e_techn) Rel(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"");
- writer.WriteLine(@"!define Interact2_Back(e_index, e_from, e_to, e_label) Rel_Back(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_Back(e_index, e_from, e_to, e_label, e_techn) Rel_Back(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"");
- writer.WriteLine(@"!define Interact2_Neighbor(e_index, e_from, e_to, e_label) Rel_Neighbor(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_Neighbor(e_index, e_from, e_to, e_label, e_techn) Rel_Neighbor(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"");
- writer.WriteLine(@"!define Interact2_Back_Neighbor(e_index, e_from, e_to, e_label) Rel_Back_Neighbor(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_Back_Neighbor(e_index, e_from, e_to, e_label, e_techn) Rel_Back_Neighbor(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"");
- writer.WriteLine(@"!define Interact2_D(e_index, e_from, e_to, e_label) Rel_D(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_D(e_index, e_from, e_to, e_label, e_techn) Rel_D(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"!define Interact2_Down(e_index, e_from, e_to, e_label) Rel_Down(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_Down(e_index, e_from, e_to, e_label, e_techn) Rel_Down(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"");
- writer.WriteLine(@"!define Interact2_U(e_index, e_from, e_to, e_label) Rel_U(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_U(e_index, e_from, e_to, e_label, e_techn) Rel_U(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"!define Interact2_Up(e_index, e_from, e_to, e_label) Rel_Up(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_Up(e_index, e_from, e_to, e_label, e_techn) Rel_Up(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"");
- writer.WriteLine(@"!define Interact2_L(e_index, e_from, e_to, e_label) Rel_L(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_L(e_index, e_from, e_to, e_label, e_techn) Rel_L(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"!define Interact2_Left(e_index, e_from, e_to, e_label) Rel_Left(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_Left(e_index, e_from, e_to, e_label, e_techn) Rel_Left(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"");
- writer.WriteLine(@"!define Interact2_R(e_index, e_from, e_to, e_label) Rel_R(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_R(e_index, e_from, e_to, e_label, e_techn) Rel_R(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"!define Interact2_Right(e_index, e_from, e_to, e_label) Rel_Right(e_from, e_to, ""e_index: e_label"")");
- writer.WriteLine(@"!define Interact2_Right(e_index, e_from, e_to, e_label, e_techn) Rel_Right(e_from, e_to, ""e_index: e_label"", e_techn)");
- writer.WriteLine(@"");
- writer.WriteLine(@"!unquoted function Interact($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"!unquoted function Interact_Back($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_Back($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Back($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_Back($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"!unquoted function Interact_Neighbor($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Neighbor($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"!unquoted function Interact_Back_Neighbor($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_Back_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Back_Neighbor($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_Back_Neighbor($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"!unquoted function Interact_D($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_D($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_D($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_D($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Down($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_Down($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Down($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_Down($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"!unquoted function Interact_U($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_U($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_U($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_U($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Up($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_Up($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Up($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_Up($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"!unquoted function Interact_L($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_L($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_L($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_L($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Left($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_Left($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Left($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_Left($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"");
- writer.WriteLine(@"!unquoted function Interact_R($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_R($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_R($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_R($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Right($e_from, $e_to, $e_label) ");
- writer.WriteLine(@" Interact2_Right($index, ""$e_from"", ""$e_to"", ""$e_label"")");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- writer.WriteLine(@"!unquoted function Interact_Right($e_from, $e_to, $e_label, $e_techn) ");
- writer.WriteLine(@" Interact2_Right($index, ""$e_from"", ""$e_to"", ""$e_label"", $e_techn)");
- writer.WriteLine(@" !$index=$inc_($index)");
- writer.WriteLine(@"!endfunction");
- }
+ diagramType = "Dynamic";
+ existingLegendTags = new HashSet { "person", "system", "container", "component", "external_person", "external_system", "external_container", "external_component" };
break;
case DeploymentView _:
- if (!string.IsNullOrWhiteSpace(CustomBaseUrl))
- {
- writer.WriteLine($"!includeurl {CustomBaseUrl}C4_Deployment.puml");
- }
- else
- {
- writer.WriteLine(@"!include ");
- // Add missing deployment nodes (until they are part of the plantuml macros)
- writer.WriteLine(@"' C4_Deployment.puml is missing, simulate it with following definitions");
-
- writer.WriteLine(@"' Scope: A single software system.");
- writer.WriteLine(@"' Primary elements: Deployment nodes and containers within the software system in scope.");
- writer.WriteLine(@"' Intended audience: Technical people inside and outside of the software development team; including software architects, developers and operations/support staff.");
- writer.WriteLine(@"");
- writer.WriteLine(@"' Colors");
- writer.WriteLine(@"' ##################################");
- writer.WriteLine(@"!define NODE_FONT_COLOR #444444");
- writer.WriteLine(@"!define NODE_BG_COLOR #FFFFFF");
- writer.WriteLine(@"");
- writer.WriteLine(@"' Styling");
- writer.WriteLine(@"' ##################################");
- writer.WriteLine(@"");
- writer.WriteLine(@"skinparam rectangle<> {");
- writer.WriteLine(@" Shadowing false");
- writer.WriteLine(@" StereotypeFontSize 0");
- writer.WriteLine(@" FontColor NODE_FONT_COLOR");
- writer.WriteLine(@" BackgroundColor NODE_BG_COLOR");
- writer.WriteLine(@" BorderColor #444444");
- writer.WriteLine(@"}");
- writer.WriteLine(@"");
- writer.WriteLine(@"' Layout");
- writer.WriteLine(@"' ##################################");
- writer.WriteLine(@"");
- writer.WriteLine(@"!definelong LAYOUT_WITH_LEGEND");
- writer.WriteLine(@"hide stereotype");
- writer.WriteLine(@"legend right");
- writer.WriteLine(@"|= |= Type |");
- writer.WriteLine(@"| | deployment node |");
- writer.WriteLine(@"| | deployment container |");
- writer.WriteLine(@"endlegend");
- writer.WriteLine(@"!enddefinelong");
- writer.WriteLine(@"");
- writer.WriteLine(@"' Nodes");
- writer.WriteLine(@"' ##################################");
- writer.WriteLine(@"' PlantUML does not support automatic line breaks of container, if e_techn is very long insert line breaks with ");
- writer.WriteLine(@"' ""\n""");
- writer.WriteLine(@"!define Node(e_alias, e_label, e_techn) rectangle ""==e_label\n[e_techn]"" <> as e_alias");
- }
+ diagramType = "Deployment";
+ existingLegendTags = new HashSet { "person", "system", "container", "external_person", "external_system", "external_container", "node" };
break;
default:
- writer.WriteLine(!string.IsNullOrWhiteSpace(CustomBaseUrl)
- ? $"!includeurl {CustomBaseUrl}C4_Container.puml"
- : $"!include "); // as long no stdlib is used the Component diagram definition can be reused
+ diagramType = "Component";
+ existingLegendTags = new HashSet { "person", "system", "container", "component", "external_person", "external_system", "external_container", "external_component" };
break;
}
+ writer.WriteLine(!string.IsNullOrWhiteSpace(CustomBaseUrl)
+ ? $"!includeurl {CustomBaseUrl}C4_{diagramType}.puml"
+ : $"!include ");
+
writer.WriteLine();
writer.WriteLine($"' {view.GetType()}: {view.Key}");
writer.WriteLine("title " + GetTitle(view));
writer.WriteLine();
- if (LayoutWithLegend)
- writer.WriteLine("LAYOUT_WITH_LEGEND()"); // C4 PlantUML workaround add ()
if (LayoutAsSketch)
- writer.WriteLine("LAYOUT_AS_SKETCH()"); // C4 PlantUML workaround add ()
+ writer.WriteLine("LAYOUT_AS_SKETCH()");
+
+ if (EnableNextFeatures)
+ writer.WriteLine("SHOW_PERSON_OUTLINE()");
+
if (Layout.HasValue)
{
switch (Layout)
@@ -588,10 +391,154 @@ protected override void WriteProlog(View view, TextWriter writer)
throw new InvalidOperationException($"Unknown {nameof(LayoutDirection)} value");
}
}
- if (LayoutWithLegend || LayoutAsSketch || Layout.HasValue)
+ if (LayoutAsSketch || Layout.HasValue)
+ writer.WriteLine();
+
+ WriteExistingStyles(view, existingLegendTags, viewConfiguration, writer);
+
+ if (!string.IsNullOrWhiteSpace(AdditionalProlog))
+ writer.WriteLine(AdditionalProlog);
+ }
+
+ protected override void WriteEpilog(View view, ViewConfiguration viewConfiguration, TextWriter writer)
+ {
+ if (view == null) throw new ArgumentNullException(nameof(view));
+ if (writer == null) throw new ArgumentNullException(nameof(writer));
+
+ if (!string.IsNullOrWhiteSpace(AdditionalEpilog))
+ writer.WriteLine(AdditionalEpilog);
+
+ if (LayoutWithLegend)
+ {
+ writer.WriteLine();
+ writer.WriteLine("SHOW_LEGEND()"); // C4 PlantUML workaround add ()
+ }
+
+ writer.WriteLine("@enduml");
+ writer.WriteLine();
+ }
+
+ protected virtual void WriteExistingStyles(View view, HashSet existingLegendTags, ViewConfiguration viewConfiguration, TextWriter writer)
+ {
+ if (view == null) throw new ArgumentNullException(nameof(view));
+ if (writer == null) throw new ArgumentNullException(nameof(writer));
+
+ ElementStyle baseES = viewConfiguration.Styles.Elements.FirstOrDefault(es => es.Tag == "Element");
+ RelationshipStyle definedRS = viewConfiguration.Styles.Relationships.FirstOrDefault(rs => rs.Tag == "Relationship");
+
+ if (EnableNextFeatures) // linestyle
+ {
+ // add Back related style (which is typically dotted in Structurizr) (and if defined then it will be overwritten with viewConfiguration.Styles.Relationships)
+ writer.WriteLine("AddRelTag(\"Back\", $textColor=$ARROW_COLOR, $lineColor=$ARROW_COLOR, $lineStyle = DottedLine())");
+ writer.WriteLine();
+ }
+
+ foreach (var es in viewConfiguration.Styles.Elements)
+ if (es != baseES) // skip Element
+ Write(es, baseES, existingLegendTags, writer);
+ foreach (var rs in viewConfiguration.Styles.Relationships)
+ Write(rs, definedRS, writer);
+
+ if (viewConfiguration.Styles.Elements.Count > 0 || viewConfiguration.Styles.Relationships.Count > 0)
writer.WriteLine();
}
+ protected virtual void Write(ElementStyle es, ElementStyle baseElementStyle, HashSet existingLegendTags, TextWriter writer)
+ {
+ var defined = StructurizrTags2DiagramTags.TryGetValue(es.Tag, out var diagramTag);
+ if (!defined)
+ diagramTag = es.Tag;
+
+ // UpdateElementStyle or AddElementTag(elementName, ?bgColor, ?fontColor, ?borderColor, ?shadowing, ?shape) // ?shadowing not used; ?shape only rounded or eight-sided
+ var allArgs = new StringBuilder();
+ WriteColor("$bgColor", es.Background, baseElementStyle?.Background, false, allArgs);
+ WriteColor("$fontColor", es.Color, baseElementStyle?.Color, false, allArgs);
+ WriteColor("$borderColor", es.Stroke, baseElementStyle?.Stroke, false, allArgs);
+ if (EnableNextFeatures)
+ {
+ // default shape of element is ignored
+ WriteShape(es.Shape, allArgs);
+ }
+
+ if (allArgs.Length > 0)
+ {
+ writer.Write(defined ? "UpdateElementStyle" : "AddElementTag");
+ writer.WriteLine($"({diagramTag}{allArgs})");
+ }
+ }
+
+ protected virtual void Write(RelationshipStyle rs, RelationshipStyle definedRelationshipStyle, TextWriter writer)
+ {
+ // only "Relationship" is predefined (which is defaultRelationshipStyle)
+ var diagramTag = rs.Tag;
+ var defined = (rs == definedRelationshipStyle);
+
+ // UpdateRelStyle or AddRelTag(tagStereo, ?textColor, ?lineColor, ?lineStyle)
+ var allArgs = new StringBuilder();
+ WriteColor("$textColor", rs.Color, definedRelationshipStyle?.Color, defined, allArgs);
+ WriteColor("$lineColor", rs.Color, definedRelationshipStyle?.Color, defined, allArgs);
+ if (!defined)
+ {
+ if (EnableNextFeatures)
+ {
+ if (rs.Dashed == true) // C# Structurize does not support all styles
+ allArgs.Append($", $lineStyle = DashedLine()");
+ }
+ }
+
+ if (allArgs.Length > 0)
+ {
+ writer.Write(defined ? "UpdateRelStyle(" : $"AddRelTag({diagramTag}, ");
+ writer.WriteLine($"{allArgs.Remove(0, 2)})"); // remove first ", "
+ }
+ }
+
+ protected void WriteColor(string argName, string elementColor, string defaultColor, bool lineColorsRequired, StringBuilder allArgs)
+ {
+ var color = elementColor;
+ if (string.IsNullOrWhiteSpace(color))
+ color = defaultColor;
+
+ if (!string.IsNullOrWhiteSpace(color))
+ allArgs.Append($", {argName} = \"{color}\"");
+ else if (lineColorsRequired)
+ allArgs.Append($", {argName} = $ARROW_COLOR");
+ }
+
+ protected void WriteShape(Shape elementShape, StringBuilder allArgs)
+ {
+ if (EnableNextFeatures)
+ {
+ switch (elementShape)
+ {
+ case Shape.RoundedBox:
+ allArgs.Append($", $shape = RoundedBoxShape()");
+ break;
+ case Shape.Hexagon:
+ allArgs.Append($", $shape = EightSidedShape()");
+ break;
+ default:
+ // all other ignored atm (Database handled via ..Db() extension)
+ break;
+ }
+ }
+ }
+
+ protected static Dictionary StructurizrTags2DiagramTags = new Dictionary
+ {
+ // Element is handled via defaultElementStyle and is not added as tag
+ ["Element"] = "",
+ ["Person"] = "person",
+ ["Software System"] = "system",
+ ["Container"] = "container",
+ ["Component"] = "component",
+ ["Deployment Node"] = "node"
+ // ?? how should this tags be mapped -> reused without special mapping atm
+ // ["Infrastructure Node"] = "",
+ // ["Software System Instance"] = "",
+ // ["Container Instance"] = "",
+ };
+
protected virtual void Write(Element element, TextWriter writer, int indentLevel = 0, bool asBoundary = false)
{
var indent = indentLevel == 0 ? "" : new string(' ', indentLevel * 2);
@@ -617,10 +564,6 @@ protected virtual void Write(Element element, TextWriter writer, int indentLevel
macro = "Node";
title = deploymentNode.Name + (deploymentNode.Instances > 1 ? $" (x{deploymentNode.Instances})" : "");
technology = deploymentNode.Technology;
- // PlantUML supports no automatic line breaks of titles, if it belongs to a surrounding object
- // make workaround with html tags (they are not working via multiple lines too)
- if (technology.Length > 30)
- technology = BlockText(technology, 30, @"\n");
break;
default:
throw new NotSupportedException($"{element.GetType()} not supported boundary type");
@@ -659,6 +602,12 @@ protected virtual void Write(Element element, TextWriter writer, int indentLevel
technology = cmp.Technology ?? "";
isDatabase = cmp.GetIsDatabase();
break;
+ case SoftwareSystemInstance sysIn:
+ macro = "System";
+ title = sysIn.SoftwareSystem.Name;
+ description = sysIn.SoftwareSystem.Description;
+ external = sysIn.SoftwareSystem.Location == Location.External;
+ break;
case ContainerInstance cntIn:
macro = "Container";
title = cntIn.Container.Name;
@@ -687,9 +636,20 @@ protected virtual void Write(Element element, TextWriter writer, int indentLevel
{
writer.Write($", \"{EscapeText(description)}\"");
}
+ WriteTags(element, writer);
writer.WriteLine(")");
}
+ private void WriteTags(Element element, TextWriter writer)
+ {
+ var tags = element.GetAllTags().Where(t => !StructurizrTags2DiagramTags.ContainsKey(t)).Reverse().ToList();
+ if (tags.Count > 0)
+ {
+ var combinedTags = string.Join("+", tags);
+ writer.Write($", $tags=\"{EscapeText(combinedTags)}\"");
+ }
+ }
+
protected virtual void Write(ISet relationships, TextWriter writer)
{
relationships
@@ -706,14 +666,37 @@ protected virtual void Write(RelationshipView relationshipView, TextWriter write
label = advancedDescription ?? relationship.Description ?? "",
tech = !string.IsNullOrWhiteSpace(relationship.Technology) ? relationship.Technology : null;
+ if (relationshipView.Response == true)
+ {
+ var swap = source;
+ source = dest;
+ dest = swap;
+ }
+
var macro = GetSpecificLayoutMacro(relationshipView);
writer.Write($"{macro}({source}, {dest}, \"{EscapeText(label)}\"");
if (tech != null)
writer.Write($", \"{EscapeText(tech)}\"");
+ WriteTags(relationshipView, writer);
writer.WriteLine(")");
}
+ private void WriteTags(RelationshipView relationshipView, TextWriter writer)
+ {
+ var relationship = relationshipView.Relationship;
+ var tags = new List();
+ if (relationshipView.Response == true)
+ tags.Add("Back");
+
+ tags.AddRange(relationship.GetAllTags().Where(t => t != "Relationship").Reverse());
+ if (tags.Count > 0)
+ {
+ var combinedTags = string.Join("+", tags);
+ writer.Write($", $tags=\"{EscapeText(combinedTags)}\"");
+ }
+ }
+
protected virtual void WriteDynamicInteractions(ISet relationships, TextWriter writer)
{
relationships
@@ -729,12 +712,20 @@ protected virtual void WriteDynamicInteraction(RelationshipView relationshipView
dest = TokenizeName(relationship.Destination),
tech = !string.IsNullOrWhiteSpace(relationship.Technology) ? relationship.Technology : null;
+ if (relationshipView.Response == true)
+ {
+ var swap = source;
+ source = dest;
+ dest = swap;
+ }
+
var macro = GetSpecificLayoutMacro(relationshipView);
- macro = "Interact2" + macro.Substring("Rel".Length);
+ macro = "RelIndex" + macro.Substring("Rel".Length);
writer.Write($"{macro}(\"{order}\", {source}, {dest}, \"{EscapeText(label)}\"");
if (tech != null)
writer.Write($", \"{EscapeText(tech)}\"");
+ WriteTags(relationshipView, writer);
writer.WriteLine(")");
}
diff --git a/Structurizr.PlantUML/IO/C4PlantUML/IPlantUMLWriter.cs b/Structurizr.PlantUML/IO/C4PlantUML/IPlantUMLWriter.cs
index 525e008..5b47e65 100644
--- a/Structurizr.PlantUML/IO/C4PlantUML/IPlantUMLWriter.cs
+++ b/Structurizr.PlantUML/IO/C4PlantUML/IPlantUMLWriter.cs
@@ -2,11 +2,12 @@
// Source base version copied from https://gist.github.com/coldacid/465fa8f3a4cd3fdd7b640a65ad5b86f4 (https://github.com/structurizr/dotnet/issues/47)
// kirchsth: Extended with dynamic and deployment view
+// kirchsth: Support ViewConfiguration, tags and styles
namespace Structurizr.IO.C4PlantUML
{
public interface IPlantUMLWriter
{
void Write(Workspace workspace, TextWriter writer);
- void Write(View view, TextWriter writer);
+ void Write(View view, ViewConfiguration viewConfiguration, TextWriter writer);
}
}
\ No newline at end of file
diff --git a/Structurizr.PlantUML/IO/C4PlantUML/ModelExtensions/ModelExtensions.cs b/Structurizr.PlantUML/IO/C4PlantUML/ModelExtensions/ModelExtensions.cs
new file mode 100644
index 0000000..4d02454
--- /dev/null
+++ b/Structurizr.PlantUML/IO/C4PlantUML/ModelExtensions/ModelExtensions.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Linq;
+using Structurizr.PlantUML.IO.C4PlantUML;
+
+namespace Structurizr.IO.C4PlantUML.ModelExtensions
+{
+ public static class ModelExtensions
+ {
+ ///
+ /// new impl. of CanonicalName starts with "{ElementType}://" or "{ElementType}://{DeploymentName}/{DeploymentName}/" instead of "/" therefore it can be optionally ignored
+ /// Additional / in staticNames have to be converted to .
+ ///
+ /// the canonical name with elementType prefix (e.g. Container://SoftwareSystem/Container) or without elementType prefix (e.g. /SoftwareSystem/Container)
+ ///
+ public static Element GetElementWithCanonicalOrStaticalName(this Model model, string canonicalName, bool compareOnlyLastPart=true)
+ {
+ if (string.IsNullOrWhiteSpace(canonicalName))
+ throw new ArgumentException("A canonical name must be specified.");
+ var found = model.GetElements().FirstOrDefault((Func) (x =>
+ {
+ if (compareOnlyLastPart)
+ return x.CanonicalName.EndsWith(canonicalName);
+ else
+ return x.CanonicalName == canonicalName;
+ }));
+
+ if (found == null)
+ {
+ var all = model.GetElements().Select(e => e.CanonicalName).ToList();
+ var combined = string.Join("\n", all);
+ throw new C4PlantUmlException(
+ $"Element {canonicalName} could not be found. Following elements exist:\n{combined}");
+ }
+ return found;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Structurizr.PlantUML/IO/C4PlantUML/ModelExtensions/RelationshipViewExtensions.cs b/Structurizr.PlantUML/IO/C4PlantUML/ModelExtensions/RelationshipViewExtensions.cs
index 1d4e309..39decbd 100644
--- a/Structurizr.PlantUML/IO/C4PlantUML/ModelExtensions/RelationshipViewExtensions.cs
+++ b/Structurizr.PlantUML/IO/C4PlantUML/ModelExtensions/RelationshipViewExtensions.cs
@@ -1,9 +1,15 @@
+using System.Collections.Generic;
+
namespace Structurizr.IO.C4PlantUML.ModelExtensions
{
+ ///
+ /// WORKAROUND: RelationshipView supports no properties anymore, therefore the direction is stored in Position
+ ///
public static class RelationshipViewExtensions
{
///
/// Get a direction of the relation which should be used in a specific C4PlantUML views
+ /// (direction is stored in Position)
///
///
/// returns true if it is defined via the view specific RelationshipView and false if it is defined via the underlying Relationship
@@ -11,7 +17,7 @@ public static class RelationshipViewExtensions
public static string GetDirection(this RelationshipView relationshipView, out bool viewSpecific)
{
string value = DirectionValues.NotSet;
- if (relationshipView.Properties?.TryGetValue(Properties.Direction, out value) == true)
+ if (relationshipView.Position.HasValue && Position2Direction.TryGetValue(relationshipView.Position.Value, out value) == true)
{
viewSpecific = true;
return value;
@@ -24,15 +30,32 @@ public static string GetDirection(this RelationshipView relationshipView, out bo
///
/// Set a direction of the relation which should be used in a specific C4PlantUML views
+ /// (direction is internal stored in Position)
///
///
/// one of
public static void SetDirection(this RelationshipView relationshipView, string direction)
{
if (string.IsNullOrWhiteSpace(direction)) // direction DirectionValues.NotSet
- relationshipView.Properties.Remove(Properties.Direction);
+ relationshipView.Position = null;
else
- relationshipView.Properties[Properties.Direction] = direction;
+ relationshipView.Position = Direction2Position[direction];
}
+
+ private static Dictionary Direction2Position = new Dictionary
+ {
+ [DirectionValues.Up] = 1,
+ [DirectionValues.Down] = 2,
+ [DirectionValues.Left] = 3,
+ [DirectionValues.Right] = 4
+ };
+
+ private static Dictionary Position2Direction = new Dictionary
+ {
+ [1] = DirectionValues.Up,
+ [2] = DirectionValues.Down,
+ [3] = DirectionValues.Left,
+ [4] = DirectionValues.Right
+ };
}
}
\ No newline at end of file
diff --git a/Structurizr.PlantUML/IO/C4PlantUML/PlantUMLWriterBase.cs b/Structurizr.PlantUML/IO/C4PlantUML/PlantUMLWriterBase.cs
index ee2285e..d8d2a96 100644
--- a/Structurizr.PlantUML/IO/C4PlantUML/PlantUMLWriterBase.cs
+++ b/Structurizr.PlantUML/IO/C4PlantUML/PlantUMLWriterBase.cs
@@ -5,6 +5,8 @@
// Source base version copied from https://gist.github.com/coldacid/465fa8f3a4cd3fdd7b640a65ad5b86f4 (https://github.com/structurizr/dotnet/issues/47)
// kirchsth: Extended with dynamic and deployment view
+// kirchsth: Support ViewConfiguration, tags and styles
+
namespace Structurizr.IO.C4PlantUML
{
///
@@ -25,16 +27,17 @@ public void Write(Workspace workspace, TextWriter writer)
CurrentViewModel = workspace.Model;
- workspace.Views.SystemLandscapeViews.ToList().ForEach(v => Write(v, writer));
- workspace.Views.SystemContextViews.ToList().ForEach(v => Write(v, writer));
- workspace.Views.ContainerViews.ToList().ForEach(v => Write(v, writer));
- workspace.Views.ComponentViews.ToList().ForEach(v => Write(v, writer));
- workspace.Views.DynamicViews.ToList().ForEach(v => Write(v, writer));
- workspace.Views.DeploymentViews.ToList().ForEach(v => Write(v, writer));
+ var viewConfiguration = workspace.Views.Configuration;
+ workspace.Views.SystemLandscapeViews.ToList().ForEach(v => Write(v, viewConfiguration, writer));
+ workspace.Views.SystemContextViews.ToList().ForEach(v => Write(v, viewConfiguration, writer));
+ workspace.Views.ContainerViews.ToList().ForEach(v => Write(v, viewConfiguration, writer));
+ workspace.Views.ComponentViews.ToList().ForEach(v => Write(v, viewConfiguration, writer));
+ workspace.Views.DynamicViews.ToList().ForEach(v => Write(v, viewConfiguration, writer));
+ workspace.Views.DeploymentViews.ToList().ForEach(v => Write(v, viewConfiguration, writer));
}
///
- public void Write(View view, TextWriter writer)
+ public void Write(View view, ViewConfiguration viewConfiguration, TextWriter writer)
{
if (view == null) throw new ArgumentNullException(nameof(view));
if (writer == null) throw new ArgumentNullException(nameof(writer));
@@ -44,22 +47,22 @@ public void Write(View view, TextWriter writer)
switch (view)
{
case SystemLandscapeView sl:
- Write(sl, writer);
+ Write(sl, viewConfiguration, writer);
break;
case SystemContextView sc:
- Write(sc, writer);
+ Write(sc, viewConfiguration, writer);
break;
case ContainerView ct:
- Write(ct, writer);
+ Write(ct, viewConfiguration, writer);
break;
case ComponentView cp:
- Write(cp, writer);
+ Write(cp, viewConfiguration, writer);
break;
case DynamicView dy:
- Write(dy, writer);
+ Write(dy, viewConfiguration, writer);
break;
case DeploymentView de:
- Write(de, writer);
+ Write(de, viewConfiguration, writer);
break;
default:
throw new NotSupportedException($"{view.GetType()} not supported for export");
@@ -71,42 +74,42 @@ public void Write(View view, TextWriter writer)
///
///
///
- protected abstract void Write(SystemLandscapeView view, TextWriter writer);
+ protected abstract void Write(SystemLandscapeView view, ViewConfiguration viewConfiguration, TextWriter writer);
///
/// Writes a system context view in PlantUML format to the provided writer.
///
///
///
- protected abstract void Write(SystemContextView view, TextWriter writer);
+ protected abstract void Write(SystemContextView view, ViewConfiguration viewConfiguration, TextWriter writer);
///
/// Writes a container view in PlantUML format to the provided writer.
///
///
///
- protected abstract void Write(ContainerView view, TextWriter writer);
+ protected abstract void Write(ContainerView view, ViewConfiguration viewConfiguration, TextWriter writer);
///
/// Writes a component view in PlantUML format to the provided writer.
///
///
///
- protected abstract void Write(ComponentView view, TextWriter writer);
+ protected abstract void Write(ComponentView view, ViewConfiguration viewConfiguration, TextWriter writer);
///
/// Writes a dynamic view in PlantUML format to the provided writer.
///
///
///
- protected abstract void Write(DynamicView view, TextWriter writer);
+ protected abstract void Write(DynamicView view, ViewConfiguration viewConfiguration, TextWriter writer);
///
/// Writes a deployment view in PlantUML format to the provided writer.
///
///
///
- protected abstract void Write(DeploymentView view, TextWriter writer);
+ protected abstract void Write(DeploymentView view, ViewConfiguration viewConfiguration, TextWriter writer);
///
/// Produces a standard PlantUML diagram prolog for the provided view.
@@ -115,7 +118,7 @@ public void Write(View view, TextWriter writer)
///
/// is .
/// is .
- protected virtual void WriteProlog(View view, TextWriter writer)
+ protected virtual void WriteProlog(View view, ViewConfiguration viewConfiguration, TextWriter writer)
{
if (view == null) throw new ArgumentNullException(nameof(view));
if (writer == null) throw new ArgumentNullException(nameof(writer));
@@ -132,7 +135,7 @@ protected virtual void WriteProlog(View view, TextWriter writer)
///
/// is .
/// is .
- protected virtual void WriteEpilog(View view, TextWriter writer)
+ protected virtual void WriteEpilog(View view, ViewConfiguration viewConfiguration, TextWriter writer)
{
if (view == null) throw new ArgumentNullException(nameof(view));
if (writer == null) throw new ArgumentNullException(nameof(writer));
@@ -165,13 +168,22 @@ protected string TokenizeName(string s, int? hash = null)
{
if (String.IsNullOrWhiteSpace(s)) return "";
- s = s
- .Trim('/')
- .Replace(" ", "")
- .Replace("-", "")
- .Replace("[", "")
- .Replace("]", "")
- .Replace("/", "__");
+ // canonically name calculation changed
+ // a) instead of "/" starts with "{ElementType}://"; remove it that it is compatible with old impl.
+ // b) deployment namespaces are added with "/"; remove it that it is shorter (unique parts created via hash)
+ // c) orig "/" in static namespaces replaced with "."; replace with "__" that it is compatible with old impl.
+ var p = s.LastIndexOf('/');
+ if (p >= 0)
+ s = s.Substring(p + 1);
+
+ s = s.Replace(" ", "")
+ .Replace("-", "")
+ .Replace("[", "")
+ .Replace("]", "")
+ .Replace("(", "")
+ .Replace(")", "")
+ .Replace(".", "__");
+
if (hash.HasValue)
{
s = s + "__" + hash.Value.ToString("x");
@@ -191,45 +203,6 @@ protected virtual string GetTitle(View view) =>
? String.IsNullOrWhiteSpace(view.Title) ? view.Name : view.Title
: throw new ArgumentNullException(nameof(view));
- protected string BlockText(string s, int blockWidth, string formattedLineBreak)
- {
- var block = s;
-
- if (blockWidth > 0 && !s.Contains("\n") && !s.Contains("\r"))
- {
- var formatted = new StringBuilder();
- int pos = 0;
- string word = "";
-
- foreach (var c in s)
- {
- word += c;
- if (c == ' ')
- {
- if (pos != 0 && pos + word.Length > blockWidth)
- {
- formatted.Append(formattedLineBreak);
- pos = 0;
- }
- formatted.Append(word);
- pos += word.Length;
- word = "";
- }
- }
-
- if (word.Length > 0)
- {
- if (pos != 0 && pos + word.Length > blockWidth)
- formatted.Append(formattedLineBreak);
- formatted.Append(word);
- }
-
- block = formatted.ToString();
- }
-
- return block;
- }
-
protected string EscapeText(string s) => s.Replace("\"", """);
}
}
\ No newline at end of file
diff --git a/Structurizr.PlantUML/Structurizr.PlantUML.csproj b/Structurizr.PlantUML/Structurizr.PlantUML.csproj
index 8c3e4da..2bb6043 100644
--- a/Structurizr.PlantUML/Structurizr.PlantUML.csproj
+++ b/Structurizr.PlantUML/Structurizr.PlantUML.csproj
@@ -16,11 +16,11 @@
- netstandard1.3;net45
+ netstandard2.0;net45
-
+
\ No newline at end of file
diff --git a/Structurizr.Reflection.Examples/Structurizr.Reflection.Examples.csproj b/Structurizr.Reflection.Examples/Structurizr.Reflection.Examples.csproj
index 8be178a..a143cdf 100644
--- a/Structurizr.Reflection.Examples/Structurizr.Reflection.Examples.csproj
+++ b/Structurizr.Reflection.Examples/Structurizr.Reflection.Examples.csproj
@@ -7,7 +7,7 @@
false
-
+
diff --git a/Structurizr.Reflection/Structurizr.Reflection.csproj b/Structurizr.Reflection/Structurizr.Reflection.csproj
index 92fc045..2a5596f 100644
--- a/Structurizr.Reflection/Structurizr.Reflection.csproj
+++ b/Structurizr.Reflection/Structurizr.Reflection.csproj
@@ -20,11 +20,7 @@
-
-
-
-
-
+
diff --git a/Structurizr.sln b/Structurizr.sln
index e62dc9f..ea60d98 100644
--- a/Structurizr.sln
+++ b/Structurizr.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26430.15
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31410.357
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{4ED0E8DB-8A5B-4DF0-9CB1-995D97A04B88}"
ProjectSection(SolutionItems) = preProject
@@ -42,6 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "images", "images", "{4FBA61
ProjectSection(SolutionItems) = preProject
docs\images\c4-plantuml-getting-started.png = docs\images\c4-plantuml-getting-started.png
docs\images\c4-plantuml-getting-started2.png = docs\images\c4-plantuml-getting-started2.png
+ docs\images\c4-plantuml-getting-started3.png = docs\images\c4-plantuml-getting-started3.png
docs\images\plantuml-getting-started.png = docs\images\plantuml-getting-started.png
docs\images\structurizr-annotations-1.png = docs\images\structurizr-annotations-1.png
docs\images\structurizr-banner.png = docs\images\structurizr-banner.png
diff --git a/docs/c4-plantuml.md b/docs/c4-plantuml.md
index 0141c60..fa51905 100644
--- a/docs/c4-plantuml.md
+++ b/docs/c4-plantuml.md
@@ -1,16 +1,14 @@
# C4-PlantUML
-Structurizr for .NET also includes a simple exporter that can create diagram definitions compatible with [C4-PlantUML](https://github.com/RicardoNiepel/C4-PlantUML). The following diagram types are supported:
+Structurizr for .NET also includes a simple exporter that can create diagram definitions compatible with [C4-PlantUML v2.2.0](https://github.com/plantuml-stdlib/C4-PlantUML).
+Following diagram types are supported:
- Enterprise Context
- System Context
- Container
- Component
-- Dynamic*
-- Deployment*
-
-*..Dynamic and Deployment diagrams are part of an open pull request (from https://github.com/kirchsth/C4-PlantUML). The diagrams can use the definitions via
-CustomBaseUrl=https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/ or if it is not set then the definition is merged in each diagram)
+- Dynamic
+- Deployment
Simply create your software architecture model and views as usual, and use the [C4PlantUMLWriter](../Structurizr.PlantUML/IO/C4PlantUML/C4PlantUMLWriter.cs) class to export the views. [For example](../Structurizr.Examples/C4PlantUML.cs):
@@ -19,7 +17,7 @@ Workspace workspace = new Workspace("Getting Started", "This is a model of my so
Model model = workspace.Model;
model.Enterprise = new Enterprise("Some Enterprise");
-
+
Person user = model.AddPerson("User", "A user of my software system.");
SoftwareSystem softwareSystem = model.AddSoftwareSystem("Software System", "My software system.");
var userUsesSystemRelation = user.Uses(softwareSystem, "Uses");
@@ -53,13 +51,13 @@ This code will generate and output a PlantUML diagram definition that looks like
' Structurizr.SystemContextView: SystemContext
title Software System - System Context
-LAYOUT_WITH_LEGEND()
-
Enterprise_Boundary(SomeEnterprise, "Some Enterprise") {
System(SoftwareSystem__33c0d9d, "Software System", "My software system.")
Person(User__378734a, "User", "A user of my software system.")
Rel_Right(User__378734a, SoftwareSystem__33c0d9d, "Uses")
}
+
+SHOW_LEGEND()
@enduml
```
@@ -67,26 +65,39 @@ If you copy/paste this into [PlantUML online](http://www.plantuml.com/plantuml/)

-__Mark containers or components as Database__
+__Mark containers or components as database or via tags__
Additional to the relation directions (via .SetDirection(), see above) is it possible to activate the database symbols in the diagrams via component and container specific *.IsDatabase(true) calls.
+[C4-PlantUML v2.2.0](https://github.com/plantuml-stdlib/C4-PlantUML) supports tags (via `.Tags =`) an styles (`.Styles.Add()`) too.
```c#
Container webApplication = softwareSystem.AddContainer("Web Application", "Delivers content", "Java and spring MVC");
+// Additional tag element
+webApplication.Tags = "Single Page App";
+
Container database = softwareSystem.AddContainer("Database", "Stores information", "Relational Database Schema");
// Additional mark it as database
database.SetIsDatabase(true);
-user.Uses(webApplication, "uses", "HTTP");
+
+var httpCall = user.Uses(webApplication, "uses", "HTTP");
+// Additional tag relationship
+httpCall.Tags = "via firewall";
+
webApplication.Uses(database, "Reads from and writes to", "JDBC").SetDirection(DirectionValues.Right);
+// add corresponding styles
+var styles = views.Configuration.Styles;
+styles.Add(new ElementStyle("Single Page App") {Background = "#5F9061", Stroke = "#2E4F2E", Color = "#FFFFFF" });
+styles.Add(new RelationshipStyle("via firewall") {Color = "#B40404", Dashed = true }); // dashed is supported with next version see below
+
var containerView = views.CreateContainerView(softwareSystem, "containers", "");
containerView.AddAllElements();
using (var stringWriter = new StringWriter())
{
var plantUmlWriter = new C4PlantUmlWriter();
- plantUmlWriter.Write(containerView, stringWriter);
+ plantUmlWriter.Write(containerView, workspace.Views.Configuration, stringWriter);
Console.WriteLine(stringWriter.ToString());
}
```
@@ -100,15 +111,18 @@ This code will generate and output a PlantUML diagram definition that looks like
' Structurizr.ContainerView: containers
title Software System - Containers
-LAYOUT_WITH_LEGEND()
+AddElementTag(Single Page App, $bgColor = "#5f9061", $fontColor = "#ffffff", $borderColor = "#2e4f2e")
+AddRelTag(via firewall, $textColor = "#b40404", $lineColor = "#b40404")
Person(User__378734a, "User", "A user of my software system.")
System_Boundary(SoftwareSystem__33c0d9d, "Software System") {
ContainerDb(SoftwareSystem__Database__202c666, "Database", "Relational Database Schema", "Stores information")
- Container(SoftwareSystem__WebApplication__2004eee, "Web Application", "Java and spring MVC", "Delivers content")
+ Container(SoftwareSystem__WebApplication__2004eee, "Web Application", "Java and spring MVC", "Delivers content", $tags="Single Page App")
}
-Rel(User__378734a, SoftwareSystem__WebApplication__2004eee, "uses", "HTTP")
+Rel(User__378734a, SoftwareSystem__WebApplication__2004eee, "uses", "HTTP", $tags="via firewall")
Rel_Right(SoftwareSystem__WebApplication__2004eee, SoftwareSystem__Database__202c666, "Reads from and writes to", "JDBC")
+
+SHOW_LEGEND()
@enduml
```
@@ -116,6 +130,55 @@ You will get something like this:

+__Use features of the next planned C4-PlantUML version (v2.3.0 ?)__
+
+The next version will support the correct Person shape and e.g. dotted lines. These features can be activated via `.EnableNextFeatures=true`
+(until the next version is released please use `.CustomBaseUrl="https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/"`)
+
+```c#
+using (var stringWriter = new StringWriter())
+{
+ var plantUmlWriter = new C4PlantUmlWriter();
+ plantUmlWriter.EnableNextFeatures = true;
+ plantUmlWriter.CustomBaseUrl = "https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/";
+
+ plantUmlWriter.Write(containerView, workspace.Views.Configuration, stringWriter);
+ Console.WriteLine(stringWriter.ToString());
+}
+```
+
+This code will generate and output a PlantUML diagram definition that looks like this:
+
+```
+@startuml
+!includeurl https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/C4_Container.puml
+
+' Structurizr.ContainerView: containers
+title Software System - Containers
+
+SHOW_PERSON_OUTLINE()
+AddRelTag("Back", $textColor=$ARROW_COLOR, $lineColor=$ARROW_COLOR, $lineStyle = DottedLine())
+
+AddElementTag(Single Page App, $bgColor = "#5f9061", $fontColor = "#ffffff", $borderColor = "#2e4f2e", $shape = RoundedBoxShape())
+AddRelTag(via firewall, $textColor = "#b40404", $lineColor = "#b40404", $lineStyle = DashedLine())
+
+Person(User__378734a, "User", "A user of my software system.")
+System_Boundary(SoftwareSystem__33c0d9d, "Software System") {
+ ContainerDb(SoftwareSystem__Database__202c666, "Database", "Relational Database Schema", "Stores information")
+ Container(SoftwareSystem__WebApplication__2004eee, "Web Application", "Java and spring MVC", "Delivers content", $tags="Single Page App")
+}
+Rel(User__378734a, SoftwareSystem__WebApplication__2004eee, "uses", "HTTP", $tags="via firewall")
+Rel_Right(SoftwareSystem__WebApplication__2004eee, SoftwareSystem__Database__202c666, "Reads from and writes to", "JDBC")
+
+SHOW_LEGEND()
+@enduml
+```
+
+You will get something like this:
+
+
+
+
## Benefits of using C4-PlantUML with Structurizr
The key benefit of using PlantUML in conjunction with the Structurizr client library is that you can create diagrams from a __model__ of your software system. The model provides a set of rules that must be followed; related to elements, relationships, and how they are exposed using diagrams. This means:
diff --git a/docs/images/c4-plantuml-getting-started.png b/docs/images/c4-plantuml-getting-started.png
index cd16e37..0e9afdd 100644
Binary files a/docs/images/c4-plantuml-getting-started.png and b/docs/images/c4-plantuml-getting-started.png differ
diff --git a/docs/images/c4-plantuml-getting-started2.png b/docs/images/c4-plantuml-getting-started2.png
index b3b63d4..a931c99 100644
Binary files a/docs/images/c4-plantuml-getting-started2.png and b/docs/images/c4-plantuml-getting-started2.png differ
diff --git a/docs/images/c4-plantuml-getting-started3.png b/docs/images/c4-plantuml-getting-started3.png
new file mode 100644
index 0000000..bfbaaf0
Binary files /dev/null and b/docs/images/c4-plantuml-getting-started3.png differ