com.github.niltz.maven.plugins.mongodb.AbstractMongoDBMojo.java Source code

Java tutorial

Introduction

Here is the source code for com.github.niltz.maven.plugins.mongodb.AbstractMongoDBMojo.java

Source

/**
 * Copyright (c) 2012 Jeff Sawatzky
 *
 * 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.
 */
package com.github.niltz.maven.plugins.mongodb;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;

import com.mongodb.CommandResult;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.ServerAddress;

/**
 * Abstract mojo that all mongodb related mojos inherit from.
 */
public abstract class AbstractMongoDBMojo extends AbstractMojo {

    private static final String SCRIPT_EXTENSION = ".js";

    /**
     * The directory that contains the scripts, looks for a subfolder named
     * after the database, and either a create/populate/update subfolder based
     * on the operation
     * 
     * @parameter default-value="${basedir}/src/main/mongodb"
     */
    private File scriptsDirectory;

    /**
     * Whether or not to execute the scripts against the database.
     * 
     * @parameter default-value="true"
     */
    private boolean executeScripts;

    /**
     * The final name of the file, which will contain a suffix based on the
     * operation
     * 
     * @parameter default-value="${project.build.finalName}"
     * @readonly
     */
    private String outputName;

    /**
     * The output folder
     * 
     * @parameter default-value="${project.build.directory}/mongodb"
     * @readonly
     */
    private String outputDirectory;

    /**
     * The database settings
     * 
     * @parameter
     * @reqiured
     */
    private DatabaseSettings[] databaseSettings;

    /**
     * @return the databaseSettings
     */
    DatabaseSettings[] getDatabaseSettings() {
        return databaseSettings;
    }

    /**
     * The {@link Settings} object.
     * 
     * @parameter default-value="${settings}"
     * @required
     * @readonly
     */
    private Settings settings;

    /**
     * Child mojos need to implement this.
     * 
     * @throws MojoExecutionException
     *             on error
     * @throws MojoFailureException
     *             on error
     */
    public abstract void executeInternal() throws MojoExecutionException, MojoFailureException;

    /**
     * {@inheritDoc}
     */
    public final void execute() throws MojoExecutionException, MojoFailureException {
        checkDbSettings(databaseSettings);
        executeInternal();
    }

    /**
     * Checks the given database connection settings.
     * 
     * @param dbSettings
     *            the settings to check
     * @param name
     *            the name of the settings
     * @throws MojoExecutionException
     *             on error
     * @throws MojoFailureException
     *             on error
     */
    private void checkDbSettings(DatabaseSettings[] databaseSettings)
            throws MojoExecutionException, MojoFailureException {

        for (int i = 0; i < this.databaseSettings.length; i++) {
            DatabaseSettings dbSettings = this.databaseSettings[i];
            ConnectionSettings connectionSettings = dbSettings.getConnectionSettings();

            if (!StringUtils.isEmpty(connectionSettings.getServerId())) {
                Server server = settings.getServer(connectionSettings.getServerId());
                if (server == null) {
                    throw new MojoFailureException(
                            "[connectionSettings] Server ID: " + connectionSettings.getServerId() + " not found!");
                }

            } else if (StringUtils.isEmpty(connectionSettings.getHostname())) {
                throw new MojoFailureException("[connectionSettings] No hostname defined!");
            }
        }
    }

    /**
     * Executes all of the scripts in a given directory using the given Mongo
     * object.
     * 
     * @param connectionSettings
     *            the connection settings for the current database
     * @param operation
     *            the operation to perform (create,update,etc) which is used to
     *            look for the scripts and create the combined file
     * @param db
     *            the db
     * @param ignore
     *            a list of scripts to ignore
     * @throws MojoFailureException
     *             on error
     * @throws MojoExecutionException
     *             on error
     * @throws IOException
     *             on error
     */
    protected void executeScriptsInDirectory(ConnectionSettings connectionSettings, String operation, DB db,
            String[] ignore) throws MojoFailureException, MojoExecutionException, IOException {

        BufferedWriter outputFileWriter = null;

        try {
            File scriptsDirectory = new File(this.scriptsDirectory, connectionSettings.getDatabase());
            scriptsDirectory = new File(scriptsDirectory, operation);

            if (!scriptsDirectory.exists()) {
                getLog().info("  no scripts found at: " + scriptsDirectory.getAbsolutePath());
                return;
            }

            File outputFile = new File(this.outputDirectory,
                    this.outputName + "." + connectionSettings.getDatabase() + "." + operation + SCRIPT_EXTENSION);
            if (outputFile.exists()) {
                getLog().info("  deleting: " + outputFile.getAbsolutePath());
                outputFile.delete();
            }

            getLog().info("  creating dir: " + outputFile.getParentFile().getAbsolutePath());
            outputFile.getParentFile().mkdirs();

            getLog().info("  creating: " + outputFile.getAbsolutePath());
            outputFile.createNewFile();

            outputFileWriter = new BufferedWriter(new FileWriter(outputFile));

            getLog().info("  executing scripts in: " + scriptsDirectory.getAbsolutePath());

            // make sure we can read it, and that it's
            // a directory and not a file
            if (!scriptsDirectory.isDirectory()) {
                throw new MojoFailureException(scriptsDirectory.getAbsolutePath() + " is not a directory");
            }

            // get all files in directory
            File[] files = scriptsDirectory.listFiles();

            // sort the scripts so that they execute in a reproducible order
            Arrays.sort(files, new Comparator<File>() {
                public int compare(File arg0, File arg1) {
                    return arg0.getName().compareTo(arg1.getName());
                }
            });

            // loop through all the files and execute them unless they are to be
            // ignored
            List<String> ignoreList = Arrays.asList(ignore);
            for (int i = 0; i < files.length; i++) {
                if (!files[i].isDirectory() && files[i].isFile()) {
                    File file = files[i];
                    String fileName = file.getName();

                    //
                    // Skip files that don't end with SCRIPT_EXTENSION
                    //
                    if (!fileName.endsWith(SCRIPT_EXTENSION)) {
                        getLog().info(
                                "    file '" + fileName + "' ignored. Doesn't end with '" + SCRIPT_EXTENSION + "'");
                        continue;
                    }

                    //
                    // Skip files that are to be ignored
                    //
                    if (ignoreList.contains(fileName)) {
                        getLog().info("    script '" + fileName + "' ignored. Already applied.");
                        continue;
                    }

                    //
                    // Execute the script
                    //
                    double startTime = System.currentTimeMillis();

                    executeScript(files[i], db, outputFileWriter);

                    double endTime = System.currentTimeMillis();
                    double elapsed = ((endTime - startTime) / 1000.0);
                    getLog().info("    script '" + fileName + "' completed execution in " + elapsed + " second(s)");
                }
            }

        } finally {
            if (null != outputFileWriter) {
                outputFileWriter.close();
                outputFileWriter = null;
            }
        }
    }

