Skip to content
This repository was archived by the owner on Dec 23, 2023. It is now read-only.

Commit

Permalink
#47 Add new C4PlantUmlWriter with C4-PlantUML support
Browse files Browse the repository at this point in the history
- Add new C4PlantUmlWriter with C4-PlantUML support (issue #47)
- ModelItem returns a list of all tags via GetAllTag()
- RelationshipView support an additional list of tags which can be used in the diagram via ViewTags.
  RelationshipView.GetAllTag() returns a merged list of ViewTags and all Relationship tags
- Update relationship descriptions and technology in BigBankPlc example
- Update PlantUMLWriterTests and C4PlantUmlWriterTests that the expected text can be (simpler) reused as UML definition
  • Loading branch information
KIRCHSTH authored and KIRCHSTH committed Oct 15, 2019
1 parent d1c04e7 commit 0057342
Show file tree
Hide file tree
Showing 20 changed files with 2,521 additions and 182 deletions.
69 changes: 69 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto

# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
#*.ts text

# Shell scripts should always have lf line endings
*.sh text eol=lf
sources.list text eol=lf

#### Visual Studio specific stuff

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
*.cs diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just comment the entries below and
# uncomment the group further below
###############################################################################
*.sln text eol=crlf
*.csproj text eol=crlf
*.vbproj text eol=crlf
*.vcxproj text eol=crlf
*.vcproj text eol=crlf
*.dbproj text eol=crlf
*.fsproj text eol=crlf
*.lsproj text eol=crlf
*.wixproj text eol=crlf
*.modelproj text eol=crlf
*.sqlproj text eol=crlf
*.wmaproj text eol=crlf

*.xproj text eol=crlf
*.props text eol=crlf
*.filters text eol=crlf
*.vcxitems text eol=crlf

*.sln merge=binary
*.csproj merge=binary
*.vbproj merge=binary
*.vcxproj merge=binary
*.vcproj merge=binary
*.dbproj merge=binary
*.fsproj merge=binary
*.lsproj merge=binary
*.wixproj merge=binary
*.modelproj merge=binary
*.sqlproj merge=binary
*.wmaproj merge=binary

*.xproj merge=binary
*.props merge=binary
*.filters merge=binary
*.vcxitems merge=binary

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![Structurizr](docs/images/structurizr-banner.png)
![Structurizr](docs/images/structurizr-banner.png)

# Structurizr for .NET

Expand Down Expand Up @@ -64,6 +64,7 @@ You can see the live workspace at [https://structurizr.com/share/25441](https://
* [Structurizr annotations](docs/structurizr-annotations.md)
* Exporting and visualising with other tools
* [PlantUML](docs/plantuml.md)
* [PlantUML with C4 layout](docs/c4-plantuml.md)
* [DGML](https://github.com/merijndejonge/Structurizr.Dgml)
* Other
* [HTTP-based health checks](docs/health-checks.md)
Expand Down
29 changes: 29 additions & 0 deletions Structurizr.Core.Tests/Model/ModelItemTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Collections.Generic;
using Xunit;

namespace Structurizr.Core.Tests
{
public class ModelItemTests : AbstractTestBase
{
[Fact]
public void Test_GetAllTags_NoTagAdded_RequiredTagsAreReturned()
{
Person user = Model.AddPerson("Person", "Description");
SoftwareSystem softwareSystem = Model.AddSoftwareSystem("Software System", "Description");
var relation = user.Uses(softwareSystem, "Uses", "");
// Relationship.GetRequiredTags() == new List<string> { Structurizr.Tags.Relationship, Structurizr.Tags.Synchronous }
Assert.Equal(new List<string> { Structurizr.Tags.Relationship, Structurizr.Tags.Synchronous }, relation.GetAllTags());
}

[Fact]
public void Test_GetAllTags_TagsAdded_AddedTagsAndRequiredTagsAreReturned()
{
Person user = Model.AddPerson("Person", "Description");
SoftwareSystem softwareSystem = Model.AddSoftwareSystem("Software System", "Description");
var relation = user.Uses(softwareSystem, "Uses", "");
relation.AddTags("TagA","TagB");
// Relationship.GetRequiredTags() == new List<string> { Structurizr.Tags.Relationship, Structurizr.Tags.Synchronous }
Assert.Equal(new List<string> { Structurizr.Tags.Relationship, Structurizr.Tags.Synchronous, "TagA","TagB" }, relation.GetAllTags());
}
}
}
26 changes: 26 additions & 0 deletions Structurizr.Core.Tests/View/RelationshipViewTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using Xunit;

namespace Structurizr.Core.Tests.View
{
public class RelationshipViewTests : AbstractTestBase
{
[Fact]
public void Test_GetAllTags_RelationshipViewTagsAdded_AddedViewTagsAndAllRelationTagsAreReturned()
{
Person user = Model.AddPerson("Person", "Description");
SoftwareSystem softwareSystem = Model.AddSoftwareSystem("Software System", "Description");
var relation = user.Uses(softwareSystem, "Uses", "");
relation.AddTags("TagA","TagB");

var relationView = new RelationshipView(relation);
relationView.AddViewTags("Rel_Left", "AnotherLayoutTag");

// var expected = new List<string>(relation.GetAllTags()) {"Rel_Left", "AnotherLayoutTag"};
var expected = new List<string>{"Rel_Left", "AnotherLayoutTag"};
expected.AddRange(relation.GetAllTags());

Assert.Equal(expected, relationView.GetAllTags());
}
}
}
8 changes: 8 additions & 0 deletions Structurizr.Core/Model/ModelItem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

Expand All @@ -18,6 +19,13 @@ public abstract class ModelItem

private List<string> _tags = new List<string>();

public IEnumerable<string> GetAllTags()
{
if (String.IsNullOrWhiteSpace(Tags))
return Enumerable.Empty<string>();
return Tags.Split(new [] { "," }, StringSplitOptions.RemoveEmptyEntries);
}

[DataMember(Name = "tags", EmitDefaultValue = false)]
public virtual string Tags
{
Expand Down
90 changes: 82 additions & 8 deletions Structurizr.Core/View/RelationshipView.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace Structurizr
{
Expand Down Expand Up @@ -39,23 +41,23 @@ public string Id
this.id = value;
}
}

/// <summary>
/// The order of this relationship (used in dynamic views only; e.g. 1.0, 1.1, 2.0, etc).
/// </summary>
[DataMember(Name="order", EmitDefaultValue=false)]
[DataMember(Name = "order", EmitDefaultValue = false)]
public string Order { get; set; }

/// <summary>
/// The description of this relationship (used in dynamic views only).
/// </summary>
[DataMember(Name="description", EmitDefaultValue=false)]
[DataMember(Name = "description", EmitDefaultValue = false)]
public string Description { get; set; }

/// <summary>
/// The set of vertices used to render the relationship.
/// </summary>
[DataMember(Name="vertices", EmitDefaultValue=false)]
[DataMember(Name = "vertices", EmitDefaultValue = false)]
public List<Vertex> Vertices { get; set; }

/// <summary>
Expand Down Expand Up @@ -93,6 +95,79 @@ public int? Position
}
}

/// <summary>
/// Relationship tags extended with additional view related tags (which are not part of the model).
/// (e.g. PlantUMLWriter uses layout specific relation tags, and via this extended tags a relation can have
/// view specific layout directions like REL_UP, REL_DOWN..)
/// </summary>
public IEnumerable<string> GetAllTags()
{
List<string> listOfTags = new List<string>(this._viewTags);
if (this.Relationship != null)
listOfTags.AddRange(this.Relationship.GetAllTags());
return listOfTags;
}

private List<string> _viewTags = new List<string>();

[DataMember(Name = "viewTags", EmitDefaultValue = false)]
public string ViewTags
{
get
{
if (_viewTags.Count == 0)
{
return "";
}

StringBuilder buf = new StringBuilder();
foreach (string tag in this._viewTags)
{
buf.Append(tag);
buf.Append(",");
}

string tagsAsString = buf.ToString();
return tagsAsString.Substring(0, tagsAsString.Length - 1);
}

set
{
this._viewTags.Clear();

if (value == null)
{
return;
}

this._viewTags.AddRange(value.Split(','));
}
}

public void AddViewTags(params string[] tags)
{
if (tags == null)
{
return;
}

foreach (string tag in tags)
{
if (tag != null)
{
this._viewTags.Add(tag);
}
}
}

public void RemoveViewTag(string tag)
{
if (tag != null)
{
this._viewTags.Remove(tag);
}
}

internal RelationshipView()
{
}
Expand Down Expand Up @@ -146,6 +221,5 @@ internal void CopyLayoutInformationFrom(RelationshipView source)
this.Position = source.Position;
}
}

}
}
10 changes: 4 additions & 6 deletions Structurizr.Examples/BigBankPlc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class BigBankPlc
private const string DatabaseTag = "Database";
private const string FailoverTag = "Failover";

