changeset 917:2d4685205bd5

Merge
author Roman Kennke <rkennke@redhat.com>
date Wed, 16 Jan 2013 12:20:36 +0100
parents d17bced3f305 (current diff) 0f4271d4e334 (diff)
children 4a2301e50857 31c6026714f5
files launcher/src/main/java/com/redhat/thermostat/launcher/CommonCommandOptions.java launcher/src/test/java/com/redhat/thermostat/launcher/CommonCommandOptionsTest.java
diffstat 36 files changed, 344 insertions(+), 332 deletions(-) [+]
line wrap: on
line diff
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java	Wed Jan 16 12:20:36 2013 +0100
@@ -44,7 +44,6 @@
 import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.launcher.CommonCommandOptions;
 import com.redhat.thermostat.storage.core.ConnectionException;
 import com.redhat.thermostat.storage.core.StorageException;
 import com.redhat.thermostat.utils.keyring.Keyring;
@@ -59,6 +58,10 @@
  */
 public class ConnectCommand extends SimpleCommand {
 
+    private static final String DB_URL_ARG = "dbUrl";
+    private static final String USERNAME_ARG = "username";
+    private static final String PASSWORD_ARG = "password";
+    
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
     private static final String NAME = "connect";
@@ -84,12 +87,12 @@
         if (prefs == null) {
             prefs = new ClientPreferences(OSGIUtils.getInstance().getService(Keyring.class));
         }
-        String dbUrl = ctx.getArguments().getArgument(CommonCommandOptions.DB_URL_ARG);
+        String dbUrl = ctx.getArguments().getArgument(DB_URL_ARG);
         if (dbUrl == null) {
             dbUrl = prefs.getConnectionUrl();
         }
-        String username = ctx.getArguments().getArgument(CommonCommandOptions.USERNAME_ARG);
-        String password = ctx.getArguments().getArgument(CommonCommandOptions.PASSWORD_ARG);
+        String username = ctx.getArguments().getArgument(USERNAME_ARG);
+        String password = ctx.getArguments().getArgument(PASSWORD_ARG);
         try {
             // may throw StorageException if storage url is not supported
             service = dbServiceFactory.createDbService(username, password, dbUrl);
--- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java	Wed Jan 16 12:20:36 2013 +0100
@@ -45,11 +45,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.osgi.framework.Bundle;
@@ -65,7 +62,6 @@
 import com.redhat.thermostat.common.cli.SimpleArguments;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.launcher.CommonCommandOptions;
 import com.redhat.thermostat.test.TestCommandContextFactory;
 
 @RunWith(PowerMockRunner.class)
@@ -168,29 +164,4 @@
         assertNotNull(cmd.getUsage());
     }
 
-    @Ignore
-    @Test
-    public void testAcceptedArguments() {
-        Options options = cmd.getOptions();
-        assertNotNull(options);
-        assertTrue(options.getOptions().size() == 3);
-
-        assertTrue(options.hasOption(CommonCommandOptions.DB_URL_ARG));
-        Option db = options.getOption(CommonCommandOptions.DB_URL_ARG);
-        assertEquals(CommonCommandOptions.DB_URL_DESC, db.getDescription());
-        assertTrue(db.isRequired());
-        assertTrue(db.hasArg());
-
-        assertTrue(options.hasOption(CommonCommandOptions.USERNAME_ARG));
-        Option user = options.getOption(CommonCommandOptions.USERNAME_ARG);
-        assertEquals(CommonCommandOptions.USERNAME_DESC, user.getDescription());
-        assertFalse(user.isRequired());
-        assertTrue(user.hasArg());
-
-        assertTrue(options.hasOption(CommonCommandOptions.PASSWORD_ARG));
-        Option pass = options.getOption(CommonCommandOptions.PASSWORD_ARG);
-        assertEquals(CommonCommandOptions.PASSWORD_DESC, pass.getDescription());
-        assertFalse(pass.isRequired());
-        assertTrue(pass.hasArg());
-    }
 }
--- a/distribution/config/commands/agent.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/agent.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -41,31 +41,15 @@
 
 description = starts and stops the thermostat agent
 
-usage = thermostat agent [-d <url> [-u <user> -p <password>]] [-s] [--debug]
+usage = agent -d <url> [-u <user> -p <password>] [-s] [--debug] [-l <level>]
 
-options = saveOnExit, dbUrl, username, password, debug
+options = AUTO_LOG_OPTION, AUTO_DB_OPTIONS, saveOnExit, dbUrl, debug
 
 saveOnExit.short = s
 saveOnExit.long = saveOnExit
 saveOnExit.description = save the data on exit
 
