From 1cb818e3cbd6154762f908be8698317fa10fbc49 Mon Sep 17 00:00:00 2001 From: "adheli.tavares" Date: Fri, 9 Apr 2021 11:51:05 +0100 Subject: Add command line handler Added a Handler for command line classes to share common strucutures. Issue-ID: POLICY-3128 Change-Id: I662911c467faf5c39b8db018bb1a564fba7587a6 Signed-off-by: adheli.tavares --- .../utils/cmd/CommandLineArgumentsHandler.java | 273 +++++++++++++++++++++ .../common/utils/cmd/CommandLineException.java | 54 ++++ 2 files changed, 327 insertions(+) create mode 100644 utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineArgumentsHandler.java create mode 100644 utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineException.java (limited to 'utils/src/main/java/org/onap') diff --git a/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineArgumentsHandler.java b/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineArgumentsHandler.java new file mode 100644 index 00000000..37a9047b --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineArgumentsHandler.java @@ -0,0 +1,273 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.cmd; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.lang3.StringUtils; +import org.onap.policy.common.utils.resources.ResourceUtils; + +/** + * Class for command line common processing. + * + * @author Adheli Tavares (adheli.tavares@est.tech) + * + */ +public class CommandLineArgumentsHandler { + private static final String FILE_MESSAGE_PREAMBLE = " file \""; + private static final int HELP_LINE_LENGTH = 120; + + private final Options options; + + private final String helpClassName; + private final String component; + + @Getter + @Setter + private String configurationFilePath = null; + + @Getter + @Setter + private String propertyFilePath = null; + + @Getter + private CommandLine commandLine = null; + + /** + * Construct the options with default values for the CLI editor. + */ + protected CommandLineArgumentsHandler(String helpClassName, String component) { + this.helpClassName = helpClassName; + this.component = component; + //@formatter:off + options = new Options(); + options.addOption(Option.builder("h") + .longOpt("help") + .desc("outputs the usage of this command") + .required(false) + .type(Boolean.class) + .build()); + options.addOption(Option.builder("v") + .longOpt("version") + .desc("outputs the version of " + this.component) + .required(false) + .type(Boolean.class) + .build()); + options.addOption(Option.builder("c") + .longOpt("config-file") + .desc(String.format("the full path to the configuration file to use, " + + "the configuration file must be a Json file containing the %s parameters", this.component)) + .hasArg().argName("CONFIG_FILE") + .required(false) + .type(String.class) + .build()); + //@formatter:on + } + + /** + * Construct the options for the CLI editor with extra options. + */ + public CommandLineArgumentsHandler(String helpClassName, String component, Option... customOptions) { + this(helpClassName, component); + if (customOptions != null && customOptions.length > 0) { + for (Option option : customOptions) { + options.addOption(option); + } + } + } + + /** + * Construct the options with brand new options for the CLI editor. + */ + public CommandLineArgumentsHandler(String helpClassName, String component, Options options) { + this.options = options; + this.helpClassName = helpClassName; + this.component = component; + } + + /** + * Parse the command line options. + * + * @param args The command line arguments + * @return a string with a message for help and version, or null if there is no message + * @throws CommandLineException on command argument errors + */ + public String parse(final String[] args) throws CommandLineException { + // Clear all our arguments + setConfigurationFilePath(null); + setPropertyFilePath(null); + + try { + commandLine = new DefaultParser().parse(options, args); + } catch (final ParseException | NullPointerException e) { + throw new CommandLineException("invalid command line arguments specified", e); + } + + // Arguments left over after Commons CLI does its stuff + final String[] remainingArgs = removeEmptyValues(commandLine.getArgs()); + + if (remainingArgs.length > 0) { + throw new CommandLineException("too many command line arguments specified: " + Arrays.toString(args)); + } + + if (commandLine.hasOption('h')) { + return help(); + } + + if (commandLine.hasOption('v')) { + return version(); + } + + if (commandLine.hasOption('c')) { + setConfigurationFilePath(commandLine.getOptionValue('c')); + } + + if (commandLine.hasOption('p')) { + setPropertyFilePath(commandLine.getOptionValue('p')); + } + + return null; + } + + /** + * Validate the command line options. + * + * @throws CommandLineException on command argument validation errors + */ + public void validate() throws CommandLineException { + validateReadableFile(this.component + " configuration", configurationFilePath); + } + + /** + * Print version information for policy distribution. + * + * @return the version string + */ + public String version() { + return ResourceUtils.getResourceAsString("version.txt"); + } + + /** + * Print help information for policy distribution. + * + * @return the help string + */ + public String help() { + final HelpFormatter helpFormatter = new HelpFormatter(); + final StringWriter stringWriter = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(stringWriter); + final String cmdLineSyntax = this.helpClassName + " [options...]"; + + helpFormatter.printHelp(printWriter, HELP_LINE_LENGTH, cmdLineSyntax, "options", options, 0, 0, ""); + + return stringWriter.toString(); + } + + /** + * Gets the full expanded configuration file path. + * + * @return the configuration file path + */ + public String getFullConfigurationFilePath() { + return ResourceUtils.getFilePath4Resource(getConfigurationFilePath()); + } + + /** + * Check set configuration file path. + * + * @return true, if check set configuration file path + */ + public boolean checkSetConfigurationFilePath() { + return StringUtils.isNotBlank(getConfigurationFilePath()); + } + + /** + * Gets the full expanded property file path. + * + * @return the property file path + */ + public String getFullPropertyFilePath() { + return ResourceUtils.getFilePath4Resource(getPropertyFilePath()); + } + + /** + * Check set property file path. + * + * @return true, if check set property file path + */ + public boolean checkSetPropertyFilePath() { + return StringUtils.isNotBlank(getPropertyFilePath()); + } + + /** + * Validate readable file. + * + * @param fileTag the file tag + * @param fileName the file name + * @throws CommandLineException on the file name passed as a parameter + */ + protected void validateReadableFile(final String fileTag, final String fileName) throws CommandLineException { + if (StringUtils.isBlank(fileName)) { + throw new CommandLineException(fileTag + " file was not specified as an argument"); + } + + // The file name refers to a resource on the local file system + final URL fileUrl = ResourceUtils.getUrl4Resource(fileName); + if (fileUrl == null) { + throw new CommandLineException(fileTag + FILE_MESSAGE_PREAMBLE + fileName + "\" does not exist"); + } + + try { + Path path = Path.of(fileUrl.toURI()); + if (!Files.isRegularFile(path)) { + throw new CommandLineException(fileTag + FILE_MESSAGE_PREAMBLE + fileName + "\" is not a normal file"); + } + if (!Files.isReadable(path)) { + throw new CommandLineException(fileTag + FILE_MESSAGE_PREAMBLE + fileName + "\" is unreadable"); + } + } catch (URISyntaxException e) { + throw new CommandLineException("Error parsing " + fileUrl.toString(), e); + } + + } + + /** + * Checks if args has any null or empty value after parsing. + * + * @param args remaining args from CLI parse. + */ + private String[] removeEmptyValues(String[] args) { + return Arrays.stream(args).filter(StringUtils::isNotBlank).toArray(String[]::new); + } +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineException.java b/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineException.java new file mode 100644 index 00000000..95870f75 --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.cmd; + +/** + * Exception used for CommandLineArguments class. + * + * @author Adheli Tavares (adheli.tavares@est.tech) + * + */ +public class CommandLineException extends Exception { + + /** + * Generated serialVersionUID. + */ + private static final long serialVersionUID = -1200607308084606425L; + + /** + * Instantiates a new exception with a message. + * + * @param message the message + */ + public CommandLineException(final String message) { + super(message); + } + + /** + * Instantiates a new exception with a message and a caused by exception. + * + * @param message the message + * @param exp the exception that caused this exception to be thrown + */ + public CommandLineException(final String message, final Exception exp) { + super(message, exp); + } +} -- cgit 1.2.3-korg