Skip to content

Commit 8f8a459

Browse files
structurizr-import: Adds support for plantuml.inline, mermaid.inline, and kroki.inline properties to inline the resulting PNG/SVG file into the workspace.
1 parent 30c61e5 commit 8f8a459

File tree

9 files changed

+204
-14
lines changed

9 files changed

+204
-14
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- structurizr-dsl: Fixes https://github.com/structurizr/java/issues/435 (Relationship archetype not applied to implicit-source relationships).
1414
- structurizr-dsl: Adds support for removing relationships between software system instance/container instances, with a view to redefining them via infrastructure nodes.
1515
- structurizr-dsl: Adds support for a `jump` property on relationship styles.
16+
- structurizr-import: Adds support for `plantuml.inline`, `mermaid.inline`, and `kroki.inline` properties to inline the resulting PNG/SVG file into the workspace.
1617
- structurizr-inspection: Adds a way to disable inspections via a workspace property named `structurizr.inspection` (`false` to disable).
1718
- structurizr-inspection: Default inspector adds a summary of error/warning/info/ignore counts as workspace properties.
1819
- structurizr-inspection: Fixes `model.deploymentnode.technology` (it was checking the description property rather than technology).

structurizr-core/src/main/java/com/structurizr/util/ImageUtils.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import java.io.IOException;
99
import java.net.URL;
1010
import java.net.URLConnection;
11+
import java.net.http.HttpClient;
12+
import java.net.http.HttpRequest;
13+
import java.net.http.HttpResponse;
1114
import java.nio.file.Files;
1215
import java.util.Base64;
1316

@@ -124,6 +127,36 @@ public static String getImageAsDataUri(File file) throws IOException {
124127
return DATA_URI_PREFIX + contentType + ";base64," + base64Content;
125128
}
126129

130+
public static String getSvgAsDataUri(@Nonnull URL url) throws Exception {
131+
HttpRequest request = HttpRequest.newBuilder()
132+
.uri(url.toURI())
133+
.header("accept", CONTENT_TYPE_IMAGE_SVG)
134+
.build();
135+
HttpClient client = HttpClient.newBuilder()
136+
.followRedirects(HttpClient.Redirect.ALWAYS)
137+
.build();
138+
139+
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
140+
String svg = response.body();
141+
142+
return DATA_URI_PREFIX + CONTENT_TYPE_IMAGE_SVG + ";base64," + Base64.getEncoder().encodeToString(svg.getBytes());
143+
}
144+
145+
public static String getPngAsDataUri(@Nonnull URL url) throws Exception {
146+
HttpRequest request = HttpRequest.newBuilder()
147+
.uri(url.toURI())
148+
.header("accept", CONTENT_TYPE_IMAGE_PNG)
149+
.build();
150+
HttpClient client = HttpClient.newBuilder()
151+
.followRedirects(HttpClient.Redirect.ALWAYS)
152+
.build();
153+
154+
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
155+
byte[] png = response.body();
156+
157+
return DATA_URI_PREFIX + CONTENT_TYPE_IMAGE_PNG + ";base64," + Base64.getEncoder().encodeToString(png);
158+
}
159+
127160
public static void validateImage(String imageDescriptor) {
128161
if (StringUtils.isNullOrEmpty(imageDescriptor)) {
129162
return;

structurizr-import/build.gradle

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,17 @@ dependencies {
44

55
}
66

7-
description = 'Utilities to import diagrams and documentation into a Structurizr workspace'
7+
description = 'Utilities to import diagrams and documentation into a Structurizr workspace'
8+
9+
test {
10+
useJUnitPlatform {
11+
excludeTags "IntegrationTest"
12+
}
13+
}
14+
15+
tasks.register("integrationTest", Test) {
16+
useJUnitPlatform {
17+
includeTags "IntegrationTest"
18+
}
19+
mustRunAfter check
20+
}

structurizr-import/src/main/java/com/structurizr/importer/diagrams/kroki/KrokiImporter.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
package com.structurizr.importer.diagrams.kroki;
22

33
import com.structurizr.importer.diagrams.AbstractDiagramImporter;
4+
import com.structurizr.util.ImageUtils;
45
import com.structurizr.util.StringUtils;
56
import com.structurizr.view.ImageView;
67

78
import java.io.File;
9+
import java.net.URL;
810
import java.nio.charset.StandardCharsets;
911
import java.nio.file.Files;
1012

1113
public class KrokiImporter extends AbstractDiagramImporter {
1214

13-
private static final String KROKI_URL_PROPERTY = "kroki.url";
14-
private static final String KROKI_FORMAT_PROPERTY = "kroki.format";
15+
public static final String KROKI_URL_PROPERTY = "kroki.url";
16+
public static final String KROKI_FORMAT_PROPERTY = "kroki.format";
17+
public static final String KROKI_INLINE_PROPERTY = "kroki.inline";
1518

1619
public void importDiagram(ImageView view, String format, File file) throws Exception {
1720
String content = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
@@ -38,7 +41,16 @@ public void importDiagram(ImageView view, String format, String content) throws
3841
String encodedDiagram = new KrokiEncoder().encode(content);
3942
String url = String.format("%s/%s/%s/%s", krokiServer, format, imageFormat, encodedDiagram);
4043

41-
view.setContent(url);
44+
String inline = getViewOrViewSetProperty(view, KROKI_INLINE_PROPERTY);
45+
if ("true".equals(inline)) {
46+
if (imageFormat.equals(SVG_FORMAT)) {
47+
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url)));
48+
} else {
49+
view.setContent(ImageUtils.getPngAsDataUri(new URL(url)));
50+
}
51+
} else {
52+
view.setContent(url);
53+
}
4254
view.setContentType(CONTENT_TYPES_BY_FORMAT.get(imageFormat));
4355
}
4456

