changeset 937:37c9527f664f

Refactor command class hierarchy Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/005343.html
author Jon VanAlten <jon.vanalten@redhat.com>
date Tue, 29 Jan 2013 00:28:43 -0500
parents 1936ad067842
children ea9ff682404a
files agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/DisconnectCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ListVMsCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMInfoCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java client/command/src/main/java/com/redhat/thermostat/client/command/cli/PingCommand.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/GUIClientCommand.java common/core/src/main/java/com/redhat/thermostat/common/Launcher.java common/core/src/main/java/com/redhat/thermostat/common/cli/AbstractCommand.java common/core/src/main/java/com/redhat/thermostat/common/cli/AbstractStateNotifyingCommand.java common/core/src/main/java/com/redhat/thermostat/common/cli/BasicCommand.java common/core/src/main/java/com/redhat/thermostat/common/cli/Command.java common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistryImpl.java common/core/src/main/java/com/redhat/thermostat/common/cli/CommandWithInfo.java common/core/src/main/java/com/redhat/thermostat/common/cli/SimpleCommand.java common/core/src/test/java/com/redhat/thermostat/common/cli/AbstractCommandTest.java common/core/src/test/java/com/redhat/thermostat/common/cli/AbstractStateNotifyingCommandTest.java common/core/src/test/java/com/redhat/thermostat/common/cli/BasicCommandTest.java common/core/src/test/java/com/redhat/thermostat/common/cli/CommandRegistryImplTest.java common/core/src/test/java/com/redhat/thermostat/common/cli/CommandWithInfoTest.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java launcher/src/test/java/com/redhat/thermostat/launcher/TestCommand.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherTest.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindObjectsCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindRootCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ListHeapDumpsCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectInfoCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/SaveHeapDumpToFileCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ShowHeapHistogramCommand.java web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceCommand.java
diffstat 36 files changed, 507 insertions(+), 471 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java	Tue Jan 29 00:28:43 2013 -0500
@@ -53,9 +53,9 @@
 import com.redhat.thermostat.agent.config.AgentStartupConfiguration;
 import com.redhat.thermostat.backend.BackendRegistry;
 import com.redhat.thermostat.backend.BackendService;
-import com.redhat.thermostat.common.cli.BasicCommand;
 import com.redhat.thermostat.common.Constants;
 import com.redhat.thermostat.common.LaunchException;
+import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
@@ -70,7 +70,7 @@
 import com.redhat.thermostat.storage.dao.DAOFactoryImpl;
 
 @SuppressWarnings("restriction")
