org.fusesource.mop.MOP.java Source code

Java tutorial

Introduction

Here is the source code for org.fusesource.mop.MOP.java

Source

/**
 *  Copyright (C) 2009 Progress Software, Inc. All rights reserved.
 *  http://fusesource.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *  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 org.fusesource.mop;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.codehaus.plexus.MutablePlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.fusesource.mop.support.ArtifactId;
import org.fusesource.mop.support.CommandDefinition;
import org.fusesource.mop.support.CommandDefinitions;
import org.fusesource.mop.support.Logger;

import static org.fusesource.mop.support.Logger.*;
import static org.fusesource.mop.support.OptionBuilder.*;

/**
 * Runs a Java class from an artifact loaded from the local maven repository
 * using optional remote repositories.
 */
public class MOP {

    private static final transient Log LOG = LogFactory.getLog(org.fusesource.mop.MOP.class);

    public static final String DEFAULT_VERSION = "RELEASE";
    public static final String DEFAULT_TYPE = "jar";
    public static final String MOP_WORKING_DIR_SYSPROPERTY = "org.fusesource.mop.workingdir";

    private MOPRepository repository = new MOPRepository();
    private Options options;
    private String className;

    private List<ArtifactId> artifactIds;
    private List<String> reminingArgs;
    private Map<String, CommandDefinition> commands;
    private String defaultVersion = DEFAULT_VERSION;
    private String defaultType = DEFAULT_TYPE;
    private File workingDirectory;
    private ProcessRunner processRunner;
    private Map<String, String> systemProperties = new HashMap<String, String>();

    static public Options createOptions() {
        Options options = new Options();
        options.addOption("h", "help", false, "Display help information");
        //        options.addOption("o", "offline", false, "Work offline");
        options.addOption("X", "debug", false, "Produce execution debug output");

        options.addOption(ob().id("n").name("no-repos").description("Do not use any default repos").op());

        options.addOption(
                ob().id("l").name("local").arg("directory").description("Specifies the local mop repo").op());

        options.addOption(ob().id("r").name("repo").arg("repo").description("Add a remote maven repo").op());

        options.addOption(ob().id("s").name("scope").arg("scope")
                .description("Maven scope of transitive dependencies to include, defaults to 'runtime'").op());

        return options;
    }

    public void displayHelp() {
        System.err.flush();
        String app = System.getProperty("mop.application", "mop");

        // The commented out line is 80 chars long.  We have it here as a visual reference
        //      p("                                                                                ");
        p();
        p("Usage: " + app + " [options] <command>");
        p();
        p("Description:");
        p();
        pw("  mop is a tool for running Java code on the command line using maven repositories to download code and create classpaths.",
                2);
        p();

        p("Options:");
        p();
        PrintWriter out = new PrintWriter(System.out);
        HelpFormatter formatter = new HelpFormatter();
        formatter.printOptions(out, 78, createOptions(), 2, 2);
        out.flush();
        p();

        checkCommandsLoaded();
        p("Commands:");
        p();
        for (Map.Entry<String, CommandDefinition> entry : commands.entrySet()) {
            CommandDefinition command = entry.getValue();
            pw("  * " + entry.getKey() + ": " + removeNewLines(command.getDescription()), 4);
            pw("      usage: " + app + " [options] " + entry.getKey() + " " + removeNewLines(command.getUsage()),
                    6);
            p();
        }

        p("Where:");
        p();
        p("  <repo>     is of the format: repo_id=repo_url");
        p("  <artifact> is of the format: ");
        p("             [groupId:]artifactId[[:type[:classifier]]:version] [+<artifact>]");
        p();
        p("Learn more at: http://mop.fusesource.org/");
    }

    private void pw(String message, int indent) {
        PrintWriter out = new PrintWriter(System.out);
        HelpFormatter formatter = new HelpFormatter();
        formatter.printWrapped(out, 78, indent, message);
        out.flush();
    }

