com.github.mavogel.ilias.printer.VelocityOutputPrinter.java Source code

Java tutorial

Introduction

Here is the source code for com.github.mavogel.ilias.printer.VelocityOutputPrinter.java

Source

package com.github.mavogel.ilias.printer;/*
                                         *  The MIT License (MIT)
                                         *
                                         *  Copyright (c) 2016 Manuel Vogel
                                         *
                                         *  Permission is hereby granted, free of charge, to any person obtaining a copy
                                         *  of this software and associated documentation files (the "Software"), to deal
                                         *  in the Software without restriction, including without limitation the rights
                                         *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                                         *  copies of the Software, and to permit persons to whom the Software is
                                         *  furnished to do so, subject to the following conditions:
                                         *
                                         *  The above copyright notice and this permission notice shall be included in all
                                         *  copies or substantial portions of the Software.
                                         *
                                         *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                                         *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                                         *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                                         *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                                         *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                                         *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
                                         *  SOFTWARE.
                                         *
                                         *  https://opensource.org/licenses/MIT
                                         */

import com.github.mavogel.ilias.utils.Defaults;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import java.io.*;
import java.nio.charset.Charset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;

/**
 * Output writer based on velocity templates.
 * <p>
 * Created by mavogel on 9/20/16.
 */
public class VelocityOutputPrinter {

    private static Logger LOG = Logger.getLogger(VelocityOutputPrinter.class);

    /**
     * The possible output types.
     */
    public enum OutputType {
        HTML(0, ".html.vm", "templates" + System.getProperty("file.separator") + "group-members.html.vm"), LATEX(1,
                ".tex.vm", "templates" + System.getProperty("file.separator") + "group-members.tex.vm");
        private final int index;
        private final String templateExtension;
        private final String defaultTemplateLocation;

        OutputType(final int index, final String templateExtension, final String defaultTemplateLocation) {
            this.templateExtension = templateExtension;
            this.index = index;
            this.defaultTemplateLocation = defaultTemplateLocation;
        }

        public String getTemplateExtension() {
            return templateExtension;
        }

        public String getFileExtension() {
            return templateExtension.replace(".vm", "");
        }

        public String getDefaultTemplateLocation() {
            return defaultTemplateLocation;
        }

        /**
         * Retrieves the {@link OutputType} at the given index.
         *
         * @param index the index
         * @return the {@link OutputType} at the index
         * @throws IllegalArgumentException if the index is out of range
         */
        public static VelocityOutputPrinter.OutputType getAtIndex(final int index) {
            return Arrays.stream(VelocityOutputPrinter.OutputType.values()).filter(t -> t.index == index)
                    .findFirst().orElseThrow(
                            () -> new IllegalArgumentException("OutputType at index '" + index + "' not found"));
        }

        /**
         * Returns a string for displaying the information of the {@link OutputType}
         * on the command line.
         *
         * @param prefix an optional header
         * @return the string
         */
        public String asDisplayString(final String prefix) {
            StringBuilder sb = new StringBuilder();
            if (prefix != null && !prefix.isEmpty())
                sb.append(prefix);
            sb.append(this.name());
            return sb.toString();
        }
    }

    /**
     * Prints the header, content and output to the given print stream.
     *
     * @param outputType   the desired output type. @see {@link OutputType}
     * @param templateName the name of the template, if empty the default template from classpath will be used
     * @param contextMap   the context for velocity
     * @throws Exception in case of a error, so the caller can handle it
     */
    public static void print(final OutputType outputType, final String templateName,
            final Map<String, Object> contextMap) throws Exception {

        if (templateName.trim().isEmpty()) {
            printWithDefaultTemplate(outputType, contextMap);
        } else {
            if (!templateName.contains(outputType.getTemplateExtension())) {
                LOG.error("Extension of output type '" + outputType.getTemplateExtension()
                        + "' does not match with the templateExtension of the template.");
                throw new Exception();
            }
            printWithCustomTemplate(outputType, templateName, contextMap);
        }
    }

