com.greenpepper.runner.ant.AntTaskRunner.java Source code

Java tutorial

Introduction

Here is the source code for com.greenpepper.runner.ant.AntTaskRunner.java

Source

/*
 * Copyright (c) 2008 Pyxis Technologies inc.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA,
 * or see the FSF site: http://www.fsf.org.
 */
package com.greenpepper.runner.ant;

import java.io.File;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.codec.StringDecoder;
import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.util.LoaderUtils;
import org.apache.xmlrpc.XmlRpcClient;

import com.greenpepper.GreenPepper;
import com.greenpepper.GreenPepperCore;
import com.greenpepper.util.DuckType;

/**
 * <p>AntTaskRunner class.</p>
 *
 * @author oaouattara
 * @version $Id: $Id
 */
public class AntTaskRunner extends Task {
    private boolean failOnError = false;
    private boolean suite = false;
    private String input;
    private File output;
    private String outputType;
    private SectionElement section;
    private SystemUnderDevelopmentElement systemDevelopment;
    private RepositoryElement repository;
    private boolean stopOnFirstFailure = false;
    private String locale;
    private String selector;
    private boolean debug = false;
    private Path classpath;
    private Path runtimeClasspath;

    /**
     * <p>Constructor for AntTaskRunner.</p>
     */
    public AntTaskRunner() {
        super();
    }

    /**
     * <p>isFailOnError.</p>
     *
     * @return a boolean.
     */
    boolean isFailOnError() {
        return failOnError;
    }

    /**
     * <p>Setter for the field <code>failOnError</code>.</p>
     *
     * @param failOnError a boolean.
     */
    public void setFailOnError(boolean failOnError) {
        this.failOnError = failOnError;
    }

    /**
     * <p>isSuite.</p>
     *
     * @return a boolean.
     */
    public boolean isSuite() {
        return suite;
    }

    /**
     * <p>Setter for the field <code>suite</code>.</p>
     *
     * @param suite a boolean.
     */
    public void setSuite(boolean suite) {
        this.suite = suite;
    }

    /**
     * <p>Getter for the field <code>input</code>.</p>
     *
     * @return a {@link java.lang.String} object.
     */
    public String getInput() {
        return input;
    }

    /**
     * <p>Setter for the field <code>input</code>.</p>
     *
     * @param input a {@link java.lang.String} object.
     */
    public void setInput(String input) {
        this.input = input;
    }

    /**
     * <p>Getter for the field <code>output</code>.</p>
     *
     * @return a {@link java.io.File} object.
     */
    public File getOutput() {
        return output;
    }

    /**
     * <p>Setter for the field <code>output</code>.</p>
     *
     * @param output a {@link java.io.File} object.
     */
    public void setOutput(File output) {
        this.output = output;
    }

    /**
     * <p>Getter for the field <code>outputType</code>.</p>
     *
     * @return a {@link java.lang.String} object.
     */
    String getOutputType() {
        return outputType;
    }

    /**
     * <p>Setter for the field <code>outputType</code>.</p>
     *
     * @param type a {@link java.lang.String} object.
     */
    public void setOutputType(String type) {
        this.outputType = type.equalsIgnoreCase("xml") ? "xml" : null;
    }

    /**
     * <p>Getter for the field <code>section</code>.</p>
     *
     * @return a {@link com.greenpepper.runner.ant.SectionElement} object.
     */
    public SectionElement getSection() {
        return section;
    }

    /**
     * <p>Setter for the field <code>section</code>.</p>
     *
     * @param section a {@link com.greenpepper.runner.ant.SectionElement} object.
     */
    public void setSection(SectionElement section) {
        this.section = section;
    }

    /**
     * <p>createSection.</p>
     *
     * @return a {@link com.greenpepper.runner.ant.SectionElement} object.
     */
    public SectionElement createSection() {
        if (getSection() != null) {
            throw new IllegalArgumentException("Section already defined!");
        }

        section = new SectionElement();
        return section;
    }

    /**
     * <p>Getter for the field <code>systemDevelopment</code>.</p>
     *
     * @return a {@link com.greenpepper.runner.ant.SystemUnderDevelopmentElement} object.
     */
    public SystemUnderDevelopmentElement getSystemDevelopment() {
        return systemDevelopment;
    }