    public static void main(String[] args) {

        String jv = System.getProperty("java.version").substring(0, 3);
        if (jv.compareTo("1.5") < 0) {
            System.err.println("The Launch Agent requires jdk 1.5 or higher to run, the current java version is "
                    + System.getProperty("java.version"));
            System.exit(-1);
            return;
        }

        MOP mop = new MOP();
        String workDir = System.getProperty(MOP_WORKING_DIR_SYSPROPERTY);
        if (workDir != null) {
            mop.setWorkingDirectory(new File(workDir));
        } else {
            String userDir = System.getProperty("user.dir");
            if (userDir != null) {
                mop.setWorkingDirectory(new File(userDir));
            }
        }
        int exitValue = mop.executeAndWait(args);
        System.exit(exitValue);
    }

    /**
     * Executes the given MOP command and waits for the response, blocking the
     * calling thread until any child processes complete.
     * 
     * @return the exit code
     */
    public int executeAndWait(String[] args) {
        int answer = execute(args);
        int answer1 = answer;
        if (processRunner != null) {
            answer1 = processRunner.join();
        }
        answer = answer1;
        return answer;
    }

    public int execute(String[] args) {
        CommandLine cli = null;
        try {
            cli = new GnuParser().parse(createOptions(), args, true);
        } catch (ParseException e) {
            System.err.println("Unable to parse command line options: " + e.getMessage());
            displayHelp();
            return 1;
        }

        // lets process the options
        Logger.debug = cli.hasOption("X");

        if (cli.hasOption("n")) {
            getRemoteRepositories().clear();
        }

        String scope = cli.getOptionValue("s", "runtime");
        repository.setScope(scope);
        String[] repos = cli.getOptionValues("r");
        if (repos != null) {
            for (String repo : repos) {
                String[] rc = repo.split("=", 2);
                if (rc.length != 2) {
                    System.err.println("Invalid repository.  Expected format is: <id>=<url>, actual: " + repo);
                    displayHelp();
                    return 1;
                }
                getRemoteRepositories().put(rc[0], rc[1]);
            }
        }

        //        repository.setOnline(!cli.hasOption("o"));
        //        LOG.debug("online mode: " + repository.isOnline());

        String localRepo = cli.getOptionValue('l');
        if (localRepo != null) {
            repository.setLocalRepo(new File(localRepo));
        }

        if (cli.hasOption("h")) {
            displayHelp();
            return 0;
        }

        // now the remaining command line args
        try {
            LinkedList<String> argList = new LinkedList<String>(Arrays.asList(cli.getArgs()));
            executeCommand(argList);
        } catch (UsageException e) {
            displayHelp();
            return 1;
        } catch (Throwable e) {
            System.err.println();
            System.err.println("Failed: " + e);
            e.printStackTrace();
            Set<Throwable> exceptions = new HashSet<Throwable>();
            exceptions.add(e);
            for (int i = 0; i < 10; i++) {
                e = e.getCause();
                if (e != null && exceptions.add(e)) {
                    System.err.println("Reason: " + e);
                    e.printStackTrace();
                } else {
                    break;
                }
            }
            return 2;
        }
        return 0;
    }

    public void executeCommand(LinkedList<String> argList) throws Exception {
        resetValues();
        if (argList.isEmpty()) {
            throw new UsageException("No command specified.");
        }

        String command = argList.removeFirst();
        if (command.equals("exec")) {
            execJava(argList);
        } else if (command.equals("execjar")) {
            execJarCommand(argList);
        } else if (command.equals("jar")) {
            jarCommand(argList);
        } else if (command.equals("run")) {
            runCommand(argList);
        } else if (command.equals("echo")) {
            echoCommand(argList);
        } else if (command.equals("classpath")) {
            classpathCommand(argList);
        } else if (command.equals("copy")) {
            copyCommand(argList);
        } else if (command.equals("war")) {
            warCommand(argList);
        } else if (command.equals("help")) {
            helpCommand(argList);
        } else if (command.equals("list")) {
            listCommand(argList);
        } else if (command.equals("uninstall")) {
            uninstallCommand(argList);
        } else {
            tryDiscoverCommand(command, argList);
        }
    }

