changeset 1124:49f6272156ff

Move command availability to command info Reviewed-by: jerboaa, neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-May/006794.html
author Omair Majid <omajid@redhat.com>
date Fri, 31 May 2013 12:15:17 -0400
parents 3694f5bb12f5
children 625f166f74d1
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/ShellCommand.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/DisconnectCommandTest.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/GUIClientCommand.java common/core/src/main/java/com/redhat/thermostat/common/cli/AbstractCommand.java common/core/src/main/java/com/redhat/thermostat/common/cli/Command.java common/core/src/test/java/com/redhat/thermostat/common/cli/AbstractCommandTest.java distribution/config/commands/agent.properties distribution/config/commands/connect.properties distribution/config/commands/disconnect.properties distribution/config/commands/gui.properties distribution/config/commands/help.properties distribution/config/commands/list-vms.properties distribution/config/commands/ping.properties distribution/config/commands/service.properties distribution/config/commands/shell.properties distribution/config/commands/storage.properties distribution/config/commands/vm-info.properties distribution/config/commands/vm-stat.properties distribution/config/commands/webservice.properties distribution/docs/thermostat-plugin.xsd integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/BasicCommandInfo.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/BuiltInCommandInfo.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/CommandInfo.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/CompoundCommandInfoSource.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfiguration.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/BasicCommandInfoTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/BuiltInCommandInfoTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/HelpCommandTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParserTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/TestCommand.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/TestCommandInfo.java vm-heap-analysis/distribution/thermostat-plugin.xml web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceCommand.java
diffstat 45 files changed, 299 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java	Fri May 31 15:21:04 2013 +0200
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java	Fri May 31 12:15:17 2013 -0400
@@ -309,11 +309,6 @@
     }
 
     @Override
-    public boolean isAvailableInShell() {
-        return false;
-    }
-    
-    @Override
     public boolean isStorageRequired() {
         return false;
     }
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java	Fri May 31 15:21:04 2013 +0200
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java	Fri May 31 12:15:17 2013 -0400
@@ -120,11 +120,6 @@
     }
 
     @Override
-    public boolean isAvailableInShell() {
-        return false;
-    }
-
-    @Override
     public boolean isStorageRequired() {
         return false;
     }
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java	Fri May 31 15:21:04 2013 +0200
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java	Fri May 31 12:15:17 2013 -0400
@@ -163,9 +163,5 @@
         return false;
     }
 
-    @Override
-    public boolean isAvailableInShell() {
-        return false;
-    }
 }
 
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java	Fri May 31 15:21:04 2013 +0200
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java	Fri May 31 12:15:17 2013 -0400
@@ -135,11 +135,6 @@
     }
 
     @Override
-    public boolean isAvailableOutsideShell() {
-        return false;
-    }
-    
-    @Override
     public boolean isStorageRequired() {
         return false;
     }
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/DisconnectCommand.java	Fri May 31 15:21:04 2013 +0200
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/DisconnectCommand.java	Fri May 31 12:15:17 2013 -0400
@@ -80,11 +80,6 @@
     }
 
     @Override
-    public boolean isAvailableOutsideShell() {
-        return false;
-    }
-    
-    @Override
     public boolean isStorageRequired() {
         return false;
     }
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java	Fri May 31 15:21:04 2013 +0200
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java	Fri May 31 12:15:17 2013 -0400
@@ -181,10 +181,5 @@
         return false;
     }
 
-    @Override
-    public boolean isAvailableInShell() {
-        return false;
-    }
-
 }
 
--- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java	Fri May 31 12:15:17 2013 -0400
@@ -155,15 +155,5 @@
         assertFalse(cmd.isStorageRequired());
     }
 
-    @Test
-    public void testIsNotAvailableOutsideShell() {
-        assertFalse(cmd.isAvailableOutsideShell());
-    }
-    
-    @Test
-    public void testIsAvailableInShell() {
-        assertTrue(cmd.isAvailableInShell());
-    }
-
 }
 
--- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/DisconnectCommandTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/DisconnectCommandTest.java	Fri May 31 12:15:17 2013 -0400
@@ -98,16 +98,6 @@
     }
 
     @Test
-    public void testIsNotAvailableOutsideShell() {
-        assertFalse(cmd.isAvailableOutsideShell());
-    }
-    
-    @Test
-    public void testIsAvailableInShell() {
-        assertTrue(cmd.isAvailableInShell());
-    }
-    
-    @Test
     public void testIsStorageRequired() {
         assertFalse(cmd.isStorageRequired());
     }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/GUIClientCommand.java	Fri May 31 15:21:04 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/GUIClientCommand.java	Fri May 31 12:15:17 2013 -0400
@@ -59,10 +59,5 @@
         return false;
     }
 
-    @Override
-    public boolean isAvailableInShell() {
-    	return false;
-    }
-
 }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/AbstractCommand.java	Fri May 31 15:21:04 2013 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/AbstractCommand.java	Fri May 31 12:15:17 2013 -0400
@@ -52,15 +52,5 @@
         return true;
     }
 
-    @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	Fri May 31 15:21:04 2013 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/Command.java	Fri May 31 12:15:17 2013 -0400
@@ -74,18 +74,5 @@
      */
     public boolean isStorageRequired();
 
