diff options
author | Norbert Preining <norbert@preining.info> | 2020-01-15 03:00:56 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2020-01-15 03:00:56 +0000 |
commit | 3bd863734612dc2fe9c5c7c1405358ffb1228afb (patch) | |
tree | 9f7d421c227b998debe92dac90f4cf8634a8f94f /support/texplate/source/main/java/org/islandoftex/texplate/util | |
parent | b3225c4301e7724de481f410444fef5463799b9d (diff) |
CTAN sync 202001150300
Diffstat (limited to 'support/texplate/source/main/java/org/islandoftex/texplate/util')
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)); + } + +} |