    //-------------------------------------------------------------------------
    // sub command implementations
    //-------------------------------------------------------------------------
    private void execJava(LinkedList<String> argList) throws Exception {
        assertNotEmpty(argList);
        artifactIds = parseArtifactList(argList);
        assertNotEmpty(argList);
        className = argList.removeFirst();
        reminingArgs = argList;

        List<File> dependencies = resolveFiles();

        execClass(dependencies);
    }

    public void execJarCommand(LinkedList<String> argList) throws Exception {
        assertNotEmpty(argList);
        artifactIds = parseArtifactList(argList);
        reminingArgs = argList;

        List<File> dependencies = resolveFiles();
        setClassNameFromExecutableJar(dependencies);

        execClass(dependencies);
    }

    private void jarCommand(LinkedList<String> argList) throws Exception {
        assertNotEmpty(argList);
        artifactIds = parseArtifactList(argList);
        reminingArgs = argList;

        List<File> dependencies = resolveFiles();
        setClassNameFromExecutableJar(dependencies);

        runClass(dependencies);
    }

    private void runCommand(LinkedList<String> argList)
            throws Exception, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        assertNotEmpty(argList);
        artifactIds = parseArtifactList(argList);
        assertNotEmpty(argList);
        className = argList.removeFirst();
        reminingArgs = argList;