    /**
     * Prints the header, content and output to the given print stream with a custom template.
     *
     * @param outputType   the desired output type. @see {@link OutputType}
     * @param templateName the name of the template
     * @param contextMap   the context for velocity
     * @throws Exception in case of a error, so the caller can handle it
     */
    private static void printWithCustomTemplate(final OutputType outputType, final String templateName,
            final Map<String, Object> contextMap) throws Exception {
        Velocity.init();
        Writer writer = null;
        try {
            final Template template = Velocity.getTemplate(templateName);
            final VelocityContext context = new VelocityContext();
            contextMap.forEach((k, v) -> context.put(k, v));
            writer = new BufferedWriter(createFileWriter(outputType, templateName));

            template.merge(context, writer);
            writer.flush();
        } catch (ResourceNotFoundException rnfe) {
            LOG.error("Couldn't find the template with name '" + templateName + "'");
            throw new Exception(rnfe.getMessage());
        } catch (ParseErrorException pee) {
            LOG.error("Syntax error: problem parsing the template ' " + templateName + "': " + pee.getMessage());
            throw new Exception(pee.getMessage());
        } catch (MethodInvocationException mie) {
            LOG.error(
                    "An invoked method on the template '" + templateName + "' threw an error: " + mie.getMessage());
            throw new Exception(mie.getMessage());
        } catch (Exception e) {
            LOG.error("Error: " + e.getMessage());
            throw e;
        } finally {
            if (writer != null)
                writer.close();
        }
    }

    /**
     * Prints the header, content and output to the given print stream with the default template from the classpath.
     *
     * @param outputType the desired output type. @see {@link OutputType}
     * @param contextMap the context for velocity
     * @throws Exception in case of a error, so the caller can handle it
     */
    private static void printWithDefaultTemplate(final OutputType outputType, final Map<String, Object> contextMap)
            throws Exception {
        VelocityEngine ve = new VelocityEngine();
        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        ve.init();

        Writer writer = null;
        final String templateName = outputType.getDefaultTemplateLocation();
        try {
            VelocityContext context = new VelocityContext();
            contextMap.forEach((k, v) -> context.put(k, v));
            Template template = ve.getTemplate(templateName, "UTF-8");
            writer = new BufferedWriter(createFileWriter(outputType, templateName));

            template.merge(context, writer);
            writer.flush();
        } catch (ResourceNotFoundException rnfe) {
            LOG.error("Couldn't find the template with name '" + templateName + "'");
            throw new Exception(rnfe.getMessage());
        } catch (ParseErrorException pee) {
            LOG.error("Syntax error: problem parsing the template ' " + templateName + "': " + pee.getMessage());
            throw new Exception(pee.getMessage());
        } catch (MethodInvocationException mie) {
            LOG.error(
                    "An invoked method on the template '" + templateName + "' threw an error: " + mie.getMessage());
            throw new Exception(mie.getMessage());
        } catch (Exception e) {
            LOG.error("Error: " + e.getMessage());
            LOG.error("Cause: " + e.getCause());
            Arrays.stream(e.getStackTrace()).forEach(LOG::error);
            throw e;
        } finally {
            if (writer != null)
                writer.close();
        }
    }

    /**
     * Creates a file writer with a timestamp from the current output type and template. Write
     * a file in the current directory. Striped the folders off the name if the given template.
     *
     * @param outputType   the output type
     * @param templateName the name of the template
     * @return the OutputStreamWriter
     * @throws IOException if the file could not be created.
     */
    private static OutputStreamWriter createFileWriter(final OutputType outputType, final String templateName)
            throws IOException {
        final String fileName;
        int lastIndexOf = templateName.lastIndexOf(System.getProperty("file.separator"));
        if (lastIndexOf == -1) {
            fileName = templateName.replace(outputType.getTemplateExtension(), "") + outputType.getFileExtension();
        } else {
            fileName = templateName.substring(lastIndexOf + 1).replace(outputType.getTemplateExtension(), "")
                    + outputType.getFileExtension();
        }
        String datedFileName = Defaults.OUTFILE_DATE_FORMAT.format(ZonedDateTime.now()) + "_" + fileName;

        LOG.info("Writing to file '" + datedFileName + "'");
        return new OutputStreamWriter(new FileOutputStream(datedFileName), Charset.forName("UTF-8"));
    }
}