Skip to content

Commit

Permalink
Removes duplicate PlantUML/Mermaid encoders, adds support for Mermaid…
Browse files Browse the repository at this point in the history
… compression, makes SVG the default formats.
  • Loading branch information
simonbrowndotje committed Oct 6, 2024
1 parent 3d22317 commit f103a7a
Show file tree
Hide file tree
Showing 13 changed files with 92 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1031,13 +1031,13 @@ void test_imageViews_ViaFiles() throws Exception {

ImageView plantumlView = (ImageView)workspace.getViews().getViewWithKey("plantuml");
assertEquals("diagram.puml", plantumlView.getTitle());
assertEquals("http://localhost:7777/png/SoWkIImgAStDuNBAJrBGjLDmpCbCJbMmKiX8pSd9vt98pKi1IW80", plantumlView.getContent());
assertEquals("image/png", plantumlView.getContentType());
assertEquals("http://localhost:7777/svg/SoWkIImgAStDuNBAJrBGjLDmpCbCJbMmKiX8pSd9vt98pKi1IW80", plantumlView.getContent());
assertEquals("image/svg+xml", plantumlView.getContentType());

ImageView mermaidView = (ImageView)workspace.getViews().getViewWithKey("mermaid");
assertEquals("diagram.mmd", mermaidView.getTitle());
assertEquals("http://localhost:8888/img/Zmxvd2NoYXJ0IFRECiAgICBTdGFydCAtLT4gU3RvcA==?type=png", mermaidView.getContent());
assertEquals("image/png", mermaidView.getContentType());
assertEquals("http://localhost:8888/svg/Zmxvd2NoYXJ0IFRECiAgICBTdGFydCAtLT4gU3RvcA==", mermaidView.getContent());
assertEquals("image/svg+xml", mermaidView.getContentType());

ImageView krokiView = (ImageView)workspace.getViews().getViewWithKey("kroki");
assertEquals("diagram.dot", krokiView.getTitle());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ void setUp() {
@Test
void test_parsePlantUML_ThrowsAnException_WhenUsingAFileNameInRestrictedMode() {
try {
ImageViewDslContext context = new ImageViewDslContext(imageView);
context.setWorkspace(workspace);
parser = new ImageViewContentParser(true);
parser.parsePlantUML(new ImageViewDslContext(imageView), null, tokens("plantuml", "image.puml"));
parser.parsePlantUML(context, null, tokens("plantuml", "image.puml"));
fail();
} catch (Exception e) {
assertEquals("PlantUML source must be specified as a URL when running in restricted mode", e.getMessage());
Expand All @@ -31,8 +33,10 @@ void test_parsePlantUML_ThrowsAnException_WhenUsingAFileNameInRestrictedMode() {
@Test
void test_parseMermaid_ThrowsAnException_WhenUsingAFileNameInRestrictedMode() {
try {
ImageViewDslContext context = new ImageViewDslContext(imageView);
context.setWorkspace(workspace);
parser = new ImageViewContentParser(true);
parser.parseMermaid(new ImageViewDslContext(imageView), null, tokens("mermaid", "image.puml"));
parser.parseMermaid(context, null, tokens("mermaid", "image.puml"));
fail();
} catch (Exception e) {
assertEquals("Mermaid source must be specified as a URL when running in restricted mode", e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ workspace {
properties {
"plantuml.url" "http://localhost:7777"
"mermaid.url" "http://localhost:8888"
"mermaid.compress" "false"
"kroki.url" "http://localhost:9999"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ workspace {
"plantuml.format" "svg"
"mermaid.url" "http://localhost:8888"
"mermaid.format" "svg"
"mermaid.compress" "false"
"kroki.url" "http://localhost:9999"
"kroki.format" "svg"
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,45 @@
package com.structurizr.importer.diagrams.mermaid;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;

/**
* Encodes a Mermaid diagram definition to base64 format, for use with image URLs, etc.
*/
public class MermaidEncoder {
public final class MermaidEncoder {

private static final String TEMPLATE = "{ \"code\":\"%s\", \"mermaid\":{\"theme\":\"default\"}}";

public String encode(String mermaidDefinition) {
return this.encode(mermaidDefinition, false);
}

public String encode(String mermaidDefinition, boolean compress) {
if (compress) {
try {
String content = String.format(TEMPLATE, mermaidDefinition.replaceAll("\n", "\\\\n").replaceAll("\"", "\\\\\""));
byte[] compressedDefinition = compress(content);
return "pako:" + Base64.getUrlEncoder().encodeToString(compressedDefinition);
} catch(Exception e) {
e.printStackTrace();
}
}

return Base64.getUrlEncoder().encodeToString(mermaidDefinition.getBytes(StandardCharsets.UTF_8));
}

private byte[] compress(String content) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Deflater deflater = new Deflater();

DeflaterOutputStream dos = new DeflaterOutputStream(baos, deflater, true);
dos.write(content.getBytes(StandardCharsets.UTF_8));
dos.finish();

return baos.toByteArray();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@

public class MermaidImporter extends AbstractDiagramImporter {

private static final String MERMAID_URL_PROPERTY = "mermaid.url";
private static final String MERMAID_FORMAT_PROPERTY = "mermaid.format";
public static final String MERMAID_URL_PROPERTY = "mermaid.url";
public static final String MERMAID_FORMAT_PROPERTY = "mermaid.format";
public static final String MERMAID_COMPRESS_PROPERTY = "mermaid.compress";

public void importDiagram(ImageView view, File file) throws Exception {
String content = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
Expand All @@ -28,14 +29,19 @@ public void importDiagram(ImageView view, String content) {

String format = getViewOrViewSetProperty(view, MERMAID_FORMAT_PROPERTY);
if (StringUtils.isNullOrEmpty(format)) {
format = PNG_FORMAT;
format = SVG_FORMAT;
}

if (!format.equals(PNG_FORMAT) && !format.equals(SVG_FORMAT)) {
throw new IllegalArgumentException(String.format("Expected a format of %s or %s", PNG_FORMAT, SVG_FORMAT));
}

String encodedMermaid = new MermaidEncoder().encode(content);
String compress = getViewOrViewSetProperty(view, MERMAID_COMPRESS_PROPERTY);
if (StringUtils.isNullOrEmpty(compress)) {
compress = "true";
}

String encodedMermaid = new MermaidEncoder().encode(content, compress.equalsIgnoreCase("true"));
String url;
if (format.equals(PNG_FORMAT)) {
url = String.format("%s/img/%s?type=png", mermaidServer, encodedMermaid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
* A Java implementation of http://plantuml.com/code-javascript-synchronous
* that uses Java's built-in Deflate algorithm.
*/
class PlantUMLEncoder {
public final class PlantUMLEncoder {

String encode(String plantUMLDefinition) throws Exception {
public String encode(String plantUMLDefinition) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, true);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

public class PlantUMLImporter extends AbstractDiagramImporter {

private static final String PLANTUML_URL_PROPERTY = "plantuml.url";
private static final String PLANTUML_FORMAT_PROPERTY = "plantuml.format";
public static final String PLANTUML_URL_PROPERTY = "plantuml.url";
public static final String PLANTUML_FORMAT_PROPERTY = "plantuml.format";
private static final String TITLE_STRING = "title ";
private static final String NEWLINE = "\n";

Expand All @@ -30,7 +30,7 @@ public void importDiagram(ImageView view, String content) throws Exception {

String format = getViewOrViewSetProperty(view, PLANTUML_FORMAT_PROPERTY);
if (StringUtils.isNullOrEmpty(format)) {
format = PNG_FORMAT;
format = SVG_FORMAT;
}

if (!format.equals(PNG_FORMAT) && !format.equals(SVG_FORMAT)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.junit.jupiter.api.Test;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import static org.junit.jupiter.api.Assertions.assertEquals;
Expand All @@ -14,15 +13,23 @@ public class MermaidEncoderTests {
public void encode_flowchart() throws Exception {
File file = new File("./src/test/resources/diagrams/mermaid/flowchart.mmd");
String mermaid = Files.readString(file.toPath());
assertEquals("Zmxvd2NoYXJ0IFRECiAgICBBW0NocmlzdG1hc10gLS0-fEdldCBtb25leXwgQihHbyBzaG9wcGluZykKICAgIEIgLS0-IEN7TGV0IG1lIHRoaW5rfQogICAgQyAtLT58T25lfCBEW0xhcHRvcF0KICAgIEMgLS0-fFR3b3wgRVtpUGhvbmVdCiAgICBDIC0tPnxUaHJlZXwgRltmYTpmYS1jYXIgQ2FyXQ==", new MermaidEncoder().encode(mermaid));
String encodedMermaid = new MermaidEncoder().encode(mermaid);
assertEquals("Zmxvd2NoYXJ0IFRECiAgICBBW0NocmlzdG1hc10gLS0-fEdldCBtb25leXwgQihHbyBzaG9wcGluZykKICAgIEIgLS0-IEN7TGV0IG1lIHRoaW5rfQogICAgQyAtLT58T25lfCBEW0xhcHRvcF0KICAgIEMgLS0-fFR3b3wgRVtpUGhvbmVdCiAgICBDIC0tPnxUaHJlZXwgRltmYTpmYS1jYXIgQ2FyXQ==", encodedMermaid);
}

@Test
public void encode_flowchart_compressed() throws Exception {
File file = new File("./src/test/resources/diagrams/mermaid/flowchart.mmd");
String mermaid = Files.readString(file.toPath());
String encodedMermaid = new MermaidEncoder().encode(mermaid, true);
assertEquals("pako:eJxVj70OgjAUhV_lppMm8gIMJlKUhUQHtspwAxfbSH9SaoihvLsgi571-85JzgSssS2xlHW9HRuJPkCV3w0sOQkuvRqCxqGGJDnGggJoa-gdIdsVFgZpnVPmsd_8bJWAT-WqEQSpzHPeEP_2r4Yi5KJEF6yrf0k12ghnoW5ymf8n0tPSuogO0w6TBj1w9DU7ANPkNaqWpRMLkvR6oqUOX31g8_wBLY9E1w==", encodedMermaid);
}

@Test
public void encode_class() throws Exception {
File file = new File("./src/test/resources/diagrams/mermaid/class.mmd");
String mermaid = Files.readString(file.toPath());
assertEquals("Y2xhc3NEaWFncmFtCiAgICBBbmltYWwgPHwtLSBEdWNrCiAgICBBbmltYWwgPHwtLSBGaXNoCiAgICBBbmltYWwgPHwtLSBaZWJyYQogICAgQW5pbWFsIDogK2ludCBhZ2UKICAgIEFuaW1hbCA6ICtTdHJpbmcgZ2VuZGVyCiAgICBBbmltYWw6ICtpc01hbW1hbCgpCiAgICBBbmltYWw6ICttYXRlKCkKICAgIGNsYXNzIER1Y2t7CiAgICAgICtTdHJpbmcgYmVha0NvbG9yCiAgICAgICtzd2ltKCkKICAgICAgK3F1YWNrKCkKICAgIH0KICAgIGNsYXNzIEZpc2h7CiAgICAgIC1pbnQgc2l6ZUluRmVldAogICAgICAtY2FuRWF0KCkKICAgIH0KICAgIGNsYXNzIFplYnJhewogICAgICArYm9vbCBpc193aWxkCiAgICAgICtydW4oKQogICAgfQo=", new MermaidEncoder().encode(mermaid));

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,25 @@ public class MermaidImporterTests {
@Test
public void importDiagram() throws Exception {
Workspace workspace = new Workspace("Name", "Description");
workspace.getViews().getConfiguration().addProperty("mermaid.url", "https://mermaid.ink");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_URL_PROPERTY, "https://mermaid.ink");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_COMPRESS_PROPERTY, "false");
ImageView view = workspace.getViews().createImageView("key");

new MermaidImporter().importDiagram(view, new File("./src/test/resources/diagrams/mermaid/flowchart.mmd"));
assertEquals("key", view.getKey());
assertNull(view.getElement());
assertNull(view.getElementId());
assertEquals("flowchart.mmd", view.getTitle());
assertEquals("https://mermaid.ink/img/Zmxvd2NoYXJ0IFRECiAgICBBW0NocmlzdG1hc10gLS0-fEdldCBtb25leXwgQihHbyBzaG9wcGluZykKICAgIEIgLS0-IEN7TGV0IG1lIHRoaW5rfQogICAgQyAtLT58T25lfCBEW0xhcHRvcF0KICAgIEMgLS0-fFR3b3wgRVtpUGhvbmVdCiAgICBDIC0tPnxUaHJlZXwgRltmYTpmYS1jYXIgQ2FyXQ==?type=png", view.getContent());
assertEquals("image/png", view.getContentType());
assertEquals("https://mermaid.ink/svg/Zmxvd2NoYXJ0IFRECiAgICBBW0NocmlzdG1hc10gLS0-fEdldCBtb25leXwgQihHbyBzaG9wcGluZykKICAgIEIgLS0-IEN7TGV0IG1lIHRoaW5rfQogICAgQyAtLT58T25lfCBEW0xhcHRvcF0KICAgIEMgLS0-fFR3b3wgRVtpUGhvbmVdCiAgICBDIC0tPnxUaHJlZXwgRltmYTpmYS1jYXIgQ2FyXQ==", view.getContent());
assertEquals("image/svg+xml", view.getContentType());
}

@Test
public void importDiagram_AsPNG() throws Exception {
Workspace workspace = new Workspace("Name", "Description");
workspace.getViews().getConfiguration().addProperty("mermaid.url", "https://mermaid.ink");
workspace.getViews().getConfiguration().addProperty("mermaid.format", "png");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_URL_PROPERTY, "https://mermaid.ink");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_FORMAT_PROPERTY, "png");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_COMPRESS_PROPERTY, "false");
ImageView view = workspace.getViews().createImageView("key");

new MermaidImporter().importDiagram(view, new File("./src/test/resources/diagrams/mermaid/flowchart.mmd"));
Expand All @@ -44,8 +46,9 @@ public void importDiagram_AsPNG() throws Exception {
@Test
public void importDiagram_AsSVG() throws Exception {
Workspace workspace = new Workspace("Name", "Description");
workspace.getViews().getConfiguration().addProperty("mermaid.url", "https://mermaid.ink");
workspace.getViews().getConfiguration().addProperty("mermaid.format", "svg");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_URL_PROPERTY, "https://mermaid.ink");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_FORMAT_PROPERTY, "svg");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_COMPRESS_PROPERTY, "false");
ImageView view = workspace.getViews().createImageView("key");

new MermaidImporter().importDiagram(view, new File("./src/test/resources/diagrams/mermaid/flowchart.mmd"));
Expand Down Expand Up @@ -73,8 +76,8 @@ public void importDiagram_WhenTheMermaidUrlIsNotDefined() throws Exception {
@Test
public void importDiagram_WhenAnInvalidFormatIsSpecified() throws Exception {
Workspace workspace = new Workspace("Name", "Description");
workspace.getViews().getConfiguration().addProperty("mermaid.url", "https://mermaid.ink");
workspace.getViews().getConfiguration().addProperty("mermaid.format", "jpg");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_URL_PROPERTY, "https://mermaid.ink");
workspace.getViews().getConfiguration().addProperty(MermaidImporter.MERMAID_FORMAT_PROPERTY, "jpg");
ImageView view = workspace.getViews().createImageView("key");

try {
Expand Down
Loading

0 comments on commit f103a7a

Please sign in to comment.