Mercurial > hg > release > thermostat-0.15
changeset 246:c1dbd9616820
Integrate arguments parsing in CLI framework.
Reviewed-by: vanaltj
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-April/000939.html
line wrap: on
line diff
--- a/agent/src/main/java/com/redhat/thermostat/agent/AgentApplication.java Mon Apr 16 23:21:57 2012 +0200 +++ b/agent/src/main/java/com/redhat/thermostat/agent/AgentApplication.java Thu Apr 19 21:15:47 2012 +0200 @@ -37,8 +37,7 @@ package com.redhat.thermostat.agent; import java.io.IOException; -import java.util.Arrays; -import java.util.List; +import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; @@ -47,6 +46,8 @@ import com.redhat.thermostat.agent.config.AgentStartupConfiguration; import com.redhat.thermostat.backend.BackendLoadException; import com.redhat.thermostat.backend.BackendRegistry; +import com.redhat.thermostat.cli.ArgumentSpec; +import com.redhat.thermostat.cli.Arguments; import com.redhat.thermostat.cli.CommandContext; import com.redhat.thermostat.cli.CommandException; import com.redhat.thermostat.common.Constants; @@ -58,16 +59,15 @@ import com.redhat.thermostat.common.dao.DAOFactory; import com.redhat.thermostat.common.dao.MongoDAOFactory; import com.redhat.thermostat.common.storage.Connection; -import com.redhat.thermostat.common.storage.StorageProvider; -import com.redhat.thermostat.common.storage.MongoStorageProvider; import com.redhat.thermostat.common.storage.Connection.ConnectionListener; import com.redhat.thermostat.common.storage.Connection.ConnectionStatus; +import com.redhat.thermostat.common.storage.MongoStorageProvider; +import com.redhat.thermostat.common.storage.StorageProvider; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.tools.BasicCommand; public final class AgentApplication extends BasicCommand { - private CommandContext contex; private static final String NAME = "agent"; // TODO: Use LocaleResources for i18n-ized strings. @@ -81,7 +81,7 @@ private AgentStartupConfiguration configuration; private AgentOptionParser parser; - private void parseArguments(List<String> args) throws InvalidConfigurationException { + private void parseArguments(Arguments args) throws InvalidConfigurationException { configuration = AgentConfigsUtils.createAgentConfigs(); parser = new AgentOptionParser(configuration, args); parser.parse(); @@ -92,7 +92,7 @@ return configuration; } - private void runAgent() { + private void runAgent(CommandContext ctx) { long startTime = System.currentTimeMillis(); configuration.setStartTime(startTime); @@ -156,7 +156,7 @@ } logger.fine("Agent started."); - contex.getConsole().getOutput().println("Agent id: " + agent.getId()); + ctx.getConsole().getOutput().println("Agent id: " + agent.getId()); logger.fine("Agent id: " + agent.getId()); try { @@ -172,10 +172,9 @@ @Override public void run(CommandContext ctx) throws CommandException { try { - contex = ctx; - parseArguments(Arrays.asList(ctx.getArguments())); + parseArguments(ctx.getArguments()); if (!parser.isHelp()) { - runAgent(); + runAgent(ctx); } } catch (InvalidConfigurationException ex) { throw new CommandException(ex); @@ -197,4 +196,9 @@ return USAGE; } + @Override + public Collection<ArgumentSpec> getAcceptedArguments() { + return AgentOptionParser.getAcceptedArguments(); + } + }
--- a/agent/src/main/java/com/redhat/thermostat/agent/config/AgentOptionParser.java Mon Apr 16 23:21:57 2012 +0200 +++ b/agent/src/main/java/com/redhat/thermostat/agent/config/AgentOptionParser.java Thu Apr 19 21:15:47 2012 +0200 @@ -36,74 +36,52 @@ package com.redhat.thermostat.agent.config; -import java.io.IOException; -import java.util.List; +import java.util.Arrays; +import java.util.Collection; import java.util.logging.Level; -import joptsimple.OptionParser; -import joptsimple.OptionSet; -import joptsimple.OptionSpec; - +import com.redhat.thermostat.cli.ArgumentSpec; +import com.redhat.thermostat.cli.Arguments; +import com.redhat.thermostat.cli.SimpleArgumentSpec; import com.redhat.thermostat.common.config.InvalidConfigurationException; import com.redhat.thermostat.common.config.ThermostatOptionParser; public class AgentOptionParser implements ThermostatOptionParser { private AgentStartupConfiguration configuration; - private OptionParser parser; - private List<String> args; + private Arguments args; private boolean isHelp; - public AgentOptionParser(AgentStartupConfiguration configuration, List<String> args) { + public AgentOptionParser(AgentStartupConfiguration configuration, Arguments args) { this.configuration = configuration; this.args = args; - parser = new OptionParser(); isHelp = false; } @Override public void parse() throws InvalidConfigurationException { - parser.accepts(Args.DEBUG.option, Args.DEBUG.description); - parser.accepts(Args.HELP.option, Args.HELP.description); - parser.accepts(Args.SAVE_ON_EXIT.option, Args.SAVE_ON_EXIT.description); - - OptionSpec<String> logLevel = - parser.accepts(Args.LEVEL.option, Args.LEVEL.description). - withRequiredArg(); - OptionSpec<String> dbUrl = - parser.accepts(Args.DB.option, Args.DB.description). - withRequiredArg(); - - OptionSet options = parser.parse(args.toArray(new String[0])); - if (options.has(Args.HELP.option)) { - displayHelp(); - isHelp = true; - return; - } - - if (options.has(Args.SAVE_ON_EXIT.option)) { + if (args.hasArgument(Args.SAVE_ON_EXIT.option)) { configuration.setPurge(false); } - if (options.has(Args.LEVEL.option)) { - String levelString = logLevel.value(options); + if (args.hasArgument(Args.LEVEL.option)) { + String levelString = args.getArgument(Args.LEVEL.option); Level level = AgentConfigsUtils.getLogLevel(levelString); configuration.setLogLevel(level); } - configuration.setDebugConsole(options.has(Args.DEBUG.option)); + configuration.setDebugConsole(args.hasArgument(Args.DEBUG.option)); - if (options.has(Args.DB.option)) { - String url = dbUrl.value(options); + if (args.hasArgument(Args.DB.option)) { + String url = args.getArgument(Args.DB.option); configuration.setDatabaseURL(url); } else { if (configuration.getDBConnectionString() == null) { System.err.println("database url not specified... must be " + "either set in config or passed on " + "the command line"); - displayHelp(); isHelp = true; } } @@ -113,13 +91,6 @@ return isHelp; } - @Override - public void displayHelp() { - try { - parser.printHelpOn(System.out); - } catch (IOException ignore) {} - } - private static enum Args { // TODO: localize @@ -137,4 +108,12 @@ this.description = description; } } + + public static Collection<ArgumentSpec> getAcceptedArguments() { + ArgumentSpec level = new SimpleArgumentSpec(Args.LEVEL.option, Args.LEVEL.description, false, true); + ArgumentSpec saveOnExit = new SimpleArgumentSpec(Args.SAVE_ON_EXIT.option, Args.SAVE_ON_EXIT.description); + ArgumentSpec db = new SimpleArgumentSpec(Args.DB.option, Args.DB.description, true, true); + ArgumentSpec debug = new SimpleArgumentSpec(Args.DEBUG.option, Args.DEBUG.description); + return Arrays.asList(level, saveOnExit, db, debug); + } }
--- a/agent/src/test/java/com/redhat/thermostat/agent/AgentApplicationTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/agent/src/test/java/com/redhat/thermostat/agent/AgentApplicationTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -37,11 +37,18 @@ package com.redhat.thermostat.agent; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; import org.junit.After; import org.junit.Before; import org.junit.Test; +import com.redhat.thermostat.cli.ArgumentSpec; +import com.redhat.thermostat.cli.SimpleArgumentSpec; + public class AgentApplicationTest { // TODO: Test i18nized versions when they come. @@ -78,4 +85,15 @@ + "With argument 'start', start the agent.\n\t" + "With argument 'stop', stop the agent.\n", usage); } + + @Test + public void testAcceptedArguments() { + Collection<ArgumentSpec> args = agent.getAcceptedArguments(); + assertNotNull(args); + assertEquals(4, args.size()); + assertTrue(args.contains(new SimpleArgumentSpec("saveOnExit", "save the data on exit"))); + assertTrue(args.contains(new SimpleArgumentSpec("debug", "launch with debug console enabled"))); + assertTrue(args.contains(new SimpleArgumentSpec("dbUrl", "connect to the given url", true, true))); + assertTrue(args.contains(new SimpleArgumentSpec("logLevel", "log level", false, true))); + } }
--- a/agent/src/test/java/com/redhat/thermostat/agent/config/AgentOptionParserTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/agent/src/test/java/com/redhat/thermostat/agent/config/AgentOptionParserTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -38,8 +38,6 @@ import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import java.util.logging.Level; import junit.framework.Assert; @@ -49,6 +47,7 @@ import org.junit.Test; import com.redhat.thermostat.TestUtils; +import com.redhat.thermostat.cli.SimpleArguments; import com.redhat.thermostat.common.config.InvalidConfigurationException; public class AgentOptionParserTest { @@ -68,12 +67,10 @@ @Test public void testConfigs1() throws IOException, InvalidConfigurationException { - List<String> args = new ArrayList<>(); - args.add("--logLevel"); - args.add("ALL"); - args.add("--dbUrl"); - args.add("testURL"); - args.add("--debug"); + SimpleArguments args = new SimpleArguments(); + args.addArgument("logLevel", "ALL"); + args.addArgument("dbUrl", "testURL"); + args.addArgument("debug", "--debug"); AgentStartupConfiguration configs = AgentConfigsUtils.createAgentConfigs(); AgentOptionParser parser = new AgentOptionParser(configs, args); @@ -88,12 +85,10 @@ @Test public void testConfigs2() throws IOException, InvalidConfigurationException { - List<String> args = new ArrayList<>(); - args.add("--logLevel"); - args.add("FINE"); - args.add("--dbUrl"); - args.add("testURL2"); - args.add("--saveOnExit"); + SimpleArguments args = new SimpleArguments(); + args.addArgument("logLevel", "FINE"); + args.addArgument("dbUrl", "testURL2"); + args.addArgument("saveOnExit", "--saveOnExit"); AgentStartupConfiguration configs = new AgentStartupConfiguration(); AgentOptionParser parser = new AgentOptionParser(configs, args);
--- a/common/pom.xml Mon Apr 16 23:21:57 2012 +0200 +++ b/common/pom.xml Thu Apr 19 21:15:47 2012 +0200 @@ -88,8 +88,8 @@ <artifactId>mongo-java-driver</artifactId> </dependency> <dependency> - <groupId>net.sf.jopt-simple</groupId> - <artifactId>jopt-simple</artifactId> + <groupId>commons-cli</groupId> + <artifactId>commons-cli</artifactId> </dependency> </dependencies>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/cli/ArgumentSpec.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +public interface ArgumentSpec { + + String getName(); + + boolean isRequired(); + + boolean isUsingAdditionalArgument(); + + String getDescription(); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/cli/Arguments.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import java.util.List; + +public interface Arguments { + List<String> getNonOptionArguments(); + boolean hasArgument(String name); + String getArgument(String name); +}
--- a/common/src/main/java/com/redhat/thermostat/cli/Command.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/cli/Command.java Thu Apr 19 21:15:47 2012 +0200 @@ -36,6 +36,9 @@ package com.redhat.thermostat.cli; +import java.util.Collection; + + public interface Command { void run(CommandContext ctx) throws CommandException; @@ -45,4 +48,6 @@ String getDescription(); String getUsage(); + + Collection<ArgumentSpec> getAcceptedArguments(); }
--- a/common/src/main/java/com/redhat/thermostat/cli/CommandContext.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/cli/CommandContext.java Thu Apr 19 21:15:47 2012 +0200 @@ -40,7 +40,7 @@ Console getConsole(); - String[] getArguments(); + Arguments getArguments(); CommandRegistry getCommandRegistry();
--- a/common/src/main/java/com/redhat/thermostat/cli/CommandContextFactory.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/cli/CommandContextFactory.java Thu Apr 19 21:15:47 2012 +0200 @@ -49,17 +49,21 @@ } private CommandRegistry commandRegistry = new CommandRegistry(); + private Console console = new SystemConsole(); - public CommandContext createContext(final String[] args) { - return new CommandContextImpl(args, commandRegistry, getAppContextSetup()); + public CommandContext createContext(Arguments args) { + return new CommandContextImpl(args, commandRegistry, getAppContextSetup(), getConsole()); } protected AppContextSetup getAppContextSetup() { return new AppContextSetupImpl(); } - protected CommandRegistry getCommandRegistry() { + public CommandRegistry getCommandRegistry() { return commandRegistry; } + public Console getConsole() { + return console ; + } }
--- a/common/src/main/java/com/redhat/thermostat/cli/CommandContextImpl.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/cli/CommandContextImpl.java Thu Apr 19 21:15:47 2012 +0200 @@ -38,23 +38,25 @@ class CommandContextImpl implements CommandContext { - private String[] arguments; + private Arguments arguments; private CommandRegistry commandRegistry; private AppContextSetup appContextSetup; + private Console console; - CommandContextImpl(String[] args, CommandRegistry cmdReg, AppContextSetup appContextSetup) { + CommandContextImpl(Arguments args, CommandRegistry cmdReg, AppContextSetup appContextSetup, Console console) { arguments = args; commandRegistry = cmdReg; this.appContextSetup = appContextSetup; + this.console = console; } @Override public Console getConsole() { - return new SystemConsole(); + return console; } @Override - public String[] getArguments() { + public Arguments getArguments() { return arguments; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/cli/CommandLineArgumentParseException.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +public class CommandLineArgumentParseException extends CommandException { + + public CommandLineArgumentParseException() { + super(); + } + + public CommandLineArgumentParseException(String message) { + super(message); + } + + public CommandLineArgumentParseException(Throwable cause) { + super(cause); + } + + public CommandLineArgumentParseException(String message, Throwable cause) { + super(message, cause); + } + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/cli/CommandLineArguments.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import java.util.List; + +import org.apache.commons.cli.CommandLine; + +class CommandLineArguments implements Arguments { + + private CommandLine cmdLine; + + public CommandLineArguments(CommandLine commandLine) { + cmdLine = commandLine; + } + + @SuppressWarnings("unchecked") + @Override + public List<String> getNonOptionArguments() { + return cmdLine.getArgList(); + } + + @Override + public boolean hasArgument(String name) { + return cmdLine.hasOption(name); + } + + @Override + public String getArgument(String name) { + return cmdLine.getOptionValue(name); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/cli/CommandLineArgumentsParser.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.GnuParser; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +public class CommandLineArgumentsParser { + + private List<ArgumentSpec> arguments = new LinkedList<>(); + + void addArguments(Collection<ArgumentSpec> args) { + arguments.addAll(args); + } + + Arguments parse(String[] args) throws CommandLineArgumentParseException { + try { + Options options = convertToCommonsCLIOptions(arguments); + CommandLineParser parser = new GnuParser(); + CommandLine commandLine; + commandLine = parser.parse(options, args); + return new CommandLineArguments(commandLine); + } catch (ParseException e) { + throw new CommandLineArgumentParseException(e); + } + } + + private Options convertToCommonsCLIOptions(List<ArgumentSpec> args) { + Options options = new Options(); + for (ArgumentSpec spec : args) { + options.addOption(convertSpecToOption(spec)); + } + return options; + } + + private Option convertSpecToOption(ArgumentSpec spec) { + Option option = new Option(spec.getName(), spec.getDescription()); + option.setRequired(spec.isRequired()); + option.setArgs(spec.isUsingAdditionalArgument() ? 1 : 0); + return option; + } +}
--- a/common/src/main/java/com/redhat/thermostat/cli/HelpCommand.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/cli/HelpCommand.java Thu Apr 19 21:15:47 2012 +0200 @@ -37,12 +37,11 @@ package com.redhat.thermostat.cli; import java.util.Collection; +import java.util.Collections; +import java.util.List; public class HelpCommand implements Command { - /** - * - */ private static final int COMMANDS_COLUMNS_WIDTH = 15; private static final String NAME = "help"; private static final String DESCRIPTION = "show help for a given command or help overview"; @@ -53,11 +52,12 @@ @Override public void run(CommandContext ctx) { - String[] args = ctx.getArguments(); - if (args.length == 0) { + Arguments args = ctx.getArguments(); + List<String> nonParsed = args.getNonOptionArguments(); + if (nonParsed.isEmpty()) { printCommandSummaries(ctx); } else { - printCommandUsage(ctx, args[0]); + printCommandUsage(ctx, nonParsed.get(0)); } } @@ -108,4 +108,9 @@ return USAGE; } + @Override + public Collection<ArgumentSpec> getAcceptedArguments() { + return Collections.emptyList(); + } + }
--- a/common/src/main/java/com/redhat/thermostat/cli/Launcher.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/cli/Launcher.java Thu Apr 19 21:15:47 2012 +0200 @@ -67,20 +67,26 @@ private void runCommand(String cmdName, String[] cmdArgs) { CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance(); - CommandRegistry registry = cmdCtxFactory.getCommandRegistry(); - Command cmd = registry.getCommand(cmdName); - CommandContext ctx = cmdCtxFactory.createContext(cmdArgs); - runCommandWithContext(cmd, ctx); + try { + parseArgsAndRunCommand(cmdName, cmdArgs, cmdCtxFactory); + } catch (CommandException e) { + cmdCtxFactory.getConsole().getError().println(e.getMessage()); + } } - private void runCommandWithContext(Command cmd, CommandContext ctx) { - try { - cmd.run(ctx); - } catch (CommandException e) { - ctx.getConsole().getError().println(e.getMessage()); - } + private void parseArgsAndRunCommand(String cmdName, String[] cmdArgs, CommandContextFactory cmdCtxFactory) + throws CommandLineArgumentParseException, CommandException { + + CommandRegistry registry = cmdCtxFactory.getCommandRegistry(); + Command cmd = registry.getCommand(cmdName); + CommandLineArgumentsParser cliArgsParser = new CommandLineArgumentsParser(); + cliArgsParser.addArguments(cmd.getAcceptedArguments()); + Arguments args = cliArgsParser.parse(cmdArgs); + CommandContext ctx = cmdCtxFactory.createContext(args); + cmd.run(ctx); } + private void registerDefaultCommands() { CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance(); CommandRegistry registry = cmdCtxFactory.getCommandRegistry();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/cli/SimpleArgumentSpec.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,115 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import java.util.Objects; + +public class SimpleArgumentSpec implements ArgumentSpec { + + private String name; + private String description; + private boolean required; + private boolean usingAddionalArgument; + + public SimpleArgumentSpec() { + this(null, null, false, false); + } + + public SimpleArgumentSpec(String name, String description) { + this(name, description, false, false); + } + + public SimpleArgumentSpec(String name, String description, boolean required, boolean usingAdditionalArgument) { + this.name = name; + this.description = description; + this.required = required; + this.usingAddionalArgument = usingAdditionalArgument; + } + + @Override + public String getName() { + return name; + } + + void setName(String name) { + this.name = name; + } + + @Override + public boolean isRequired() { + return required; + } + + public void setRequired(boolean required) { + this.required = required; + } + + @Override + public boolean isUsingAdditionalArgument() { + return usingAddionalArgument; + } + + public void setUsingAdditionalArgument(boolean usingAddionalArgument) { + this.usingAddionalArgument = usingAddionalArgument; + } + + @Override + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean equals(Object o) { + if (! (o instanceof SimpleArgumentSpec)) { + return false; + } + SimpleArgumentSpec other = (SimpleArgumentSpec) o; + return Objects.equals(name, other.name) + && Objects.equals(description, other.description) + && usingAddionalArgument == other.usingAddionalArgument + && required == other.required; + } + + public int hashCode() { + return Objects.hashCode(name) ^ Objects.hashCode(description) + ^ Boolean.valueOf(usingAddionalArgument).hashCode() + ^ Boolean.valueOf(required).hashCode(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/cli/SimpleArguments.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SimpleArguments implements Arguments { + + private Map<String,String> arguments = new HashMap<>(); + + @Override + public boolean hasArgument(String name) { + return arguments.containsKey(name); + } + + @Override + public String getArgument(String name) { + return arguments.get(name); + } + + public void addArgument(String name, String value) { + arguments.put(name, value); + + } + + @Override + public List<String> getNonOptionArguments() { + return null; + } + +}
--- a/common/src/main/java/com/redhat/thermostat/common/config/ThermostatOptionParser.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/common/config/ThermostatOptionParser.java Thu Apr 19 21:15:47 2012 +0200 @@ -38,5 +38,4 @@ public interface ThermostatOptionParser { void parse() throws InvalidConfigurationException; - void displayHelp(); }
--- a/common/src/main/java/com/redhat/thermostat/test/TestCommandContextFactory.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/test/TestCommandContextFactory.java Thu Apr 19 21:15:47 2012 +0200 @@ -42,6 +42,7 @@ import java.io.PrintStream; import com.redhat.thermostat.cli.AppContextSetup; +import com.redhat.thermostat.cli.Arguments; import com.redhat.thermostat.cli.CommandContext; import com.redhat.thermostat.cli.CommandContextFactory; import com.redhat.thermostat.cli.CommandRegistry; @@ -67,6 +68,8 @@ } }; + private TestConsole console; + private class TestConsole implements Console { @Override @@ -87,7 +90,7 @@ } @Override - public CommandContext createContext(final String[] args) { + public CommandContext createContext(final Arguments args) { return new CommandContext() { @Override @@ -96,7 +99,7 @@ } @Override - public String[] getArguments() { + public Arguments getArguments() { return args; } @@ -139,5 +142,10 @@ out = new ByteArrayOutputStream(); err = new ByteArrayOutputStream(); in = new ByteArrayInputStream(new byte[0]); + console = new TestConsole(); + } + + public Console getConsole() { + return console; } }
--- a/common/src/test/java/com/redhat/thermostat/cli/CommandContextFactoryTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/test/java/com/redhat/thermostat/cli/CommandContextFactoryTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -39,17 +39,19 @@ import static org.junit.Assert.*; import org.junit.Test; +import static org.mockito.Mockito.*; public class CommandContextFactoryTest { @Test public void testDefaultInstance() { CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance(); - CommandContext ctx = cmdCtxFactory.createContext(new String[] {"arg1", "arg2"}); + Arguments args = mock(Arguments.class); + CommandContext ctx = cmdCtxFactory.createContext(args); assertSame(System.out, ctx.getConsole().getOutput()); assertSame(System.err, ctx.getConsole().getError()); assertSame(System.in, ctx.getConsole().getInput()); - assertArrayEquals(new String[] {"arg1", "arg2"}, ctx.getArguments()); + assertSame(args, ctx.getArguments()); assertNotNull(cmdCtxFactory.getCommandRegistry()); assertNotNull(ctx.getCommandRegistry()); assertSame(cmdCtxFactory.getCommandRegistry(), ctx.getCommandRegistry());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/cli/CommandLineArgumentsParserTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,114 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class CommandLineArgumentsParserTest { + + private CommandLineArgumentsParser parser; + + private ArgumentSpec arg3; + + @Before + public void setUp() { + parser = new CommandLineArgumentsParser(); + + ArgumentSpec arg1 = mock(ArgumentSpec.class); + when(arg1.getName()).thenReturn("test1"); + when(arg1.isRequired()).thenReturn(true); + + ArgumentSpec arg2 = mock(ArgumentSpec.class); + when(arg2.getName()).thenReturn("test2"); + when(arg2.isRequired()).thenReturn(false); + + arg3 = mock(ArgumentSpec.class); + when(arg3.getName()).thenReturn("test3"); + when(arg3.isRequired()).thenReturn(false); + when(arg3.isUsingAdditionalArgument()).thenReturn(true); + + parser.addArguments(Arrays.asList(arg1, arg2, arg3)); + } + + @After + public void tearDown() { + parser = null; + arg3 = null; + } + + @Test + public void testSimpleArgs() throws CommandLineArgumentParseException { + Arguments args = parser.parse(new String[] { "--test1", "--test2" }); + + assertTrue(args.hasArgument("test1")); + assertEquals(null, args.getArgument("test1")); + assertTrue(args.hasArgument("test2")); + assertEquals(null, args.getArgument("test2")); + } + + @Test(expected=CommandLineArgumentParseException.class) + public void testNoMatchingArgs() throws CommandLineArgumentParseException { + parser.parse(new String[] { "--test1", "--no-match" }); + } + + @Test(expected=CommandLineArgumentParseException.class) + public void testMissingRequiredArgument() throws CommandLineArgumentParseException { + parser.parse(new String[] { "--test2" }); + } + + @Test + public void testArgumentWithAdditionalArgument() throws CommandLineArgumentParseException { + Arguments args = parser.parse(new String[] { "--test3", "parameter", "--test1" } ); + assertTrue(args.hasArgument("test3")); + assertEquals("parameter", args.getArgument("test3")); + assertTrue(args.hasArgument("test1")); + } + + @Test(expected=CommandLineArgumentParseException.class) + public void testMissingAdditionalArgument() throws CommandLineArgumentParseException { + parser.parse(new String[] { "--test3" }); + } +}
--- a/common/src/test/java/com/redhat/thermostat/cli/CommandRegistryTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/test/java/com/redhat/thermostat/cli/CommandRegistryTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -87,7 +87,8 @@ private void runAndVerifyCommand(String name, Command cmd) throws CommandException { Command actualCmd = registry.getCommand(name); TestCommandContextFactory cf = new TestCommandContextFactory(); - CommandContext ctx = cf.createContext(new String[0]); + Arguments args = mock(Arguments.class); + CommandContext ctx = cf.createContext(args); actualCmd.run(ctx); verify(cmd).run(ctx); }
--- a/common/src/test/java/com/redhat/thermostat/cli/HelpCommandTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/test/java/com/redhat/thermostat/cli/HelpCommandTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -37,6 +37,8 @@ package com.redhat.thermostat.cli; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.Arrays; @@ -75,7 +77,8 @@ public void verifyHelpNoArgPrintsListOfCommandsNoCommands() { HelpCommand cmd = new HelpCommand(); - cmd.run(ctxFactory.createContext(new String[0])); + Arguments args = mock(Arguments.class); + cmd.run(ctxFactory.createContext(args)); String expected = "list of commands:\n\n"; String actual = ctxFactory.getOutput(); assertEquals(expected, actual); @@ -91,7 +94,8 @@ ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1, cmd2)); HelpCommand cmd = new HelpCommand(); - cmd.run(ctxFactory.createContext(new String[0])); + Arguments args = mock(Arguments.class); + cmd.run(ctxFactory.createContext(args)); String expected = "list of commands:\n\n" + " test1 test command 1\n" + " test2longname test command 2\n"; @@ -107,7 +111,9 @@ ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1)); HelpCommand cmd = new HelpCommand(); - cmd.run(ctxFactory.createContext(new String[] { "test1" })); + Arguments args = mock(Arguments.class); + when(args.getNonOptionArguments()).thenReturn(Arrays.asList("test1")); + cmd.run(ctxFactory.createContext(args)); String actual = ctxFactory.getOutput(); assertEquals(usage, actual); @@ -121,7 +127,8 @@ ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1)); HelpCommand cmd = new HelpCommand(); - cmd.run(ctxFactory.createContext(new String[] { "test12" })); + Arguments args = mock(Arguments.class); + cmd.run(ctxFactory.createContext(args)); String expected = "list of commands:\n\n" + " test1 test command 1\n";
--- a/common/src/test/java/com/redhat/thermostat/cli/LauncherTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/test/java/com/redhat/thermostat/cli/LauncherTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -52,7 +52,8 @@ @Override public void run(CommandContext ctx) { - ctx.getConsole().getOutput().print(ctx.getArguments()[0] + ", " + ctx.getArguments()[1]); + Arguments args = ctx.getArguments(); + ctx.getConsole().getOutput().print(args.getArgument("arg1") + ", " + args.getArgument("arg2")); } } @@ -60,7 +61,8 @@ private static class TestCmd2 implements TestCommand.Handle { @Override public void run(CommandContext ctx) { - ctx.getConsole().getOutput().print(ctx.getArguments()[1] + ": " + ctx.getArguments()[0]); + Arguments args = ctx.getArguments(); + ctx.getConsole().getOutput().print(args.getArgument("arg4") + ": " + args.getArgument("arg3")); } } @@ -74,8 +76,22 @@ CommandContextFactory.setInstance(ctxFactory); TestCommand cmd1 = new TestCommand("test1", new TestCmd1()); + SimpleArgumentSpec arg1 = new SimpleArgumentSpec(); + arg1.setName("arg1"); + arg1.setUsingAdditionalArgument(true); + SimpleArgumentSpec arg2 = new SimpleArgumentSpec(); + arg2.setName("arg2"); + arg2.setUsingAdditionalArgument(true); + cmd1.addArguments(arg1, arg2); cmd1.setDescription("description 1"); TestCommand cmd2 = new TestCommand("test2", new TestCmd2()); + SimpleArgumentSpec arg3 = new SimpleArgumentSpec(); + arg3.setName("arg3"); + arg3.setUsingAdditionalArgument(true); + SimpleArgumentSpec arg4 = new SimpleArgumentSpec(); + arg4.setName("arg4"); + arg4.setUsingAdditionalArgument(true); + cmd2.addArguments(arg3, arg4); cmd2.setDescription("description 2"); ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1, cmd2, new HelpCommand())); @@ -88,11 +104,11 @@ @Test public void testMain() { - runAndVerifyCommand(new String[] {"test1", "Hello", "World"}, "Hello, World"); + runAndVerifyCommand(new String[] {"test1", "--arg1", "Hello", "--arg2", "World"}, "Hello, World"); ctxFactory.reset(); - runAndVerifyCommand(new String[] {"test2", "Hello", "World"}, "World: Hello"); + runAndVerifyCommand(new String[] {"test2", "--arg3", "Hello", "--arg4", "World"}, "World: Hello"); } @Test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/cli/SimpleArgumentSpecTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,163 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class SimpleArgumentSpecTest { + + private SimpleArgumentSpec spec; + private SimpleArgumentSpec other; + + @Before + public void setUp() { + spec = new SimpleArgumentSpec(); + other = new SimpleArgumentSpec(); + } + + @After + public void tearDown() { + spec = null; + other = null; + } + + @Test + public void testName() { + spec.setName("test1"); + assertEquals("test1", spec.getName()); + spec.setName("test2"); + assertEquals("test2", spec.getName()); + } + + @Test + public void testDescription() { + spec.setDescription("test1"); + assertEquals("test1", spec.getDescription()); + spec.setDescription("test2"); + assertEquals("test2", spec.getDescription()); + } + + @Test + public void testRequired() { + spec.setRequired(true); + assertTrue(spec.isRequired()); + spec.setRequired(false); + assertFalse(spec.isRequired()); + } + + @Test + public void testUsesAdditionalArgument() { + spec.setUsingAdditionalArgument(true); + assertTrue(spec.isUsingAdditionalArgument()); + spec.setUsingAdditionalArgument(false); + assertFalse(spec.isUsingAdditionalArgument()); + } + + @Test + public void testEquals() { + prepareSpecForEqualsTest(spec); + prepareSpecForEqualsTest(other); + + assertTrue(spec.equals(other)); + } + + @Test + public void testEqualsUnequalName() { + prepareSpecForEqualsTest(spec); + prepareSpecForEqualsTest(other); + + other.setName("fluff"); + + assertFalse(spec.equals(other)); + } + + @Test + public void testEqualsUnequalDescription() { + prepareSpecForEqualsTest(spec); + prepareSpecForEqualsTest(other); + + other.setDescription("fluff"); + + assertFalse(spec.equals(other)); + } + + @Test + public void testEqualsUnequalUsingAdditionalArgument() { + prepareSpecForEqualsTest(spec); + prepareSpecForEqualsTest(other); + + other.setUsingAdditionalArgument(false); + + assertFalse(spec.equals(other)); + } + + @Test + public void testEqualsUnequalRequired() { + prepareSpecForEqualsTest(spec); + prepareSpecForEqualsTest(other); + + other.setRequired(false); + + assertFalse(spec.equals(other)); + } + + @Test + public void testEqualsNull() { + prepareSpecForEqualsTest(spec); + + assertFalse(spec.equals(null)); + } + + @Test + public void testHashCode() { + prepareSpecForEqualsTest(spec); + prepareSpecForEqualsTest(other); + + assertEquals(spec.hashCode(), other.hashCode()); + } + + private void prepareSpecForEqualsTest(SimpleArgumentSpec spec) { + spec.setName("test"); + spec.setDescription("description"); + spec.setUsingAdditionalArgument(true); + spec.setRequired(true); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/cli/SimpleArgumentsTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class SimpleArgumentsTest { + + private SimpleArguments args; + + @Before + public void setUp() { + args = new SimpleArguments(); + } + + @After + public void tearDown() { + args = null; + } + + @Test + public void testSimpleArgs() { + args.addArgument("fluff", "fluffor"); + assertTrue(args.hasArgument("fluff")); + assertEquals("fluffor", args.getArgument("fluff")); + assertFalse(args.hasArgument("foo")); + assertNull(args.getArgument("bar")); + } + +}
--- a/common/src/test/java/com/redhat/thermostat/cli/TestCommand.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/test/java/com/redhat/thermostat/cli/TestCommand.java Thu Apr 19 21:15:47 2012 +0200 @@ -36,6 +36,11 @@ package com.redhat.thermostat.cli; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + class TestCommand implements Command { @@ -44,6 +49,8 @@ private String description; private String usage; + private List<ArgumentSpec> arguments = new LinkedList<ArgumentSpec>(); + static interface Handle { public void run(CommandContext ctx) throws CommandException; } @@ -84,4 +91,13 @@ void setUsage(String usage) { this.usage = usage; } + + @Override + public Collection<ArgumentSpec> getAcceptedArguments() { + return arguments; + } + + void addArguments(ArgumentSpec... arguments) { + this.arguments.addAll(Arrays.asList(arguments)); + } }
--- a/common/src/test/java/com/redhat/thermostat/tools/BasicCommandTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/common/src/test/java/com/redhat/thermostat/tools/BasicCommandTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -38,10 +38,13 @@ import static org.junit.Assert.assertNotNull; +import java.util.Collection; + import org.junit.After; import org.junit.Before; import org.junit.Test; +import com.redhat.thermostat.cli.ArgumentSpec; import com.redhat.thermostat.cli.CommandContext; import com.redhat.thermostat.cli.CommandException; import com.redhat.thermostat.common.config.StartupConfiguration; @@ -78,6 +81,11 @@ public StartupConfiguration getConfiguration() { return null; } + + @Override + public Collection<ArgumentSpec> getAcceptedArguments() { + return null; + } }; }
--- a/pom.xml Mon Apr 16 23:21:57 2012 +0200 +++ b/pom.xml Thu Apr 19 21:15:47 2012 +0200 @@ -66,7 +66,7 @@ <jdktools.version>1.7.0</jdktools.version> <jfreechart.version>1.0.14</jfreechart.version> <mongo-driver.version>2.7.3</mongo-driver.version> - <jopt.version>4.3</jopt.version> + <commons-cli.version>1.2</commons-cli.version> </properties> @@ -171,9 +171,9 @@ <version>${mongo-driver.version}</version> </dependency> <dependency> - <groupId>net.sf.jopt-simple</groupId> - <artifactId>jopt-simple</artifactId> - <version>${jopt.version}</version> + <groupId>commons-cli</groupId> + <artifactId>commons-cli</artifactId> + <version>${commons-cli.version}</version> </dependency> <dependency>
--- a/tools/src/main/java/com/redhat/thermostat/tools/ThermostatService.java Mon Apr 16 23:21:57 2012 +0200 +++ b/tools/src/main/java/com/redhat/thermostat/tools/ThermostatService.java Thu Apr 19 21:15:47 2012 +0200 @@ -36,10 +36,16 @@ package com.redhat.thermostat.tools; +import java.util.Arrays; +import java.util.Collection; + import com.redhat.thermostat.agent.AgentApplication; +import com.redhat.thermostat.cli.ArgumentSpec; import com.redhat.thermostat.cli.CommandContext; import com.redhat.thermostat.cli.CommandContextFactory; import com.redhat.thermostat.cli.CommandException; +import com.redhat.thermostat.cli.SimpleArgumentSpec; +import com.redhat.thermostat.cli.SimpleArguments; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ActionNotifier; @@ -123,7 +129,8 @@ }); String dbUrl = database.getConfiguration().getDBConnectionString(); - String[] args = new String[] { "--dbUrl", dbUrl }; + SimpleArguments args = new SimpleArguments(); + args.addArgument("dbUrl", dbUrl); try { System.err.println("starting agent now..."); agent.run(CommandContextFactory.getInstance().createContext(args)); @@ -156,4 +163,11 @@ public String getUsage() { return USAGE; } + + @Override + public Collection<ArgumentSpec> getAcceptedArguments() { + ArgumentSpec start = new SimpleArgumentSpec("start", "start the database and agent"); + ArgumentSpec stop = new SimpleArgumentSpec("stop", "stop the database and agent"); + return Arrays.asList(start, stop); + } }
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/ListVMsCommand.java Mon Apr 16 23:21:57 2012 +0200 +++ b/tools/src/main/java/com/redhat/thermostat/tools/cli/ListVMsCommand.java Thu Apr 19 21:15:47 2012 +0200 @@ -36,15 +36,14 @@ package com.redhat.thermostat.tools.cli; +import java.util.Arrays; import java.util.Collection; -import joptsimple.OptionException; -import joptsimple.OptionParser; -import joptsimple.OptionSet; - +import com.redhat.thermostat.cli.ArgumentSpec; import com.redhat.thermostat.cli.Command; import com.redhat.thermostat.cli.CommandContext; import com.redhat.thermostat.cli.CommandException; +import com.redhat.thermostat.cli.SimpleArgumentSpec; import com.redhat.thermostat.common.appctx.ApplicationContext; import com.redhat.thermostat.common.dao.DAOFactory; import com.redhat.thermostat.common.dao.HostInfoDAO; @@ -64,11 +63,14 @@ + "Options:\n\n" + "--dbUrl URL the URL of the storage to connect to.\n"; + private static final String DB_URL_ARG = "dbUrl"; + + private static final String DB_URL_DESC = "the URL of the storage to connect to"; + @Override public void run(CommandContext ctx) throws CommandException { - OptionSet options = parseArguments(ctx); - String dbUrl = getDBURL(options); + String dbUrl = ctx.getArguments().getArgument(DB_URL_ARG); ctx.getAppContextSetup().setupAppContext(dbUrl); @@ -86,25 +88,6 @@ formatter.format(ctx.getConsole().getOutput()); } - private OptionSet parseArguments(CommandContext ctx) throws CommandException { - OptionParser parser = new OptionParser(); - parser.accepts("dbUrl").withRequiredArg(); - try { - OptionSet options = parser.parse(ctx.getArguments()); - if (! options.nonOptionArguments().isEmpty()) { - throw new CommandException("Unknown arguments: " + options.nonOptionArguments()); - } - return options; - } catch (OptionException ex) { - throw new CommandException(ex); - } - } - - private String getDBURL(OptionSet options) { - String dbUrl = (String) options.valueOf("dbUrl"); - return dbUrl; - } - @Override public String getName() { return NAME; @@ -120,4 +103,10 @@ return USAGE; } + @Override + public Collection<ArgumentSpec> getAcceptedArguments() { + ArgumentSpec dbUrl = new SimpleArgumentSpec(DB_URL_ARG, DB_URL_DESC, true, true); + return Arrays.asList(dbUrl); + } + }
--- a/tools/src/main/java/com/redhat/thermostat/tools/db/DBOptionParser.java Mon Apr 16 23:21:57 2012 +0200 +++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBOptionParser.java Thu Apr 19 21:15:47 2012 +0200 @@ -36,12 +36,12 @@ package com.redhat.thermostat.tools.db; -import java.io.IOException; -import java.util.List; +import java.util.Arrays; +import java.util.Collection; -import joptsimple.OptionParser; -import joptsimple.OptionSet; - +import com.redhat.thermostat.cli.ArgumentSpec; +import com.redhat.thermostat.cli.Arguments; +import com.redhat.thermostat.cli.SimpleArgumentSpec; import com.redhat.thermostat.common.config.InvalidConfigurationException; import com.redhat.thermostat.common.config.ThermostatOptionParser; import com.redhat.thermostat.tools.ApplicationState; @@ -52,50 +52,33 @@ private DBStartupConfiguration configuration; - private List<String> args; - private OptionParser parser; + private Arguments args; private DBArgs serviceAction; private boolean dryRun; - DBOptionParser(DBStartupConfiguration configuration, List<String> args) { + DBOptionParser(DBStartupConfiguration configuration, Arguments args) { this.args = args; this.configuration = configuration; - parser = new OptionParser(); } @Override public void parse() throws InvalidConfigurationException { - parser.accepts(DBArgs.START.option, DBArgs.START.description); - parser.accepts(DBArgs.STOP.option, DBArgs.STOP.description); - - parser.accepts(DBArgs.DRY.option, DBArgs.DRY.description); - - parser.accepts(DBArgs.HELP.option, DBArgs.HELP.description); - parser.accepts(DBArgs.QUIET.option, DBArgs.QUIET.description); - - OptionSet options = parser.parse(args.toArray(new String[0])); - if (!options.hasOptions() || options.has(DBArgs.HELP.option)) { - displayHelp(); - return; - } - - if (options.has(DBArgs.START.option)) { + if (args.hasArgument(DBArgs.START.option)) { serviceAction = DBArgs.START; - } else if (options.has(DBArgs.STOP.option)) { + } else if (args.hasArgument(DBArgs.STOP.option)) { serviceAction = DBArgs.STOP; - } else { throw new InvalidConfigurationException("either --start or --stop must be given"); } - if (options.has(DBArgs.DRY.option)) { + if (args.hasArgument(DBArgs.DRY.option)) { dryRun = true; } - if (options.has(DBArgs.QUIET.option)) { + if (args.hasArgument(DBArgs.QUIET.option)) { quiet = true; } @@ -103,7 +86,7 @@ String url = configuration.getUrl(); long port = configuration.getLocalPort(); configuration.setLocal(true); - if (options.has(DBArgs.CLUSTER.option)) { + if (args.hasArgument(DBArgs.CLUSTER.option)) { port = configuration.getClusterPort(); configuration.setLocal(false); } @@ -114,27 +97,16 @@ return dryRun; } - @Override - public void displayHelp() { - - if (quiet) return; - - try { - System.out.println("Module [DBService]"); - parser.printHelpOn(System.out); - } catch (IOException ignore) {} - } - ApplicationState getAction() { return serviceAction.state; } - + static enum DBArgs { CLUSTER("cluster", "launch the db in cluster mode, if not specified, " + "local mode is the default", ApplicationState.NONE), - DRY("dry-run", "run the service in dry run mode", ApplicationState.NONE), + DRY("dryRun", "run the service in dry run mode", ApplicationState.NONE), HELP("help", "print this usage help", ApplicationState.HELP), @@ -157,4 +129,13 @@ boolean isQuiet() { return quiet; } + + static Collection<ArgumentSpec> getAcceptedArguments() { + ArgumentSpec cluster = new SimpleArgumentSpec(DBArgs.CLUSTER.option, DBArgs.CLUSTER.description); + ArgumentSpec dryRun = new SimpleArgumentSpec(DBArgs.DRY.option, DBArgs.DRY.description); + ArgumentSpec start = new SimpleArgumentSpec(DBArgs.START.option, DBArgs.START.description); + ArgumentSpec stop = new SimpleArgumentSpec(DBArgs.STOP.option, DBArgs.STOP.description); + ArgumentSpec quiet = new SimpleArgumentSpec(DBArgs.QUIET.option, DBArgs.QUIET.description); + return Arrays.asList(cluster, dryRun, start, stop, quiet); + } }
--- a/tools/src/main/java/com/redhat/thermostat/tools/db/DBService.java Mon Apr 16 23:21:57 2012 +0200 +++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBService.java Thu Apr 19 21:15:47 2012 +0200 @@ -39,10 +39,11 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.Arrays; -import java.util.List; +import java.util.Collection; import java.util.Properties; +import com.redhat.thermostat.cli.ArgumentSpec; +import com.redhat.thermostat.cli.Arguments; import com.redhat.thermostat.cli.CommandContext; import com.redhat.thermostat.cli.CommandException; import com.redhat.thermostat.common.config.ConfigUtils; @@ -68,7 +69,7 @@ private MongoProcessRunner runner; - private void parseArguments(List<String> args) throws InvalidConfigurationException { + private void parseArguments(Arguments args) throws InvalidConfigurationException { this.configuration = new DBStartupConfiguration(); // configs, read everything that is in the configs @@ -95,7 +96,7 @@ private void parseArgsAndRun(CommandContext ctx) throws InvalidConfigurationException { - parseArguments(Arrays.asList(ctx.getArguments())); + parseArguments(ctx.getArguments()); // dry run means we don't do anything at all if (parser.isDryRun()) return; @@ -206,4 +207,9 @@ return USAGE; } + @Override + public Collection<ArgumentSpec> getAcceptedArguments() { + return DBOptionParser.getAcceptedArguments(); + } + }
--- a/tools/src/test/java/com/redhat/thermostat/tools/ThermostatServiceTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/tools/src/test/java/com/redhat/thermostat/tools/ThermostatServiceTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -36,12 +36,19 @@ package com.redhat.thermostat.tools; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; import org.junit.After; import org.junit.Before; import org.junit.Test; +import com.redhat.thermostat.cli.ArgumentSpec; +import com.redhat.thermostat.cli.SimpleArgumentSpec; + public class ThermostatServiceTest { private ThermostatService thermostatService; @@ -76,4 +83,12 @@ + "With argument 'start', start the storage amd agent\n\t" + "With argument 'stop', stop the storage and agent.\n", usage); } + + @Test + public void testArgumentSpecs() { + Collection<ArgumentSpec> args = thermostatService.getAcceptedArguments(); + assertNotNull(args); + assertTrue(args.contains(new SimpleArgumentSpec("start", "start the database and agent"))); + assertTrue(args.contains(new SimpleArgumentSpec("stop", "stop the database and agent"))); + } }
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/ListVMsCommandTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/tools/src/test/java/com/redhat/thermostat/tools/cli/ListVMsCommandTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -37,20 +37,26 @@ package com.redhat.thermostat.tools.cli; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.Arrays; +import java.util.Collection; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.redhat.thermostat.cli.AppContextSetup; +import com.redhat.thermostat.cli.ArgumentSpec; import com.redhat.thermostat.cli.CommandContext; import com.redhat.thermostat.cli.CommandContextFactory; import com.redhat.thermostat.cli.CommandException; +import com.redhat.thermostat.cli.SimpleArgumentSpec; +import com.redhat.thermostat.cli.SimpleArguments; import com.redhat.thermostat.common.appctx.ApplicationContext; import com.redhat.thermostat.common.appctx.ApplicationContextUtil; import com.redhat.thermostat.common.dao.DAOFactory; @@ -113,7 +119,9 @@ @Test public void testRunCreatesConnectionFromArgumentURL() throws CommandException { - CommandContext ctx = cmdCtxFactory.createContext(new String[] { "--dbUrl", "mongo://fluff:12345" }); + SimpleArguments args = new SimpleArguments(); + args.addArgument("dbUrl", "mongo://fluff:12345"); + CommandContext ctx = cmdCtxFactory.createContext(args); cmd.run(ctx); @@ -121,35 +129,6 @@ } - @Test(expected=CommandException.class) - public void testUnknownOptionThrowsCommandException() throws CommandException { - - CommandContext ctx = cmdCtxFactory.createContext(new String[] { "--fluff", "mongo://fluff:12345" }); - - cmd.run(ctx); - } - - @Test(expected=CommandException.class) - public void testMissingURLThrowsCommandException() throws CommandException { - CommandContext ctx = cmdCtxFactory.createContext(new String[] { "--dbUrl" }); - - cmd.run(ctx); - } - - @Test(expected=CommandException.class) - public void testUnknownOptions() throws CommandException { - CommandContext ctx = cmdCtxFactory.createContext(new String[] { "--dbUrl", "fluff", "fluff"}); - - cmd.run(ctx); - } - - @Test(expected=CommandException.class) - public void testUnknownOptions2() throws CommandException { - CommandContext ctx = cmdCtxFactory.createContext(new String[] { "--dbUrl"}); - - cmd.run(ctx); - } - @Test public void verifyOutputFormatOneLine() throws CommandException { @@ -157,7 +136,9 @@ when(hostsDAO.getHosts()).thenReturn(Arrays.asList(host1)); when(vmsDAO.getVMs(host1)).thenReturn(Arrays.asList(new VmRef(host1, 1, "n"))); - CommandContext ctx = cmdCtxFactory.createContext(new String[] { "--dbUrl", "fluff" }); + SimpleArguments args = new SimpleArguments(); + args.addArgument("--dbUrl", "fluff"); + CommandContext ctx = cmdCtxFactory.createContext(args); cmd.run(ctx); @@ -176,7 +157,9 @@ when(vmsDAO.getVMs(host1)).thenReturn(Arrays.asList(new VmRef(host1, 1, "n"), new VmRef(host1, 2, "n1"))); when(vmsDAO.getVMs(host2)).thenReturn(Arrays.asList(new VmRef(host2, 123456, "longvmname"))); - CommandContext ctx = cmdCtxFactory.createContext(new String[] { "--dbUrl", "fluff" }); + SimpleArguments args = new SimpleArguments(); + args.addArgument("--dbUrl", "fluff"); + CommandContext ctx = cmdCtxFactory.createContext(args); cmd.run(ctx); @@ -206,4 +189,12 @@ assertEquals(expected, cmd.getUsage()); } + + @Test + public void testAcceptedArguments() { + Collection<ArgumentSpec> args = cmd.getAcceptedArguments(); + assertNotNull(args); + assertEquals(1, args.size()); + assertTrue(args.contains(new SimpleArgumentSpec("dbUrl", "the URL of the storage to connect to", true, true))); + } }
--- a/tools/src/test/java/com/redhat/thermostat/tools/db/DBServiceTest.java Mon Apr 16 23:21:57 2012 +0200 +++ b/tools/src/test/java/com/redhat/thermostat/tools/db/DBServiceTest.java Thu Apr 19 21:15:47 2012 +0200 @@ -37,6 +37,8 @@ package com.redhat.thermostat.tools.db; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -44,6 +46,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.util.Collection; import java.util.Properties; import java.util.Random; import java.util.concurrent.CountDownLatch; @@ -53,8 +56,11 @@ import org.junit.Before; import org.junit.Test; +import com.redhat.thermostat.cli.ArgumentSpec; import com.redhat.thermostat.cli.CommandContext; import com.redhat.thermostat.cli.CommandException; +import com.redhat.thermostat.cli.SimpleArgumentSpec; +import com.redhat.thermostat.cli.SimpleArguments; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.config.InvalidConfigurationException; @@ -108,8 +114,10 @@ @Test public void testConfig() throws CommandException { - - String[] args = new String[] {"--quiet", "--start", "--dry-run" }; + SimpleArguments args = new SimpleArguments(); + args.addArgument("quiet", "--quiet"); + args.addArgument("start", "--start"); + args.addArgument("dry-run", "--dry-run"); CommandContext ctx = mock(CommandContext.class); when(ctx.getArguments()).thenReturn(args); @@ -214,7 +222,9 @@ } private CommandContext prepareContext() { - String[] args = new String[] { "--quiet", "--start" }; + SimpleArguments args = new SimpleArguments(); + args.addArgument("quiet", "--quiet"); + args.addArgument("start", "--start"); CommandContext ctx = mock(CommandContext.class); when(ctx.getArguments()).thenReturn(args); return ctx; @@ -243,4 +253,17 @@ + "With argument 'start', start the storage.\n\t" + "With argument 'stop', stop the storage.\n", usage); } + + @Test + public void testArguments() { + DBService dbService = new DBService(); + Collection<ArgumentSpec> args = dbService.getAcceptedArguments(); + assertNotNull(args); + assertEquals(5, args.size()); + assertTrue(args.contains(new SimpleArgumentSpec("cluster", "launch the db in cluster mode, if not specified, local mode is the default"))); + assertTrue(args.contains(new SimpleArgumentSpec("dryRun", "run the service in dry run mode"))); + assertTrue(args.contains(new SimpleArgumentSpec("start", "start the database"))); + assertTrue(args.contains(new SimpleArgumentSpec("stop", "stop the database"))); + assertTrue(args.contains(new SimpleArgumentSpec("quiet", "don't produce any output"))); + } }