-    /**
-     * Whether the command is available to be invoked from within the shell.
-     * @return true if the command can be invoked from within the shell
-     */
-    public boolean isAvailableInShell();
-
-    /**
-     * Indicates if the command is available to be invoked from outside the
-     * 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/test/java/com/redhat/thermostat/common/cli/AbstractCommandTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/cli/AbstractCommandTest.java	Fri May 31 12:15:17 2013 -0400
@@ -48,8 +48,6 @@
         AbstractCommand command = createCommandForTest();
 
         assertTrue(command.isStorageRequired());
-        assertTrue(command.isAvailableInShell());
-        assertTrue(command.isAvailableOutsideShell());
     }
 
     private AbstractCommand createCommandForTest() {
--- a/distribution/config/commands/agent.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/agent.properties	Fri May 31 12:15:17 2013 -0400
@@ -30,3 +30,5 @@
 saveOnExit.description = save the data on exit
 saveOnExit.required = false
 saveOnExit.hasarg = false
+
+environments = cli
--- a/distribution/config/commands/connect.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/connect.properties	Fri May 31 12:15:17 2013 -0400
@@ -19,3 +19,5 @@
 options = AUTO_LOG_OPTION, AUTO_DB_OPTIONS, dbUrl
 
 dbUrl.required = true
+
+environments = shell
--- a/distribution/config/commands/disconnect.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/disconnect.properties	Fri May 31 12:15:17 2013 -0400
@@ -5,3 +5,5 @@
 usage = disconnect [-l <level>]
 
 options = AUTO_LOG_OPTION
+
+environments = shell
--- a/distribution/config/commands/gui.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/gui.properties	Fri May 31 12:15:17 2013 -0400
@@ -27,3 +27,5 @@
 usage = gui [-l <level>]
 
 options = AUTO_LOG_OPTION
+
+environments = cli
--- a/distribution/config/commands/help.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/help.properties	Fri May 31 12:15:17 2013 -0400
@@ -5,3 +5,5 @@
 
 # This command does not have any options
 #options =
+
+environments = cli, shell
--- a/distribution/config/commands/list-vms.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/list-vms.properties	Fri May 31 12:15:17 2013 -0400
@@ -17,3 +17,5 @@
 
 # This command does not have any options
 options = AUTO_DB_OPTIONS, AUTO_LOG_OPTION
+
+environments = cli, shell
--- a/distribution/config/commands/ping.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/ping.properties	Fri May 31 12:15:17 2013 -0400
@@ -18,3 +18,5 @@
 usage = ping <agentId> [-d <url>] [-l <level>]
 
 options = AUTO_DB_OPTIONS, AUTO_LOG_OPTION
+
+environments = cli, shell
--- a/distribution/config/commands/service.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/service.properties	Fri May 31 12:15:17 2013 -0400
@@ -16,3 +16,5 @@
 usage = service [-l <level>]
 
 options = AUTO_LOG_OPTION
+
+environments = cli
--- a/distribution/config/commands/shell.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/shell.properties	Fri May 31 12:15:17 2013 -0400
@@ -7,3 +7,5 @@
 
 # This command does not have any options
 #options =
+
+environments = cli
--- a/distribution/config/commands/storage.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/storage.properties	Fri May 31 12:15:17 2013 -0400
@@ -33,3 +33,5 @@
 quiet.hasarg = false
 quiet.required = false
 quiet.description = don't produce any output
+
+environments = cli
--- a/distribution/config/commands/vm-info.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/vm-info.properties	Fri May 31 12:15:17 2013 -0400
@@ -28,3 +28,5 @@
 vmId.hasarg = true
 vmId.required = false
 vmId.description = the ID of the VM to monitor
+
+environments= cli, shell
--- a/distribution/config/commands/vm-stat.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/vm-stat.properties	Fri May 31 12:15:17 2013 -0400
@@ -34,3 +34,5 @@
 continuous.hasarg = false
 continuous.required = false
 continuous.description = print data continuously
+
+environments = cli, shell
--- a/distribution/config/commands/webservice.properties	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/config/commands/webservice.properties	Fri May 31 12:15:17 2013 -0400
@@ -40,3 +40,5 @@
 bindAddrs.required = true
 bindAddrs.description = A comma separated list of IP address, \
 port pairs used for binding (e.g. 127.0.0.1:8888,127.0.0.1:8889)
+
+environments = cli
--- a/distribution/docs/thermostat-plugin.xsd	Fri May 31 15:21:04 2013 +0200
+++ b/distribution/docs/thermostat-plugin.xsd	Fri May 31 12:15:17 2013 -0400
@@ -67,6 +67,7 @@
       <xs:element ref="description"/>
       <xs:element ref="arguments" minOccurs="0" maxOccurs="1"/>
       <xs:element ref="options"/>
+      <xs:element ref="environments"/>
       <xs:element ref="bundles"/>
       <xs:element ref="dependencies"/>
     </xs:sequence>
@@ -120,6 +121,30 @@
   </xs:complexType>
 </xs:element>
 
+<xs:element name="environments">
+  <xs:complexType>
+    <xs:sequence>
+      <xs:element ref="environment" minOccurs="0" maxOccurs="unbounded"/>
+    </xs:sequence>
+  </xs:complexType>
+</xs:element>
+
+<xs:element name="environment">
+  <xs:simpleType>
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="shell">
+        <xs:annotation>
+          <xs:documentation>Indicates that the command is available to be invoked from within the thermostat shell.</xs:documentation>
+        </xs:annotation>
+      </xs:enumeration>
+      <xs:enumeration value="cli">
+        <xs:annotation>
+          <xs:documentation>Indicates that the command is available to be invoked as an argument to the main thermostat program.</xs:documentation>
+        </xs:annotation>
+      </xs:enumeration>
+    </xs:restriction>
+  </xs:simpleType>
+</xs:element>
 
 <xs:element name="bundles">
   <xs:complexType>
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java	Fri May 31 12:15:17 2013 -0400
@@ -122,6 +122,10 @@
                     "    <command>" +
                     "      <name>" + command + "</name>" +
                     "      <description>" + description + "</description>" +
+                    "      <environments>" +
+                    "        <environment>shell</environment>" +
+                    "        <environment>cli</environment>" +
+                    "      </environments>" +
                     "      <options>" +
                     "        <option>" +
                     "         <long>aaaaa</long>" +
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BasicCommandInfo.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BasicCommandInfo.java	Fri May 31 12:15:17 2013 -0400
@@ -37,23 +37,25 @@
 package com.redhat.thermostat.launcher.internal;
 
 import java.util.List;
+import java.util.Set;
 
 import org.apache.commons.cli.Options;
 
-
 public class BasicCommandInfo implements CommandInfo {
 
     private final String name;
     private final String description;
     private final String usage;
     private final Options options;
+    private final Set<Environment> environments;
     private final List<String> resources;
 
-    public BasicCommandInfo(String name, String description, String usage, Options options, List<String> resources) {
+    public BasicCommandInfo(String name, String description, String usage, Options options, Set<Environment> environments, List<String> resources) {
         this.name = name;
         this.description = description;
         this.usage = usage;
         this.options = options;
+        this.environments = environments;
         this.resources = resources;
     }
 
@@ -78,6 +80,11 @@
     }
 
     @Override
+    public Set<Environment> getEnvironments() {
+        return environments;
+    }
+
+    @Override
     public List<String> getDependencyResourceNames() {
         return resources;
     }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BuiltInCommandInfo.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BuiltInCommandInfo.java	Fri May 31 12:15:17 2013 -0400
@@ -40,9 +40,11 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Properties;
+import java.util.Set;
 import java.util.logging.Logger;
 
 import org.apache.commons.cli.Option;
@@ -50,6 +52,7 @@
 import org.apache.commons.cli.Options;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 
 public class BuiltInCommandInfo implements CommandInfo {
 
@@ -58,6 +61,7 @@
     private static final String PROPERTY_DESC = "description";
     private static final String PROPERTY_USAGE = "usage";
     private static final String PROPERTY_OPTIONS = "options";
+    private static final String PROPERTY_ENVIRONMENTS = "environments";
 
     private static final String PROP_SHORTOPT = ".short";
     private static final String PROP_LONGOPT = ".long";
@@ -67,6 +71,7 @@
     
     private String name, description, usage;
     private Options options;
+    private EnumSet<Environment> environment;
     private List<String> dependencies;
 
     BuiltInCommandInfo(String commandName, Properties properties, String libRoot) {
@@ -82,6 +87,8 @@
                 usage = properties.getProperty(key);
             } else if (key.equals(PROPERTY_OPTIONS)) {
                 learnOptions((String) entry.getValue(), properties);
+            } else if (key.equals(PROPERTY_ENVIRONMENTS)) {
+                environment = parseEnvironment(properties.getProperty(key));
             }
         }
     }
@@ -329,6 +336,27 @@
                 option.getArgName());
     }
 
+    private EnumSet<Environment> parseEnvironment(String value) {
+        EnumSet<Environment> result = EnumSet.noneOf(Environment.class);
+        String[] terms = value.split(",");
+        for (String term : terms) {
+            term = term.trim();
+            if (term.equals("shell")) {
+                result.add(Environment.SHELL);
+            } else if (term.equals("cli")) {
+                result.add(Environment.CLI);
+            } else {
+                logger.info("Command " + this.name + " is available in unknown context: " + term);
+            }
+        }
+
+        if (result.isEmpty()) {
+            throw new InvalidConfigurationException("no value for environments");
+        }
+
+        return result;
+    }
+
     public String getName() {
         return name;
     }
@@ -345,6 +373,11 @@
         return options;
     }
 
+    @Override
+    public Set<Environment> getEnvironments() {
+        return environment;
+    }
+
     public List<String> getDependencyResourceNames() {
         return dependencies;
     }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CommandInfo.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CommandInfo.java	Fri May 31 12:15:17 2013 -0400
@@ -37,10 +37,17 @@
 package com.redhat.thermostat.launcher.internal;
 
 import java.util.List;
+import java.util.Set;
 
 import org.apache.commons.cli.Options;
 
 public interface CommandInfo {
+
+    public enum Environment {
+        SHELL,
+        CLI,
+    }
+
     /**
      * Returns a name for this command. This will be used by the user to select
      * this command.
@@ -58,6 +65,11 @@
     public String getUsage();
 
     /**
+     * Environments where this command is available
+     */
+    public Set<Environment> getEnvironments();
+
+    /**
      * Returns the Options that the command is prepared to handle.
      * If the user provides unknown or malformed arguments, this command will
      * not be invoked.
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CompoundCommandInfoSource.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CompoundCommandInfoSource.java	Fri May 31 12:15:17 2013 -0400
@@ -42,9 +42,12 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 import org.apache.commons.cli.Options;
 
+import com.redhat.thermostat.launcher.internal.CommandInfo.Environment;
+
 
 /**
  * Presents multiple {@link CommandInfoSource}s as one
@@ -129,11 +132,12 @@
         String description = selectBest(info1.getDescription(), info2.getDescription());
         String usage = selectBest(info1.getUsage(), info2.getUsage());
         Options options = selectBest(info1.getOptions(), info2.getOptions());
+        Set<Environment> environment = selectBest(info1.getEnvironments(), info2.getEnvironments());
         List<String> resources = new ArrayList<>();
         resources.addAll(info1.getDependencyResourceNames());
         resources.addAll(info2.getDependencyResourceNames());
 
-        return new BasicCommandInfo(name, description, usage, options, resources);
+        return new BasicCommandInfo(name, description, usage, options, environment, resources);
     }
 
     private <T> T selectBest(T first, T second) {
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Fri May 31 12:15:17 2013 -0400
@@ -67,6 +67,7 @@
 import com.redhat.thermostat.common.tools.StorageAuthInfoGetter;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.launcher.BundleManager;
+import com.redhat.thermostat.launcher.internal.CommandInfo.Environment;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 import com.redhat.thermostat.shared.locale.Translate;
@@ -251,7 +252,7 @@
             return;
         }
 
-        if ((inShell && !cmd.isAvailableInShell()) || (!inShell && !cmd.isAvailableOutsideShell())) {
+        if ((inShell && !cmdInfo.getEnvironments().contains(Environment.SHELL)) || (!inShell && !cmdInfo.getEnvironments().contains(Environment.CLI))) {
         	outputBadShellContext(inShell, out, cmdName);
         	return;
         }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java	Fri May 31 12:15:17 2013 -0400
@@ -149,6 +149,7 @@
                     command.getDescription(),
                     usage,
                     command.getOptions(),
+                    command.getEnvironments(),
                     bundlePaths);
 
             allNewCommands.put(commandName, info);
@@ -180,6 +181,7 @@
                         old.getDescription(),
                         old.getUsage(),
                         old.getOptions(),
+                        old.getEnvironments(),
                         updatedResources);
                 allNewCommands.put(entry.getKey(), updated);
                 iter.remove();
@@ -194,7 +196,7 @@
         }
         List<String> bundles = additionalBundlesForExistingCommands.get(name);
         if (bundles != null) {
-            return new BasicCommandInfo(name, null, null, null, bundles);
+            return new BasicCommandInfo(name, null, null, null, null, bundles);
         }
         throw new CommandInfoNotFoundException(name);
     }
@@ -204,7 +206,7 @@
         List<CommandInfo> result = new ArrayList<>();
         result.addAll(allNewCommands.values());
         for (Entry<String, List<String>> entry : additionalBundlesForExistingCommands.entrySet()) {
-            result.add(new BasicCommandInfo(entry.getKey(), null, null, null, entry.getValue()));
+            result.add(new BasicCommandInfo(entry.getKey(), null, null, null, null, entry.getValue()));
         }
         return result;
     }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfiguration.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfiguration.java	Fri May 31 12:15:17 2013 -0400
@@ -38,9 +38,12 @@
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.commons.cli.Options;
 
+import com.redhat.thermostat.launcher.internal.CommandInfo.Environment;
+
 public class PluginConfiguration {
 
     private final List<CommandExtensions> extensions;
@@ -91,17 +94,20 @@
         private final String description;
         private final List<String> positionalArguments;
         private final Options options;
+        private final Set<Environment> environment;
         private final List<String> additionalResources;
         private final List<String> coreDeps;
 
         public NewCommand(String name, String usage, String description,
                 List<String> positionalArguments, Options options,
+                Set<Environment> environment,
                 List<String> additionalResources, List<String> coreDeps) {
             this.commandName = name;
             this.usage = usage;
             this.description = description;
             this.positionalArguments = positionalArguments;
             this.options = options;
+            this.environment = environment;
             this.additionalResources = additionalResources;
             this.coreDeps = coreDeps;
         }
@@ -133,6 +139,11 @@
             return options;
         }
 
+        /** Returns the environments where this command is available to be used */
+        public Set<Environment> getEnvironments() {
+            return Collections.unmodifiableSet(environment);
+        }
+
         public List<String> getPluginBundles() {
             return Collections.unmodifiableList(additionalResources);
         }