        List<File> dependencies = resolveFiles();
        runClass(dependencies);
    }

    private void echoCommand(LinkedList<String> argList) throws Exception {
        artifactIds = parseArtifactList(argList);
        String classpath = classpath();
        System.out.print("java -cp \"" + classpath + "\"");
        for (String arg : argList) {
            System.out.print(" \"" + arg + "\"");
        }
        p();
    }

    private void classpathCommand(LinkedList<String> argList) throws Exception {
        artifactIds = parseArtifactList(argList);
        String classpath = classpath();
        p(classpath);
    }

    private void copyCommand(LinkedList<String> argList) throws Exception {
        assertNotEmpty(argList);
        artifactIds = parseArtifactList(argList);
        assertNotEmpty(argList);
        File targetDir = new File(argList.removeFirst());
        repository.copy(targetDir, artifactIds);
    }

    protected void warCommand(LinkedList<String> argList) throws Exception {
        assertNotEmpty(argList);
        defaultType = "war";
        artifactIds = parseArtifactList(argList);
        reminingArgs = argList;

        // lets default the artiact to WAR and then find all the files and pass them in as a command line argumnet
        repository.setTransitive(false); // We just need the wars.. not the transitive deps.
        List<File> files = repository.resolveFiles(artifactIds);
        // We will need transitive deps to load up jettty
        repository.setTransitive(true);

        LOG.debug("Running war with files: " + files);

        LinkedList<String> newArgs = new LinkedList<String>();
        newArgs.add("jar");
        newArgs.add("org.mortbay.jetty:jetty-runner:RELEASE");
        newArgs.addAll(argList);
        for (File file : files) {
            newArgs.add(file.toString());
        }

        LOG.debug("About to run: " + newArgs);
        executeCommand(newArgs);
    }

    protected void helpCommand(LinkedList<String> argList) {
        if (argList.isEmpty()) {
            displayHelp();
            return;
        }
        for (String commandName : argList) {
            checkCommandsLoaded();
            CommandDefinition command = commands.get(commandName);
            if (command == null) {
                p("No such command '" + command + "'");
            } else {
                p();
                p("mop command: " + command.getName());
                p();
                p("usage:");
                p("\t mop [options] " + command.getName() + " " + command.getUsage());
                p();
                p(command.getDescription());
                p();
            }
        }
    }

    private void listCommand(LinkedList<String> argList) throws Exception {
        String type = "installed";
        if (!argList.isEmpty()) {
            type = argList.removeFirst();
        }

        this.artifactIds = parseArtifactList(argList);
        Set<ArtifactId> artifactIds = repository.list(type);
        for (ArtifactId a : artifactIds) {
            System.out.println(a);
        }
    }

    private void uninstallCommand(LinkedList<String> argList) throws Exception {
        artifactIds = parseArtifactList(argList);
        List<String> errorMessages = repository.uninstall(artifactIds);
        for (String errorMessage : errorMessages) {
            p(errorMessage);
        }
    }

    protected void tryDiscoverCommand(String commandText, LinkedList<String> argList) throws Exception {
        checkCommandsLoaded();

        defaultVersion = DEFAULT_VERSION;
        CommandDefinition command = commands.get(commandText);
        if (command == null) {
            // if we have used a colon then extract the version argument
            int idx = commandText.lastIndexOf(':');
            if (idx > 1) {
                defaultVersion = commandText.substring(idx + 1);
                commandText = commandText.substring(0, idx);
                command = commands.get(commandText);
            }
        }
        if (command == null) {
            throw new UsageException("Unknown command '" + commandText + "'");
        }
        command.executeCommand(this, argList);
    }

    //-------------------------------------------------------------------------
    // Other plublic methods... perhaps this needs a little clean up...
    //-------------------------------------------------------------------------

    public Artifacts getArtifacts(LinkedList<String> argList) throws UsageException {
        artifactIds = parseArtifactList(argList);
        reminingArgs = argList;

        return new Artifacts() {
            @Override
            protected List<File> createFiles() throws Exception {
                return resolveFiles();
            }

            @Override
            protected Set<Artifact> createArtifacts() throws Exception {
                return resolveArtifacts();
            }
        };
    }

    /**
     * Appends the currently defined system properties to this command line as a
     * series of <code>-Dname=value</code> parameters
     */
    public void addSystemProperties(List<String> commandLine) {
        Set<Map.Entry<String, String>> entries = systemProperties.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            commandLine.add("-D" + entry.getKey() + "=" + entry.getValue());
        }
    }

    public void exec(List<String> commandLine) throws Exception {
        exec(commandLine, null);
    }

    public void exec(List<String> commandLine, String[] envOverride) throws Exception {
        LOG.info("execing: " + commandLine);
        processRunner = doExec(commandLine, true, envOverride);
    }

    public void execAndWait(List<String> commandLine) throws Exception {
        ProcessRunner pRunner = doExec(commandLine, false, null);
        if (pRunner != null) {
            pRunner.join();
        }
    }

    private ProcessRunner doExec(List<String> commandLine, boolean redirectInput, String[] envOverride)
            throws Exception {
        LOG.info("MOP Executing " + commandLine);

        String[] cmd = commandLine.toArray(new String[commandLine.size()]);

        Map<String, String> envMap = System.getenv();
        String[] env = new String[envOverride != null ? envOverride.length + envMap.size() : envMap.size()];
        int ind = 0;
        if (envOverride != null) {
            for (; ind < envOverride.length; ind++) {
                env[ind] = envOverride[ind];
                if (envMap.containsKey(envOverride[ind])) {
                    envMap.remove(envOverride[ind]);
                }
                LOG.info("overriding env: " + env[ind]);
            }
        }
        for (Map.Entry<String, String> entry : envMap.entrySet()) {
            env[ind++] = entry.getKey() + "=" + entry.getValue();
            LOG.debug("setting env: " + env[ind - 1]);
        }

        return ProcessRunner.newInstance(ProcessRunner.newId("process"), cmd, env, workingDirectory, redirectInput);
    }

    public String classpath() throws Exception {
        return repository.classpath(artifactIds);
    }

    public ArtifactId parseArtifactId(String value) throws UsageException {
        ArtifactId id = ArtifactId.parse(value, defaultVersion, defaultType);
        if (id == null) {
            throw new UsageException("Invalid artifactId: " + value);
        }
        return id;
    }

    public Map<String, String> getSystemProperties() {
        return systemProperties;
    }

    /**
     * Adds the system property used for any child forked JVM if the value is
     * not null else remove the property
     */
    public void setSystemProperty(String name, String value) {
        if (value != null) {
            systemProperties.put(name, value);
            System.setProperty(name, value);
        } else {
            systemProperties.remove(name);
        }
    }

    /**
     * Returns true if this is an additional artifact string; typically if it
     * begins with +
     */
    public boolean isAnotherArtifactId(String arg) {
        return arg.startsWith("+");
    }

    //-------------------------------------------------------------------------
    // Implementation methods
    //-------------------------------------------------------------------------

    private Set<Artifact> resolveArtifacts() throws Exception {
        return repository.resolveArtifacts(artifactIds);
    }

    /**
     * Removes any newlines in the text so its one big line
     */
    private String removeNewLines(String text) {
        StringBuilder buffer = new StringBuilder();
        BufferedReader reader = new BufferedReader(new StringReader(text.trim()));
        boolean first = true;
        while (true) {
            try {
                String line = reader.readLine();
                if (line == null) {
                    break;
                }
                if (first) {
                    first = false;
                } else {
                    buffer.append(" ");
                }
                buffer.append(line.trim());
            } catch (IOException e) {
                LOG.warn("This should never happen. Caught: " + e, e);
            }
        }
        return buffer.toString();
    }

    protected void resetValues() {
        // lets reset values in case we chain things together...
        processRunner = null;
        defaultVersion = DEFAULT_VERSION;
        defaultType = DEFAULT_TYPE;
        repository.setTransitive(true);

        // lets not clear the system properties as they tend to be expected to flow through to the next invocation...
        //systemProperties.clear();
    }

    protected void execClass(List<File> dependencies) throws Exception {
        List<String> commandLine = new ArrayList<String>();
        commandLine.add("java");
        addSystemProperties(commandLine);
        commandLine.add("-cp");
        commandLine.add(MOPRepository.classpathFiles(dependencies));
        commandLine.add(className);
        commandLine.addAll(reminingArgs);

        exec(commandLine);
    }

    protected void setClassNameFromExecutableJar(List<File> dependencies) throws Exception, UsageException {
        // now lets figure out the className from the manifest
        // lets assume that the first file in the dependency list is usually the one we want to execute
        for (File file : dependencies) {
            JarFile jar = new JarFile(file);
            Manifest manifest = jar.getManifest();
            if (manifest != null) {
                Attributes attributes = manifest.getMainAttributes();
                if (attributes != null) {
                    //debug("file " + file + " has main attributes: " + new HashMap(attributes));
                    className = attributes.getValue(Attributes.Name.MAIN_CLASS);
                    if (className != null && className.length() > 0) {
                        className = className.trim();
                        if (className.length() > 0) {
                            break;
                        }
                    }
                } else {
                    LOG.debug("file " + file + " has no manifest main attributes: " + attributes);
                }
            } else {
                LOG.debug("file " + file + " has no manifest");
            }
        }
        if (className == null) {
            throw new Exception("No Main-Class attribute could be found in the dependent jars!");
        }
    }

    private List<File> resolveFiles() throws Exception {
        return repository.resolveFiles(artifactIds);
    }

    protected void runClass(List<File> dependencies) throws Exception {
        URLClassLoader classLoader = MOPRepository.createFileClassLoader(null, dependencies);
        Thread.currentThread().setContextClassLoader(classLoader);

        LOG.debug("Attempting to load class: " + className);
        Class<?> aClass = classLoader.loadClass(className);
        Method method = aClass.getMethod("main", String[].class);
        String[] commandLineArgs = reminingArgs.toArray(new String[reminingArgs.size()]);
        Object[] methodArgs = { commandLineArgs };
        method.invoke(null, methodArgs);
    }

    private ArrayList<ArtifactId> parseArtifactList(LinkedList<String> values) throws UsageException {
        ArrayList<ArtifactId> rc = new ArrayList<ArtifactId>();
        assertNotEmpty(values);
        String value = values.removeFirst();
        ArtifactId id = parseArtifactId(value);
        rc.add(id);

        while (!values.isEmpty() && isAnotherArtifactId(values.getFirst())) {
            value = values.removeFirst().substring(1);
            id = parseArtifactId(value);
            rc.add(id);
        }

        return rc;

    }

    static private class UsageException extends Exception {
        private static final long serialVersionUID = 1L;

        public UsageException(String message) {
            super(message);
        }
    }

    private void assertNotEmpty(LinkedList<String> args) throws UsageException {
        if (args.isEmpty()) {
            throw new UsageException("Empty argument list");
        }
    }

    void checkCommandsLoaded() {

        if (commands == null) {

            File mopHome = repository.getLocalRepo().getParentFile();
            File pluginConf = new File(mopHome, "command-ext.conf");
            ClassLoader classLoader = getClass().getClassLoader();

            if (pluginConf.exists()) {

                ArrayList<File> extensions = new ArrayList<File>();
                BufferedReader reader = null;
                boolean wasonline = repository.isOnline();
                repository.setOnline(false);
                try {
                    reader = new BufferedReader(new FileReader(pluginConf));
                    String line;
                    while ((line = reader.readLine()) != null) {
                        String[] artifacts = line.split("\\s+");
                        ArrayList<ArtifactId> artifactList;
                        try {
                            artifactList = parseArtifactList(new LinkedList<String>(Arrays.asList(artifacts)));
                        } catch (UsageException e) {
                            debug("Invalid command-ext.conf entry: " + line, e);
                            continue;
                        }

                        try {
                            extensions.addAll(repository.resolveFiles(artifactList));
                        } catch (Exception e) {
                            debug("Could not locate artifacts: " + line, e);
                            continue;
                        }

                    }
                } catch (IOException e) {
                    debug("Could not load command-ext.conf", e);
                } finally {
                    repository.setOnline(wasonline);
                    try {
                        reader.close();
                    } catch (Throwable e) {
                    }
                }

                if (!extensions.isEmpty()) {
                    try {
                        classLoader = MOPRepository.createFileClassLoader(classLoader, extensions);
                    } catch (MalformedURLException e) {
                        debug("Could not create extensions classloader.", e);
                    }
                }
            }

            commands = CommandDefinitions.loadCommands(classLoader);
            registerDefaultCommands();
            CommandDefinitions.addCommandDescriptions(commands, classLoader);
        }
    }

    protected void registerDefaultCommands() {
        registerDefaultCommand("jar",
                "uses an embedded class loader to run the Main class from the executable jar");
        registerDefaultCommand("execjar",
                "spawns a separate process to run the Main class from the executable jar in a new JVM");

        registerDefaultCommand("run", "<artifact(s)> <className> [<args(s)>]",
                "uses an embedded class loader to run the class's main() method");
        registerDefaultCommand("exec", "<artifact(s)> <className> [<args(s)>]",
                "spawns a separate process to run the class's main() method in a new JVM");

        registerDefaultCommand("echo", "<artifact(s)> [<className>] [<arg(s)>]",
                "displays the command line to set the classpath and run the class's main() method");
        registerDefaultCommand("classpath", "<artifact(s)>", "displays the classpath for the artifact");

        registerDefaultCommand("copy", "<artifact(s)> targetDirectory",
                "copies all the jars into the given directory");
        registerDefaultCommand("war",
                "runs the given (typically war) archetypes in the jetty servlet engine via jetty-runner");

        registerDefaultCommand("help", "<command(s)>",
                "displays help summarising all of the commands or shows custom help for each command listed");
    }

    protected void registerDefaultCommand(String name, String description) {
        registerDefaultCommand(name, "<artifact(s)> [<args(s)>]", description);
    }

    protected void registerDefaultCommand(String name, String usage, String description) {
        CommandDefinition commandDefinition = new CommandDefinition(name, usage, description);
        registerCommand(commandDefinition);
    }

    protected void registerCommand(CommandDefinition commandDefinition) {
        commands.put(commandDefinition.getName(), commandDefinition);
    }

    private void p() {
        System.out.println();
    }

    private void p(String s) {
        System.out.println(s);
    }

    //-------------------------------------------------------------------------
    // Properties
    //-------------------------------------------------------------------------
    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public Options getOptions() {
        return options;
    }

    public Map<String, CommandDefinition> getCommands() {
        checkCommandsLoaded();
        return commands;
    }

    public void setOptions(Options options) {
        this.options = options;
    }

    public List<String> getReminingArgs() {
        return reminingArgs;
    }

    public void setReminingArgs(List<String> reminingArgs) {
        this.reminingArgs = reminingArgs;
    }

    public List<ArtifactId> getArtifactIds() {
        return artifactIds;
    }

    public void setArtifactIds(List<ArtifactId> artifactIds) {
        this.artifactIds = artifactIds;
    }

    public void setArtifactIds(ArtifactId... artifactIds) {
        this.artifactIds = Arrays.asList(artifactIds);
    }

    public String getDefaultType() {
        return defaultType;
    }

    public void setDefaultType(String defaultType) {
        this.defaultType = defaultType;
    }

    public String getDefaultVersion() {
        return defaultVersion;
    }

    public void setDefaultVersion(String defaultVersion) {
        this.defaultVersion = defaultVersion;
    }

    public ProcessRunner getProcessRunner() {
        return processRunner;
    }

    public File getWorkingDirectory() {
        return workingDirectory;
    }

    public void setWorkingDirectory(File workingDirectory) {
        this.workingDirectory = workingDirectory;
    }

    public void setTransitive(boolean transitive) {
        repository.setTransitive(transitive);
    }

    public void setLocalRepo(File localRepo) {
        repository.setLocalRepo(localRepo);
    }

    public void setOnline(boolean online) {
        repository.setOnline(online);
    }

    /**
     * @param updatePolicy
     *            The update policy to use (e.g. always, never)
     * @see ArtifactRepositoryPolicy
     */
    public void setUpdatePolicy(String updatePolicy) {
        repository.setUpdatePolicy(updatePolicy);
    }

    /**
     * @return the current update policy
     * @see ArtifactRepositoryPolicy
     */
    public String getUpdatePolicy() {
        return repository.getUpdatePolicy();
    }

    public void setScope(String scope) {
        repository.setScope(scope);
    }

    public PlexusContainer getContainer() {
        return repository.getContainer();
    }

    public File getLocalRepo() {
        return repository.getLocalRepo();
    }

    public String getScope() {
        return repository.getScope();
    }

    public boolean isOnline() {
        return repository.isOnline();
    }

    public boolean isTransitive() {
        return repository.isTransitive();
    }

    public void setContainer(MutablePlexusContainer container) {
        repository.setContainer(container);
    }

    public MOPRepository getRepository() {
        return repository;
    }

    public void setRepository(MOPRepository repository) {
        this.repository = repository;
    }

    public LinkedHashMap<String, String> getRemoteRepositories() {
        return repository.getRemoteRepositories();
    }

    public void setRemoteRepositories(LinkedHashMap<String, String> remoteRepositories) {
        repository.setRemoteRepositories(remoteRepositories);
    }

    /**
     * Purges the local repository:
     */
    public void purgeRepository() throws Exception {
        repository.purge();
    }
}