-dbUrl.short = d
-dbUrl.long = dbUrl
-dbUrl.hasarg = true
 dbUrl.required = true
-dbUrl.description = connect to the given URL
-
-username.short = u
-username.long = username
-username.hasarg = true
-username.required = false
-username.description = the username to use for authentication
-
-password.short = p
-password.long = password
-password.hasarg = true
-password.required = false
-password.description = the password to use for authentication
 
 debug.short = v
 debug.long = debug
--- a/distribution/config/commands/connect.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/connect.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -14,24 +14,8 @@
 
 description = persistently connect to storage
 
-usage = connect -d <url> [-u <username>] [-p <password>]
-
-options = dbUrl, username, password
-
-dbUrl.short = d
-dbUrl.long = dbUrl
-dbUrl.hasarg = true
-dbUrl.required = true
-dbUrl.description = the URL of the storage to connect to
+usage = connect -d <url> [-u <username>] [-p <password>] [-l <level>]
 
-username.short = u
-username.long = username
-username.hasarg = true
-username.required = false
-username.description = the username to use for authentication
+options = AUTO_LOG_OPTION, AUTO_DB_OPTIONS, dbUrl
 
-password.short = p
-password.long = password
-password.hasarg = true
-password.required = false
-password.description = the password to use for authentication
+dbUrl.required = true
--- a/distribution/config/commands/disconnect.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/disconnect.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -2,7 +2,6 @@
 
 description = disconnect from the currently used storage
 
-usage = disconnect
+usage = disconnect [-l <level>]
 
-# No options necessary for this command
-#options =
+options = AUTO_LOG_OPTION
--- a/distribution/config/commands/dump-heap.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/dump-heap.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -19,9 +19,9 @@
 
 description = trigger a heap dump on the VM
 
-usage = thermostat dump-heap --hostId <host> --vmId <vm>
+usage = dump-heap --hostId <host> --vmId <vm> [-d <url> [-u <user> -p <password>]] [-l <level>]
 
-options = hostId, vmId
+options = hostId, vmId, AUTO_DB_OPTIONS, AUTO_LOG_OPTION
 
 hostId.short = a
 hostId.long = hostId
--- a/distribution/config/commands/find-objects.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/find-objects.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -18,9 +18,9 @@
 
 description = Finds objects in a heapdump
 
-usage = thermostat find-objects --heapId <id> --limit <limit> <pattern>
+usage = find-objects [-d <url> [-u <user> -p <password>]] [-l <level>] --heapId <id> --limit <limit> <pattern>
 
-options = heapId, limit
+options = heapId, limit, AUTO_DB_OPTIONS, AUTO_LOG_OPTION
 
 heapId.short = h
 heapId.long = heapId
@@ -28,7 +28,7 @@
 heapId.required = true
 heapId.description = the ID of the heapdump to analyze
 
-limit.short = l
+limit.short = L
 limit.long = limit
 limit.hasarg = true
 limit.required = false
--- a/distribution/config/commands/find-root.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/find-root.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -18,9 +18,9 @@
 
 description = finds the shortest path from an object to a GC root
 
-usage = thermostat find-root --heapId <heap> --objectId <object> [-a]
+usage = find-root --heapId <heap> --objectId <object> [-a] [-d <url> [-u <user> -p <password>]] [-l <level>]
 
-options = heapId, objectId, all
+options = heapId, objectId, all, AUTO_DB_OPTIONS, AUTO_LOG_OPTION
 
 heapId.short = h
 heapId.long = heapId
--- a/distribution/config/commands/gui.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/gui.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -55,7 +55,6 @@
 
 description = launches the GUI client
 
-usage = thermostat gui
+usage = gui [-l <level>]
 
-# This command does not have any options
-#options =
+options = AUTO_LOG_OPTION
--- a/distribution/config/commands/help.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/help.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -1,7 +1,7 @@
 # HelpCommand is provided by launcher, and needs no other bundles to be loaded.
 bundles =
 description = show help for a given command or help overview
-usage = thermostat help [command-name]
+usage = help [command-name]
 
 # This command does not have any options
 #options =
--- a/distribution/config/commands/list-heap-dumps.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/list-heap-dumps.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -18,9 +18,9 @@
 
 description = list all heap dumps
 
-usage = thermostat list-heap-dumps --hostId <host> --vmId <vm>
+usage = list-heap-dumps --hostId <host> --vmId <vm> [-d <url> [-u <user> -p <password>]] [-l <level>]
 
-options = hostId, vmId
+options = hostId, vmId, AUTO_DB_OPTIONS, AUTO_LOG_OPTION
 
 hostId.short = a
 hostId.long = hostId
