org.smallmind.license.SourceNoticeMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.smallmind.license.SourceNoticeMojo.java

Source

package org.smallmind.license;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.regex.Pattern;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
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.apache.maven.project.MavenProject;
import org.smallmind.license.stencil.JavaDocStencil;
import org.smallmind.license.stencil.Stencil;

// Generates and/or replaces notice headers in source files
@Mojo(name = "generate-notice-headers", defaultPhase = LifecyclePhase.PROCESS_SOURCES, threadSafe = true)
public class SourceNoticeMojo extends AbstractMojo {

    private static final Stencil[] DEFAULT_STENCILS = new Stencil[] { new JavaDocStencil() };

    private static enum NoticeState {

        FIRST, LAST, COMPLETED, TERMINATED
    }

    @Parameter(readonly = true, property = "project")
    private MavenProject project;
    @Parameter
    private Root root;
    @Parameter
    private Stencil[] stencils;
    @Parameter
    private Rule[] rules;
    @Parameter(defaultValue = "false")
    private boolean allowNoticeRemoval;
    @Parameter(defaultValue = "true")
    private boolean includeResources;
    @Parameter(defaultValue = "false")
    private boolean includeTests;
    @Parameter(defaultValue = "false")
    private boolean verbose;

    //TODO: Excludes, Seek/Process Optimization

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {

        MavenProject rootProject = project;
        Stencil[] mergedStencils;
        char[] buffer = new char[8192];

        while ((root == null) ? !(rootProject.getParent() == null)
                : !(root.getGroupId().equals(rootProject.getGroupId())
                        && root.getArtifactId().equals(rootProject.getArtifactId()))) {
            rootProject = rootProject.getParent();
        }

        mergedStencils = new Stencil[(stencils != null) ? stencils.length + DEFAULT_STENCILS.length
                : DEFAULT_STENCILS.length];
        System.arraycopy(DEFAULT_STENCILS, 0, mergedStencils, 0, DEFAULT_STENCILS.length);
        if (stencils != null) {
            System.arraycopy(stencils, 0, mergedStencils, DEFAULT_STENCILS.length, stencils.length);
        }

        for (Rule rule : rules) {

            FileFilter[] fileFilters;
            String[] noticeArray;
            boolean noticed;
            boolean stenciled;

            if (verbose) {
                getLog().info(String.format("Processing rule(%s)...", rule.getId()));
            }

            noticed = true;
            if (rule.getNotice() == null) {
                if (!allowNoticeRemoval) {
                    throw new MojoExecutionException("No notice was provided for rule(" + rule.getId()
                            + "), but notice removal has not been enabled(allowNoticeRemoval = false)");
                }

                noticeArray = null;
            } else {

                File noticeFile;

                noticeFile = new File(rule.getNotice());
                if ((noticeArray = getFileAsLineArray(noticeFile.isAbsolute() ? noticeFile.getAbsolutePath()
                        : rootProject.getBasedir() + System.getProperty("file.separator")
                                + noticeFile.getPath())) == null) {
                    noticed = false;
                }
            }

            if (!noticed) {
                getLog().warn(String.format("Unable to acquire the notice file(%s), skipping notice updating...",
                        rule.getNotice()));
            } else {
                if ((rule.getFileTypes() == null) || (rule.getFileTypes().length == 0)) {
                    throw new MojoExecutionException("No file types were specified for rule(" + rule.getId() + ")");
                }

                fileFilters = new FileFilter[rule.getFileTypes().length];
                for (int count = 0; count < fileFilters.length; count++) {
                    fileFilters[count] = new FileTypeFilenameFilter(rule.getFileTypes()[count]);
                }

                stenciled = false;
                for (Stencil stencil : mergedStencils) {
                    if (stencil.getId().equals(rule.getStencilId())) {
                        stenciled = true;

                        updateNotice(stencil, noticeArray, buffer, project.getBuild().getSourceDirectory(),
                                fileFilters);
                        updateNotice(stencil, noticeArray, buffer, project.getBuild().getScriptSourceDirectory(),
                                fileFilters);

                        if (includeResources) {
                            for (Resource resource : project.getBuild().getResources()) {
                                updateNotice(stencil, noticeArray, buffer, resource.getDirectory(), fileFilters);
                            }
                        }

                        if (includeTests) {
                            updateNotice(stencil, noticeArray, buffer, project.getBuild().getTestSourceDirectory(),
                                    fileFilters);

                            if (includeResources) {
                                for (Resource testResource : project.getBuild().getTestResources()) {
                                    updateNotice(stencil, noticeArray, buffer, testResource.getDirectory(),
                                            fileFilters);
                                }
                            }
                        }

                        break;
                    }
                }

                if (!stenciled) {
                    throw new MojoExecutionException(
                            "No stencil found with id(" + rule.getStencilId() + ") for rule(" + rule.getId() + ")");
                }
            }
        }
    }