structurizr-import/src/main/java/com/structurizr/importer/diagrams/mermaid/MermaidImporter.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package com.structurizr.importer.diagrams.mermaid;
22

33
import com.structurizr.importer.diagrams.AbstractDiagramImporter;
4+
import com.structurizr.util.ImageUtils;
45
import com.structurizr.util.StringUtils;
56
import com.structurizr.view.ImageView;
67

78
import java.io.File;
9+
import java.net.URL;
810
import java.nio.charset.StandardCharsets;
911
import java.nio.file.Files;
1012

@@ -13,6 +15,7 @@ public class MermaidImporter extends AbstractDiagramImporter {
1315
public static final String MERMAID_URL_PROPERTY = "mermaid.url";
1416
public static final String MERMAID_FORMAT_PROPERTY = "mermaid.format";
1517
public static final String MERMAID_COMPRESS_PROPERTY = "mermaid.compress";
18+
public static final String MERMAID_INLINE_PROPERTY = "mermaid.inline";
1619

1720
public void importDiagram(ImageView view, File file) throws Exception {
1821
String content = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
@@ -21,7 +24,7 @@ public void importDiagram(ImageView view, File file) throws Exception {
2124
importDiagram(view, content);
2225
}
2326

24-
public void importDiagram(ImageView view, String content) {
27+
public void importDiagram(ImageView view, String content) throws Exception {
2528
String mermaidServer = getViewOrViewSetProperty(view, MERMAID_URL_PROPERTY);
2629
if (StringUtils.isNullOrEmpty(mermaidServer)) {
2730
throw new IllegalArgumentException("Please define a view/viewset property named " + MERMAID_URL_PROPERTY + " to specify your Mermaid server");
@@ -49,7 +52,16 @@ public void importDiagram(ImageView view, String content) {
4952
url = String.format("%s/svg/%s", mermaidServer, encodedMermaid);
5053
}
5154

52-
view.setContent(url);
55+
String inline = getViewOrViewSetProperty(view, MERMAID_INLINE_PROPERTY);
56+
if ("true".equals(inline)) {
57+
if (format.equals(SVG_FORMAT)) {
58+
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url)));
59+
} else {
60+
view.setContent(ImageUtils.getPngAsDataUri(new URL(url)));
61+
}
62+
} else {
63+
view.setContent(url);
64+
}
5365
view.setContentType(CONTENT_TYPES_BY_FORMAT.get(format));
5466
}
5567

structurizr-import/src/main/java/com/structurizr/importer/diagrams/plantuml/PlantUMLImporter.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
package com.structurizr.importer.diagrams.plantuml;
22

33
import com.structurizr.importer.diagrams.AbstractDiagramImporter;
4+
import com.structurizr.util.ImageUtils;
45
import com.structurizr.util.StringUtils;
6+
import com.structurizr.util.Url;
57
import com.structurizr.view.ImageView;
68

79
import java.io.File;
10+
import java.net.URL;
811
import java.nio.charset.StandardCharsets;
912
import java.nio.file.Files;
1013

1114
public class PlantUMLImporter extends AbstractDiagramImporter {
1215

1316
public static final String PLANTUML_URL_PROPERTY = "plantuml.url";
1417
public static final String PLANTUML_FORMAT_PROPERTY = "plantuml.format";
18+
public static final String PLANTUML_INLINE_PROPERTY = "plantuml.inline";
1519
private static final String TITLE_STRING = "title ";
1620
private static final String NEWLINE = "\n";
1721

@@ -39,7 +43,17 @@ public void importDiagram(ImageView view, String content) throws Exception {
3943

4044
String encodedPlantUML = new PlantUMLEncoder().encode(content);
4145
String url = String.format("%s/%s/%s", plantUMLServer, format, encodedPlantUML);
42-
view.setContent(url);
46+
47+
String inline = getViewOrViewSetProperty(view, PLANTUML_INLINE_PROPERTY);
48+
if ("true".equals(inline)) {
49+
if (format.equals(SVG_FORMAT)) {
50+
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url)));
51+
} else {
52+
view.setContent(ImageUtils.getPngAsDataUri(new URL(url)));
53+
}
54+
} else {
55+
view.setContent(url);
56+
}
4357
view.setContentType(CONTENT_TYPES_BY_FORMAT.get(format));
4458

4559
String[] lines = content.split(NEWLINE);

0 commit comments

Comments
 (0)