diff --git a/src/net/sourceforge/plantuml/tim/TContext.java b/src/net/sourceforge/plantuml/tim/TContext.java index 50898cf64..78e798a19 100644 --- a/src/net/sourceforge/plantuml/tim/TContext.java +++ b/src/net/sourceforge/plantuml/tim/TContext.java @@ -106,6 +106,7 @@ import net.sourceforge.plantuml.tim.stdlib.InvokeProcedure; import net.sourceforge.plantuml.tim.stdlib.IsDark; import net.sourceforge.plantuml.tim.stdlib.IsLight; import net.sourceforge.plantuml.tim.stdlib.Lighten; +import net.sourceforge.plantuml.tim.stdlib.LoadJson; import net.sourceforge.plantuml.tim.stdlib.LogicalNot; import net.sourceforge.plantuml.tim.stdlib.Lower; import net.sourceforge.plantuml.tim.stdlib.Newline; @@ -177,6 +178,7 @@ public class TContext { functionsSet.addFunction(new Hex2dec()); functionsSet.addFunction(new Dec2hex()); functionsSet.addFunction(new HslColor()); + functionsSet.addFunction(new LoadJson()); functionsSet.addFunction(new Chr()); functionsSet.addFunction(new Size()); // %standard_exists_function diff --git a/src/net/sourceforge/plantuml/tim/stdlib/LoadJson.java b/src/net/sourceforge/plantuml/tim/stdlib/LoadJson.java new file mode 100644 index 000000000..299b4a6f5 --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/stdlib/LoadJson.java @@ -0,0 +1,186 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2021, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + */ +package net.sourceforge.plantuml.tim.stdlib; + +import net.sourceforge.plantuml.FileSystem; +import net.sourceforge.plantuml.FileUtils; +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.json.Json; +import net.sourceforge.plantuml.json.JsonValue; +import net.sourceforge.plantuml.json.ParseException; +import net.sourceforge.plantuml.security.SFile; +import net.sourceforge.plantuml.security.SURL; +import net.sourceforge.plantuml.tim.*; +import net.sourceforge.plantuml.tim.expression.TValue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Loads JSON data from file or URL source. + *
+ * Supports three parameters for datasource, default JSON value and charset. The datasource will be checked against + * the security rules. + *
+ * Examples: + *
+ * @ startuml + * ' loads a local file + * !$JSON_LOCAL_RELATIVE=%loadJSON("file.json") + * + * ' loads a local file from an absolute file path + * !$JSON_LOCAL_ABS=%loadJSON("c:/loaded/data/file.json") + * + * ' tries to load a local file and returns an empty JSON + * !$JSON_LOCAL_REL_EMPTY=%loadJSON("file-not-existing.json") + * + * ' tries to load a local file and returns an default JSON + * !$DEF_JSON={"status":"No data found"} + * !$JSON_LOCAL_REL_DEF=%loadJSON("file-not-existing.json", $DEF_JSON) + * + * ' loads a local file with a specific charset (default is UTF-8) + * !$JSON_LOCAL_RELATIVE_CHARSET=%loadJSON("file.json", "{}", "iso-8859-1") + * + * ' loads a remote JSON from an endpoint (and default, if not reachable) + * !$STATUS_NO_CONNECTION={"status": "No connection"} + * !$JSON_REMOTE_DEF=%loadJSON("https://localhost:7778/management/health", $STATUS_NO_CONNECTION) + * status -> $JSON_REMOTE_DEF.status + * @ enduml + *+ * @author Aljoscha Rittner + */ +public class LoadJson extends SimpleReturnFunction { + + private static final String VALUE_CHARSET_DEFAULT = "UTF-8"; + + private static final String VALUE_DEFAULT_DEFAULT = "{}"; + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%loadJSON", 3 ); + } + + public boolean canCover(int nbArg, Set
+ * Current limitation: Only local file tests, not tests to a http rest endpoint
+ */
+class LoadJsonTest {
+
+ private static final String[] COMMON_OPTIONS = {"-tutxt"};
+
+ private static final String JSON = "{\"jsonTestKey\": \"exampleValue\"}";
+
+ private static final String DEF_JSON = "{\"jsonTestKey\": \"exampleDefaultValue\"}";
+
+ // ************ Test DSL data
+ private static final String DIAGRAM = "" +
+ "@startuml\n" +
+ "!$JSON_DATA=%loadJSON(test.json)\n" +
+
+ // title should have the value from the JSON file
+ "title $JSON_DATA.jsonTestKey\n" +
+ "a -> b\n" +
+ "@enduml\n";
+
+ private static final String DIAGRAM_DEF = "" +
+ "@startuml\n" +
+ "!$DEF_JSON=" + DEF_JSON + "\n" +
+ "!$JSON_DATA=%loadJSON(\"test-notfound.json\", $DEF_JSON)\n" +
+
+ // title should have the value from the default (because the file doesn't exist)
+ "title $JSON_DATA.jsonTestKey\n" +
+ "a -> b\n" +
+ "@enduml\n";
+
+ private static final String DIAGRAM_DEF_EMPTY = "" +
+ "@startuml\n" +
+ "!$JSON_DATA=%loadJSON(\"test-notfound.json\")\n" +
+ // JSON_DATA is defined, but empty (loadJSON default). So, title contains only "xx yy".
+ "title xx $JSON_DATA.jsonTestKey yy\n" +
+ "a -> b\n" +
+ "@enduml\n";
+
+
+ @TempDir
+ Path tempDir;
+
+ /**
+ * Resets the current directory.
+ */
+ @AfterAll
+ static void cleanUp() {
+ FileSystem.getInstance().reset();
+ }
+
+ /**
+ * Prepares test JSON file and sets the current directory for each test.
+ *
+ * @throws Exception hopefully not
+ */
+ @BeforeEach
+ public void beforeEach() throws Exception {
+ writeUtf8File(tempDir.resolve("test.json"), JSON);
+ FileSystem.getInstance().setCurrentDir(new SFile(tempDir.toFile().getAbsolutePath()));
+ }
+
+ /**
+ * Tests, if the loadJSON is loading the JSON file from test tmp folder.
+ *
+ * @throws Exception if something went wrong in this test
+ */
+ @Test
+ void testLoadJsonSimple() throws Exception {
+ String rendered = render(DIAGRAM);
+ assertThat(rendered).doesNotContain("syntax").contains("exampleValue");
+
+ }
+
+ /**
+ * Tests, if the loadJSON is using the default JSON given as parameter.
+ *
+ * @throws Exception if something went wrong in this test
+ */
+ @Test
+ void testLoadJsonNotFoundWithDefaultParameter() throws Exception {
+ String rendered = render(DIAGRAM_DEF);
+ assertThat(rendered).doesNotContain("syntax").contains("exampleDefaultValue");
+ }
+
+ /**
+ * Tests, if the loadJSON is using the default JSON.
+ *
+ * @throws Exception if something went wrong in this test
+ */
+ @Test
+ void testLoadJsonNotFoundWithDefaultEmpty() throws Exception {
+ String rendered = render(DIAGRAM_DEF_EMPTY);
+ assertThat(rendered).doesNotContain("syntax").contains("xx yy");
+ }
+
+ private String[] optionArray(String... extraOptions) {
+ final List