    /**
     * <p>createSystemUnderDevelopment.</p>
     *
     * @return a {@link com.greenpepper.runner.ant.SystemUnderDevelopmentElement} object.
     */
    public SystemUnderDevelopmentElement createSystemUnderDevelopment() {
        if (systemDevelopment != null) {
            throw new IllegalArgumentException("SystemUnderDevelopment already defined!");
        }

        systemDevelopment = new SystemUnderDevelopmentElement();
        return systemDevelopment;
    }

    /**
     * <p>Getter for the field <code>repository</code>.</p>
     *
     * @return a {@link com.greenpepper.runner.ant.RepositoryElement} object.
     */
    public RepositoryElement getRepository() {
        return repository;
    }

    /**
     * <p>createRepository.</p>
     *
     * @return a {@link com.greenpepper.runner.ant.RepositoryElement} object.
     */
    public RepositoryElement createRepository() {
        if (repository != null) {
            throw new IllegalArgumentException("Repository already defined!");
        }

        repository = new RepositoryElement();
        return repository;
    }

    /**
     * <p>isStopOnFirstFailure.</p>
     *
     * @return a boolean.
     */
    public boolean isStopOnFirstFailure() {
        return stopOnFirstFailure;
    }

    /**
     * <p>Setter for the field <code>stopOnFirstFailure</code>.</p>
     *
     * @param stopOnFirstFailure a boolean.
     */
    public void setStopOnFirstFailure(boolean stopOnFirstFailure) {
        this.stopOnFirstFailure = stopOnFirstFailure;
    }

    /**
     * <p>Getter for the field <code>locale</code>.</p>
     *
     * @return a {@link java.lang.String} object.
     */
    public String getLocale() {
        return locale;
    }

    /**
     * <p>Setter for the field <code>locale</code>.</p>
     *
     * @param locale a {@link java.lang.String} object.
     */
    public void setLocale(String locale) {
        this.locale = locale;
    }

    /**
     * <p>Getter for the field <code>selector</code>.</p>
     *
     * @return a {@link java.lang.String} object.
     */
    public String getSelector() {
        return selector;
    }

    /**
     * <p>Setter for the field <code>selector</code>.</p>
     *
     * @param selector a {@link java.lang.String} object.
     */
    public void setSelector(String selector) {
        this.selector = selector;
    }

    /**
     * <p>isDebug.</p>
     *
     * @return a boolean.
     */
    public boolean isDebug() {
        return debug;
    }

    /**
     * <p>Setter for the field <code>debug</code>.</p>
     *
     * @param debug a boolean.
     */
    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    /**
     * <p>createClasspath.</p>
     *
     * @return a {@link org.apache.tools.ant.types.Path} object.
     */
    public Path createClasspath() {
        if (classpath == null) {
            classpath = new Path(getProject());
        }
        return classpath;
    }

    /**
     * <p>execute.</p>
     *
     * @throws org.apache.tools.ant.BuildException if any.
     */
    public void execute() throws BuildException {
        try {
            verboseHeaderToLog();

            List<String> args = buildCommandLine();

            verboseCommandLineToLog(args);

            doRun(args);

        } catch (BuildException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new BuildException("AntTaskRunner", ex);
        }
    }

    private void verboseHeaderToLog() {
        log("\n-------------------------------------------------------", Project.MSG_INFO);
        log(" G R E E N  P E P P E R  S P E C I F I C A T I O N S   ", Project.MSG_INFO);
        log("-------------------------------------------------------\n", Project.MSG_INFO);
    }

    private List<String> buildCommandLine() {
        String currentDirectory = getCurrentDirectory();

        log(String.format("CurrentDir \"%s\"", currentDirectory), Project.MSG_VERBOSE);
        log(String.format("BaseDir \"%s\"", getProject().getBaseDir()), Project.MSG_VERBOSE);

        if (createRuntimeClasspath() != null && createRuntimeClasspath().size() > 0) {
            log("Classpath :", Project.MSG_VERBOSE);
            for (String path : createRuntimeClasspath().list()) {
                log(String.format("\t%s", path), Project.MSG_VERBOSE);
            }
        }

        List<String> args = new ArrayList<String>();

        if (getLocale() != null) {
            args.add("--locale");
            args.add(getLocale());
            log(String.format("Locale \"%s\"", getLocale()), Project.MSG_VERBOSE);
        }

        if (getSelector() != null) {
            args.add("--selector");
            args.add(getSelector());
            log(String.format("Selector \"%s\"", getSelector()), Project.MSG_VERBOSE);
        }

        if (getSystemDevelopment() != null) {
            args.add("-f");
            args.add(getSystemDevelopment().toArgument(this));
        }

        if (getRepository() != null) {
            args.add("-r");
            args.add(getRepository().toArgument(this));
        }

        String outputLocation = currentDirectory;

        if (getOutput() != null) {
            outputLocation = getOutput().getAbsolutePath();
        }

        log(String.format("Output \"%s\"", outputLocation), Project.MSG_VERBOSE);
        args.add("-o");
        args.add(outputLocation);

        if (isSuite()) {
            log(String.format("Suite ? \"%s\"", isSuite()), Project.MSG_VERBOSE);
            args.add("-s");
        }

        if (getSection() != null) {
            args.add("-t");
            args.add(getSection().toArgument(this));
        }

        if (getOutputType() != null) {
            args.add("--xml");
        }

        if (isStopOnFirstFailure()) {
            args.add("--stop");
        }

        if (isDebug()) {
            args.add("--debug");
        }

        log(String.format("Input \"%s\"", getInput()), Project.MSG_VERBOSE);

        args.add(getInput());
        return args;
    }