    /**
     * Executes the given script, using the given Mongo.
     * 
     * @param file
     *            the file to execute
     * @param mongo
     *            the db
     * @throws MojoFailureException
     *             on error
     * @throws MojoExecutionException
     *             on error
     * @throws IOException
     *             on error
     */
    protected void executeScript(File file, DB db, BufferedWriter outputFileWriter)
            throws MojoFailureException, MojoExecutionException, IOException {

        // talk a bit :)
        getLog().info("    executing script: " + file.getName());

        // make sure we can read it, and that it's
        // a file and not a directory
        if (!file.exists() || !file.canRead() || file.isDirectory() || !file.isFile()) {
            throw new MojoFailureException(file.getName() + " is not a file");
        }

        // our file reader
        StringBuffer data = new StringBuffer();
        BufferedReader inputFileReader = null;
        try {
            inputFileReader = new BufferedReader(new FileReader(file));

            String line;

            // loop through the statements
            while ((line = inputFileReader.readLine()) != null) {
                // append the line
                line.trim();
                data.append("\n").append(line);
            }
        } finally {
            inputFileReader.close();
        }

        // execute last statement
        try {
            if (this.executeScripts) {
                CommandResult result = db.doEval(data.toString(), new Object[0]);

                if (!result.ok()) {
                    getLog().warn("Error executing " + file.getName() + ": " + result.getErrorMessage(),
                            result.getException());
                } else {
                    this.appendScriptToFileWriter(outputFileWriter, file, data);
                    getLog().info("    " + file.getName() + " executed successfully");
                }
            } else {
                this.appendScriptToFileWriter(outputFileWriter, file, data);
            }
        } catch (Exception e) {
            getLog().error("    error executing " + file.getName(), e);
        }
    }

    /**
     * 
     * @param outputFileWriter
     * @param scriptFile
     * @param scriptData
     * @throws IOException
     */
    private void appendScriptToFileWriter(BufferedWriter outputFileWriter, File scriptFile, StringBuffer scriptData)
            throws IOException {
        outputFileWriter.append("//").append("\n");
        outputFileWriter.append("// -------------------- " + scriptFile.getName()).append("\n");
        outputFileWriter.append("//").append("\n");
        outputFileWriter.append(scriptData.toString());
        outputFileWriter.flush();
    }

    /**
     * Opens a connection using the given settings.
     * 
     * @param dbSettings
     *            the connection settings
     * @return the Connection
     * @throws MojoFailureException
     *             on error
     * @throws UnknownHostException
     */
    protected Mongo openConnection(ConnectionSettings connectionSettings)
            throws MojoFailureException, UnknownHostException {

        // get server address
        ServerAddress serverAddr = (connectionSettings.getPort() != null)
                ? new ServerAddress(connectionSettings.getHostname(), connectionSettings.getPort().intValue())
                : new ServerAddress(connectionSettings.getHostname());

        // get Mongo
        Mongo mongo = (connectionSettings.getOptions() != null)
                ? new Mongo(serverAddr, connectionSettings.getOptions())
                : new Mongo(serverAddr);

        // we're good :)
        return mongo;
    }

    /**
     * Returns a DB from the given settings and mongo.
     * 
     * @param mongo
     *            the mongo
     * @param dbSettings
     *            the settings
     * @return the DB
     */
    protected DB getDatabase(ConnectionSettings connectionSettings, Mongo mongo) {

        String username, password = null;

        // use settings to get authentication info for the given server
        if (!StringUtils.isEmpty(connectionSettings.getServerId())) {
            Server server = settings.getServer(connectionSettings.getServerId());
            username = server.getUsername();
            password = server.getPassword();

            // use settings in pom.xml
        } else {
            username = connectionSettings.getUserName();
            password = connectionSettings.getPassword();
        }

        // get the DB and optionaly authenticate
        DB db = mongo.getDB(connectionSettings.getDatabase());
        if (username != null && password != null) {
            db.authenticate(username, password.toCharArray());
        }
        return db;
    }

    /**
     * Drops the configured mongo database.
     * 
     * @param mongo
     *            the mogno
     */
    protected void dropDatabase(ConnectionSettings connectionSettings, Mongo mongo) {
        mongo.dropDatabase(connectionSettings.getDatabase());
    }
}