summaryrefslogtreecommitdiff
path: root/support/texplate/source/main/java/org/islandoftex/texplate/util
diff options
context:
space:
mode:
Diffstat (limited to 'support/texplate/source/main/java/org/islandoftex/texplate/util')
-rw-r--r--support/texplate/source/main/java/org/islandoftex/texplate/util/HandlerUtils.java31
-rw-r--r--support/texplate/source/main/java/org/islandoftex/texplate/util/MergingUtils.java186
-rw-r--r--support/texplate/source/main/java/org/islandoftex/texplate/util/MessageUtils.java84
-rw-r--r--support/texplate/source/main/java/org/islandoftex/texplate/util/PathUtils.java123
-rw-r--r--support/texplate/source/main/java/org/islandoftex/texplate/util/ValidatorUtils.java75
5 files changed, 499 insertions, 0 deletions
diff --git a/support/texplate/source/main/java/org/islandoftex/texplate/util/HandlerUtils.java b/support/texplate/source/main/java/org/islandoftex/texplate/util/HandlerUtils.java
new file mode 100644
index 0000000000..7ab01f7328
--- /dev/null
+++ b/support/texplate/source/main/java/org/islandoftex/texplate/util/HandlerUtils.java
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.islandoftex.texplate.model.handlers.BooleanHandler;
+import org.islandoftex.texplate.model.handlers.CSVListHandler;
+import org.islandoftex.texplate.model.handlers.Handler;
+
+/**
+ * Provides the map of handlers.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class HandlerUtils {
+
+ /**
+ * Gets the map of handlers.
+ *
+ * @return Map of handlers.
+ */
+ public static Map<String, Handler> getHandlers() {
+ Map<String, Handler> handlers = new HashMap<>();
+ handlers.put("to-csv-list", new CSVListHandler());
+ handlers.put("to-boolean", new BooleanHandler());
+ return handlers;
+ }
+
+}
diff --git a/support/texplate/source/main/java/org/islandoftex/texplate/util/MergingUtils.java b/support/texplate/source/main/java/org/islandoftex/texplate/util/MergingUtils.java
new file mode 100644
index 0000000000..d7ffbddc4d
--- /dev/null
+++ b/support/texplate/source/main/java/org/islandoftex/texplate/util/MergingUtils.java
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import io.vavr.control.Try;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.exception.TemplateInitException;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.RuntimeSingleton;
+import org.apache.velocity.runtime.parser.ParseException;
+import org.islandoftex.texplate.exceptions.TemplateMergingException;
+import org.islandoftex.texplate.model.Template;
+import org.islandoftex.texplate.model.handlers.Handler;
+import org.slf4j.helpers.NOPLoggerFactory;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.Writer;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Merging utilities.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class MergingUtils {
+
+ /**
+ * Merges both template and data.
+ *
+ * @param template The template object.
+ * @param map The data map.
+ * @param output The output path.
+ * @param cmap The configuration map.
+ * @return The length of the generated output.
+ * @throws TemplateMergingException The merging failed.
+ */
+ private static long mergeTemplate(Template template,
+ Map<String, String> map, Path output,
+ Map<String, Object> cmap)
+ throws TemplateMergingException {
+
+ // create the context map
+ Map<String, Object> context = handle(template, map, cmap);
+
+ // create a file writer for
+ // the output reference
+ try (Writer writer = new FileWriter(output.toFile())) {
+
+ // the document is actually read
+ // into a string reader
+ StringReader reader = new StringReader(template.getDocument());
+
+ // load both runtime services and
+ // the template model from Velocity
+ RuntimeServices services = RuntimeSingleton.getRuntimeServices();
+ services.addProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE,
+ new NOPLoggerFactory().getLogger(""));
+ org.apache.velocity.Template reference
+ = new org.apache.velocity.Template();
+
+ // set both runtime services
+ // and document data into the
+ // template document
+ reference.setRuntimeServices(services);
+ reference.setData(services.parse(reader, reference));
+ reference.initDocument();
+
+ // create the context based on
+ // the data map previously set
+ VelocityContext entries = new VelocityContext(context);
+
+ // merge both template and data
+ // into the file writer
+ reference.merge(entries, writer);
+
+ } catch (IOException | MethodInvocationException
+ | ParseErrorException | ParseException
+ | ResourceNotFoundException
+ | TemplateInitException exception) {
+
+ // an exception has happened, so a
+ // new exception is thrown, attaching
+ // the original throwable cause
+ throw new TemplateMergingException("An error occurred while "
+ + "trying to merge the template reference with the "
+ + "provided data. Make sure the template is correct "
+ + "and try again. The raised exception might give us "
+ + "some hints on what exactly happened. Typically, "
+ + "make sure the template strictly follows the "
+ + "Velocity 2.0 language syntax.", exception);
+ }
+
+ // simply return the length of
+ // the generated output file
+ return output.toFile().length();
+ }
+
+ /**
+ * Merges template and data.
+ *
+ * @param template The template model.
+ * @param map The data map.
+ * @param output The path reference.
+ * @param cmap The configuration map.
+ * @return The length of the generated output, enclosed as a Try object.
+ */
+ public static Try<Long> merge(Template template, Map<String, String> map,
+ Path output, Map<String, Object> cmap) {
+ return Try.of(() -> mergeTemplate(template, map, output, cmap));
+ }
+
+ /**
+ * Handles the context map.
+ *
+ * @param template The template model.
+ * @param map The context map.
+ * @return The new context map.
+ */
+ private static Map<String, Object> handle(Template template,
+ Map<String, String> map,
+ Map<String, Object> cmap) {
+
+ // no handlers found
+ if (template.getHandlers() == null) {
+
+ // create a new map from the
+ // command line map and put the
+ // values from the configuration
+ // file, if absent
+ Map<String, Object> result = new HashMap<>(map);
+ cmap.forEach(result::putIfAbsent);
+ return result;
+
+ } else {
+
+ // get default handlers and
+ // set the resulting map
+ Map<String, Handler> handlers = HandlerUtils.getHandlers();
+ Map<String, Object> result = new HashMap<>();
+
+ // check each key from the map
+ map.forEach((String key, String value) -> {
+
+ // there is a handler for
+ // the current key
+ if (template.getHandlers().containsKey(key)) {
+
+ // the handler seems valid
+ if (handlers.containsKey(template.getHandlers().get(key))) {
+
+ // apply the handler and
+ // store the value in the map
+ result.put(key, handlers.get(template.
+ getHandlers().get(key)).apply(value));
+ } else {
+
+ // simply store the value
+ result.put(key, value);
+ // TODO: should we warn about an invalid handler?
+ }
+ } else {
+
+ // simply store the value
+ result.put(key, value);
+ }
+ });
+
+ // put remaining values from
+ // the configuration file, if
+ // absent
+ cmap.forEach(result::putIfAbsent);
+
+ // return the map
+ return result;
+ }
+ }
+
+}
diff --git a/support/texplate/source/main/java/org/islandoftex/texplate/util/MessageUtils.java b/support/texplate/source/main/java/org/islandoftex/texplate/util/MessageUtils.java
new file mode 100644
index 0000000000..948d18d953
--- /dev/null
+++ b/support/texplate/source/main/java/org/islandoftex/texplate/util/MessageUtils.java
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import org.apache.commons.text.TextStringBuilder;
+import org.apache.commons.text.WordUtils;
+
+import java.time.LocalDate;
+
+/**
+ * Message helper methods.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class MessageUtils {
+
+ // the message width
+ private static final int WIDTH = 60;
+
+ // the application version
+ private static final String VERSION = "1.0.0";
+
+ /**
+ * Prints a line in the terminal, without a line break.
+ *
+ * @param message The message to be printed.
+ */
+ public static void line(String message) {
+ System.out.print(new TextStringBuilder()
+ .appendFixedWidthPadRight(message.concat(" "), WIDTH - 9, '.')
+ .append(" ")
+ .toString()
+ );
+ }
+
+ /**
+ * Prints the status in the terminal.
+ *
+ * @param result The boolean value.
+ */
+ public static void status(boolean result) {
+ System.out.println(result ? "[ DONE ]" : "[FAILED]");
+ }
+
+ /**
+ * Prints the error in the terminal.
+ *
+ * @param throwable The throwable reference.
+ */
+ public static void error(Throwable throwable) {
+ System.out.println(
+ new TextStringBuilder("\n")
+ .appendFixedWidthPadRight("HOUSTON, WE'VE GOT"
+ + " A PROBLEM ", WIDTH, '-')
+ .append("\n")
+ .appendln(WordUtils.wrap(throwable.getMessage(), WIDTH))
+ .appendFixedWidthPadLeft("", WIDTH, '-')
+ .append("\n")
+ .toString());
+ }
+
+ /**
+ * Prints the application logo in the terminal.
+ */
+ public static void drawLogo() {
+ System.out.println(
+ " ______ __ __ ___ __ \n" +
+ "/\\__ _\\ /\\ \\ /\\ \\ /\\_ \\ /\\ \\__ \n" +
+ "\\/_/\\ \\/ __ \\ `\\`\\/'/' _____\\//\\ \\ __ \\ \\ ,_\\ __ \n" +
+ " \\ \\ \\ /'__`\\`\\/ > < /\\ '__`\\\\ \\ \\ /'__`\\ \\ \\ \\/ /'__`\\ \n" +
+ " \\ \\ \\/\\ __/ \\/'/\\`\\\\ \\ \\L\\ \\\\_\\ \\_/\\ \\L\\.\\_\\ \\ \\_/\\ __/ \n" +
+ " \\ \\_\\ \\____\\ /\\_\\\\ \\_\\ \\ ,__//\\____\\ \\__/.\\_\\\\ \\__\\ \\____\\\n" +
+ " \\/_/\\/____/ \\/_/ \\/_/\\ \\ \\/ \\/____/\\/__/\\/_/ \\/__/\\/____/\n" +
+ " \\ \\_\\ \n" +
+ " \\/_/ \n"
+ );
+ System.out.println(
+ "TeXplate " + VERSION + ", a document structure creation tool\n" +
+ "Copyright (c) " + LocalDate.now().getYear() + ", Island of TeX\n" +
+ "All rights reserved.\n"
+ );
+ }
+
+}
diff --git a/support/texplate/source/main/java/org/islandoftex/texplate/util/PathUtils.java b/support/texplate/source/main/java/org/islandoftex/texplate/util/PathUtils.java
new file mode 100644
index 0000000000..26e101b9ad
--- /dev/null
+++ b/support/texplate/source/main/java/org/islandoftex/texplate/util/PathUtils.java
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import io.vavr.control.Try;
+import java.io.FileNotFoundException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.islandoftex.texplate.Main;
+
+/**
+ * Helper methods for path handling.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class PathUtils {
+
+ // the templates folder
+ private static final String TEMPLATES_FOLDER = "templates";
+
+ // the user application folder
+ private static final String USER_APPLICATION_FOLDER = ".texplate";
+
+ /**
+ * Gets the application path.
+ *
+ * @return The application path.
+ */
+ private static Path getApplicationPath() {
+ return Try.of(() -> Paths.get(Main.class.getProtectionDomain().
+ getCodeSource().getLocation().toURI().getPath()).resolve("..").
+ normalize()).getOrElse(Paths.get("."));
+ }
+
+ /**
+ * Gets the default template path.
+ *
+ * @return The default template path.
+ */
+ private static Path getDefaultTemplatePath() {
+ return getApplicationPath().resolve(TEMPLATES_FOLDER);
+ }
+
+ /**
+ * Gets the user template path.
+ *
+ * @return The user template path.
+ */
+ private static Path getUserTemplatePath() {
+ return Try.of(() -> Paths.get(System.getProperty("user.home"),
+ USER_APPLICATION_FOLDER, TEMPLATES_FOLDER)).
+ getOrElse(Paths.get("."));
+ }
+
+ /**
+ * Searchs all paths looking for the provided template.
+ *
+ * @param name The name to be associated to a template file.
+ * @return The corresponding template file.
+ * @throws FileNotFoundException The template file could not be found.
+ */
+ private static Path searchTemplatePath(String name)
+ throws FileNotFoundException {
+
+ // the file has to be a TOML format,
+ // so we add the extension
+ name = name.concat(".toml");
+
+ // the first reference is based on the
+ // user template path resolved with the
+ // file name
+ Path reference = getUserTemplatePath().resolve(name);
+
+ // if the file actually exists,
+ // the search is done!
+ if (Files.exists(reference)) {
+
+ // return the template
+ // file reference
+ return reference;
+
+ } else {
+
+ // the reference was not found in the
+ // user location, so let us try the
+ // system counterpart
+ reference = getDefaultTemplatePath().resolve(name);
+
+ // if the file actually exists,
+ // the search is done!
+ if (Files.exists(reference)) {
+
+ // return the template
+ // file reference
+ return reference;
+
+ } else {
+
+ // the file reference could not be
+ // found, so an exception is thrown
+ throw new FileNotFoundException("I am sorry, but the template "
+ + "file '" + name + "' could not be found in the "
+ + "default template locations (system and user). Make "
+ + "sure the reference is correct and try again. For "
+ + "reference, these are the paths I searched: '"
+ + getUserTemplatePath() + "' and '"
+ + getDefaultTemplatePath() + "' (in this order).");
+ }
+ }
+ }
+
+ /**
+ * Gets the template path based on the provided template name.
+ *
+ * @param name The template name.
+ * @return The template path, enclosed in a Try object.
+ */
+ public static Try<Path> getTemplatePath(String name) {
+ return Try.of(() -> searchTemplatePath(name));
+ }
+
+}
diff --git a/support/texplate/source/main/java/org/islandoftex/texplate/util/ValidatorUtils.java b/support/texplate/source/main/java/org/islandoftex/texplate/util/ValidatorUtils.java
new file mode 100644
index 0000000000..b400731242
--- /dev/null
+++ b/support/texplate/source/main/java/org/islandoftex/texplate/util/ValidatorUtils.java
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util;
+
+import io.vavr.control.Try;
+import org.islandoftex.texplate.exceptions.InvalidKeySetException;
+import org.islandoftex.texplate.model.Template;
+
+import java.util.Map;
+
+/**
+ * Helper methods for validation.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+public class ValidatorUtils {
+
+ /**
+ * Validates the data map based on the template requirements.
+ *
+ * @param template The template.
+ * @param map The data map.
+ * @return A boolean value indicating whether the data map is valid.
+ */
+ private static boolean validateRequirements(Template template,
+ Map<String, String> map) {
+ return template.getRequirements().isEmpty() ||
+ template.getRequirements().containsAll(map.keySet());
+ }
+
+ /**
+ * Validates the template pattern and the data map and throws an exception
+ * in case of failure.
+ *
+ * @param template The template.
+ * @param map The data map.
+ * @return The data map.
+ * @throws InvalidKeySetException There are invalid keys in the map.
+ */
+ private static Map<String, String> checkValidation(Template template,
+ Map<String, String> map)
+ throws InvalidKeySetException {
+
+ // for starters, we try to validate
+ // the template requirements
+ if (validateRequirements(template, map)) {
+
+ // everything is validated, so
+ // we simply return the map
+ return map;
+
+ } else {
+
+ // the requirements were missing,
+ // so an exception is thrown
+ throw new InvalidKeySetException("The provided map does not "
+ + "contain all the keys required by the chosen "
+ + "template. Make sure to define such keys and try "
+ + "again. Check the user manual for further details.");
+ }
+ }
+
+ /**
+ * Validates the template pattern and the data map.
+ *
+ * @param template The template.
+ * @param map The data map.
+ * @return The data map, enclosed in a Try object.
+ */
+ public static Try<Map<String, String>> validate(Template template,
+ Map<String, String> map) {
+ return Try.of(() -> checkValidation(template, map));
+ }
+
+}