--- a/distribution/config/commands/list-vms.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/list-vms.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -13,7 +13,7 @@
 
 description = lists all currently monitored VMs
 
-usage = thermostat list-vms [-d <url> [-u <username> -p <password>]]
+usage = list-vms [-d <url> [-u <username> -p <password>]] [-l <level>]
 
 # This command does not have any options
-#options =
+options = AUTO_DB_OPTIONS, AUTO_LOG_OPTION
--- a/distribution/config/commands/object-info.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/object-info.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -18,9 +18,9 @@
 
 description = prints information about an object in a heap dump
 
-usage = thermostat object-info --heapId <heap> --objectId <object>
+usage = object-info --heapId <heap> --objectId <object> [-d <url> [-u <user> -p <password>]] [-l <level>]
 
-options = heapId, objectId
+options = heapId, objectId, AUTO_DB_OPTIONS, AUTO_LOG_OPTION
 
 heapId.short = h
 heapId.long = heapId
--- a/distribution/config/commands/ping.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/ping.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -14,7 +14,6 @@
 
 description = using the Command Channel, send a ping to a running agent
 
-usage = ping <agentId>
+usage = ping <agentId> [-d <url> [-u <user> -p <password>]] [-l <level>]
 
-# This command does not have any options
-#options =
+options = AUTO_DB_OPTIONS, AUTO_LOG_OPTION
--- a/distribution/config/commands/save-heap-dump-to-file.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/save-heap-dump-to-file.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -18,9 +18,9 @@
 
 description = saves a heap dump to a local file
 
-usage = thermostat save-heap-dump-to-file --heapId <heap> --file <filename>
+usage = save-heap-dump-to-file --heapId <heap> --file <filename> [-d <url> [-u <user> -p <password>]] [-l <level>]
 
-options = heapId, file
+options = heapId, file, AUTO_DB_OPTIONS, AUTO_LOG_OPTION
 
 heapId.short = h
 heapId.long = heapId
--- a/distribution/config/commands/service.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/service.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -14,7 +14,6 @@
 
 description = starts and stops the thermostat storage and agent
 
-usage = thermostat service
+usage = service [-l <level>]
 
-# This command does not have any options
-#options =
+options = AUTO_LOG_OPTION
--- a/distribution/config/commands/shell.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/shell.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -3,7 +3,7 @@
 
 description = launches the Thermostat interactive shell
 
-usage = thermostat shell
+usage = shell
 
 # This command does not have any options
 #options =
--- a/distribution/config/commands/show-heap-histogram.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/show-heap-histogram.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -18,9 +18,9 @@
 
 description = show the heap histogram
 
-usage = thermostat show-heap-histogram --heapId <heap>
+usage = show-heap-histogram --heapId <heap> [-d <url> [-u <user> -p <password>]] [-l <level>]
 
-options = heapId
+options = heapId, AUTO_DB_OPTIONS, AUTO_LOG_OPTION
 
 heapId.short = h
 heapId.long = heapId
--- a/distribution/config/commands/storage.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/storage.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -8,9 +8,9 @@
 
 description = starts and stops the thermostat storage
 
-usage = thermostat storage <--start|--stop>
+usage = storage <--start|--stop> [--dryRun] [-q] [-l <level>]
 
-options = dryRun, start|stop, quiet
+options = dryRun, start|stop, quiet, AUTO_LOG_OPTION
 
 dryRun.short = d
 dryRun.long = dryRun
--- a/distribution/config/commands/vm-info.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/vm-info.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -13,9 +13,9 @@
 
 description = shows basic information about a VM
 
-usage = thermostat vm-info [--vmId <vm>] [--hostId <host>]
+usage = vm-info [--vmId <vm>] [--hostId <host>] [-d <url> [-u <user> -p <password>]] [-l <level>]
 
-options = hostId, vmId
+options = hostId, vmId, AUTO_DB_OPTIONS, AUTO_LOG_OPTION
 
 hostId.short = a
 hostId.long = hostId
--- a/distribution/config/commands/vm-stat.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/vm-stat.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -17,9 +17,9 @@
 
 description = show various statistics about a VM
 
-usage = thermostat vm-stat --hostId <host> --vmId <vm>
+usage = vm-stat --hostId <host> --vmId <vm> [-d <url> [-u <user> -p <password>]] [-l <level>]
 
-options = hostId, vmId, continuous
+options = hostId, vmId, continuous, AUTO_DB_OPTIONS, AUTO_LOG_OPTION
 
 hostId.short = a
 hostId.long = hostId