@@ -140,6 +151,8 @@
         public List<String> getDepenedencyBundles() {
             return Collections.unmodifiableList(coreDeps);
         }
+
+
     }
 
 }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java	Fri May 31 12:15:17 2013 -0400
@@ -48,9 +48,11 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.logging.Logger;
 
 import javax.xml.parsers.DocumentBuilder;
@@ -73,6 +75,7 @@
 import org.xml.sax.SAXParseException;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.launcher.internal.CommandInfo.Environment;
 import com.redhat.thermostat.launcher.internal.PluginConfiguration.CommandExtensions;
 import com.redhat.thermostat.launcher.internal.PluginConfiguration.NewCommand;
 import com.redhat.thermostat.shared.locale.Translate;
@@ -328,6 +331,7 @@
         String description = null;
         List<String> arguments = new ArrayList<>();
         Options options = new Options();
+        Set<Environment> availableInEnvironments = EnumSet.noneOf(Environment.class);
         List<String> bundles = new ArrayList<>();
         List<String> dependencies = new ArrayList<>();
 
@@ -344,6 +348,8 @@
                 arguments = parseArguments(pluginName, name, node);
             } else if (node.getNodeName().equals("options")) {
                 options = parseOptions(node);
+            } else if (node.getNodeName().equals("environments")) {
+                availableInEnvironments = parseEnvironment(pluginName, name, node);
             } else if (node.getNodeName().equals("bundles")) {
                 bundles.addAll(parseBundles(pluginName, name, node));
             } else if (node.getNodeName().equals("dependencies")) {
@@ -358,12 +364,12 @@
             logger.warning("plugin " + pluginName  + " provides a new command " + name + " but lists no dependencies on thermostat");
         }
 
