croche.maven.plugin.dbupgrade.CreateUpgradeScriptMojo.java Source code

Java tutorial

Introduction

Here is the source code for croche.maven.plugin.dbupgrade.CreateUpgradeScriptMojo.java

Source

/*
 * Copyright  2012 Avego Ltd., All Rights Reserved.
 * For licensing terms please contact Avego LTD.
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package croche.maven.plugin.dbupgrade;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;

/**
 * The CreateUpgradeScriptMojo represents a mojo that builds the merged db upgrade script
 * @goal create-upgrade-scripts
 * @phase process-resources
 * @requiresProject
 * @version $Id$
 * @author conorroche
 */
public class CreateUpgradeScriptMojo extends AbstractMojo {

    /**
     * The source directory where it will scan for files, it will look in this directory and all of its subdirectories
     * @parameter
     * @required
     */
    protected File sourceDir;

    /**
     * The target dir that the files created files will be written to
     * @parameter
     * @required
     */
    protected File targetDir;

    /**
     * This is include pattern for files to include
     * @parameter
     */
    protected String[] includes;

    /**
     * This is exclude pattern for files
     * @parameter
     */
    protected String[] excludes;

    /**
     * <pre>
     * This is an optional separator output above merged files in the combined file.
     * In the separator 3 variables are supported: 
     * 1. \n will translate into a line break in the output file, 
     * 2. #{file.name} will be replaced with the name of the file that is being appended into the target file, 
     * 3. #{parent.name} will be replaced with the directory name containing the file that is being appended into
     * the target file.
     * </pre>
     * @parameter
     */
    protected String separator;

    /**
     * This is an optional encoding to use when reading/writing the files being merged, if not specified
     * then UTF-8 will be used
     * @parameter default-value="UTF-8"
     */
    protected String encoding;

    /**
     * This is the names of the directories of the core specific projects
     * @parameter
     * @required
     */
    protected String[] coreDirs;

    /**
     * This is the names of the directories of the www specific projects
     * @parameter
     * @required
     */
    protected String[] wwwDirs;

    /**
     * This is the file name used for the generated sql file that contains all the sql files
     * @parameter default-value="upgrade-all.sql"
     */
    protected String allInOneFileName;

    /**
     * This is the file name used for the generated sql file that contains the www sql files
     * @parameter default-value="upgrade-www.sql"
     */
    protected String wwwFileName;

    /**
     * This is the file name used for the generated sql file that contains the core sql files
     * @parameter default-value="upgrade-core.sql"
     */
    protected String coreFileName;