--- a/distribution/config/commands/webservice.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/config/commands/webservice.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -27,27 +27,11 @@
 
 description = starts and stops the thermostat web service
 
-usage = thermostat webservice
-
-options = storageURL, username, password, bindAddrs
-
-storageURL.short = d
-storageURL.long = storageURL
-storageURL.hasarg = true
-storageURL.required = true
-storageURL.description = connect to the given URL
+usage = webservice -d <url> -b <addrs> [-u <user> -p <password>] [-l <level>]
 
-username.short = u
-username.long = username
-username.hasarg = true
-username.required = false
-username.description = the username to authenticate against the storage
+options = AUTO_DB_OPTIONS, dbUrl, bindAddrs, AUTO_LOG_OPTION
 
-password.short = p
-password.long = password
-password.hasarg = true
-password.required = false
-password.description = the password to authenticate against the storage
+dbUrl.required = true
 
 bindAddrs.long = bindAddrs
 bindAddrs.short = b
--- a/distribution/src/test/java/com/redhat/thermostat/distribution/CliTest.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/distribution/src/test/java/com/redhat/thermostat/distribution/CliTest.java	Wed Jan 16 12:20:36 2013 +0100
@@ -144,13 +144,10 @@
 
         String[] lines = stdOut.split("\n");
         String usage = lines[0];
-        assertTrue(usage.matches("^usage: shell \\[.*\\]$"));
+        assertTrue(usage.matches("^usage: thermostat shell$"));
         String description = lines[1];
-
-        for (int i = 2; i < lines.length; i++) {
-            String argLine = lines[i];
-            assertTrue(argLine.matches("^\\s+--\\w+\\s.*$"));
-        }
+        assertTrue(description.matches("^\\s+launches the Thermostat interactive shell$"));
+        assertTrue(lines[2].matches("thermostat shell"));
     }
 
     @Test
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/CommonCommandOptions.java	Wed Jan 16 12:20:04 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * 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.launcher;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.common.cli.CommandInfo;
-
-public class CommonCommandOptions {
-
-    public static final String DB_URL_ARG = "dbUrl";
-    public static final String USERNAME_ARG = "username";
-    public static final String PASSWORD_ARG = "password";
-
-    public static final String DB_URL_DESC = "the URL of the storage to connect to";
-    public static final String USERNAME_DESC = "the username to use for authentication";
-    public static final String PASSWORD_DESC = "the password to use for authentication";
-
-    public static final String LOG_LEVEL_ARG = "logLevel";
-    private static final String LOG_LEVEL_DESC = "log level";
-
-    public Options getOptionsFor(Command cmd) {
-
-        Options options = cmd.getOptions();
-        addDbUrlOptionForStorageCommand(cmd, options);
-        addLogLevelOption(options);
-        addOptionalAuthenticationArguments(options);
-        return options;
-    }
-
-    public Options getOptionsFor(CommandInfo info) {
-        // TODO make storageRequired part of CommandInfo (in command.properties)
-        Options options = info.getOptions();
-        addLogLevelOption(options);
-        addOptionalAuthenticationArguments(options);
-        return options;
-    }
-
-    private void addDbUrlOptionForStorageCommand(Command cmd, Options options) {
-        if (cmd.isStorageRequired()) {
-            Option option = new Option("d", DB_URL_ARG, true, DB_URL_DESC);
-            option.setRequired(false);
-            options.addOption(option);
-        }
-    }
-
-    private void addLogLevelOption(Options options) {
-        Option option = new Option(null, LOG_LEVEL_ARG, true, LOG_LEVEL_DESC);
-        option.setRequired(false);
-        options.addOption(option);
-    }
-
-    private void addOptionalAuthenticationArguments(Options options) {
-
-        Option userOption = new Option(null, USERNAME_ARG, true, USERNAME_DESC);
-        userOption.setRequired(false);
-        options.addOption(userOption);
-        Option passwordOption = new Option(null, PASSWORD_ARG, true, PASSWORD_DESC);
-        passwordOption.setRequired(false);
-        options.addOption(passwordOption);
-    }
-
-}
-
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CommandInfoImpl.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CommandInfoImpl.java	Wed Jan 16 12:20:36 2013 +0100
@@ -65,7 +65,7 @@
     private static final String PROP_OPTHASARG = ".hasarg";
     private static final String PROP_OPTREQUIRED = ".required";
     private static final String PROP_OPTDESC = ".description";
-
+    
     private String name, description, usage;
     private Options options;
     private List<String> dependencies;