-        if (name == null || description == null) {
+        if (name == null || description == null || availableInEnvironments.isEmpty()) {
             logger.warning("plugin " + pluginName + " provides an incomplete new command: " +
                     "name='" + name + "', description='" + description + "', options='" + options + "'");
             return null;
         } else {
-            return new NewCommand(name, usage, description, arguments, options, bundles, dependencies);
+            return new NewCommand(name, usage, description, arguments, options, availableInEnvironments, bundles, dependencies);
         }
     }
 
@@ -379,25 +385,6 @@
         return parseNodeAsList(pluginName, commandName, argumentsNode, "argument");
     }
 
-    private List<String> parseNodeAsList(String pluginName, String commandName, Node parentNode, String childElementName) {
-        List<String> result = new ArrayList<>();
-        NodeList nodes = parentNode.getChildNodes();
-        for (int i = 0; i < nodes.getLength(); i++) {
-            Node node = nodes.item(i);
-            if (node.getNodeName().equals(childElementName)) {
-                String data = node.getTextContent().trim();
-                result.add(data);
-            }
-        }
-
-        if (result.isEmpty()) {
-            logger.warning("plugin " + pluginName + " has an empty " + parentNode.getNodeName()
-                + " element for command " + commandName);
-        }
-
-        return result;
-    }
-
     private Options parseOptions(Node optionsNode) {
         Options opts = new Options();
         NodeList nodes = optionsNode.getChildNodes();
@@ -515,6 +502,39 @@
         return opt;
     }
 