    private void updateNotice(Stencil stencil, String[] noticeArray, char[] buffer, String directoryPath,
            FileFilter... fileFilters) throws MojoExecutionException {

        File tempFile;
        BufferedReader fileReader;
        FileWriter fileWriter;
        Pattern skipPattern = null;
        String unprocessedLine;
        int charsRead;

        if (stencil.getSkipLines() != null) {
            skipPattern = Pattern.compile(stencil.getSkipLines());
        }

        for (File licensedFile : new LicensedFileIterator(new File(directoryPath), fileFilters)) {
            if (verbose) {
                getLog().info(String.format(
                        ((noticeArray == null) ? "Removing" : "Updating") + " license notice for file(%s)...",
                        licensedFile.getAbsolutePath()));
            }

            try {
                fileWriter = new FileWriter(tempFile = new File(
                        licensedFile.getParent() + System.getProperty("file.separator") + "license.temp"));

                try {
                    fileReader = new BufferedReader(new FileReader(licensedFile));

                    unprocessedLine = seekNotice(stencil, skipPattern, fileReader, fileWriter);

                    if (noticeArray != null) {
                        applyNotice(stencil, noticeArray, fileWriter);
                    }

                    if (unprocessedLine != null) {
                        fileWriter.write(unprocessedLine);
                        fileWriter.write(System.getProperty("line.separator"));
                    }

                    while ((charsRead = fileReader.read(buffer)) >= 0) {
                        fileWriter.write(buffer, 0, charsRead);
                    }

                    fileWriter.close();
                    fileReader.close();

                    if (!licensedFile.delete()) {
                        throw new MojoFailureException(
                                "Unable to delete file(" + licensedFile.getAbsolutePath() + ")");
                    }
                } catch (Exception exception) {
                    tempFile.delete();
                    throw new MojoExecutionException("Exception during notice processing", exception);
                }

                if (!tempFile.renameTo(licensedFile)) {
                    throw new MojoFailureException("Unable to rename temp file(" + tempFile.getAbsolutePath()
                            + ") to processed file(" + licensedFile.getAbsolutePath() + ")");
                }
            } catch (MojoExecutionException mojoExecutionException) {
                throw mojoExecutionException;
            } catch (Exception exception) {
                throw new MojoExecutionException("Exception during notice processing", exception);
            }
        }
    }

    private String[] getFileAsLineArray(String noticePath) throws MojoExecutionException {

        BufferedReader noticeReader;
        LinkedList<String> lineList;
        String[] lineArray;
        String singleLine;

        try {
            noticeReader = new BufferedReader(new FileReader(noticePath));
            lineList = new LinkedList<String>();
            while ((singleLine = noticeReader.readLine()) != null) {
                lineList.add(singleLine);
            }
        } catch (IOException ioException) {

            return null;
        }

        lineArray = new String[lineList.size()];
        lineList.toArray(lineArray);

        return lineArray;
    }

    private String seekNotice(Stencil stencil, Pattern skipPattern, BufferedReader fileReader,
            FileWriter fileWriter) throws IOException, MojoFailureException {

        NoticeState noticeState;
        String singleLine = null;
        String generalPrefix = (stencil.getBeforeEachLine() != null) ? stencil.getBeforeEachLine() : "";
        int whitespaceIndex = generalPrefix.length();

        while ((whitespaceIndex > 0) && Character.isWhitespace(generalPrefix.charAt(whitespaceIndex - 1))) {
            whitespaceIndex--;
        }
        generalPrefix = generalPrefix.substring(0, whitespaceIndex);

        noticeState = (stencil.getFirstLine() != null) ? NoticeState.FIRST : NoticeState.LAST;
        while ((!(noticeState.equals(NoticeState.COMPLETED) || noticeState.equals(NoticeState.TERMINATED)))
                && ((singleLine = fileReader.readLine()) != null)) {
            if ((skipPattern == null) || (!skipPattern.matcher(singleLine).matches())) {
                switch (noticeState) {
                case FIRST:
                    if (singleLine.length() > 0) {
                        noticeState = singleLine.equals(stencil.getFirstLine()) ? NoticeState.LAST
                                : NoticeState.TERMINATED;
                    }
                    break;
                case LAST:
                    if ((stencil.getLastLine() != null) && singleLine.equals(stencil.getLastLine())) {
                        noticeState = NoticeState.COMPLETED;
                    } else if ((singleLine.length() > 0) && (!singleLine.startsWith(generalPrefix))) {
                        noticeState = NoticeState.TERMINATED;
                    } else if ((singleLine.length() == 0) && stencil.willPrefixBlankLines()) {
                        noticeState = NoticeState.TERMINATED;
                    }
                    break;
                default:
                    throw new MojoFailureException(
                            "Unknown or inappropriate notice seeking state(" + noticeState.name() + ")");
                }
            } else {
                fileWriter.write(singleLine);
                fileWriter.write(System.getProperty("line.separator"));
            }
        }

        if (noticeState.equals(NoticeState.COMPLETED) || ((singleLine != null) && (singleLine.length() == 0))) {
            do {
                singleLine = fileReader.readLine();
            } while ((singleLine != null) && (singleLine.length() == 0));
        }

        return singleLine;
    }

    private void applyNotice(Stencil stencil, String[] noticeArray, FileWriter fileWriter) throws IOException {

        for (int count = 0; count < stencil.getBlankLinesBefore(); count++) {
            fileWriter.write(System.getProperty("line.separator"));
        }

        if (stencil.getFirstLine() != null) {
            fileWriter.write(stencil.getFirstLine());
            fileWriter.write(System.getProperty("line.separator"));
        }

        for (String noticeLine : noticeArray) {
            if ((stencil.getBeforeEachLine() != null)
                    && ((noticeLine.length() > 0) || stencil.willPrefixBlankLines())) {
                fileWriter.write(stencil.getBeforeEachLine());
            }
            fileWriter.write(noticeLine);
            fileWriter.write(System.getProperty("line.separator"));
        }

        if (stencil.getLastLine() != null) {
            fileWriter.write(stencil.getLastLine());
            fileWriter.write(System.getProperty("line.separator"));
        }

        for (int count = 0; count < stencil.getBlankLinesAfter(); count++) {
            fileWriter.write(System.getProperty("line.separator"));
        }
    }
}