    private String getCurrentDirectory() {
        return System.getProperty("user.dir");
    }

    private void verboseCommandLineToLog(List<String> args) {
        for (String arg : args) {
            log(arg, Project.MSG_VERBOSE);
        }
    }

    private void doRun(List<String> args) throws Exception {
        AntClassLoader classLoader = new AntClassLoader(null, createRuntimeClasspath(), false);

        try {
            classLoader.setThreadContextLoader();

            log(classLoader.toString(), Project.MSG_DEBUG);

            AntTaskRunnerMonitor recorderMonitor = new AntTaskRunnerMonitor();
            Object runnerInstance = createRunner(classLoader, new AntTaskRunnerLogger(this), recorderMonitor);
            CommandLineRunnerMirror runner = DuckType.implement(CommandLineRunnerMirror.class, runnerInstance);

            String[] arguments = new String[args.size()];
            args.toArray(arguments);

            runner.run(arguments);

            log(String.format("Results: %s for %s specification(s)", recorderMonitor.getStatistics().toString(),
                    recorderMonitor.getLocationCount()), Project.MSG_INFO);

            checkResults(recorderMonitor.hasException(), "Some greenpepper tests did not run");
            checkResults(recorderMonitor.hasTestFailures(), "There were greenpepper tests failures");
        } finally {
            classLoader.resetThreadContextLoader();
        }
    }

    private Path createRuntimeClasspath() {
        if (runtimeClasspath == null) {
            runtimeClasspath = new Path(getProject());
            runtimeClasspath.append(createClasspath());

            appendGreenPepperCoreClasspath(runtimeClasspath);
        }

        return runtimeClasspath;
    }

    private void appendGreenPepperCoreClasspath(Path path) {
        appendClasspath(path, AntTaskRunner.class,
                String.format("greenpepper-extensions-java-%s.jar", GreenPepperCore.VERSION));
        appendClasspath(path, GreenPepper.class, String.format("greenpepper-core-%s.jar", GreenPepperCore.VERSION));
    }

    private void appendClasspath(Path path, Class c, String expectedJar) {

        File location = LoaderUtils.getClassSource(c);

        if (location != null) {
            path.createPath().setLocation(location);

            log(String.format("Implicitly adding '%s' to CLASSPATH", location), Project.MSG_VERBOSE);
        } else {
            log(String.format("Couldn't found classpath for '%s'", c), Project.MSG_WARN);
            log(String.format("Make sure you have '%s' in the <classpath/> of taskdef of GreenPepper",
                    expectedJar));
        }
    }

    private Object createRunner(ClassLoader classLoader, CommandLineRunnerMirror.CommandLineLogger logger,
            CommandLineRunnerMirror.CommandLineMonitor monitor) {
        try {
            Class<?> runnerClass = classLoader.loadClass("com.greenpepper.runner.ant.CommandLineRunnerMirrorImpl");

            if (runnerClass.getClassLoader() != classLoader) {
                throw new BuildException("Overdelegating loader", getLocation());
            }

            Constructor runnerCtr = runnerClass.getConstructor(Object.class, Object.class);

            return runnerCtr.newInstance(logger, monitor);
        } catch (Exception ex) {
            throw new BuildException(ex, getLocation());
        }
    }

    private void checkResults(boolean state, String message) {
        if (state) {
            if (isFailOnError()) {
                throw new BuildException(message);
            } else {
                log(String.format("\nWarning : %s", message), Project.MSG_WARN);
            }
        }
    }
}