org.testeditor.dsl.common.util.MavenExecutor.java Source code

Java tutorial

Introduction

Here is the source code for org.testeditor.dsl.common.util.MavenExecutor.java

Source

/*******************************************************************************
 * Copyright (c) 2012 - 2016 Signal Iduna Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Signal Iduna Corporation - initial API and implementation
 * akquinet AG
 * itemis AG
 *******************************************************************************/
package org.testeditor.dsl.common.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.SystemUtils;
import org.apache.maven.cli.MavenCli;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.annotations.VisibleForTesting;

/**
 * Executes a maven build in a new jvm using the embedded maven. The maven
 * embedder api allows a maven build without a m2 variable configuration.
 *
 */
public class MavenExecutor {

    private static Logger logger = LoggerFactory.getLogger(MavenExecutor.class);
    public static int MAVEN_MIMIMUM_MAJOR_VERSION = 3;
    public static int MAVEN_MIMIMUM_MINOR_VERSION = 2;
    public static String TE_MAVEN_HOME = "TE_MAVEN_HOME";

    public enum MavenVersionValidity {
        wrong_version, unknown_version, ok, no_maven
    }

    /**
     * Executes the maven build using maven embedder. It allways starts with a
     * clean operation to delete old test results.
     * 
     * @param parameters
     *            for maven (separated by spaces, e.g. "clean integration-test"
     *            to execute the given goals)
     * @param pathToPom
     *            path to the folder where the pom.xml is located.
     * @return int with exit code
     * 
     */
    public int execute(String parameters, String pathToPom) {
        System.setProperty("maven.multiModuleProjectDirectory", pathToPom);
        MavenCli cli = new MavenCli();
        List<String> params = new ArrayList<String>();
        params.addAll(Arrays.asList(parameters.split(" ")));
        String mavenSettings = System.getProperty("TE.MAVENSETTINGSPATH");
        if (mavenSettings != null && mavenSettings.length() > 0) {
            params.add("-s");
            params.add(mavenSettings);
        }
        int result = cli.doMain(params.toArray(new String[] {}), pathToPom, System.out, System.err);
        return result;
    }

    /**
     * Executes a maven build in a new jvm. The executable of the current jvm is
     * used to create a new jvm.
     * 
     * @param parameters
     *            for maven (separated by spaces, e.g. "clean integration-test"
     *            to execute the given goals)
     * @param pathtoPom
     *            path to the folder where the pom.xml is located.
     * @param testParam
     *            pvm parameter to identify the test case to be executed.
     * @param monitor
     *            Progress monitor to handle cancel events.
     * @return the result interpreted as {@link IStatus}.
     * @throws IOException
     *             on failure
     */
    public int executeInNewJvm(String parameters, String pathToPom, String testParam, IProgressMonitor monitor,
            OutputStream outputStream) throws IOException {
        List<String> command = createMavenExecCommand(parameters, testParam);
        ProcessBuilder processBuilder = new ProcessBuilder();
        processBuilder.directory(new File(pathToPom));
        logger.info("Executing maven in folder='{}'.", pathToPom);
        logger.info("Executing maven in new jvm with command='{}'.", command);
        processBuilder.command(command);
        Process process = processBuilder.start();
        PrintStream out = new PrintStream(outputStream);
        OutputStreamCopyUtil outputCopyThread = new OutputStreamCopyUtil(process.getInputStream(), out);
        OutputStreamCopyUtil errorCopyThread = new OutputStreamCopyUtil(process.getErrorStream(), out);
        outputCopyThread.start();
        errorCopyThread.start();
        try {
            while (!process.waitFor(100, TimeUnit.MILLISECONDS)) {
                if (monitor.isCanceled()) {
                    process.destroy();
                    out.println("Operation cancelled.");
                    return IStatus.CANCEL;
                }
            }
            return process.exitValue() == 0 ? IStatus.OK : IStatus.CANCEL;
        } catch (InterruptedException e) {
            logger.error("Caught exception.", e);
            return IStatus.ERROR;
        }
    }

    protected String getPathToMavenHome() {
        return System.getenv(TE_MAVEN_HOME);
    }

    private List<String> createMavenExecCommand(String parameters, String testParam) {
        List<String> command = new ArrayList<String>();
        command.addAll(getExecuteMavenScriptCommand(getPathToMavenHome(), parameters, testParam,
                SystemUtils.IS_OS_WINDOWS));
        if (Boolean.getBoolean("te.workOffline")) {
            command.add("-o");
        }
        return command;
    }