private static Workspace Create()
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;
Expand Down Expand Up @@ -76,7 +76,7 @@ private static Workspace Create()
customer.Uses(webApplication, "Uses", "HTTPS");
customer.Uses(singlePageApplication, "Uses", "");
customer.Uses(mobileApp, "Uses", "");
webApplication.Uses(singlePageApplication, "Delivers", "");
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");
Expand All @@ -91,8 +91,8 @@ private static Workspace Create()
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, "Uses", "HTTPS"));
apiApplication.Components.Where(c => "Spring MVC Rest Controller".Equals(c.Technology)).ToList().ForEach(c => mobileApp.Uses(c, "Uses", "HTTPS"));
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");
Expand Down Expand Up @@ -261,7 +261,5 @@ static void Main()
StructurizrClient structurizrClient = new StructurizrClient(ApiKey, ApiSecret);
structurizrClient.PutWorkspace(WorkspaceId, Create());
}

}

}
45 changes: 45 additions & 0 deletions Structurizr.Examples/C4PlantUML.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.IO;
using System.Linq;
using Structurizr.IO.C4PlantUML;

namespace Structurizr.Examples
{
/// <summary>
/// An example of how to use the C4PlantUML writer. Run this program and copy/paste
/// the output into http://www.plantuml.com/plantuml/
/// </summary>
public class C4PlantUML
{
static void Main()
{
Workspace workspace = new Workspace("Getting Started", "This is a model of my software system.");
Model model = workspace.Model;

model.Enterprise = new Enterprise("Some Enterprise");

Person user = model.AddPerson("User", "A user of my software system.");
SoftwareSystem softwareSystem = model.AddSoftwareSystem("Software System", "My software system.");
var userUsesSystemRelation = user.Uses(softwareSystem, "Uses");
// layout could be added to relation (active in all views)
// userUsesSystemRelation.AddTags(C4PlantUmlWriter.Tags.Rel_Right);

ViewSet views = workspace.Views;
SystemContextView contextView = views.CreateSystemContextView(softwareSystem, "SystemContext", "An example of a System Context diagram.");
contextView.AddAllSoftwareSystems();
contextView.AddAllPeople();

// C4PlantUMLWriter support relation layouts tags, e.g. "User" should be left of "Software System" in view
contextView.Relationships
.First(rv => rv.Relationship.SourceId == user.Id && rv.Relationship.DestinationId == softwareSystem.Id)
.AddViewTags(C4PlantUmlWriter.Tags.Rel_Right);

using (var stringWriter = new StringWriter())
{
var plantUmlWriter = new C4PlantUmlWriter();
plantUmlWriter.Write(workspace, stringWriter);
Console.WriteLine(stringWriter.ToString());
}
}
}
}
Loading

0 comments on commit 0057342

Please sign in to comment.