@@ -122,8 +122,20 @@
     }
 
     private void learnOption(String name, Properties props) {
-        Option option = optionFromProperties(name, props);
-        options.addOption(option);
+        if (name.equals(CommonOptions.OPTIONS_COMMON_DB_OPTIONS)) {
+            addDbOptions();
+        } else if (name.equals(CommonOptions.OPTIONS_COMMON_LOG_OPTION)) {
+            options.addOption(CommonOptions.getLogOption());
+        } else {
+            Option option = optionFromProperties(name, props);
+            options.addOption(option);
+        }
+    }
+
+    private void addDbOptions() {
+        for (Option opt: CommonOptions.getDbOptions()) {
+            options.addOption(opt);
+        }
     }
 
     /* TODO currently this assumes that any set of mutually exclusive options will be
@@ -153,6 +165,17 @@
         String argKey = name + PROP_OPTHASARG;
         String requiredKey = name + PROP_OPTREQUIRED;
         String descKey = name + PROP_OPTDESC;
+        
+        // required property of common options are allowed to be overridden by
+        // command.properties files
+        if (CommonOptions.ALL_COMMON_OPTIONS.contains(name) && options.hasOption(name)) {
+            if (props.containsKey(requiredKey)) {
+                Option optionToChange = options.getOption(name);
+                required = Boolean.parseBoolean((String) props.getProperty(requiredKey));
+                optionToChange.setRequired(required);
+                return optionToChange;
+            }
+        }
 
         if (props.containsKey(optKey)) {
             opt = (String) props.getProperty(optKey);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CommonOptions.java	Wed Jan 16 12:20:36 2013 +0100
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2013 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.launcher.internal;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.cli.Option;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+/*
+ * Container class for launcher-added options, such as dbUrl.
+ */
+final class CommonOptions {
+
+    // The launcher uses username, password and dbUrl options for establishing a
+    // DB connection before the command is run. These options can be added via
+    // this special option in the options section of command.properties.
+    static final String OPTIONS_COMMON_DB_OPTIONS = "AUTO_DB_OPTIONS";
+    // The launcher will auto-add a logLevel option if this special option is
+    // specified in the command.properties option section. 
+    static final String OPTIONS_COMMON_LOG_OPTION = "AUTO_LOG_OPTION";
+    
+    static final String LOG_LEVEL_ARG = "logLevel";
+    static final String DB_URL_ARG = "dbUrl";
+    static final String USERNAME_ARG = "username";
+    static final String PASSWORD_ARG = "password";
+    static final Set<String> ALL_COMMON_OPTIONS = new HashSet<>(4);
+    
+    static {
+        ALL_COMMON_OPTIONS.add(LOG_LEVEL_ARG);
+        ALL_COMMON_OPTIONS.add(DB_URL_ARG);
+        ALL_COMMON_OPTIONS.add(USERNAME_ARG);
+        ALL_COMMON_OPTIONS.add(PASSWORD_ARG);
+    }
+    
+    static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
+    
+    static List<Option> getDbOptions() {
+        String dbUrlDesc = t.localize(LocaleResources.OPTION_DB_URL_DESC);
+        Option dbUrlOption = new Option("d", DB_URL_ARG, true, dbUrlDesc);
+        dbUrlOption.setRequired(false);
+        dbUrlOption.setArgName(DB_URL_ARG);
+        String usernameDesc = t.localize(LocaleResources.OPTION_USERNAME_DESC);
+        Option usernameOption = new Option("u", USERNAME_ARG, true, usernameDesc);
+        usernameOption.setRequired(false);
+        usernameOption.setArgName(USERNAME_ARG);
+        String passwordDesc = t.localize(LocaleResources.OPTION_PASSWORD_DESC);
+        Option passwordOption = new Option("p", PASSWORD_ARG, true, passwordDesc);
+        passwordOption.setRequired(false);
+        passwordOption.setArgName(PASSWORD_ARG);
+        List<Option> options = new ArrayList<>(3);
+        options.add(dbUrlOption);
+        options.add(usernameOption);
+        options.add(passwordOption);
+        return options;
+    }
+    
+    static Option getLogOption() {
+        String desc = t.localize(LocaleResources.OPTION_LOG_LEVEL_DESC);
+        Option logOption = new Option("l", LOG_LEVEL_ARG, true, desc);
+        logOption.setRequired(false);
+        logOption.setArgName(LOG_LEVEL_ARG);
+        return logOption;
+    }
+}
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java	Wed Jan 16 12:20:36 2013 +0100
@@ -57,7 +57,6 @@
 import com.redhat.thermostat.common.cli.SimpleCommand;
 import com.redhat.thermostat.common.cli.TableRenderer;
 import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.launcher.CommonCommandOptions;
 
 public class HelpCommand extends SimpleCommand {
 
@@ -65,6 +64,7 @@
 
     private static final int COMMANDS_COLUMNS_WIDTH = 14;
     private static final String NAME = "help";
+    private static final String APP_NAME = "thermostat";
 
     private static final CommandInfoComparator comparator = new CommandInfoComparator();
 
@@ -119,10 +119,12 @@
 
     private void printHelp(CommandContext ctx, CommandInfo info) {
         HelpFormatter helpFormatter = new HelpFormatter();
+        
         PrintWriter pw = new PrintWriter(ctx.getConsole().getOutput());
-        CommonCommandOptions commonOpts = new CommonCommandOptions();
-        Options options = commonOpts.getOptionsFor(info);
-        helpFormatter.printHelp(pw, 80, info.getName(), info.getUsage(), options, 2, 4, null, true);
+        Options options = info.getOptions();
+        String name = APP_NAME + " " + info.getName();
+        String usage = APP_NAME + " " + info.getUsage() + "\n" + info.getDescription();
+        helpFormatter.printHelp(pw, 80, usage, name, options, 2, 4, null);
         pw.flush();
     }
 
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Wed Jan 16 12:20:36 2013 +0100
@@ -69,7 +69,6 @@
 import com.redhat.thermostat.common.tools.BasicCommand;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.launcher.CommonCommandOptions;
 import com.redhat.thermostat.launcher.Launcher;
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.storage.core.ConnectionException;
@@ -237,8 +236,7 @@
                 notifier.addActionListener(listener);
             }
         }