    @VisibleForTesting
    protected List<String> getExecuteMavenScriptCommand(String mavenHome, String parameters, String testParam,
            boolean isOsWindows) {
        List<String> command = new ArrayList<String>();
        command.add(getPathToMavenExecutable(mavenHome, isOsWindows));
        command.addAll(Arrays.asList(parameters.split(" ")));
        if (testParam != null && testParam.length() > 0) {
            command.add("-D" + testParam);
        }
        command.add("-V");
        return command;
    }

    private String getPathToMavenExecutable(String mavenHome, boolean isOsWindows) {
        if (mavenHome == null) {
            return "";
        }
        if (isOsWindows) {
            return mavenHome + "\\bin\\mvn.bat";
        } else {
            return mavenHome + "/bin/mvn";
        }
    }

    /**
     * Entry point of the new jvm used for the maven build.
     * 
     * @param args
     *            the maven parameter.
     */
    public static void main(String[] args) {
        logger.info("Proxy host: {}", System.getProperty("http.proxyHost"));
        if (args.length > 2) {
            if (args[2].contains("=")) {
                logger.info("Running maven build with settings='{}'", args[2]);
                String[] split = args[2].split("=");
                System.setProperty(split[0], split[1]);
            } else {
                logger.warn("Running maven build IGNORING MISSPELLED settings='{}' (missing infix '=')", args[2]);
            }
        } else {
            logger.info("Running maven build without settings");
        }
        int result = new MavenExecutor().execute(args[0], args[1]);
        if (result != 0) {
            System.exit(result);
        }
    }

    public MavenVersionValidity getMavenVersionValidity() throws IOException {
        if (getPathToMavenHome() == null) {
            logger.info("No maven found. Environment variable {}='{}' not set correctly!", TE_MAVEN_HOME,
                    getPathToMavenHome());
            return MavenVersionValidity.no_maven;
        }
        String[] lines = linesFromMavenVersionCall();
        if (lines == null) {
            logger.info("Maven execution to get the version produced no output!");
            return MavenVersionValidity.no_maven;
        }

        String versionLine = findVersionLine(lines);
        if (versionLine == null) {
            return MavenVersionValidity.unknown_version;
        }
        logger.info("Maven Version: '{}'", versionLine);
        logMavenPropertiesIn(lines);

        int[] version = parseVersionInformation(versionLine);
        return validateVersionInformation(version);
    }

    private void logMavenPropertiesIn(String[] lines) {
        for (String line : lines) {
            if (line.indexOf(": ") >= 0) {
                String[] keyPropPair = line.split(": ", 2);
                logger.info("Maven Property '{}' : '{}'", keyPropPair[0].trim(), keyPropPair[1].trim());
            }
        }
    }

    private String findVersionLine(String[] lines) {
        for (String line : lines) {
            if (line.startsWith("Apache Maven ")) {
                return line;
            }
        }
        return null;
    }

    private String[] linesFromMavenVersionCall() throws IOException {
        OutputStream versionOut = new ByteArrayOutputStream();
        int infoResult = executeInNewJvm("-version", ".", "", new NullProgressMonitor(), versionOut);
        if (infoResult != IStatus.OK) {
            logger.error("Error during determine of maven version");
            return null;
        }
        return versionOut.toString().split("(\r)?\n");
    }

    @VisibleForTesting
    protected int[] parseVersionInformation(String mavenVersionLine) {
        Pattern versionNumber = Pattern.compile("^([A-Za-z ]+)([0-9]+)\\.([0-9]+)(\\.([0-9]+))?.*");
        Matcher matcher = versionNumber.matcher(mavenVersionLine);
        if (!matcher.matches()) {
            return null;
        }
        int[] result = new int[2];
        result[0] = Integer.parseInt(matcher.group(2));
        result[1] = Integer.parseInt(matcher.group(3));
        return result;
    }

    @VisibleForTesting
    protected MavenVersionValidity validateVersionInformation(int[] versionNumbers) {
        if (versionNumbers == null || versionNumbers.length < 2) {
            return MavenVersionValidity.unknown_version;
        }
        int major = versionNumbers[0];
        int minor = versionNumbers[1];
        if ((major > MAVEN_MIMIMUM_MAJOR_VERSION)
                || (major == MAVEN_MIMIMUM_MAJOR_VERSION && minor >= MAVEN_MIMIMUM_MINOR_VERSION)) {
            return MavenVersionValidity.ok;
        }
        return MavenVersionValidity.wrong_version;
    }

}