    /**
     * Gets the comma separated list of effective include patterns.
     * @return The comma separated list of effective include patterns, never <code>null</code>.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    String getIncludesCSV() {
        Collection patterns = new LinkedHashSet();
        if (this.includes != null) {
            patterns.addAll(Arrays.asList(this.includes));
        }
        if (patterns.isEmpty()) {
            patterns.add("**/*");
        }
        return StringUtils.join(patterns.iterator(), ",");
    }

    /**
     * Gets the comma separated list of effective exclude patterns.
     * @return The comma separated list of effective exclude patterns, never <code>null</code>.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    String getExcludesCSV() {
        Collection patterns = new LinkedHashSet(FileUtils.getDefaultExcludesAsList());
        // add on the target files as excludes
        patterns.addAll(Arrays.asList(this.allInOneFileName, this.coreFileName, this.wwwFileName));
        if (this.excludes != null) {
            patterns.addAll(Arrays.asList(this.excludes));
        }
        return StringUtils.join(patterns.iterator(), ",");
    }

    static class Sprint {

        String version;
        List<File> wwwFiles = new ArrayList<File>();
        List<File> coreFiles = new ArrayList<File>();
        List<File> allInOneFiles = new ArrayList<File>();

    }

    private Map<String, Sprint> sprints = new HashMap<String, Sprint>();

    /**
     * {@inheritDoc}
     * @see org.apache.maven.plugin.Mojo#execute()
     */
    public void execute() throws MojoExecutionException, MojoFailureException {

        // scan the directories to build the total number of sprints for which there are upgrade scripts
        buildSprintData();

        // now create the files for all in one, www and core for each sprint
        for (Sprint sprint : this.sprints.values()) {
            try {
                createSprintFiles(sprint);
            } catch (IOException ex) {
                throw new MojoExecutionException("Failed to create the sprint files for the sprint: " + sprint, ex);
            }
        }
    }

    void createSprintFiles(Sprint sprint) throws IOException, MojoExecutionException {
        // remove existing target dir if it exists
        File sprintDir = new File(this.targetDir + File.separator + sprint.version);
        if (!sprintDir.exists()) {
            sprintDir.mkdirs();
        }
        FileUtils.cleanDirectory(sprintDir);

        // build the merged all in one sql file
        mergeFiles(sprint.allInOneFiles, new File(sprintDir, this.allInOneFileName));

        // then the www one
        mergeFiles(sprint.wwwFiles, new File(sprintDir, this.wwwFileName));

        // finally the core one
        mergeFiles(sprint.coreFiles, new File(sprintDir, this.coreFileName));

        // copy all the files into the sprint dir
        for (File file : sprint.allInOneFiles) {
            FileUtils.copyFile(file, new File(sprintDir, file.getParentFile().getParentFile().getName() + ".sql"));
        }
    }

    private int mergeFiles(List<File> files, File targetFile) throws MojoExecutionException {

        int numMergedFiles = 0;
        // now append the files that have been found in the order required
        Writer ostream = null;
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(targetFile, true);
            ostream = new OutputStreamWriter(fos, this.encoding);
            BufferedWriter output = new BufferedWriter(ostream);

            getLog().info("Appending: " + files.size() + " files to the target file: "
                    + targetFile.getAbsolutePath() + "...");
            for (File file : files) {
                String fileName = file.getName();
                getLog().info("Appending file: " + file.getAbsolutePath() + " to the target file: "
                        + targetFile.getAbsolutePath() + "...");
                InputStream input = null;
                try {
                    input = new FileInputStream(file);

                    // add separator if present
                    if (this.separator != null && this.separator.trim().length() > 0) {
                        String replaced = this.separator.trim();
                        // remove any line breaks and tabs due to xml formatting
                        replaced = replaced.replace("\n", "");
                        replaced = replaced.replace("\t", "");
                        // replace the file name and parent name variables
                        replaced = replaced.replace("#{file.name}", fileName);
                        replaced = replaced.replace("#{parent.name}",
                                file.getParentFile() != null ? file.getParentFile().getName() : "");
                        replaced = replaced.replace("#{grandparent.name}",
                                (file.getParentFile() != null && file.getParentFile().getParentFile() != null)
                                        ? file.getParentFile().getParentFile().getName()
                                        : "");
                        // add in any requested line breaks and tabs
                        replaced = replaced.replace("\\n", "\n");
                        replaced = replaced.replace("\\t", "\t");
                        getLog().debug("Appending separator: " + replaced);
                        IOUtils.copy(new StringReader(replaced), output);
                    }
                    // add file contents
                    IOUtils.copy(input, output, this.encoding);
                } catch (IOException ioe) {
                    throw new MojoExecutionException("Failed to append file: " + fileName + " to output file", ioe);
                } finally {
                    IOUtils.closeQuietly(input);
                }
                numMergedFiles++;
            }

            output.flush();
        } catch (IOException ioe) {
            throw new MojoExecutionException(
                    "Failed to open stream file to output file: " + targetFile.getAbsolutePath(), ioe);
        } finally {
            if (fos != null) {
                IOUtils.closeQuietly(fos);
            }
            if (ostream != null) {
                IOUtils.closeQuietly(ostream);
            }
        }
        return numMergedFiles;
    }

    @SuppressWarnings("unchecked")
    void buildSprintData() throws MojoExecutionException {
        getLog().info("Scanning source directory: " + this.sourceDir.getAbsolutePath()
                + " for db upgrade sql scripts...");

        String including = getIncludesCSV();
        String excluding = getExcludesCSV();

        // first find matching files
        List<File> matchingFiles;
        try {
            matchingFiles = FileUtils.getFiles(this.sourceDir, including, excluding);
        } catch (IOException ioe) {
            throw new MojoExecutionException(
                    "Failed to find matching files of the source dir: " + this.sourceDir.getAbsolutePath(), ioe);
        }

        int numFiles = matchingFiles == null ? 0 : matchingFiles.size();
        getLog().info("Sourced directory: " + this.sourceDir.getAbsolutePath() + " contains " + numFiles
                + " upgrade scripts.");

        if (matchingFiles != null) {
            for (File file : matchingFiles) {
                // see what version it is if any
                try {
                    SprintVersion version = new SprintVersion(getFileNameNoExt(file.getName()));
                    String versionName = version.toString();
                    Sprint sprint = this.sprints.get(versionName);
                    if (sprint == null) {
                        sprint = new Sprint();
                        sprint.version = versionName;
                        this.sprints.put(versionName, sprint);
                    }

                    // add to the all inone and core or www list
                    sprint.allInOneFiles.add(file);
                    if (isWwwFile(file)) {
                        sprint.wwwFiles.add(file);
                    } else if (isCoreFile(file)) {
                        sprint.coreFiles.add(file);
                    } else {
                        throw new MojoExecutionException(
                                "The file: " + file.getAbsolutePath() + " did not match the www or core files");
                    }

                } catch (SprintVersionException ex) {
                    getLog().warn(
                            "Skipping file: " + file.getAbsolutePath() + " as it does not match a sprint version.");
                }
            }
        }

    }

    private boolean isWwwFile(File file) {
        if (this.wwwDirs != null) {
            for (String dir : this.wwwDirs) {
                if (file.getAbsolutePath().contains(dir)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isCoreFile(File file) {
        if (this.coreDirs != null) {
            for (String dir : this.coreDirs) {
                if (file.getAbsolutePath().contains(dir)) {
                    return true;
                }
            }
        }
        return false;
    }

    private String getFileNameNoExt(String fileName) {
        int lastDotPos = fileName.lastIndexOf(".");
        return fileName.substring(0, lastDotPos);
    }

}