-        CommonCommandOptions commonOpts = new CommonCommandOptions();
-        Options options = commonOpts.getOptionsFor(cmd);
+        Options options = cmd.getOptions();
         Arguments args = parseCommandArguments(cmdArgs, options);
         setupLogLevel(args);
         CommandContext ctx = setupCommandContext(cmd, args);
@@ -246,8 +244,8 @@
     }
 
     private void setupLogLevel(Arguments args) {
-        if (args.hasArgument(CommonCommandOptions.LOG_LEVEL_ARG)) {
-            String levelOption = args.getArgument(CommonCommandOptions.LOG_LEVEL_ARG);
+        if (args.hasArgument(CommonOptions.LOG_LEVEL_ARG)) {
+            String levelOption = args.getArgument(CommonOptions.LOG_LEVEL_ARG);
             setLogLevel(levelOption);
         }
     }
@@ -292,12 +290,12 @@
         if (cmd.isStorageRequired()) {
             ServiceReference dbServiceReference = context.getServiceReference(DbService.class);
             if (dbServiceReference == null) {
-                String dbUrl = ctx.getArguments().getArgument(CommonCommandOptions.DB_URL_ARG);
+                String dbUrl = ctx.getArguments().getArgument(CommonOptions.DB_URL_ARG);
                 if (dbUrl == null) {
                     dbUrl = prefs.getConnectionUrl();
                 }
-                String username = ctx.getArguments().getArgument(CommonCommandOptions.USERNAME_ARG);
-                String password = ctx.getArguments().getArgument(CommonCommandOptions.PASSWORD_ARG);
+                String username = ctx.getArguments().getArgument(CommonOptions.USERNAME_ARG);
+                String password = ctx.getArguments().getArgument(CommonOptions.PASSWORD_ARG);
                 try {
                     // this may throw storage exception
                     DbService service = dbServiceFactory.createDbService(username, password, dbUrl);
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LocaleResources.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LocaleResources.java	Wed Jan 16 12:20:36 2013 +0100
@@ -42,6 +42,10 @@
 
     UNKNOWN_COMMAND,
     COMMAND_HELP_COMMAND_LIST_HEADER,
+    OPTION_DB_URL_DESC,
+    OPTION_USERNAME_DESC,
+    OPTION_PASSWORD_DESC,
+    OPTION_LOG_LEVEL_DESC,
     ;
 
     static final String RESOURCE_BUNDLE = "com.redhat.thermostat.launcher.internal.strings";
--- a/launcher/src/main/resources/com/redhat/thermostat/launcher/internal/strings.properties	Wed Jan 16 12:20:04 2013 +0100
+++ b/launcher/src/main/resources/com/redhat/thermostat/launcher/internal/strings.properties	Wed Jan 16 12:20:36 2013 +0100
@@ -1,3 +1,10 @@
 UNKNOWN_COMMAND = unknown command ''{0}''\n
 
-COMMAND_HELP_COMMAND_LIST_HEADER = list of commands:\n\n
\ No newline at end of file
+COMMAND_HELP_COMMAND_LIST_HEADER = list of commands:\n\n
+
+OPTION_DB_URL_DESC = connect to the given URL
+OPTION_USERNAME_DESC = the username to use for authentication
+OPTION_PASSWORD_DESC = the password to use for authentication
+OPTION_LOG_LEVEL_DESC = sets the log level for this invocation. Possible values\
+ for <level> in decreasing severity are: SEVERE, WARNING, INFO, CONFIG, FINE,\
+ FINER, FINEST and OFF
\ No newline at end of file
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/CommonCommandOptionsTest.java	Wed Jan 16 12:20:04 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * 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.launcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.junit.Test;
-
-import com.redhat.thermostat.test.cli.TestCommand;
-
-public class CommonCommandOptionsTest {
-
-    @Test
-    public void verifyStorageCommandAddsDbUrlOption() {
-        TestCommand cmd = new TestCommand("test1");
-        cmd.setStorageRequired(true);
-
-        CommonCommandOptions commonOpts = new CommonCommandOptions();
-        Options cmdOpts = commonOpts.getOptionsFor(cmd);
-
-        assertTrue(cmdOpts.hasOption("dbUrl"));
-        Option db = cmdOpts.getOption("dbUrl");
-        assertEquals("d", db.getOpt());
-        assertEquals("the URL of the storage to connect to", db.getDescription());
-        assertFalse(db.isRequired());
-        assertTrue(db.hasArg());
-    }
-
-    @Test
-    public void verifyLogLevelOption() {
-        TestCommand cmd = new TestCommand("test1");
-
-        CommonCommandOptions commonOpts = new CommonCommandOptions();
-        Options cmdOpts = commonOpts.getOptionsFor(cmd);
-
-        assertTrue(cmdOpts.hasOption("logLevel"));
-        Option log = cmdOpts.getOption("logLevel");
-        assertEquals("log level", log.getDescription());
-        assertFalse(log.isRequired());
-        assertTrue(log.hasArg());
-    }
-}
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/CommandInfoImplTest.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/CommandInfoImplTest.java	Wed Jan 16 12:20:36 2013 +0100
@@ -55,6 +55,8 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import com.redhat.thermostat.common.locale.Translate;
+
 public class CommandInfoImplTest {
 
     private Path tempThermostatHome, someJarName1, someJarName2, missingJarName;
@@ -191,6 +193,53 @@
         assertFalse(bar.isRequired());
         assertEquals("the bar option", bar.getDescription());
     }
+    
+    @Test
+    public void canAddCommonDBOptions() {
+        Properties props = new Properties();
+        String name = "name";
+        props.put("options", "AUTO_DB_OPTIONS");
+        CommandInfoImpl info = new CommandInfoImpl(name, props, tempThermostatHome.toString());
+
+        Options options = info.getOptions();
+        assertTrue(options.hasOption(CommonOptions.DB_URL_ARG));
+        assertTrue(options.hasOption(CommonOptions.USERNAME_ARG));
+        assertTrue(options.hasOption(CommonOptions.PASSWORD_ARG));
+        assertFalse(options.getOption(CommonOptions.DB_URL_ARG).isRequired());
+        Option dbUrlOption = options.getOption(CommonOptions.DB_URL_ARG);
+        Translate<LocaleResources> t = LocaleResources.createLocalizer();
+        assertEquals(t.localize(LocaleResources.OPTION_DB_URL_DESC), dbUrlOption.getDescription());
+        assertEquals("d", dbUrlOption.getOpt());
+        assertEquals("dbUrl", dbUrlOption.getLongOpt());
+    }
+    
+    @Test
+    public void requiredCommandPropertyOverridesCommonDbOptions() {
+        Properties props = new Properties();
+        String name = "name";
+        props.put("options", "AUTO_DB_OPTIONS, dbUrl");
+        props.put("dbUrl.long", "ignored");
+        props.put("dbUrl.required", "true");
+        CommandInfoImpl info = new CommandInfoImpl(name, props, tempThermostatHome.toString());
+
+        Options options = info.getOptions();
+        assertTrue(options.hasOption(CommonOptions.DB_URL_ARG));
+        Option dbUrlOption = options.getOption(CommonOptions.DB_URL_ARG);
+        assertTrue(dbUrlOption.isRequired());
+        assertEquals("dbUrl", dbUrlOption.getLongOpt());
+    }
+    
+    @Test
+    public void canAddLogOption() {
+        Properties props = new Properties();
+        String name = "name";
+        props.put("options", "AUTO_LOG_OPTION");
+        CommandInfoImpl info = new CommandInfoImpl(name, props, tempThermostatHome.toString());
+
+        Options options = info.getOptions();
+        assertTrue(options.hasOption(CommonOptions.LOG_LEVEL_ARG));
+        assertFalse(options.getOption(CommonOptions.LOG_LEVEL_ARG).isRequired());
+    }
 
     @Test
     public void verifyOptionGroup() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/CommonOptionsTest.java	Wed Jan 16 12:20:36 2013 +0100
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2013 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.launcher.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.junit.Test;
+
+
+public class CommonOptionsTest {
+
+    @Test
+    public void canGetLogLevel() {
+        Option logOption = CommonOptions.getLogOption();
+        Options options = new Options();
+        options.addOption(logOption);
+        assertTrue(options.hasOption("logLevel"));
+        assertTrue(options.hasOption("l"));
+        assertFalse(logOption.isRequired());
+        assertTrue(logOption.hasArg());
+    }
+    
+    @Test
+    public void canGetDbOptions() {
+        List<Option> opts = CommonOptions.getDbOptions();
+        Options options = new Options();
+        for (Option opt: opts) {
+            options.addOption(opt);
+        }
+        assertTrue(options.hasOption("dbUrl"));
+        assertTrue(options.hasOption("username"));
+        assertTrue(options.hasOption("password"));
+        assertFalse(options.getOption("dbUrl").isRequired());
+        assertFalse(options.getOption("username").isRequired());
+        assertFalse(options.getOption("password").isRequired());
+        assertTrue(options.getOption("dbUrl").hasArg());
+        assertTrue(options.getOption("username").hasArg());
+        assertTrue(options.getOption("password").hasArg());
+        Option dbUrlOption = options.getOption("dbUrl");
+        assertEquals(CommonOptions.DB_URL_ARG, dbUrlOption.getArgName());
+        assertEquals(CommonOptions.USERNAME_ARG, options.getOption(CommonOptions.USERNAME_ARG).getArgName());
+    }
+}
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherTest.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherTest.java	Wed Jan 16 12:20:36 2013 +0100
@@ -165,7 +165,11 @@
         options1.addOption(opt1);
         Option opt2 = new Option(null, "arg2", true, null);
         options1.addOption(opt2);
-        cmd1.addOptions(opt1, opt2);
+        // cmd1 needs logLevel option since it is used in tests if logLevel
+        // option is properly set up
+        Option logLevel = new Option("l", "logLevel", true, null);
+        options1.addOption(logLevel);
+        cmd1.addOptions(opt1, opt2, logLevel);
         cmd1.setDescription("description 1");
         when(info1.getDescription()).thenReturn("description 1");
         when(info1.getOptions()).thenReturn(options1);
--- a/web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceCommand.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceCommand.java	Wed Jan 16 12:20:36 2013 +0100
@@ -60,7 +60,7 @@
 
     @Override
     public void run(CommandContext ctx) throws CommandException {
-        String storageURL = ctx.getArguments().getArgument("storageURL");
+        String storageURL = ctx.getArguments().getArgument("dbUrl");
         String username = ctx.getArguments().getArgument("username");
         String password = ctx.getArguments().getArgument("password");
         serviceLauncher.setIpAddresses(parseIPsPorts(ctx.getArguments().getArgument("bindAddrs")));
--- a/web/cmd/src/test/java/com/redhat/thermostat/web/cmd/WebServiceCommandTest.java	Wed Jan 16 12:20:04 2013 +0100
+++ b/web/cmd/src/test/java/com/redhat/thermostat/web/cmd/WebServiceCommandTest.java	Wed Jan 16 12:20:36 2013 +0100
@@ -83,7 +83,7 @@
     public void verifyLauncherStart() throws Exception {
         SimpleArguments args = new SimpleArguments();
         String storageUrl = "mongodb://127.0.0.1:27518";
-        args.addArgument("storageURL", storageUrl);
+        args.addArgument("dbUrl", storageUrl);
         args.addArgument("bindAddrs", "127.0.0.1:8888,127.0.0.2:9999");
         try {
             cmd.run(cmdCtxFactory.createContext(args));
@@ -102,7 +102,7 @@
     public void verifyLauncherStartWithAuth() throws Exception {
         SimpleArguments args = new SimpleArguments();
         String storageUrl = "mongodb://127.0.0.1:27518";
-        args.addArgument("storageURL", storageUrl);
+        args.addArgument("dbUrl", storageUrl);
         args.addArgument("bindAddrs", "127.0.0.1:8888,127.0.0.2:9999");
         args.addArgument("username", "testuser");
         args.addArgument("password", "testpasswd");