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/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..22b43f4 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,8 +46,6 @@ public void test_writeBigBankPlcWorkspace()
' Structurizr.SystemLandscapeView: SystemLandscape
title System Landscape for Big Bank plc
-LAYOUT_WITH_LEGEND()
-
Person_Ext(PersonalBankingCustomer__9bc576, ""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."")
@@ -62,10 +60,12 @@ public void test_writeBigBankPlcWorkspace()
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_Down(InternetBankingSystem__2aef74c, MainframeBankingSystem__f50ffa, ""Gets account information from, and makes payments using"")
Rel(PersonalBankingCustomer__9bc576, ATM__22fc739, ""Withdraws cash using"")
Rel(PersonalBankingCustomer__9bc576, CustomerServiceStaff__a35be5, ""Asks questions to"", ""Telephone"")
-Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__2aef74c, ""Uses"")
+Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__2aef74c, ""Views account balances, and makes payments using"")
+
+SHOW_LEGEND()
@enduml
@startuml
@@ -74,16 +74,16 @@ 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"")
+Rel(InternetBankingSystem__2aef74c, MainframeBankingSystem__f50ffa, ""Gets account information from, and makes payments using"")
+Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__2aef74c, ""Views account balances, and makes payments using"")
+
+SHOW_LEGEND()
@enduml
@startuml
@@ -92,8 +92,6 @@ 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."")
@@ -106,14 +104,16 @@ title Internet Banking System - Containers
}
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_Left(InternetBankingSystem__APIApplication__2c36bed, MainframeBankingSystem__f50ffa, ""Makes API calls to"", ""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(PersonalBankingCustomer__9bc576, InternetBankingSystem__MobileApp__38a070b, ""Views account balances, and makes payments using"")
+Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__SinglePageApplication__1414c79, ""Views account balances, and makes payments using"")
+Rel(PersonalBankingCustomer__9bc576, InternetBankingSystem__WebApplication__1bb919c, ""Visits bigbank.com/ib using"", ""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"")
+
+SHOW_LEGEND()
@enduml
@startuml
@@ -122,8 +122,6 @@ 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."")
@@ -150,346 +148,115 @@ title Internet Banking System - API Application - Components
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"")
+
+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."")
}
-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__1414c79, InternetBankingSystem__APIApplication__SignInController__22cc62b, ""Submits credentials to"", ""JSON/HTTPS"")
+RelIndex(""2"", InternetBankingSystem__APIApplication__SignInController__22cc62b, InternetBankingSystem__APIApplication__SecurityComponent__a4474, ""Validates credentials using"")
+RelIndex_Right(""3"", InternetBankingSystem__APIApplication__SecurityComponent__a4474, InternetBankingSystem__Database__18307f7, ""select * from users where username = ?"", ""JDBC"")
+RelIndex_Left(""4"", InternetBankingSystem__Database__18307f7, InternetBankingSystem__APIApplication__SecurityComponent__a4474, ""Returns user data to"", ""JDBC"")
+RelIndex(""5"", InternetBankingSystem__APIApplication__SecurityComponent__a4474, InternetBankingSystem__APIApplication__SignInController__22cc62b, ""Returns true if the hashed password matches"")
+RelIndex_Left(""6"", InternetBankingSystem__APIApplication__SignInController__22cc62b, InternetBankingSystem__SinglePageApplication__1414c79, ""Sends back an authentication token to"", ""JSON/HTTPS"")
+
+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()
+title Internet Banking System - Deployment - Development
-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"") {
+Node(BigBankplc__13491b2, ""Big Bank plc"", ""Big Bank plc data center"") {
+ Node(bigbankdev001__2f4813f, ""bigbank-dev001"") {
+ System(MainframeBankingSystem1__1b2a42c, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."")
+ }
+}
+Node(DeveloperLaptop__389f399, ""Developer Laptop"", ""Microsoft Windows 10 or Apple macOS"") {
+ Node(DockerContainerWebServer__1b73d2e, ""Docker Container - Web Server"", ""Docker"") {
+ Node(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."")
}
}
- Node(Deployment__Development__DeveloperLaptop__DockerContainerDatabaseServer__2eae566, ""Docker Container - Database Server"", ""Docker"") {
- Node(Deployment__Development__DeveloperLaptop__DockerContainerDatabaseServer__DatabaseServer__24d13de, ""Database Server"", ""Oracle 12c"") {
+ Node(DockerContainerDatabaseServer__2eae566, ""Docker Container - Database Server"", ""Docker"") {
+ Node(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(Deployment__Development__DeveloperLaptop__WebBrowser__3930fd, ""Web Browser"", ""Google Chrome, Mozilla \nFirefox, Apple Safari or \nMicrosoft Edge"") {
+ Node(WebBrowser__3930fd, ""Web Browser"", ""Chrome, Firefox, Safari, or Edge"") {
Container(InternetBankingSystem__SinglePageApplication1__bbe85d, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."")
}
}
Rel(InternetBankingSystem__APIApplication1__1f227f4, InternetBankingSystem__Database1__3296ca6, ""Reads from and writes to"", ""JDBC"")
+Rel(InternetBankingSystem__APIApplication1__1f227f4, MainframeBankingSystem1__1b2a42c, ""Makes API calls to"", ""XML/HTTPS"")
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"")
+
+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()
+title Internet Banking System - Deployment - Live
-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."")
+Node(BigBankplc__3ffe15e, ""Big Bank plc"", ""Big Bank plc data center"") {
+ Node(bigbankprod001__f5e94d, ""bigbank-prod001"") {
+ System(MainframeBankingSystem1__3db6dd2, ""Mainframe Banking System"", ""Stores all of the core banking information about customers, accounts, transactions, etc."")
+ }
+ Node(bigbankweb***__3f92e18, ""bigbank-web*** (x4)"", ""Ubuntu 16.04 LTS"") {
+ Node(ApacheTomcat__27b4383, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+ Container(InternetBankingSystem__WebApplication1__1720850, ""Web Application"", ""Java and Spring MVC"", ""Delivers the static content and the Internet banking single page application."")
}
}
- 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***__263d9e8, ""bigbank-api*** (x8)"", ""Ubuntu 16.04 LTS"") {
+ Node(ApacheTomcat__3b84ab, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+ Container(InternetBankingSystem__APIApplication1__1408a33, ""API Application"", ""Java and Spring MVC"", ""Provides Internet banking functionality via a JSON/HTTPS API."")
}
}
- 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__35ec592, ""bigbank-db01"", ""Ubuntu 16.04 LTS"") {
+ Node(OraclePrimary__19fd8f, ""Oracle - Primary"", ""Oracle 12c"") {
+ ContainerDb(InternetBankingSystem__Database1__1c974ec, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."")
}
}
- 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__1db08a2, ""bigbank-db02"", ""Ubuntu 16.04 LTS"") {
+ Node(OracleSecondary__1c4ec22, ""Oracle - Secondary"", ""Oracle 12c"") {
+ ContainerDb(InternetBankingSystem__Database1__d89394, ""Database"", ""Relational Database Schema"", ""Stores user registration information, hashed authentication credentials, access logs, etc."")
}
}
}
-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__2510bf3, ""Customer's computer"", ""Microsoft Windows or Apple macOS"") {
+ Node(WebBrowser__ba951, ""Web Browser"", ""Chrome, Firefox, Safari, or Edge"") {
+ Container(InternetBankingSystem__SinglePageApplication1__298b31c, ""Single-Page Application"", ""JavaScript and Angular"", ""Provides all of the Internet banking functionality to customers via their web browser."")
}
}
-Node(Deployment__Live__Customer'smobiledevice__1d6bcb6, ""Customer's mobile device"", ""Apple iOS or Android"") {
+Node(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."")
}
-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__1408a33, InternetBankingSystem__Database1__1c974ec, ""Reads from and writes to"", ""JDBC"")
+Rel(InternetBankingSystem__APIApplication1__1408a33, InternetBankingSystem__Database1__d89394, ""Reads from and writes to"", ""JDBC"")
+Rel(InternetBankingSystem__APIApplication1__1408a33, MainframeBankingSystem1__3db6dd2, ""Makes API calls to"", ""XML/HTTPS"")
+Rel(InternetBankingSystem__MobileApp1__d004b3, InternetBankingSystem__APIApplication1__1408a33, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel_Left(OraclePrimary__19fd8f, OracleSecondary__1c4ec22, ""Replicates data to"")
+Rel(InternetBankingSystem__SinglePageApplication1__298b31c, InternetBankingSystem__APIApplication1__1408a33, ""Makes API calls to"", ""JSON/HTTPS"")
+Rel_Up(InternetBankingSystem__WebApplication1__1720850, InternetBankingSystem__SinglePageApplication1__298b31c, ""Delivers to the customer's web browser"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -504,9 +271,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 +286,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 +301,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,29 +361,34 @@ 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);
}
@@ -615,17 +397,15 @@ public void test_writeWorkspace_WithCustomBaseUrl()
{
PopulateWorkspace();
- _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/";
+ _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/";
_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()
-
System_Ext(EmailSystem__1127701, ""E-mail System"")
Enterprise_Boundary(SomeEnterprise, ""Some Enterprise"") {
Person(User__387cc75, ""User"")
@@ -634,16 +414,16 @@ 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()
-
Enterprise_Boundary(SomeEnterprise, ""Some Enterprise"") {
System_Ext(EmailSystem__1127701, ""E-mail System"")
System(SoftwareSystem__31d545b, ""Software System"")
@@ -652,16 +432,16 @@ 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()
-
System_Ext(EmailSystem__1127701, ""E-mail System"")
Person(User__387cc75, ""User"")
System_Boundary(SoftwareSystem__31d545b, ""Software System"") {
@@ -672,16 +452,16 @@ 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()
-
ContainerDb(SoftwareSystem__Database__39bccb8, ""Database"", ""Relational Database Schema"", ""Stores information"")
System_Ext(EmailSystem__1127701, ""E-mail System"")
Person(User__387cc75, ""User"")
@@ -696,46 +476,48 @@ 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()
-
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
@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()
-
-Node(Deployment__Default__DatabaseServer__1edef6c, ""Database Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__DatabaseServer__MySQL__1fa4f18, ""MySQL"", ""MySQL 5.5.x"") {
+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"")
}
}
-Node(Deployment__Default__WebServer__1e2ffe, ""Web Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__WebServer__ApacheTomcat__2b8afb4, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+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"")
}
}
Rel(SoftwareSystem__WebApplication1__31f1f25, SoftwareSystem__Database1__bb9c73, ""Reads from and writes to"", ""JDBC"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -756,8 +538,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 +546,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 +560,16 @@ public void test_writeEnterpriseContextView_WithCustomBaseUrl()
PopulateWorkspace();
SystemLandscapeView systemLandscapeView = _workspace.Views.SystemLandscapeViews.First();
- _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/";
+ _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/";
_plantUMLWriter.Write(systemLandscapeView, _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 +578,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());
@@ -819,8 +601,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 +609,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());
@@ -849,8 +631,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 +641,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());
@@ -881,8 +663,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 +677,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());
@@ -913,192 +695,22 @@ public void test_writeDynamicView()
// 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());
@@ -1114,62 +726,24 @@ public void test_writeDeploymentView()
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
+title Software System - Deployment - Default
-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"") {
+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"")
}
}
-Node(Deployment__Default__WebServer__1e2ffe, ""Web Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__WebServer__ApacheTomcat__2b8afb4, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+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"")
}
}
Rel(SoftwareSystem__WebApplication1__31f1f25, SoftwareSystem__Database1__bb9c73, ""Reads from and writes to"", ""JDBC"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
@@ -1181,29 +755,29 @@ public void test_writeDeploymentView_WithCustomBaseUrl()
PopulateWorkspace();
DeploymentView deploymentView = _workspace.Views.DeploymentViews.First();
- _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/master/";
+ _plantUMLWriter.CustomBaseUrl = @"https://raw.githubusercontent.com/kirchsth/C4-PlantUML/extended/";
_plantUMLWriter.Write(deploymentView, _stringWriter);
Assert.Equal(
@"@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()
-
-Node(Deployment__Default__DatabaseServer__1edef6c, ""Database Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__DatabaseServer__MySQL__1fa4f18, ""MySQL"", ""MySQL 5.5.x"") {
+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"")
}
}
-Node(Deployment__Default__WebServer__1e2ffe, ""Web Server"", ""Ubuntu 12.04 LTS"") {
- Node(Deployment__Default__WebServer__ApacheTomcat__2b8afb4, ""Apache Tomcat"", ""Apache Tomcat 8.x"") {
+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"")
}
}
Rel(SoftwareSystem__WebApplication1__31f1f25, SoftwareSystem__Database1__bb9c73, ""Reads from and writes to"", ""JDBC"")
+
+SHOW_LEGEND()
@enduml
".UnifyNewLine().UnifyHashValues(), _stringWriter.ToString().UnifyHashValues());
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..bb5c1ec 100644
--- a/Structurizr.PlantUML/IO/C4PlantUML/C4PlantUmlWriter.cs
+++ b/Structurizr.PlantUML/IO/C4PlantUML/C4PlantUmlWriter.cs
@@ -6,6 +6,9 @@
// 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: Add tags/styles support
+// 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,12 +26,13 @@ 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;
protected override void Write(SystemLandscapeView view, TextWriter writer)
{
@@ -258,6 +262,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 +305,11 @@ private string TypeOf(Element e)
return "Container";
}
+ if (e is SoftwareSystemInstance)
+ {
+ return "Software System";
+ }
+
return "";
}
@@ -307,6 +321,9 @@ private bool HasValue(string s)
protected override void WriteProlog(View view, TextWriter writer)
{
+ if (view == null) throw new ArgumentNullException(nameof(view));
+ if (writer == null) throw new ArgumentNullException(nameof(writer));
+
writer.WriteLine("@startuml");
switch (view)
@@ -325,237 +342,15 @@ protected override void WriteProlog(View view, TextWriter writer)
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");
- }
+ writer.WriteLine(!string.IsNullOrWhiteSpace(CustomBaseUrl)
+ ? $"!includeurl {CustomBaseUrl}C4_Dynamic.puml"
+ : $"!include ");
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");
- }
+ writer.WriteLine(!string.IsNullOrWhiteSpace(CustomBaseUrl)
+ ? $"!includeurl {CustomBaseUrl}C4_Deployment.puml"
+ : $"!include ");
break;
default:
@@ -570,8 +365,6 @@ protected override void WriteProlog(View view, TextWriter writer)
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 ()
if (Layout.HasValue)
@@ -588,8 +381,23 @@ 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();
+ }
+
+ protected virtual void WriteEpilog(View view, TextWriter writer)
+ {
+ if (view == null) throw new ArgumentNullException(nameof(view));
+ if (writer == null) throw new ArgumentNullException(nameof(writer));
+
+ if (LayoutWithLegend)
+ {
writer.WriteLine();
+ writer.WriteLine("SHOW_LEGEND()"); // C4 PlantUML workaround add ()
+ }
+
+ writer.WriteLine("@enduml");
+ writer.WriteLine("");
}
protected virtual void Write(Element element, TextWriter writer, int indentLevel = 0, bool asBoundary = false)
@@ -617,10 +425,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 +463,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;
@@ -706,6 +516,13 @@ protected virtual void Write(RelationshipView relationshipView, TextWriter write
label = advancedDescription ?? relationship.Description ?? "",
tech = !string.IsNullOrWhiteSpace(relationship.Technology) ? relationship.Technology : null;
+ if (relationshipView.Response ?? false)
+ {
+ var swap = source;
+ source = dest;
+ dest = swap;
+ }
+
var macro = GetSpecificLayoutMacro(relationshipView);
writer.Write($"{macro}({source}, {dest}, \"{EscapeText(label)}\"");
@@ -729,8 +546,15 @@ protected virtual void WriteDynamicInteraction(RelationshipView relationshipView
dest = TokenizeName(relationship.Destination),
tech = !string.IsNullOrWhiteSpace(relationship.Technology) ? relationship.Technology : null;
+ if (relationshipView.Response ?? false)
+ {
+ 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)
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..262911b 100644
--- a/Structurizr.PlantUML/IO/C4PlantUML/PlantUMLWriterBase.cs
+++ b/Structurizr.PlantUML/IO/C4PlantUML/PlantUMLWriterBase.cs
@@ -165,13 +165,20 @@ 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(".", "__");
+
if (hash.HasValue)
{
s = s + "__" + hash.Value.ToString("x");
@@ -191,45 +198,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/docs/c4-plantuml.md b/docs/c4-plantuml.md
index 0141c60..ddf30ba 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):
@@ -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
```
@@ -100,8 +98,6 @@ This code will generate and output a PlantUML diagram definition that looks like
' Structurizr.ContainerView: containers
title Software System - Containers
-LAYOUT_WITH_LEGEND()
-
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")
@@ -109,6 +105,8 @@ System_Boundary(SoftwareSystem__33c0d9d, "Software System") {
}
Rel(User__378734a, SoftwareSystem__WebApplication__2004eee, "uses", "HTTP")
Rel_Right(SoftwareSystem__WebApplication__2004eee, SoftwareSystem__Database__202c666, "Reads from and writes to", "JDBC")
+
+SHOW_LEGEND()
@enduml
```
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..dbf8db0 100644
Binary files a/docs/images/c4-plantuml-getting-started2.png and b/docs/images/c4-plantuml-getting-started2.png differ