-public final class AgentApplication extends BasicCommand {
+public final class AgentApplication extends AbstractStateNotifyingCommand {
 
     private static final String NAME = "agent";
 
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -48,7 +48,7 @@
 import com.redhat.thermostat.common.Launcher;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.tools.ApplicationState;
 import com.redhat.thermostat.common.utils.OSGIUtils;
@@ -57,7 +57,7 @@
  * Simple service that allows starting Agent and DB Backend
  * in a single step.
  */
-public class ServiceCommand extends SimpleCommand implements ActionListener<ApplicationState> {
+public class ServiceCommand extends AbstractCommand implements ActionListener<ApplicationState> {
     
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -39,7 +39,7 @@
 import java.io.File;
 import java.io.IOException;
 
-import com.redhat.thermostat.common.cli.BasicCommand;
+import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
@@ -48,7 +48,7 @@
 import com.redhat.thermostat.common.tools.ApplicationException;
 import com.redhat.thermostat.common.tools.ApplicationState;
 
-public class StorageCommand extends BasicCommand {
+public class StorageCommand extends AbstractStateNotifyingCommand {
 
     private static final String NAME = "storage";
 
@@ -146,5 +146,14 @@
         return NAME;
     }
 
+    @Override
+    public boolean isStorageRequired() {
+        return false;
+    }
+
+    @Override
+    public boolean isAvailableInShell() {
+        return false;
+    }
 }
 
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -38,7 +38,7 @@
 
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
@@ -56,7 +56,7 @@
  * it can be used to retrieve a DB connection.
  * 
  */
-public class ConnectCommand extends SimpleCommand {
+public class ConnectCommand extends AbstractCommand {
 
     private static final String DB_URL_ARG = "dbUrl";
     private static final String USERNAME_ARG = "username";
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/DisconnectCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/DisconnectCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -40,13 +40,13 @@
 
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.storage.core.ConnectionException;
 import com.redhat.thermostat.storage.core.DbService;
 
-public class DisconnectCommand extends SimpleCommand {
+public class DisconnectCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ListVMsCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ListVMsCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -38,9 +38,9 @@
 
 import java.util.Collection;
 
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -49,7 +49,7 @@
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.VmInfo;
 
-public class ListVMsCommand extends SimpleCommand {
+public class ListVMsCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -53,15 +53,15 @@
 import org.osgi.framework.ServiceReference;
 
 import com.redhat.thermostat.common.Launcher;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
 import com.redhat.thermostat.common.cli.Console;
-import com.redhat.thermostat.common.cli.SimpleCommand;
 import com.redhat.thermostat.common.config.Configuration;
 import com.redhat.thermostat.common.config.InvalidConfigurationException;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
-public class ShellCommand extends SimpleCommand {
+public class ShellCommand extends AbstractCommand {
 
     private static final Logger logger = LoggingUtils.getLogger(ShellCommand.class);
 
@@ -183,5 +183,10 @@
         return false;
     }
 
+    @Override
+    public boolean isAvailableInShell() {
+        return false;
+    }
+
 }
 
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMInfoCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMInfoCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -41,9 +41,9 @@
 import java.util.Date;
 
 import com.redhat.thermostat.client.cli.HostVMArguments;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-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.common.utils.OSGIUtils;
@@ -53,7 +53,7 @@
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.VmInfo;
 
-public class VMInfoCommand extends SimpleCommand {
+public class VMInfoCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -54,13 +54,13 @@
 import com.redhat.thermostat.client.cli.VMStatPrintDelegate;
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.core.VmRef;
 
-public class VMStatCommand extends SimpleCommand {
+public class VMStatCommand extends AbstractCommand {
 
     private static final Logger log = LoggingUtils.getLogger(VMStatCommand.class);
     private static final String CMD_NAME = "vm-stat";
--- a/client/command/src/main/java/com/redhat/thermostat/client/command/cli/PingCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/client/command/src/main/java/com/redhat/thermostat/client/command/cli/PingCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -46,7 +46,7 @@
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.command.Request;
 import com.redhat.thermostat.common.command.Request.RequestType;
 import com.redhat.thermostat.common.command.RequestResponseListener;
@@ -57,7 +57,7 @@
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 
-public class PingCommand extends SimpleCommand {
+public class PingCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/GUIClientCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/GUIClientCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -38,9 +38,9 @@
 
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 
-public class GUIClientCommand extends SimpleCommand {
+public class GUIClientCommand extends AbstractCommand {
 
     private Main clientMain;
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/Launcher.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/common/core/src/main/java/com/redhat/thermostat/common/Launcher.java	Tue Jan 29 00:28:43 2013 -0500
@@ -56,7 +56,7 @@
 
     /**
      * Invoked in order to start a command, either when Thermostat starts, or within
-     * the thermostat shell.  If the command being run happens to be a BasicCommand,
+     * the thermostat shell.  If the command being run happens to be a AbstractStateNotifyingCommand,
      * and the argument is non-null, the listeners will be added to the command for
      * life cycle notifications.  Otherwise, the argument is ignored.
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/AbstractCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2012, 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.common.cli;
+
+import java.util.logging.Logger;
+
+import org.apache.commons.cli.Options;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+/**
+ * A partial implementation of {@link Command} that most implementations should extend.  Includes
+ * sane behaviour regarding {@link CommandInfo} methods and those getters that return data that
+ * is included in a {@link CommandInfo object}.  By default, any extension of this class will
+ * require {@link Storage}, and be available both in and out of the Thermostat shell; override
+ * the appropriate method to return false if other behaviour is needed for a particular {@link Command}.
+ * The only methods not provided as default implementation are {@link Command#getName()} and
+ * {@link Command#run(CommandContext)}.
+ * <p>
+ * Concrete implementations must be registered as OSGi services with {@link Command} as the
+ * class.  This may be done through the use of a BundleActivator which descends from
+ * {@link CommandLoadingBundleActivator}
+ *
+ */
+public abstract class AbstractCommand implements Command {
+
+    private static final Logger logger = LoggingUtils.getLogger(AbstractCommand.class);
+    private CommandInfo info;
+    private static final String noDesc = "Description not available.";
+    private static final String noUsage = "Usage not available.";
+
+    public void setCommandInfo(CommandInfo info) {
+        this.info = info; 
+    }
+
+    public boolean hasCommandInfo() {
+        return info != null;
+    }
+
+    @Override
+    public String getDescription() {
+        String desc = null;
+        if (hasCommandInfo()) {
+            desc = info.getDescription();
+        }
+        if (desc == null) {
+            desc = noDesc;
+        }
+        return desc;
+    }
+
+    @Override
+    public String getUsage() {
+        String usage = null;
+        if (hasCommandInfo()) { 
+            usage = info.getUsage();
+        }
+        if (usage == null) {
+            usage = noUsage;
+        }
+        return usage;
+    }
+
+    @Override
+    public Options getOptions() {
+        try {
+            return info.getOptions();
+        } catch (NullPointerException e) {
+            logger.warning("CommandInfo not yet set, returning empty Options.");
+            return new Options();
+        }
+    }
+
+    @Override
+    public boolean isStorageRequired() {
+        return true;
+    }
+
+    @Override
+    public boolean isAvailableInShell() {
+        return true;
+    }
+
+    @Override
+    public boolean isAvailableOutsideShell() {
+        return true;
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/AbstractStateNotifyingCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012, 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.common.cli;
+
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.tools.ApplicationState;
+
+/**
+ * Abstract {@link Command} implementation including all the default functionality of
+ * {@link AbstractCommand}, but also contains an {@link ActionNotifier<ApplicationState>}
+ * so that concrete implementations of this class can use this to provide updates with regards
+ * to their runtime status to other components.
+ * <p>
+ * Concrete implementations must be registered as OSGi services with {@link Command} as the
+ * class.  This may be done through the use of a BundleActivator which descends from
+ * {@link CommandLoadingBundleActivator}
+ */
+public abstract class AbstractStateNotifyingCommand extends AbstractCommand {
+
+    private ActionNotifier<ApplicationState> notifier;
+    private boolean storageRequired;
+    
+    public AbstractStateNotifyingCommand() {
+        this.notifier = new ActionNotifier<>(this);
+    }
+
+    public ActionNotifier<ApplicationState> getNotifier() {
+        return notifier;
+    }
+
+    @Override
+    public boolean isStorageRequired() {
+        return storageRequired;
+    }
+
+    protected void setStorageRequired(boolean storageRequired) {
+        this.storageRequired = storageRequired;
+    }
+}
+
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/BasicCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*
- * Copyright 2012, 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.common.cli;
-
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.tools.ApplicationState;
-
-/**
- * Common base class for all daemon and application
- */
-public abstract class BasicCommand extends CommandWithInfo {
-
-    private ActionNotifier<ApplicationState> notifier;
-    private boolean storageRequired;
-    
-    public BasicCommand() {
-        this.notifier = new ActionNotifier<>(this);
-    }
-
-    public ActionNotifier<ApplicationState> getNotifier() {
-        return notifier;
-    }
-
-    @Override
-    public boolean isStorageRequired() {
-        return storageRequired;
-    }
-
-    protected void setStorageRequired(boolean storageRequired) {
-        this.storageRequired = storageRequired;
-    }
-
-    @Override
-    public boolean isAvailableInShell() {
-        return true;
-    }
-
-    @Override
-    public boolean isAvailableOutsideShell() {
-        return true;
-    }
-}
-
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/Command.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/Command.java	Tue Jan 29 00:28:43 2013 -0500
@@ -43,15 +43,27 @@
 /**
  * Represents a command on the command line.
  * <p>
- * To register a custom command, use the CommandRegistry, registering the
+ * In order to be runnable, a command must be registered as an OSGi service
+ * with the {@link #NAME} set to the value of {@link #getName()}. If this is
+ * done directly, the developer is then responsible for enabling and disabling
+ * it at the appropriate times.
+ * <p>
+ * Bundles which provide {@link Command}s may choose to have their BundleActivator
+ * extend from {@link CommandLoadingBundleActivator} and in so doing avoid needing to
+ * explicitly register their {@link Command} implementations as services.
+ * <p>
+ * It is also possible to use an instance of {@link CommandRegistry}, registering the
  * {@link Command}s when the bundle starts and and unregistering them when the
  * bundle stops.
  * <p>
- * You can also register a custom command by registering it as an OSGi service
- * with the {@link #NAME} set to the value of {@link #getName()}. You are
- * responsible for enabling and disabling it at appropriate times then.
+ * Most {@link Command} implementations will want to choose one of the {@link AbstractCommand}
+ * or {@link AbstractStateNotifyingCommand} classes to descend from, as they provide
+ * sensible default implementations of most methods and/or provide some other functionality.
  * <p>
+ * @see CommandLoadingBundleActivator
  * @see CommandRegistry
+ * @see AbstractCommand
+ * @see AbstractStateNotifyingCommand
  */
 @ExtensionPoint
 public interface Command {
@@ -86,6 +98,10 @@
      */
     public Options getOptions();
 
+    /**
+     * Whether the command depends on {@link Storage}
+     * @return true if {@link Storage} is required.
+     */
     public boolean isStorageRequired();
 
     /**
@@ -96,7 +112,7 @@
 
     /**
      * Indicates if the command is available to be invoked from outside the
-     * shell (from the main command line).
+     * shell (as an argument to the main thermostat program).
      * @return true if can command can be invoked from the command line
      */
     public boolean isAvailableOutsideShell();
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistryImpl.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistryImpl.java	Tue Jan 29 00:28:43 2013 -0500
@@ -82,13 +82,13 @@
     @Override
     public Command getCommand(String name) {
         Command command = proxy.getService(name);
-        if (command instanceof CommandWithInfo) {
-            initializeCommandInfo((CommandWithInfo) command);
+        if (command != null && command instanceof AbstractCommand) {
+        	initializeCommandInfo((AbstractCommand) command);
         }
         return command;
     }
 
-    void initializeCommandInfo(CommandWithInfo command) {
+    void initializeCommandInfo(AbstractCommand command) {
         if (!command.hasCommandInfo()) {
             @SuppressWarnings("rawtypes")
             ServiceReference infosRef = context.getServiceReference(CommandInfoSource.class);
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandWithInfo.java	Mon Jan 28 16:03:37 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/*
- * Copyright 2012, 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.common.cli;
-
-import java.util.logging.Logger;
-
-import org.apache.commons.cli.Options;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-
-public abstract class CommandWithInfo implements Command {
-
-    private static final Logger logger = LoggingUtils.getLogger(CommandWithInfo.class);
-    private CommandInfo info;
-    private static final String noDesc = "Description not available.";
-    private static final String noUsage = "Usage not available.";
-
-    void setCommandInfo(CommandInfo info) {
-        this.info = info; 
-    }
-
-    boolean hasCommandInfo() {
-        return info != null;
-    }
-
-    @Override
-    public String getDescription() {
-        String desc = null;
-        if (hasCommandInfo()) {
-            desc = info.getDescription();
-        }
-        if (desc == null) {
-            desc = noDesc;
-        }
-        return desc;
-    }
-
-    @Override
-    public String getUsage() {
-        String usage = null;
-        if (hasCommandInfo()) { 
-            usage = info.getUsage();
-        }
-        if (usage == null) {
-            usage = noUsage;
-        }
-        return usage;
-    }
-
-    @Override
-    public Options getOptions() {
-        try {
-            return info.getOptions();
-        } catch (NullPointerException e) {
-            logger.warning("CommandInfo not yet set, returning empty Options.");
-            return new Options();
-        }
-    }
-
-    @Override
-    public boolean isStorageRequired() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public boolean isAvailableInShell() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public boolean isAvailableOutsideShell() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-}
-
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/SimpleCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012, 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.common.cli;
-
-public abstract class SimpleCommand extends CommandWithInfo {
-
-    @Override
-    public boolean isStorageRequired() {
-        return true;
-    }
-
-    @Override
-    public boolean isAvailableInShell() {
-        return true;
-    }
-
-    @Override
-    public boolean isAvailableOutsideShell() {
-        return true;
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/cli/AbstractCommandTest.java	Tue Jan 29 00:28:43 2013 -0500
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012, 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.common.cli;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AbstractCommandTest {
+
+    @Test
+    public void testHasCommandInfo() {
+        AbstractCommand command = createCommandForTest();
+        CommandInfo info = mock(CommandInfo.class);
+        assertFalse(command.hasCommandInfo());
+        command.setCommandInfo(info);
+        assertTrue(command.hasCommandInfo());
+    }
+
+    @Test
+    public void testGettersReturnCorrectly() {
+        AbstractCommand command = createCommandForTest();
+
+        CommandInfo info = mock(CommandInfo.class);
+        when(info.getDescription()).thenReturn("The description");
+        when(info.getUsage()).thenReturn("The usage.");
+        Options options = new Options();
+        Option option = new Option("option", "description");
+        options.addOption(option);
+        when(info.getOptions()).thenReturn(options);
+        command.setCommandInfo(info);
+
+        // The values that should be returned based on the CommandInfo supplied.
+        assertTrue(command.hasCommandInfo());
+        assertEquals(options, command.getOptions());
+        assertEquals("The description", command.getDescription());
+        assertEquals("The usage.", command.getUsage());
+    }
+
+    @Test
+    public void testDefaultReturnValues() {
+        AbstractCommand command = createCommandForTest();
+
+        // The default values used before CommandInfo injected.
+        assertEquals("Description not available.", command.getDescription());
+        assertEquals("Usage not available.", command.getUsage());
+        Options options = command.getOptions();
+        assertTrue(options.getOptions().isEmpty());
+        assertTrue(command.isStorageRequired());
+        assertTrue(command.isAvailableInShell());
+        assertTrue(command.isAvailableOutsideShell());
+    }
+
+    private AbstractCommand createCommandForTest() {
+        return new AbstractCommand() {
+
+            @Override
+            public void run(CommandContext ctx) throws CommandException {
+                // Do nothing.
+            }
+
+            @Override
+            public String getName() {
+                return "name";
+            }
+            
+        };
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/cli/AbstractStateNotifyingCommandTest.java	Tue Jan 29 00:28:43 2013 -0500
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2012, 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.common.cli;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+
+public class AbstractStateNotifyingCommandTest {
+
+    private AbstractStateNotifyingCommand application;
+
+    @Before
+    public void setUp() {
+        application = new AbstractStateNotifyingCommand() {
+
+            @Override
+            public void run(CommandContext ctx) throws CommandException {
+                // Nothing to do here.
+            }
+
+            @Override
+            public String getName() {
+                return null;
+            }
+
+            @Override
+            public String getDescription() {
+                return null;
+            }
+
+            @Override
+            public String getUsage() {
+                return null;
+            }
+
+            @Override
+            public Options getOptions() {
+                return new Options();
+            }
+
+            @Override
+            public boolean isStorageRequired() {
+                return false;
+            }
+        };
+    }
+
+    @After
+    public void tearDown() {
+        application = null;
+    }
+
+    @Test
+    public void testNotfier() {
+        assertNotNull(application.getNotifier());
+    }
+}
+
--- a/common/core/src/test/java/com/redhat/thermostat/common/cli/BasicCommandTest.java	Mon Jan 28 16:03:37 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * Copyright 2012, 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.common.cli;
-
-import static org.junit.Assert.assertNotNull;
-
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.cli.BasicCommand;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-
-public class BasicCommandTest {
-
-    private BasicCommand application;
-
-    @Before
-    public void setUp() {
-        application = new BasicCommand() {
-
-            @Override
-            public void run(CommandContext ctx) throws CommandException {
-                // Nothing to do here.
-            }
-
-            @Override
-            public String getName() {
-                return null;
-            }
-
-            @Override
-            public String getDescription() {
-                return null;
-            }
-
-            @Override
-            public String getUsage() {
-                return null;
-            }
-
-            @Override
-            public Options getOptions() {
-                return new Options();
-            }
-
-            @Override
-            public boolean isStorageRequired() {
-                return false;
-            }
-        };
-    }
-
-    @After
-    public void tearDown() {
-        application = null;
-    }
-
-    @Test
-    public void testNotfier() {
-        assertNotNull(application.getNotifier());
-    }
-}
-
--- a/common/core/src/test/java/com/redhat/thermostat/common/cli/CommandRegistryImplTest.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/common/core/src/test/java/com/redhat/thermostat/common/cli/CommandRegistryImplTest.java	Tue Jan 29 00:28:43 2013 -0500
@@ -40,6 +40,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -52,7 +53,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
@@ -71,6 +71,12 @@
     public void setUp() {
         bundleContext = mock(BundleContext.class);
         commandRegistry = new CommandRegistryImpl(bundleContext);
+        ServiceReference infoSourceReference = mock(ServiceReference.class);
+        CommandInfoSource infoSource = mock(CommandInfoSource.class);
+        CommandInfo info = mock(CommandInfo.class);
+        when(infoSource.getCommandInfo(any(String.class))).thenReturn(info);
+        when(bundleContext.getServiceReference(eq(CommandInfoSource.class))).thenReturn(infoSourceReference);
+        when(bundleContext.getService(infoSourceReference)).thenReturn(infoSource);
     }
 
     @After
@@ -215,7 +221,7 @@
         ServiceReference infosRef = mock(ServiceReference.class);
         CommandInfo info = mock(CommandInfo.class);
         when(infos.getCommandInfo("name")).thenReturn(info);
-        CommandWithInfo command = mock(CommandWithInfo.class);
+        AbstractCommand command = mock(AbstractCommand.class);
         when(command.getName()).thenReturn("name");
         when(command.hasCommandInfo()).thenReturn(false);
 
--- a/common/core/src/test/java/com/redhat/thermostat/common/cli/CommandWithInfoTest.java	Mon Jan 28 16:03:37 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012, 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.common.cli;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-public class CommandWithInfoTest {
-
-    @Test
-    public void testHasCommandInfo() {
-        CommandWithInfo command = new CommandWithInfo() {
-
-            @Override
-            public void run(CommandContext ctx) throws CommandException {
-                // Do nothing.
-            }
-
-            @Override
-            public String getName() {
-                return "name";
-            }
-            
-        };
-        CommandInfo info = mock(CommandInfo.class);
-        assertFalse(command.hasCommandInfo());
-        command.setCommandInfo(info);
-        assertTrue(command.hasCommandInfo());
-    }
-}
-
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -54,11 +54,11 @@
 import com.redhat.thermostat.common.cli.CommandInfo;
 import com.redhat.thermostat.common.cli.CommandInfoNotFoundException;
 import com.redhat.thermostat.common.cli.CommandInfoSource;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.TableRenderer;
 import com.redhat.thermostat.common.locale.Translate;
 
-public class HelpCommand extends SimpleCommand {
+public class HelpCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Tue Jan 29 00:28:43 2013 -0500
@@ -50,12 +50,12 @@
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceReference;
 
-import com.redhat.thermostat.common.cli.BasicCommand;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ActionNotifier;
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.Launcher;
 import com.redhat.thermostat.common.Version;
+import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.Command;
 import com.redhat.thermostat.common.cli.CommandContext;
@@ -229,8 +229,8 @@
             runHelpCommandFor(cmdName);
             return;
         }
-        if (listeners != null && cmd instanceof BasicCommand) {
-            BasicCommand basicCmd = (BasicCommand) cmd;
+        if (listeners != null && cmd instanceof AbstractStateNotifyingCommand) {
+            AbstractStateNotifyingCommand basicCmd = (AbstractStateNotifyingCommand) cmd;
             ActionNotifier<ApplicationState> notifier = basicCmd.getNotifier();
             for (ActionListener<ApplicationState> listener : listeners) {
                 notifier.addActionListener(listener);
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/TestCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/TestCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -42,6 +42,7 @@
 import com.redhat.thermostat.common.cli.Command;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.CommandInfo;
 
 
 public class TestCommand implements Command {
@@ -53,6 +54,7 @@
     private boolean storageRequired;
     private boolean availableInShell = true;
     private boolean availableOutsideShell = true;
+    private CommandInfo info;
 
     private Options options = new Options();
 
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherTest.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherTest.java	Tue Jan 29 00:28:43 2013 -0500
@@ -72,12 +72,12 @@
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
-import com.redhat.thermostat.common.cli.BasicCommand;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ActionNotifier;
 import com.redhat.thermostat.common.ApplicationInfo;
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.Version;
+import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.Command;
 import com.redhat.thermostat.common.cli.CommandContext;
@@ -92,7 +92,6 @@
 import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.launcher.TestCommand;
-import com.redhat.thermostat.launcher.TestCommand.Handle;
 import com.redhat.thermostat.launcher.internal.HelpCommand;
 import com.redhat.thermostat.launcher.internal.LauncherImpl;
 import com.redhat.thermostat.launcher.internal.LauncherImpl.LoggingInitializer;
@@ -197,7 +196,7 @@
         when(info3.getDescription()).thenReturn("description 3");
         when(info3.getOptions()).thenReturn(new Options());
 
-        BasicCommand basicCmd = mock(BasicCommand.class);
+        AbstractStateNotifyingCommand basicCmd = mock(AbstractStateNotifyingCommand.class);
         CommandInfo basicInfo = mock(CommandInfo.class);
         when(basicCmd.getName()).thenReturn("basic");
         when(basicInfo.getName()).thenReturn("basic");
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -39,16 +39,16 @@
 import java.util.concurrent.Semaphore;
 
 import com.redhat.thermostat.client.cli.HostVMArguments;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
 
 
-public class DumpHeapCommand extends SimpleCommand {
+public class DumpHeapCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
     private static final String NAME = "dump-heap";
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindObjectsCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindObjectsCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -41,7 +41,7 @@
 
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.TableRenderer;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
@@ -51,7 +51,7 @@
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
 import com.sun.tools.hat.internal.model.JavaHeapObject;
 
-public class FindObjectsCommand extends SimpleCommand {
+public class FindObjectsCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindRootCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindRootCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -42,7 +42,7 @@
 
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.vm.heap.analysis.command.FindRoot;
@@ -54,7 +54,7 @@
 import com.sun.tools.hat.internal.model.Root;
 import com.sun.tools.hat.internal.model.Snapshot;
 
-public class FindRootCommand extends SimpleCommand {
+public class FindRootCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ListHeapDumpsCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ListHeapDumpsCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -41,9 +41,9 @@
 import java.util.Date;
 
 import com.redhat.thermostat.client.cli.HostVMArguments;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-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.common.utils.OSGIUtils;
@@ -55,7 +55,7 @@
 import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
 
-public class ListHeapDumpsCommand extends SimpleCommand {
+public class ListHeapDumpsCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectInfoCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectInfoCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -41,7 +41,7 @@
 
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.TableRenderer;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
@@ -54,7 +54,7 @@
 import com.sun.tools.hat.internal.model.JavaHeapObjectVisitor;
 import com.sun.tools.hat.internal.model.Snapshot;
 
-public class ObjectInfoCommand extends SimpleCommand {
+public class ObjectInfoCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/SaveHeapDumpToFileCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/SaveHeapDumpToFileCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -47,7 +47,7 @@
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.common.utils.StreamUtils;
@@ -55,7 +55,7 @@
 import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
 
-public class SaveHeapDumpToFileCommand extends SimpleCommand {
+public class SaveHeapDumpToFileCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ShowHeapHistogramCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ShowHeapHistogramCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -41,7 +41,7 @@
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.common.cli.TableRenderer;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.OSGIUtils;
@@ -51,7 +51,7 @@
 import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord;
 import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
 
-public class ShowHeapHistogramCommand extends SimpleCommand {
+public class ShowHeapHistogramCommand extends AbstractCommand {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceCommand.java	Mon Jan 28 16:03:37 2013 -0500
+++ b/web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceCommand.java	Tue Jan 29 00:28:43 2013 -0500
@@ -41,11 +41,11 @@
 
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.AbstractCommand;
 import com.redhat.thermostat.web.server.IpPortPair;
 import com.redhat.thermostat.web.server.IpPortsParser;
 
-public class WebServiceCommand extends SimpleCommand {
+public class WebServiceCommand extends AbstractCommand {
 
     private WebServiceLauncher serviceLauncher;
     
@@ -94,6 +94,11 @@
         return false;
     }
 
+    @Override
+    public boolean isAvailableInShell() {
+    	return false;
+    }
+
     private List<IpPortPair> parseIPsPorts(String rawIpsPorts) throws CommandException {
         IpPortsParser parser = new IpPortsParser(rawIpsPorts);
         try {