com.hp.mqm.clt.CliParser.java Source code

Java tutorial

Introduction

Here is the source code for com.hp.mqm.clt.CliParser.java

Source

/*
 *     Copyright 2017 Hewlett-Packard Development Company, L.P.
 *     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 com.hp.mqm.clt;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

public class CliParser {

    private static final String CMD_LINE_SYNTAX = "java -jar test-result-collection-tool.jar [OPTIONS]... FILE [FILE]...\n";
    private static final String HEADER = "HP Lifecycle Management Test Result Collection Tool";
    private static final String FOOTER = "";
    private static final String VERSION = "1.0";

    private Options options = new Options();
    private LinkedList<String> argsWithSingleOccurrence = new LinkedList<String>();
    private LinkedList<String> argsRestrictedForInternal = new LinkedList<String>();

    public CliParser() {
        options.addOption("h", "help", false, "show this help");
        options.addOption("v", "version", false, "show version of this tool");

        options.addOption("i", "internal", false, "supplied XML files are in the API internal XML format");
        options.addOption("e", "skip-errors", false, "skip errors on the server side");
        options.addOption(Option.builder("o").longOpt("output-file")
                .desc("write output to file instead of pushing it to the server").hasArg().argName("FILE").build());
        options.addOption(Option.builder("c").longOpt("config-file").desc("configuration file location").hasArg()
                .argName("FILE").build());

        options.addOption(Option.builder("s").longOpt("server").desc("server URL with protocol and port").hasArg()
                .argName("URL:PORT").build());
        options.addOption(Option.builder("d").longOpt("shared-space").desc("server shared space to push to")
                .hasArg().argName("ID").type(Number.class).build());
        options.addOption(Option.builder("w").longOpt("workspace").desc("server workspace to push to").hasArg()
                .argName("ID").type(Number.class).build());

        options.addOption(
                Option.builder("u").longOpt("user").desc("server username").hasArg().argName("USERNAME").build());
        OptionGroup passGroup = new OptionGroup();
        passGroup.addOption(Option.builder("p").longOpt("password").desc("server password").hasArg()
                .argName("PASSWORD").optionalArg(true).build());
        passGroup.addOption(Option.builder().longOpt("password-file").desc("location of file with server password")
                .hasArg().argName("FILE").build());
        options.addOptionGroup(passGroup);

        options.addOption(
                Option.builder().longOpt("proxy-host").desc("proxy host").hasArg().argName("HOSTNAME").build());
        options.addOption(Option.builder().longOpt("proxy-port").desc("proxy port").hasArg().argName("PORT")
                .type(Number.class).build());
        options.addOption(
                Option.builder().longOpt("proxy-user").desc("proxy username").hasArg().argName("USERNAME").build());

        OptionGroup proxyPassGroup = new OptionGroup();
        proxyPassGroup.addOption(Option.builder().longOpt("proxy-password").desc("proxy password").hasArg()
                .argName("PASSWORD").optionalArg(true).build());
        proxyPassGroup.addOption(Option.builder().longOpt("proxy-password-file")
                .desc("location of file with proxy password").hasArg().argName("FILE").build());
        options.addOptionGroup(proxyPassGroup);

        options.addOption(
                Option.builder().longOpt("check-result").desc("check test result status after push").build());
        options.addOption(Option.builder().longOpt("check-result-timeout")
                .desc("timeout for test result push status retrieval").hasArg().argName("SEC").type(Number.class)
                .build());

        options.addOption(Option.builder("t").longOpt("tag").desc("assign tag to test result").hasArg()
                .argName("TYPE:VALUE").build());
        options.addOption(Option.builder("f").longOpt("field").desc("assign field tag to test result").hasArg()
                .argName("TYPE:VALUE").build());

        options.addOption(Option.builder("r").longOpt("release").desc("assign release to test result").hasArg()
                .argName("ID").type(Number.class).build());
        options.addOption(Option.builder("a").longOpt("product-area").desc("assign the test result to product area")
                .hasArg().argName("ID").type(Number.class).build());
        options.addOption(Option.builder("b").longOpt("backlog-item").desc("assign the test result to backlog item")
                .hasArg().argName("ID").type(Number.class).build());
        options.addOption(Option.builder().longOpt("started").desc("start time in milliseconds").hasArg()
                .argName("TIMESTAMP").type(Number.class).build());

        argsWithSingleOccurrence.addAll(Arrays.asList("o", "c", "s", "d", "w", "u", "p", "password-file", "r",
                "started", "check-status", "check-status-timeout", "proxy-host", "proxy-port", "proxy-user",
                "proxy-password", "proxy-password-file"));
        argsRestrictedForInternal.addAll(Arrays.asList("o", "t", "f", "r", "a", "b", "started"));
    }

    public Settings parse(String[] args) {
        Settings settings = new Settings();
        CommandLineParser parser = new DefaultParser();
        try {
            CommandLine cmd = parser.parse(options, args);

            if (cmd.hasOption("h")) {
                printHelp();
                System.exit(ReturnCode.SUCCESS.getReturnCode());
            }

            if (cmd.hasOption("v")) {
                printVersion();
                System.exit(ReturnCode.SUCCESS.getReturnCode());
            }

            if (!areCmdArgsValid(cmd)) {
                printHelp();
                System.exit(ReturnCode.FAILURE.getReturnCode());
            }

            if (!addInputFilesToSettings(cmd, settings)) {
                printHelp();
                System.exit(ReturnCode.FAILURE.getReturnCode());
            }

            // load config
            String filename = null;
            if (cmd.hasOption("c")) {
                filename = cmd.getOptionValue("c");
            }
            try {
                settings.load(filename);
            } catch (NumberFormatException e) {
                System.out.println("Can not convert string from properties file to integer: " + e.getMessage());
                System.exit(ReturnCode.FAILURE.getReturnCode());
            } catch (IllegalArgumentException e) {
                // Inform user that loading was not successful
                // Configuration must be specified in arguments in this case
                System.out.println(e.getMessage());
            } catch (IOException e) {
                System.out.println("Can not read from properties file: " + filename);
                System.exit(ReturnCode.FAILURE.getReturnCode());
            }

            if (cmd.hasOption("i")) {
                settings.setInternal(true);
            }

            if (cmd.hasOption("e")) {
                settings.setSkipErrors(true);
            }

            if (cmd.hasOption("o")) {
                settings.setOutputFile(cmd.getOptionValue("o"));
            }

            if (cmd.hasOption("s")) {
                settings.setServer(cmd.getOptionValue("s"));
            }

            if (cmd.hasOption("d")) {
                settings.setSharedspace(((Long) cmd.getParsedOptionValue("d")).intValue());
            }

            if (cmd.hasOption("w")) {
                settings.setWorkspace(((Long) cmd.getParsedOptionValue("w")).intValue());
            }

            if (cmd.hasOption("u")) {
                settings.setUser(cmd.getOptionValue("u"));
            }

            if (settings.getOutputFile() == null) {
                if (cmd.hasOption("p")) {
                    settings.setPassword(cmd.getOptionValue("p"));
                } else if (cmd.hasOption("password-file")) {
                    try {
                        settings.setPassword(
                                FileUtils.readFileToString(new File(cmd.getOptionValue("password-file"))));
                    } catch (IOException e) {
                        System.out
                                .println("Can not read the password file: " + cmd.getOptionValue("password-file"));
                        System.exit(ReturnCode.FAILURE.getReturnCode());
                    }
                } else {
                    System.out.println("Please enter your password if it's required and hit enter: ");
                    settings.setPassword(new String(System.console().readPassword()));
                }
            }

            if (cmd.hasOption("proxy-host")) {
                settings.setProxyHost(cmd.getOptionValue("proxy-host"));
            }

            if (cmd.hasOption("proxy-port")) {
                settings.setProxyPort(((Long) cmd.getParsedOptionValue("proxy-port")).intValue());
            }

            if (cmd.hasOption("proxy-user")) {
                settings.setProxyUser(cmd.getOptionValue("proxy-user"));
            }

            if (settings.getOutputFile() == null && StringUtils.isNotEmpty(settings.getProxyUser())) {
                if (cmd.hasOption("proxy-password")) {
                    settings.setProxyPassword(cmd.getOptionValue("proxy-password"));
                } else if (cmd.hasOption("proxy-password-file")) {
                    try {
                        settings.setProxyPassword(
                                FileUtils.readFileToString(new File(cmd.getOptionValue("proxy-password-file"))));
                    } catch (IOException e) {
                        System.out.println(
                                "Can not read the password file: " + cmd.getOptionValue("proxy-password-file"));
                        System.exit(ReturnCode.FAILURE.getReturnCode());
                    }
                } else {
                    System.out.println("Please enter your proxy password if it's required and hit enter: ");
                    settings.setProxyPassword(new String(System.console().readPassword()));
                }
            }

            if (cmd.hasOption("check-result")) {
                settings.setCheckResult(true);
            }

            if (cmd.hasOption("check-result-timeout")) {
                settings.setCheckResultTimeout(
                        ((Long) cmd.getParsedOptionValue("check-status-timeout")).intValue());
            }

            if (cmd.hasOption("t")) {
                settings.setTags(Arrays.asList(cmd.getOptionValues("t")));
            }

            if (cmd.hasOption("f")) {
                settings.setFields(Arrays.asList(cmd.getOptionValues("f")));
            }

            if (cmd.hasOption("r")) {
                settings.setRelease(((Long) cmd.getParsedOptionValue("r")).intValue());
            }

            if (cmd.hasOption("started")) {
                settings.setStarted((Long) cmd.getParsedOptionValue("started"));
            }

            if (cmd.hasOption("a")) {
                settings.setProductAreas(cmd.getOptionValues("a"));
            }

            if (cmd.hasOption("b")) {
                settings.setBacklogItems(cmd.getOptionValues("b"));
            }

            if (!areSettingsValid(settings)) {
                System.exit(ReturnCode.FAILURE.getReturnCode());
            }

        } catch (ParseException e) {
            printHelp();
            System.exit(ReturnCode.FAILURE.getReturnCode());
        }
        return settings;
    }

    private boolean addInputFilesToSettings(CommandLine cmd, Settings settings) {
        List<String> argList = cmd.getArgList();
        List<String> inputFiles = new LinkedList<String>();
        for (String inputFile : argList) {
            if (!new File(inputFile).isFile()) {
                System.out.println("Path '" + inputFile + "' does not lead to a file");
                continue;
            }
            if (!new File(inputFile).canRead()) {
                System.out.println("File '" + inputFile + "' is not readable");
                continue;
            }
            inputFiles.add(inputFile);
        }

        if (inputFiles.isEmpty()) {
            System.out.println("No readable files with tests to push");
            return false;
        }

        settings.setInputXmlFileNames(inputFiles);
        return true;
    }

    private boolean areCmdArgsValid(CommandLine cmd) {
        List<String> argList = cmd.getArgList();
        if (argList.isEmpty()) {
            System.out.println("At least one XML file must be specified as input for push");
            return false;
        }

        for (String arg : argsWithSingleOccurrence) {
            if (cmd.getOptionProperties(arg).size() > 1) {
                System.out.println("Only single occurrence is allowed for argument: '" + arg + "'");
                return false;
            }
        }

        if (cmd.hasOption("i")) {
            for (String arg : argsRestrictedForInternal) {
                if (cmd.hasOption(arg)) {
                    System.out.println("Invalid argument for internal mode: '" + arg + "'");
                    return false;
                }
            }
        }

        if (!isTagFormatValid(cmd, "t") || !isTagFormatValid(cmd, "f")) {
            return false;
        }

        String configurationFile = cmd.getOptionValue("c");
        if (configurationFile != null && !(new File(configurationFile).canRead())) {
            System.out.println("Can not read the configuration file: " + configurationFile);
            return false;
        }

        String passwordFile = cmd.getOptionValue("password-file");
        if (passwordFile != null && !(new File(passwordFile).canRead())) {
            System.out.println("Can not read the password file: " + passwordFile);
            return false;
        }

        String proxyPasswordFile = cmd.getOptionValue("proxy-password-file");
        if (proxyPasswordFile != null && !new File(proxyPasswordFile).canRead()) {
            System.out.println("Can not read the proxy password file: " + passwordFile);
            return false;
        }

        String outputFilePath = cmd.getOptionValue("o");
        if (outputFilePath != null) {
            if (argList.size() != 1) {
                System.out.println("Only single JUnit input file is allowed for output mode");
                return false;
            }
            File outputFile = new File(outputFilePath);
            if (!outputFile.exists()) {
                try {
                    if (!outputFile.createNewFile()) {
                        System.out.println("Can not create the output file: " + outputFile.getAbsolutePath());
                        return false;
                    }
                } catch (IOException e) {
                    System.out.println("Can not create the output file: " + outputFile.getAbsolutePath());
                    return false;
                }
            }
            if (!outputFile.canWrite()) {
                System.out.println("Can not write to the output file: " + outputFile.getAbsolutePath());
                return false;
            }
        }
        return true;
    }

    private boolean isTagFormatValid(CommandLine cmd, String option) {
        String[] tags = cmd.getOptionValues(option);
        if (tags == null) {
            return true;
        }
        // CODE REVIEW, Johnny, 19Oct2015 - consult with Mirek with regards to localization, this is very probably
        // good for this release, but I can imagine it will have to be relaxed once we for example start to support
        // languages like French (and all their funny characters)
        Pattern pattern = Pattern.compile("^\\w+:\\w+$");
        for (String tag : tags) {
            if (!pattern.matcher(tag).matches()) {
                System.out.println("Tag and field tag arguments must be in TYPE:VALUE format: " + tag);
                return false;
            }
        }
        return true;
    }

    private boolean areSettingsValid(Settings settings) {
        if (settings.getOutputFile() == null) {
            // Server access is required
            if (!isSettingPresent(settings.getServer(), "server")) {
                return false;
            }

            if (!isSettingPresent(settings.getSharedspace(), "sharedspace")) {
                return false;
            }

            if (!isSettingPresent(settings.getWorkspace(), "workspace")) {
                return false;
            }

            if (settings.getProxyHost() != null && settings.getProxyPort() == null) {
                System.out.println("Proxy port was not specified for proxy host: " + settings.getProxyHost());
                return false;
            }

            if (settings.getProxyPassword() != null && settings.getProxyUser() == null) {
                System.out.println("Proxy user name was not specified for proxy password");
                return false;
            }

            if (settings.getCheckResultTimeout() != null && settings.getCheckResultTimeout() < 1) {
                System.out.println("Timeout has to be positive integer");
                return false;
            }
        }
        return true;
    }

    boolean isSettingPresent(Object setting, String settingName) {
        if (setting == null) {
            System.out.println("Mandatory setting '" + settingName
                    + "' was not specified in the CLI arguments or configuration file");
            return false;
        }
        return true;
    }

    private void printVersion() {
        System.out.println(HEADER);
        System.out.println("Version: " + VERSION);
        System.out.println(FOOTER);
    }

    private void printHelp() {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp(CMD_LINE_SYNTAX, HEADER, options, FOOTER);
    }
}