ReportingMojo.java

package org.thewonderlemming.c4plantuml.mojo;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.thewonderlemming.c4plantuml.graphml.C4Graph;

/**
 * A MOJO that parses the C4 PlantUML files that are contained in the output directory and generates a GraphML file with
 * the gathered information.
 *
 * @author thewonderlemming
 *
 */
@Mojo(name = "report", defaultPhase = LifecyclePhase.PROCESS_CLASSES)
public class ReportingMojo extends AbstractParentMojo {

    /**
     * Default value for the {@code failOnParseErrors} property.
     */
    public static final String FAIL_ON_PARSE_ERRORS_DEFAULT_VALUE = "false";

    /**
     * Default value for the {@code formatOutput} property.
     */
    public static final String FORMAT_OUTPUT_DEFAULT_VALUE = "true";

    /**
     * Default value for the generated GraphML filename.
     * <p>
     * It is linked to the {@code outputFilename} property. If the given {@code outputFilename} is not an absolute path,
     * then it will be created in the {@code outputDirectory}.
     */
    public static final String OUTPUT_FILENAME_DEFAULT_VALUE = "c4graph.graphml";

    @Parameter(property = "failOnParseErrors", defaultValue = FAIL_ON_PARSE_ERRORS_DEFAULT_VALUE,
        alias = "failOnParseErrors")
    private boolean failOnParseErrors;

    @Parameter(property = "formatOutput", defaultValue = FORMAT_OUTPUT_DEFAULT_VALUE, alias = "formatOutput")
    private boolean formatOutput;

    @Parameter(property = "outputFilename", defaultValue = OUTPUT_FILENAME_DEFAULT_VALUE, alias = "outputFilename")
    private String outputFilename;


    /**
     * Gathers information from the C4 PlantUML files and outputs it as a GraphML file.
     * <p>
     * {@inheritDoc}
     */
    @Override
    protected void doExecute() throws MojoExecutionException, MojoFailureException {

        validateOutputFilename();
        generateReportFile();
    }

    private void generateReportFile() throws MojoFailureException {

        try {

            final C4Graph c4Graph = new C4Graph(getCurrentCharset(), this.formatOutput, this.failOnParseErrors);
            final List<Path> c4Files = new ArrayList<>();

            processOutputDirectoryFiles(c4Files::add);

            if (c4Files.isEmpty()) {
                throw new MojoFailureException("No data found to report");
            }

            final Optional<String> content = c4Graph.addAndProcessC4Files(c4Files).export();

            if (content.isPresent()) {
                writeReportFile(content.get());

            } else {
                throw new MojoFailureException("Unable to export to GraphML format");
            }

        } catch (final Throwable e) {

            final String errMsg = String
                .format("Cannot process output directory: \"%s\" for reporting because of the following: %s",
                    getOutputDirectory(),
                    e.getMessage());

            throw new MojoFailureException(errMsg, e);
        }
    }

    private void validateOutputFilename() {

        assert (this.outputFilename != null) : "Expected outputFilename to be set";

        final File outputFile = new File(this.outputFilename);

        if (!outputFile.isAbsolute()) {

            this.outputFilename = getOutputDirectory() + "/" + this.outputFilename;

            getLog()
                .info(
                    "The given report filename is not absolute. \"" + this.outputFilename + "\" will be used instead.");
        }
    }

    private void writeReportFile(final String content) throws IOException {

        try (final FileOutputStream fos = new FileOutputStream(this.outputFilename);
            final DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(fos))) {

            dos.write(content.getBytes(getCurrentCharset()));
        }
    }
}