+    private Set<Environment> parseEnvironment(String pluginName, String commandName, Node environmentNode) {
+        EnumSet<Environment> result = EnumSet.noneOf(Environment.class);
+        List<String> environments = parseNodeAsList(pluginName, commandName, environmentNode, "environment");
+        for (String environment : environments) {
+            if (environment.equals("shell")) {
+                result.add(Environment.SHELL);
+            } else if (environment.equals("cli")) {
+                result.add(Environment.CLI);
+            }
+        }
+        return result;
+    }
+
+    private List<String> parseNodeAsList(String pluginName, String commandName, Node parentNode, String childElementName) {
+        List<String> result = new ArrayList<>();
+        NodeList nodes = parentNode.getChildNodes();
+        for (int i = 0; i < nodes.getLength(); i++) {
+            Node node = nodes.item(i);
+            if (node.getNodeName().equals(childElementName)) {
+                String data = node.getTextContent().trim();
+                result.add(data);
+            }
+        }
+
+        if (result.isEmpty()) {
+            logger.warning("plugin " + pluginName + " has an empty " + parentNode.getNodeName()
+                + " element for command " + commandName);
+        }
+
+        return result;
+    }
+
+
     private static class ConfigurationParserErrorHandler implements ErrorHandler {
 
         @Override
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BasicCommandInfoTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BasicCommandInfoTest.java	Fri May 31 12:15:17 2013 -0400
@@ -39,11 +39,15 @@
 import static org.junit.Assert.assertEquals;
 
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.commons.cli.Options;
 import org.junit.Test;
 
+import com.redhat.thermostat.launcher.internal.CommandInfo.Environment;
+
 public class BasicCommandInfoTest {
 
     @Test
@@ -52,9 +56,10 @@
         final String DESCRIPTION = "some-description";
         final String USAGE = "some-usage";
         final Options OPTIONS = new Options();
+        final Set<Environment> ENVIRONMENT = EnumSet.noneOf(Environment.class);
         final List<String> RESOURCES = Collections.emptyList();
 
-        BasicCommandInfo info = new BasicCommandInfo(NAME, DESCRIPTION, USAGE, OPTIONS, RESOURCES);
+        BasicCommandInfo info = new BasicCommandInfo(NAME, DESCRIPTION, USAGE, OPTIONS, ENVIRONMENT, RESOURCES);
 
         assertEquals(NAME, info.getName());
         assertEquals(DESCRIPTION, info.getDescription());
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BuiltInCommandInfoTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BuiltInCommandInfoTest.java	Fri May 31 12:15:17 2013 -0400
@@ -49,6 +49,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Properties;
+import java.util.Set;
 
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.OptionGroup;
@@ -56,6 +57,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import com.redhat.thermostat.launcher.internal.CommandInfo.Environment;
 import com.redhat.thermostat.shared.locale.Translate;
 
 public class BuiltInCommandInfoTest {
@@ -344,4 +346,17 @@
         @SuppressWarnings("unused")
         BuiltInCommandInfo info = new BuiltInCommandInfo(name, props, tempLibs.toString());
     }
+
+    @Test
+    public void verifyEnviornment() {
+        Properties props = new Properties();
+        String name = "name";
+        String env = "cli, shell";
+        props.put("environments", env);
+        BuiltInCommandInfo info = new BuiltInCommandInfo(name, props, tempLibs.toString());
+
+        Set<Environment> commandEnv = info.getEnvironments();
+        assertTrue(commandEnv.contains(Environment.CLI));
+        assertTrue(commandEnv.contains(Environment.SHELL));
+    }
 }
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/HelpCommandTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/HelpCommandTest.java	Fri May 31 12:15:17 2013 -0400
@@ -38,7 +38,6 @@
 
 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;
 
@@ -67,13 +66,6 @@
     }
 
     @Test
