From bc6f13289b019ee8caee20d70d19e6f538230338 Mon Sep 17 00:00:00 2001 From: parthiv39731 <70740707+parthiv39731@users.noreply.github.com> Date: Mon, 4 Mar 2024 21:18:10 +0530 Subject: [PATCH 1/3] BAEL-7618, Intro to the Apache Commons CLI --- libraries-cli/pom.xml | 6 + .../commonscli/CommonsCliUnitTest.java | 176 ++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 libraries-cli/src/test/java/com/baeldung/commonscli/CommonsCliUnitTest.java diff --git a/libraries-cli/pom.xml b/libraries-cli/pom.xml index d204f3c735..31940c0c92 100644 --- a/libraries-cli/pom.xml +++ b/libraries-cli/pom.xml @@ -50,6 +50,11 @@ lombok ${lombok.version} + + commons-cli + commons-cli + ${commons-cli.version} + @@ -62,6 +67,7 @@ 4.7.0 1.78 2.7.2 + 1.6.0 2.7.8 5.3.25 diff --git a/libraries-cli/src/test/java/com/baeldung/commonscli/CommonsCliUnitTest.java b/libraries-cli/src/test/java/com/baeldung/commonscli/CommonsCliUnitTest.java new file mode 100644 index 0000000000..6d99e4a440 --- /dev/null +++ b/libraries-cli/src/test/java/com/baeldung/commonscli/CommonsCliUnitTest.java @@ -0,0 +1,176 @@ +package com.baeldung.commonscli; + +import org.apache.commons.cli.AlreadySelectedException; +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.MissingArgumentException; +import org.apache.commons.cli.MissingOptionException; +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 static org.junit.jupiter.api.Assertions.*; + +import org.apache.commons.cli.UnrecognizedOptionException; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CommonsCliUnitTest { + Logger logger = LoggerFactory.getLogger(CommonsCliUnitTest.class); + + @Test + void whenMutuallyExclusiveOptionsProvidedTogether_thenThrowAlreadySelectedException() { + Option interactiveOption = new Option("i", false, "Prompts the user before overwriting the existing files"); + Option forceOption = new Option("f", false, "Overwrites the existing files without prompting"); + + OptionGroup optionGroup = new OptionGroup(); + optionGroup.addOption(interactiveOption) + .addOption(forceOption); + + Options options = new Options(); + options.addOptionGroup(optionGroup); + + String[] commandWithConflictingOptions = new String[]{"cp", "-i", "-f", "file1", "file2"}; + CommandLineParser commandLineParser = new DefaultParser(); + assertThrows(AlreadySelectedException.class, () -> { + try { + CommandLine commandLine = commandLineParser.parse(options, commandWithConflictingOptions); + } catch (ParseException e) { + assertTrue(e instanceof AlreadySelectedException); + handleException(new RuntimeException(e)); + throw e; + } + }); + } + + @Test + void whenMandatoryOptionMissing_thenThrowMissingOptionException() { + Options options = createOptions(); + String[] commandWithMissingMandatoryOption = new String[]{"-h", "PGSERVER", "-U", "postgres"}; + CommandLineParser commandLineParser = new DefaultParser(); + assertThrows(MissingOptionException.class, () -> { + try { + CommandLine commandLine = commandLineParser.parse(options, commandWithMissingMandatoryOption); + } catch (ParseException e) { + assertTrue(e instanceof MissingOptionException); + handleException(new RuntimeException(e)); + throw e; + } + }); + } + + @Test + void whenOptionArgumentIsMissing_thenThrowMissingArgumentException() { + Options options = createOptions(); + String[] commandWithOptionArgumentOption = new String[]{"-h", "PGSERVER", "-U", "postgres", "-d"}; + CommandLineParser commandLineParser = new DefaultParser(); + assertThrowsExactly(MissingArgumentException.class, () -> { + try { + CommandLine commandLine = commandLineParser.parse(options, commandWithOptionArgumentOption); + } catch (ParseException e) { + assertTrue(e instanceof MissingArgumentException); + handleException(new RuntimeException(e)); + throw e; + } + }); + } + + @Test + void whenUnrecognizedOptionProvided_thenThrowUnrecognizedOptionException() { + Options options = createOptions(); + String[] commandWithIncorrectOption = new String[]{"-h", "PGSERVER", "-U", "postgres", "-d", "empDB", "-y"}; + CommandLineParser commandLineParser = new DefaultParser(); + assertThrows(UnrecognizedOptionException.class, () -> { + try { + CommandLine commandLine = commandLineParser.parse(options, commandWithIncorrectOption); + } catch (ParseException e) { + assertTrue(e instanceof UnrecognizedOptionException); + handleException(new RuntimeException(e)); + throw e; + } + }); + } + + private void handleException(RuntimeException e) { + logger.error("handle exception:" + e.getMessage()); + } + + @Test + void whenNeedHelp_thenPrintHelp() { + HelpFormatter helpFormatter = new HelpFormatter(); + Options options = createOptions(); + options.addOption("?", "help", false, "Display help information"); + helpFormatter.printHelp("psql -U username -h host -d empDB", options); + } + + @Test + void whenCliOptionProvided_thenParseAndExtractOptionAndArgumentValues() throws ParseException { + + Options options = new Options(); + + Option hostOption = createOption("h", "host", "HOST","Database server host", false); + Option userNameOption = createOption("U", "username", "USERNAME", "Database user name", true); + Option dbNameOption = createOption("d", "dbName", "DBNAME", "Database name to connect to", true); + + options.addOption(hostOption) + .addOption(dbNameOption) + .addOption(userNameOption); + + String[] commandWithShortNameOptions = new String[] { "-h", "PGSERVER", "-U", "postgres", "-d", "empDB" }; + parseThenProcessCommand(options, commandWithShortNameOptions, "h", "U", "d" ); + + String[] commandWithLongNameOptions = new String[] { "--username", "postgres", "--dbName", "empDB" }; + parseThenProcessCommand(options, commandWithLongNameOptions, "host", "username", "dbName" ); + } + + private Options createOptions() { + Options options = new Options(); + + Option hostOption = createOption("h", "host", "HOST", "Database server host", true); + Option userNameOption = createOption("U", "username", "USERNAME", "Database user name", true); + Option dbNameOption = createOption("d", "dbName", "DBNAME", "Database name to connect to", true); + + return options.addOption(hostOption) + .addOption(dbNameOption) + .addOption(userNameOption); + } + + private void parseThenProcessCommand(Options options, String[] commandArgs, String hostOption, + String usernameOption, String dbNameOption) throws ParseException { + CommandLineParser commandLineParser = new DefaultParser(); + + CommandLine commandLine = commandLineParser.parse(options, commandArgs); + String hostname = commandLine.hasOption("h") ? commandLine.getOptionValue(hostOption) : "localhost"; + String userName = commandLine.getOptionValue(usernameOption); + String dbName = commandLine.getOptionValue(dbNameOption); + + if (commandLine.hasOption("h")) { + assertEquals("PGSERVER", hostname); + } else { + assertEquals("localhost", hostname); + } + + assertEquals("postgres", userName); + assertEquals("empDB", dbName); + createConnection(hostname, userName, dbName); + } + + private void createConnection(String host, String userName, String dbName) { + //call underlying service + } + + private Option createOption(String shortName, String longName, String argName, String description, boolean required) { + return Option.builder(shortName) + .longOpt(longName) + .argName(argName) + .desc(description) + .hasArg() + .required(required) + .build(); + } + +} From af09ea71c8a0204bf97259d16d3df4e9b562d82d Mon Sep 17 00:00:00 2001 From: parthiv39731 <70740707+parthiv39731@users.noreply.github.com> Date: Tue, 5 Mar 2024 00:27:45 +0530 Subject: [PATCH 2/3] BAEL-7618, Intro to the Apache Commons CLI --- .../main/resources/common-cli-classdg.puml | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 libraries-cli/src/main/resources/common-cli-classdg.puml diff --git a/libraries-cli/src/main/resources/common-cli-classdg.puml b/libraries-cli/src/main/resources/common-cli-classdg.puml new file mode 100644 index 0000000000..1212b7d563 --- /dev/null +++ b/libraries-cli/src/main/resources/common-cli-classdg.puml @@ -0,0 +1,62 @@ +@startuml +hide empty attributes +skinparam Handwritten false +skinparam ClassBorderColor black +skinparam BackgroundColor #fffce8/#f8f9fa +skinparam class { + ArrowColor SeaGreen + BackgroundColor #fffce8 +} + +interface CommandLineParser { + +parse():CommandLine +} +class CommandLine { + +getOptionValue():String + +hasOption():boolean +} +class DefaultParser { + +parse():CommandLine +} + +class OptionGroup { + +addOption():OptionGroup +} +class Options { + +addOptions():Options + +addOptionGroup():Options + +hasOption():boolean +} + +class Option { + +Option.Builder +} + + +class HelpFormatter { + +printHelp() +} + +class MissingOptionException +class MissingArgumentException +class UnrecognizedOptionException +class AlreadySelectedException +class ParseException + +HelpFormatter -down-> Options:uses +Options -right-> Option:uses +Options -up-> OptionGroup:uses +OptionGroup -down-> Option:uses + +CommandLineParser -up-> Options:uses +DefaultParser -up-|> CommandLineParser:implements + +ParseException -up-|> AlreadySelectedException:implements +ParseException -up-|> MissingOptionException:implements +ParseException -down-|> MissingArgumentException:implements +ParseException -down-|> UnrecognizedOptionException:implements + +CommandLineParser -left-> ParseException:throws +CommandLineParser -right-> CommandLine:creates + +@enduml \ No newline at end of file From b7de895554a79c18a9a9138f98b31a55c1381122 Mon Sep 17 00:00:00 2001 From: parthiv39731 <70740707+parthiv39731@users.noreply.github.com> Date: Wed, 6 Mar 2024 23:10:26 +0530 Subject: [PATCH 3/3] BAEL-7618, Intro to the Apache Commons CLI --- libraries-cli/src/main/resources/common-cli-classdg.puml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries-cli/src/main/resources/common-cli-classdg.puml b/libraries-cli/src/main/resources/common-cli-classdg.puml index 1212b7d563..b7578a85f5 100644 --- a/libraries-cli/src/main/resources/common-cli-classdg.puml +++ b/libraries-cli/src/main/resources/common-cli-classdg.puml @@ -51,10 +51,10 @@ OptionGroup -down-> Option:uses CommandLineParser -up-> Options:uses DefaultParser -up-|> CommandLineParser:implements -ParseException -up-|> AlreadySelectedException:implements -ParseException -up-|> MissingOptionException:implements -ParseException -down-|> MissingArgumentException:implements -ParseException -down-|> UnrecognizedOptionException:implements +ParseException <|-up- AlreadySelectedException:implements +ParseException <|-up- MissingOptionException:implements +ParseException <|-down- MissingArgumentException:implements +ParseException <|-down- UnrecognizedOptionException:implements CommandLineParser -left-> ParseException:throws CommandLineParser -right-> CommandLine:creates