-    public void verifyCommandIsAvailableEverywhere() {
-        HelpCommand cmd = new HelpCommand();
-        assertTrue(cmd.isAvailableInShell());
-        assertTrue(cmd.isAvailableOutsideShell());
-    }
-
-    @Test
     public void verifyStorageIsNotRequired() {
         HelpCommand cmd = new HelpCommand();
         assertFalse(cmd.isStorageRequired());
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Fri May 31 12:15:17 2013 -0400
@@ -48,6 +48,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.EnumSet;
 import java.util.concurrent.ExecutorService;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -76,6 +77,7 @@
 import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.common.tools.ApplicationState;
 import com.redhat.thermostat.launcher.BundleManager;
+import com.redhat.thermostat.launcher.internal.CommandInfo.Environment;
 import com.redhat.thermostat.launcher.internal.DisallowSystemExitSecurityManager.ExitException;
 import com.redhat.thermostat.launcher.internal.HelpCommand;
 import com.redhat.thermostat.launcher.internal.LauncherImpl;
@@ -166,6 +168,7 @@
         options1.addOption(logLevel);
         when(info1.getDescription()).thenReturn("description 1");
         when(info1.getOptions()).thenReturn(options1);
+        when(info1.getEnvironments()).thenReturn(EnumSet.of(Environment.SHELL, Environment.CLI));
 
         TestCommand cmd2 = new TestCommand(new TestCmd2());
         CommandInfo info2 = mock(CommandInfo.class);
@@ -177,6 +180,8 @@
         options2.addOption(opt4);
         when(info2.getDescription()).thenReturn("description 2");
         when(info2.getOptions()).thenReturn(options2);
+        when(info2.getEnvironments()).thenReturn(EnumSet.of(Environment.SHELL, Environment.CLI));
+
 
         TestCommand cmd3 = new TestCommand();
         CommandInfo info3 = mock(CommandInfo.class);
@@ -184,14 +189,14 @@
         cmd3.setStorageRequired(true);
         when(info3.getDescription()).thenReturn("description 3");
         when(info3.getOptions()).thenReturn(new Options());
+        when(info3.getEnvironments()).thenReturn(EnumSet.of(Environment.SHELL, Environment.CLI));
 
         AbstractStateNotifyingCommand basicCmd = mock(AbstractStateNotifyingCommand.class);
         CommandInfo basicInfo = mock(CommandInfo.class);
         when(basicInfo.getName()).thenReturn("basic");
         when(basicInfo.getDescription()).thenReturn("nothing that means anything");
+        when(basicInfo.getEnvironments()).thenReturn(EnumSet.of(Environment.SHELL, Environment.CLI));
         when(basicCmd.isStorageRequired()).thenReturn(false);
-        when(basicCmd.isAvailableInShell()).thenReturn(true);
-        when(basicCmd.isAvailableOutsideShell()).thenReturn(true);
         Options options = new Options();
         when(basicInfo.getOptions()).thenReturn(options);
         notifier = mock(ActionNotifier.class);
@@ -203,6 +208,8 @@
         when(helpCommandInfo.getDependencyResourceNames()).thenReturn(new ArrayList<String>());
         when(helpCommandInfo.getOptions()).thenReturn(new Options());
         when(helpCommandInfo.getUsage()).thenReturn("thermostat help");
+        when(helpCommandInfo.getEnvironments()).thenReturn(EnumSet.of(Environment.SHELL, Environment.CLI));
+
 
         HelpCommand helpCommand = new HelpCommand();
 
@@ -404,6 +411,7 @@
         CommandInfo cmdInfo = mock(CommandInfo.class);
         when(cmdInfo.getName()).thenReturn("error");
         when(cmdInfo.getOptions()).thenReturn(new Options());
+        when(cmdInfo.getEnvironments()).thenReturn(EnumSet.of(Environment.SHELL, Environment.CLI));
         when(infos.getCommandInfo("error")).thenReturn(cmdInfo);
 
         wrappedRun(launcher, new String[] { "error" }, false);
@@ -468,14 +476,13 @@
     public void verifyDbServiceConnectIsCalledForStorageCommand() throws Exception {
         Command mockCmd = mock(Command.class);
         when(mockCmd.isStorageRequired()).thenReturn(true);
-        when(mockCmd.isAvailableInShell()).thenReturn(true);
-        when(mockCmd.isAvailableOutsideShell()).thenReturn(true);
         
         ctxFactory.getCommandRegistry().registerCommand("dummy", mockCmd);
         
         CommandInfo cmdInfo = mock(CommandInfo.class);
         when(cmdInfo.getName()).thenReturn("dummy");
         when(cmdInfo.getOptions()).thenReturn(new Options());
+        when(cmdInfo.getEnvironments()).thenReturn(EnumSet.of(Environment.SHELL, Environment.CLI));
         when(infos.getCommandInfo("dummy")).thenReturn(cmdInfo);
 
         DbService dbService = mock(DbService.class);
@@ -560,12 +567,19 @@
     		boolean isAvailableOutsideShell, String expected) {
     	Command mockCmd = mock(Command.class);
         when(mockCmd.isStorageRequired()).thenReturn(false);
-        when(mockCmd.isAvailableInShell()).thenReturn(isAvailableInShell);
-        when(mockCmd.isAvailableOutsideShell()).thenReturn(isAvailableOutsideShell);
+
+        EnumSet<Environment> available = EnumSet.noneOf(Environment.class);
+        if (isAvailableInShell) {
+            available.add(Environment.SHELL);
+        }
+        if (isAvailableOutsideShell) {
+            available.add(Environment.CLI);
+        }
 
         CommandInfo cmdInfo = mock(CommandInfo.class);
         when(cmdInfo.getName()).thenReturn(cmdName);
         when(cmdInfo.getOptions()).thenReturn(new Options());
+        when(cmdInfo.getEnvironments()).thenReturn(available);
         when(infos.getCommandInfo(cmdName)).thenReturn(cmdInfo);
 
         ctxFactory.getCommandRegistry().registerCommand(cmdName, mockCmd);
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java	Fri May 31 12:15:17 2013 -0400
@@ -53,7 +53,9 @@
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.commons.cli.Options;
 import org.junit.After;
@@ -61,6 +63,7 @@
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
+import com.redhat.thermostat.launcher.internal.CommandInfo.Environment;
 import com.redhat.thermostat.launcher.internal.PluginConfiguration.CommandExtensions;
 import com.redhat.thermostat.launcher.internal.PluginConfiguration.NewCommand;
 
@@ -181,6 +184,7 @@
         final String DESCRIPTION = "description of the command";
         final String USAGE = "usage";
         final Options OPTIONS = new Options();
+        final Set<Environment> ENVIRONMENTS = EnumSet.of(Environment.SHELL);
         final String PLUGIN_BUNDLE = "plugin-bundle.jar";
         final String DEPENDENCY_BUNDLE = "dependency-bundle.jar";
 
@@ -197,6 +201,7 @@
         when(cmd.getDescription()).thenReturn(DESCRIPTION);
         when(usageBuilder.getUsage(NAME, OPTIONS)).thenReturn(USAGE);
         when(cmd.getOptions()).thenReturn(OPTIONS);
+        when(cmd.getEnvironments()).thenReturn(ENVIRONMENTS);
         when(cmd.getPluginBundles()).thenReturn(Arrays.asList(PLUGIN_BUNDLE));
         when(cmd.getDepenedencyBundles()).thenReturn(Arrays.asList(DEPENDENCY_BUNDLE));
 
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParserTest.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParserTest.java	Fri May 31 12:15:17 2013 -0400
@@ -44,14 +44,23 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import java.io.*;
-import java.util.*;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.List;
+
 import javax.xml.transform.stream.StreamSource;
+
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.OptionGroup;
 import org.apache.commons.cli.Options;
 import org.junit.Test;
 
+import com.redhat.thermostat.launcher.internal.CommandInfo.Environment;
 import com.redhat.thermostat.launcher.internal.PluginConfiguration.CommandExtensions;
 import com.redhat.thermostat.launcher.internal.PluginConfiguration.NewCommand;
 import com.redhat.thermostat.shared.locale.Translate;
@@ -228,6 +237,10 @@
                 "    <command>\n" +
                 "      <name>test</name>\n" +
                 "      <description>description</description>\n" +
+                "      <environments>" +
+                "        <environment>shell</environment>" +
+                "        <environment>cli</environment>" +
+                "      </environments>" +
                 "      <bundles>\n" +
                 "        <bundle>foo</bundle>\n" +
                 "        <bundle>bar</bundle>\n" +
@@ -255,6 +268,8 @@
         Options opts = newCommand.getOptions();
         assertTrue(opts.getOptions().isEmpty());
         assertTrue(opts.getRequiredOptions().isEmpty());
+        assertTrue(newCommand.getEnvironments().contains(Environment.SHELL));
+        assertTrue(newCommand.getEnvironments().contains(Environment.CLI));
         assertEquals(Arrays.asList("foo", "bar", "baz"), newCommand.getPluginBundles());
         assertEquals(Arrays.asList("thermostat-foo"), newCommand.getDepenedencyBundles());
     }
@@ -305,6 +320,10 @@
                 "      <arguments>\n" +
                 "        <argument>file</argument>\n" +
                 "      </arguments>\n" +
+                "      <environments>" +
+                "        <environment>shell</environment>" +
+                "        <environment>cli</environment>" +
+                "      </environments>" +
                 "    </command>\n" +
                 "  </commands>\n" +
                 "</plugin>";
@@ -327,6 +346,9 @@
         List<String> args = command.getPositionalArguments();
         assertEquals(1, args.size());
         assertEquals("file", args.get(0));
+
+        assertTrue(command.getEnvironments().contains(Environment.SHELL));
+        assertTrue(command.getEnvironments().contains(Environment.CLI));
     }
 
     @Test
@@ -365,6 +387,10 @@
                 "          <description>some required and long option</description>\n" +
                 "        </option>\n" +
                 "      </options>\n" +
+                "      <environments>" +
+                "        <environment>shell</environment>" +
+                "        <environment>cli</environment>" +
+                "      </environments>" +
                 "      <bundles>\n" +
                 "        <bundle>\n \t  \nfoo\t \n \n</bundle>\n" +
                 "        <bundle>\tbar  baz\n</bundle>\n" +
@@ -422,6 +448,10 @@
                 "          <description>some required and long option</description>\n" +
                 "        </option>\n" +
                 "      </options>\n" +
+                "      <environments>" +
+                "        <environment>shell</environment>" +
+                "        <environment>cli</environment>" +
+                "      </environments>" +
                 "    </command>\n" +
                 "  </commands>\n" +
                 "</plugin>";
@@ -471,6 +501,10 @@
                 "    <command>\n" +
                 "      <name>test</name>\n" +
                 "      <description>just a test</description>\n" +
+                "      <environments>" +
+                "        <environment>shell</environment>" +
+                "        <environment>cli</environment>" +
+                "      </environments>" +
                 "      <options>\n" +
                 "        <option common=\"true\">\n" +
                 "          <long>dbUrl</long>\n" +
@@ -517,6 +551,10 @@
                 "    <command>\n" +
                 "      <name>test</name>\n" +
                 "      <description>just a test</description>\n" +
+                "      <environments>" +
+                "        <environment>shell</environment>" +
+                "        <environment>cli</environment>" +
+                "      </environments>" +
                 "      <options>\n" +
                 "        <option common=\"true\">\n" +
                 "          <long>foobarbaz</long>\n" +
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/TestCommand.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/TestCommand.java	Fri May 31 12:15:17 2013 -0400
@@ -47,9 +47,6 @@
     private Handle handle;
 
     private boolean storageRequired;
-    private boolean availableInShell = true;
-    private boolean availableOutsideShell = true;
-
 
     public static interface Handle {
         public void run(CommandContext ctx) throws CommandException;
@@ -79,22 +76,5 @@
         this.storageRequired = storageRequired;
     }
 
-    @Override
-    public boolean isAvailableInShell() {
-        return availableInShell;
-    }
-
-    void setAvailableInShell(boolean available) {
-        this.availableInShell = available;
-    }
-
-    @Override
-    public boolean isAvailableOutsideShell() {
-        return availableOutsideShell;
-    }
-
-    void setAvailableOutsideShell(boolean available) {
-        this.availableOutsideShell = available;
-    }
 }
 
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/TestCommandInfo.java	Fri May 31 15:21:04 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/TestCommandInfo.java	Fri May 31 12:15:17 2013 -0400
@@ -38,6 +38,7 @@
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
@@ -49,6 +50,7 @@
     private String usage;
 
     private Options options = new Options();
+    private Set<Environment> environments;
 
     public TestCommandInfo(String name) {
         this.name = name;
@@ -89,6 +91,15 @@
     }
 
     @Override
+    public Set<Environment> getEnvironments() {
+        return environments;
+    }
+
+    public void setAvailable(Set<Environment> environments) {
+        this.environments = environments;
+    }
+
+    @Override
     public List<String> getDependencyResourceNames() {
         return Collections.emptyList();
     }
--- a/vm-heap-analysis/distribution/thermostat-plugin.xml	Fri May 31 15:21:04 2013 +0200
+++ b/vm-heap-analysis/distribution/thermostat-plugin.xml	Fri May 31 12:15:17 2013 -0400
@@ -65,6 +65,10 @@
           <long>logLevel</long>
         </option>
       </options>
+      <environments>
+        <environment>cli</environment>
+        <environment>shell</environment>
+      </environments>
       <bundles>
         <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-heap-analysis-command-${project.version}.jar</bundle>
@@ -116,6 +120,10 @@
           <long>logLevel</long>
         </option>
       </options>
+      <environments>
+        <environment>cli</environment>
+        <environment>shell</environment>
+      </environments>
       <bundles>
         <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-heap-analysis-command-${project.version}.jar</bundle>
@@ -170,6 +178,10 @@
           <long>logLevel</long>
         </option>
       </options>
+      <environments>
+        <environment>cli</environment>
+        <environment>shell</environment>
+      </environments>
       <bundles>
         <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-heap-analysis-command-${project.version}.jar</bundle>
@@ -218,6 +230,10 @@
           <long>logLevel</long>
         </option>
       </options>
+      <environments>
+        <environment>cli</environment>
+        <environment>shell</environment>
+      </environments>
       <bundles>
         <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-heap-analysis-command-${project.version}.jar</bundle>
@@ -266,6 +282,10 @@
           <long>logLevel</long>
         </option>
       </options>
+      <environments>
+        <environment>cli</environment>
+        <environment>shell</environment>
+      </environments>
       <bundles>
         <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-heap-analysis-command-${project.version}.jar</bundle>
@@ -314,6 +334,10 @@
           <long>logLevel</long>
         </option>
       </options>
+      <environments>
+        <environment>cli</environment>
+        <environment>shell</environment>
+      </environments>
       <bundles>
         <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-heap-analysis-command-${project.version}.jar</bundle>
@@ -355,6 +379,10 @@
           <long>logLevel</long>
         </option>
       </options>
+      <environments>
+        <environment>cli</environment>
+        <environment>shell</environment>
+      </environments>
       <bundles>
         <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-heap-analysis-command-${project.version}.jar</bundle>
--- a/web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceCommand.java	Fri May 31 15:21:04 2013 +0200
+++ b/web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceCommand.java	Fri May 31 12:15:17 2013 -0400
@@ -91,11 +91,6 @@
         return false;
     }
 
-    @Override
-    public boolean isAvailableInShell() {
-    	return false;
-    }
-
     private List<HostPortPair> parseIPsPorts(String rawIpsPorts) throws CommandException {
         HostPortsParser parser = new HostPortsParser(rawIpsPorts);
         parser.parse();