changeset 1066:c8d427902c6b

Schema for plugin.xml files reviewed-by: neugens, omajid, jerboaa, vanaltj contributed-by: obryan review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-April/006307.html
author Mario Torre <neugens.limasoftware@gmail.com>
date Mon, 15 Apr 2013 15:45:04 +0200
parents ef9be67db1ad
children f0f0027e0724
files host-cpu/distribution/plugin.xml host-memory/distribution/plugin.xml host-overview/distribution/plugin.xml 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/PluginConfigurationParserTest.java numa/distribution/plugin.xml thread/distribution/plugin.xml vm-classstat/distribution/plugin.xml vm-cpu/distribution/plugin.xml vm-gc/distribution/plugin.xml vm-heap-analysis/distribution/plugin.xml vm-memory/distribution/plugin.xml vm-overview/distribution/plugin.xml
diffstat 14 files changed, 339 insertions(+), 254 deletions(-) [+]
line wrap: on
line diff
--- a/host-cpu/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/host-cpu/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,29 +36,31 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-host-cpu-common-${project.version}.jar</bundle>
         <bundle>thermostat-host-cpu-client-core-${project.version}.jar</bundle>
         <bundle>thermostat-host-cpu-client-swing-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>agent</name>
       <bundles>
         <bundle>thermostat-host-cpu-common-${project.version}.jar</bundle>
         <bundle>thermostat-host-cpu-agent-${project.version}.jar</bundle>
       </bundles>
-    </command>
+    </extension>
     <!-- Requires all storage entity classes to be loaded -->
-    <command type="extends">
+    <extension>
       <name>webservice</name>
       <bundles>
         <bundle>thermostat-host-cpu-common-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
-</plugin>
\ No newline at end of file
+    </extension>
+  </extensions>
+</plugin>
--- a/host-memory/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/host-memory/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,29 +36,31 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-host-memory-common-${project.version}.jar</bundle>
         <bundle>thermostat-host-memory-client-core-${project.version}.jar</bundle>
         <bundle>thermostat-host-memory-client-swing-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>agent</name>
       <bundles>
         <bundle>thermostat-host-memory-common-${project.version}.jar</bundle>
         <bundle>thermostat-host-memory-agent-${project.version}.jar</bundle>
       </bundles>
-    </command>
+    </extension>
     <!-- Requires all storage entity classes to be loaded -->
-    <command type="extends">
+    <extension>
       <name>webservice</name>
       <bundles>
         <bundle>thermostat-host-memory-common-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
-</plugin>
\ No newline at end of file
+    </extension>
+  </extensions>
+</plugin>
--- a/host-overview/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/host-overview/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,14 +36,16 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-host-overview-client-core-${project.version}.jar</bundle>
         <bundle>thermostat-host-overview-client-swing-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
-</plugin>
\ No newline at end of file
+    </extension>
+  </extensions>
+</plugin>
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfiguration.java	Mon Apr 08 17:06:45 2013 -0400
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfiguration.java	Mon Apr 15 15:45:04 2013 +0200
@@ -88,16 +88,15 @@
 
         private final String commandName;
         private final String description;
-        private final String usage;
+        private String usage;
         private final Options options;
         private final List<String> additionalResources;
         private final List<String> coreDeps;
 
-        public NewCommand(String name, String usage, String description,
+        public NewCommand(String name, String description,
                 Options options, List<String> additionalResources, List<String> coreDeps) {
             this.commandName = name;
             this.description = description;
-            this.usage = usage;
             this.options = options;
             this.additionalResources = additionalResources;
             this.coreDeps = coreDeps;
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java	Mon Apr 08 17:06:45 2013 -0400
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java	Mon Apr 15 15:45:04 2013 +0200
@@ -74,44 +74,115 @@
  * A example configuration looks like the following:
  *
  * <pre>
- * &lt;?xml version="1.0"?&gt;
- * &lt;plugin&gt;
- *   &lt;commands&gt;
- *     &lt;command type="extends"&gt;
- *       &lt;name&gt;gui&lt;/name&gt;
- *       &lt;bundles&gt;
- *         &lt;bundle&gt;hello-world-plugin-0.1-SNAPSHOT.jar&lt;/bundle&gt;
- *       &lt;/bundles&gt;
- *       &lt;dependencies&gt;
- *         &lt;dependency&gt;thermostat-client-core-0.6.0-SNAPSHOT.jar&lt;/dependency&gt;
- *       &lt;/dependencies&gt;
- *     &lt;/command&gt;
- *     &lt;command type="provides"&gt;
- *       &lt;name&gt;hello&lt;/name&gt;
- *       &lt;description&gt;print hello&lt;/description&gt;
- *       &lt;usage&gt;hello&lt;/usage&gt;
- *       &lt;options&gt;
- *         &lt;options&gt;
- *           &lt;long&gt;long&lt;/long&gt;
- *           &lt;short&gt;l&lt;/short&gt;
- *           &lt;hasArg&gt;true&lt;/hasArg&gt;
- *           &lt;required&gt;true&lt;/required&gt;
- *           &lt;description&gt;some required and long option&lt;/description&gt;
- *         &lt;/option&gt;
- *         &lt;options common="true"&gt;
- *           &lt;long&gt;dbUrl&lt;/long&gt;
- *           &lt;required&gt;true&lt;/required&gt;
- *         &lt;/option&gt;
- *       &lt;/options&gt;
- *       &lt;bundles&gt;
- *         &lt;bundle&gt;hello-world-plugin-0.1-SNAPSHOT.jar&lt;/bundle&gt;
- *       &lt;/bundles&gt;
- *       &lt;dependencies&gt;
- *         &lt;dependency&gt;thermostat-client-core-0.6.0-SNAPSHOT.jar&lt;/dependency&gt;
- *       &lt;/dependencies&gt;
- *     &lt;/command&gt;
- *   &lt;/commands&gt;
- * &lt;/plugin&gt;
+ * 
+&lt;?xml version="1.0" encoding="UTF-8"?&gt;
+&lt;plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0"&gt;
+  &lt;commands&gt;  
+    &lt;command&gt;
+      &lt;name&gt;platform&lt;/name&gt;
+      &lt;description&gt;launches a bare bone Platform Client&lt;/description&gt;
+      &lt;options&gt; 
+	&lt;group&gt;
+	  &lt;required&gt;true&lt;/required&gt;
+	  &lt;option&gt;
+	    &lt;long&gt;optA&lt;/long&gt;
+	    &lt;short&gt;a&lt;/short&gt;
+	    &lt;required&gt;true&lt;/required&gt;
+	  &lt;/option&gt;
+	  &lt;option&gt;
+	    &lt;long&gt;optB&lt;/long&gt;
+	    &lt;short&gt;b&lt;/short&gt;
+	    &lt;required&gt;true&lt;/required&gt;
+          &lt;/option&gt;
+	  &lt;option&gt;
+	    &lt;long&gt;optC&lt;/long&gt;
+	    &lt;short&gt;b&lt;/short&gt;	    
+	    &lt;required&gt;false&lt;/required&gt;
+	  &lt;/option&gt;
+	  &lt;option common="true"&gt;
+            &lt;long&gt;dbUrl&lt;/long&gt;
+          &lt;/option&gt;
+          &lt;option common="true"&gt;
+            &lt;long&gt;username&lt;/long&gt;
+          &lt;/option&gt;
+          &lt;option common="true"&gt;
+            &lt;long&gt;password&lt;/long&gt;
+          &lt;/option&gt;
+          &lt;option common="true"&gt;
+            &lt;long&gt;logLevel&lt;/long&gt;
+          &lt;/option&gt;
+	&lt;/group&gt;   
+	&lt;option&gt;
+	  &lt;long&gt;heapId&lt;/long&gt;
+	  &lt;short&gt;h&lt;/short&gt;
+	  &lt;argument&gt;heapArgument&lt;/argument&gt;
+	  &lt;required&gt;true&lt;/required&gt;
+	  &lt;description&gt;the ID of the heapdump to analyze&lt;/description&gt;
+	&lt;/option&gt;
+	&lt;option&gt;
+	  &lt;long&gt;limit&lt;/long&gt;
+	  &lt;short&gt;L&lt;/short&gt;
+	  &lt;argument&gt;limitArgument&lt;/argument&gt;
+	  &lt;required&gt;false&lt;/required&gt;
+	  &lt;description&gt;limit search to top N results, defaults to 10&lt;/description&gt;
+	&lt;/option&gt;
+      &lt;/options&gt;
+      &lt;bundles&gt;
+	&lt;bundle&gt;thermostat-platform-common-0.6.0-SNAPSHOT.jar&lt;/bundle&gt;
+	&lt;bundle&gt;thermostat-platform-swing-0.6.0-SNAPSHOT.jar&lt;/bundle&gt;
+      &lt;/bundles&gt;
+      &lt;dependencies&gt;
+	&lt;dependency&gt;thermostat-client-core-0.6.0-SNAPSHOT.jar&lt;/dependency&gt;
+      &lt;/dependencies&gt;
+    &lt;/command&gt;
+    &lt;command&gt;
+      &lt;name&gt;platform2&lt;/name&gt;
+      &lt;description&gt;launches a bare bone Platform Client&lt;/description&gt;
+       &lt;options&gt; 
+	&lt;option&gt;
+	  &lt;long&gt;heapId2&lt;/long&gt;
+	  &lt;short&gt;h&lt;/short&gt;
+	  &lt;argument&gt;heapId2Argument&lt;/argument&gt;
+	  &lt;required&gt;true&lt;/required&gt;
+	  &lt;description&gt;the ID of the heapdump to analyze&lt;/description&gt;
+	&lt;/option&gt;
+	&lt;option&gt;
+	  &lt;long&gt;limit2&lt;/long&gt;
+	  &lt;short&gt;L&lt;/short&gt;
+	  &lt;argument&gt;limit2Argument&lt;/argument&gt;
+	  &lt;required&gt;false&lt;/required&gt;
+	  &lt;description&gt;limit search to top N results, defaults to 10&lt;/description&gt;
+	&lt;/option&gt;
+      &lt;/options&gt;
+      &lt;bundles&gt;
+	&lt;bundle&gt;thermostat-platform-common-0.6.0-SNAPSHOT.jar&lt;/bundle&gt;
+	&lt;bundle&gt;thermostat-platform-controllers-0.6.0-SNAPSHOT.jar&lt;/bundle&gt;
+      &lt;/bundles&gt;
+      &lt;dependencies&gt;
+	&lt;dependency&gt;thermostat-common-core-0.6.0-SNAPSHOT.jar&lt;/dependency&gt;
+      &lt;/dependencies&gt;
+    &lt;/command&gt;
+  &lt;/commands&gt;
+  &lt;extensions&gt;
+    &lt;extension&gt;
+      &lt;name&gt;platform3&lt;/name&gt;
+      &lt;bundles&gt;
+        &lt;bundle&gt;thermostat-platform-common-0.6.0-SNAPSHOT.jar&lt;/bundle&gt;
+	&lt;bundle&gt;thermostat-platform-controllers-0.6.0-SNAPSHOT.jar&lt;/bundle&gt;
+	&lt;bundle&gt;thermostat-platform-command-0.6.0-SNAPSHOT.jar&lt;/bundle&gt;
+	&lt;bundle&gt;thermostat-platform-common-export-0.6.0-SNAPSHOT.jar&lt;/bundle&gt;
+	&lt;bundle&gt;thermostat-platform-swing-0.6.0-SNAPSHOT.jar&lt;/bundle&gt;
+      &lt;/bundles&gt;
+      &lt;dependencies&gt;
+	&lt;dependency&gt;thermostat-common-core-0.6.0-SNAPSHOT.jar&lt;/dependency&gt;
+	&lt;dependency&gt;thermostat-client-core-0.6.0-SNAPSHOT.jar&lt;/dependency&gt;
+      &lt;/dependencies&gt;
+    &lt;/extension&gt;
+  &lt;/extensions&gt;
+&lt;/plugin&gt;
+
  * </pre>
  * <p>
  * This class is thread-safe
@@ -144,49 +215,56 @@
     }
 
     private PluginConfiguration parseRootElement(String pluginName, Node root) {
-        List<NewCommand> newCommands = Collections.emptyList();
+        List<NewCommand> commands = Collections.emptyList();
         List<CommandExtensions> extensions = Collections.emptyList();
 
-        Pair<List<NewCommand>, List<CommandExtensions>> commands = new Pair<>(newCommands, extensions);
         if (root.getNodeName().equals("plugin")) {
             NodeList nodes = root.getChildNodes();
             for (int i = 0; i < nodes.getLength(); i++) {
                 Node node = nodes.item(i);
                 if (node.getNodeName().equals("commands")) {
                     commands = parseCommands(pluginName, node);
+                } else if (node.getNodeName().equals("extensions")) {
+                	extensions = parseExtensions(pluginName, node);
                 }
             }
         }
 
-        if (commands.getFirst().isEmpty() && commands.getSecond().isEmpty()) {
+        if (commands.isEmpty() && extensions.isEmpty()) {
             logger.warning("plugin " + pluginName + " does not extend any command or provide any new commands");
         }
 
-        return new PluginConfiguration(commands.getFirst(), commands.getSecond());
+        return new PluginConfiguration(commands, extensions);
     }
 
-    private Pair<List<NewCommand>, List<CommandExtensions>> parseCommands(String pluginName, Node commandsNode) {
+    private List<NewCommand> parseCommands(String pluginName, Node commandsNode) {
         List<NewCommand> newCommands = new ArrayList<NewCommand>();
-        List<CommandExtensions> extendedCommands = new ArrayList<CommandExtensions>();
         NodeList childNodes = commandsNode.getChildNodes();
         for (int i = 0; i < childNodes.getLength(); i++) {
             Node node = childNodes.item(i);
             if (node.getNodeName().equals("command")) {
-                String type = node.getAttributes().getNamedItem("type").getNodeValue();
-                if (type.equals("extends")) {
-                    CommandExtensions additions = parseAdditionsToExistingCommand(pluginName, node);
-                    if (additions != null) {
-                        extendedCommands.add(additions);
-                    }
-                } else if (type.equals("provides")) {
-                    NewCommand newCmd = parseNewCommand(pluginName, node);
-                    if (newCmd != null) {
-                        newCommands.add(newCmd);
-                    }
+                NewCommand newCmd = parseNewCommand(pluginName, node);
+                if (newCmd != null) {
+                    newCommands.add(newCmd);
                 }
             }
         }
-        return new Pair<>(newCommands, extendedCommands);
+        return newCommands;
+    }
+    
+    private List<CommandExtensions> parseExtensions(String pluginName, Node extensionsNode) {
+        List<CommandExtensions> commandExtensions = new ArrayList<CommandExtensions>();
+        NodeList childNodes = extensionsNode.getChildNodes();
+        for (int i = 0; i < childNodes.getLength(); i++) {
+            Node node = childNodes.item(i);
+            if (node.getNodeName().equals("extension")) {
+                CommandExtensions additions = parseAdditionsToExistingCommand(pluginName, node);
+                if (additions != null) {
+                    commandExtensions.add(additions);
+                }
+            }
+        }
+        return commandExtensions;
     }
 
     private CommandExtensions parseAdditionsToExistingCommand(String pluginName, Node commandNode) {
@@ -219,7 +297,6 @@
 
     private NewCommand parseNewCommand(String pluginName, Node commandNode) {
         String name = null;
-        String usage = null;
         String description = null;
         Options options = new Options();
         List<String> bundles = new ArrayList<>();
@@ -230,8 +307,6 @@
             Node node = nodes.item(i);
             if (node.getNodeName().equals("name")) {
                 name = node.getTextContent().trim();
-            } else if (node.getNodeName().equals("usage")) {
-                usage = node.getTextContent().trim();
             } else if (node.getNodeName().equals("description")) {
                 description = node.getTextContent().trim();
             } else if (node.getNodeName().equals("options")) {
@@ -250,12 +325,12 @@
             logger.warning("plugin " + pluginName  + " provides a new command " + name + " but lists no dependencies on thermostat");
         }
 
-        if (name == null || usage == null || description == null) {
+        if (name == null || description == null) {
             logger.warning("plugin " + pluginName + " provides an incomplete new command: " +
-                    "name='" + name + "', usage='" + usage + "', description='" + description + "', options='" + options + "'");
+                    "name='" + name + "', description='" + description + "', options='" + options + "'");
             return null;
         } else {
-            return new NewCommand(name, usage, description, options, bundles, dependencies);
+            return new NewCommand(name, description, options, bundles, dependencies);
         }
     }
 
@@ -376,7 +451,7 @@
             }
         }
 
-        logger.warning("The option " + longName != null ? longName : shortName + " claims to be a common option but isnt");
+        logger.warning("The option " + longName != null ? longName : shortName + " claims to be a common option but it isn't");
 
         return null;
     }
@@ -384,9 +459,9 @@
     private Option parseNormalOption(Node optionNode) {
         String longName = null;
         String shortName = null;
+        String argument = null;
         String description = null;
         boolean required = false;
-        boolean hasArg = false;
 
         NodeList nodes = optionNode.getChildNodes();
         for (int i = 0; i < nodes.getLength(); i++) {
@@ -395,16 +470,16 @@
                 longName = node.getTextContent().trim();
             } else if (node.getNodeName().equals("short")) {
                 shortName = node.getTextContent().trim();
+            } else if (node.getNodeName().equals("argument")) {
+                argument = node.getTextContent().trim();
             } else if (node.getNodeName().equals("description")) {
                 description = node.getTextContent().trim();
-            } else if (node.getNodeName().equals("hasArg")) {
-                hasArg = Boolean.valueOf(node.getTextContent().trim());
             } else if (node.getNodeName().equals("required")) {
                 required = Boolean.valueOf(node.getTextContent().trim());
             }
         }
 
-        Option opt = new Option(shortName, longName, hasArg, description);
+        Option opt = new Option(shortName, longName, Boolean.parseBoolean(argument), description);
         opt.setArgName(longName != null? longName : shortName);
         opt.setRequired(required);
         return opt;
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParserTest.java	Mon Apr 08 17:06:45 2013 -0400
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParserTest.java	Mon Apr 15 15:45:04 2013 +0200
@@ -85,8 +85,8 @@
     public void testConfigurationThatExtendsExistingCommand() throws UnsupportedEncodingException {
         String config = "<?xml version=\"1.0\"?>\n" +
                 "<plugin>\n" +
-                "  <commands>\n" +
-                "    <command type='extends'>\n" +
+                "  <extensions>\n" +
+                "    <extension>\n" +
                 "      <name>test</name>\n" +
                 "      <bundles>\n" +
                 "        <bundle>foo</bundle>\n" +
@@ -96,8 +96,8 @@
                 "      <dependencies>\n" +
                 "        <dependency>thermostat-foo</dependency>\n" +
                 "      </dependencies>\n" +
-                "    </command>\n" +
-                "  </commands>\n" +
+                "    </extension>\n" +
+                "  </extensions>\n" +
                 "</plugin>";
 
         PluginConfiguration result = new PluginConfigurationParser()
@@ -119,9 +119,8 @@
         String config = "<?xml version=\"1.0\"?>\n" +
                 "<plugin>\n" +
                 "  <commands>\n" +
-                "    <command type='provides'>\n" +
+                "    <command>\n" +
                 "      <name>test</name>\n" +
-                "      <usage>usage: test</usage>\n" +
                 "      <description>description</description>\n" +
                 "      <bundles>\n" +
                 "        <bundle>foo</bundle>\n" +
@@ -146,7 +145,6 @@
 
         NewCommand newCommand = newCommands.get(0);
         assertEquals("test", newCommand.getCommandName());
-        assertEquals("usage: test", newCommand.getUsage());
         assertEquals("description", newCommand.getDescription());
         Options opts = newCommand.getOptions();
         assertTrue(opts.getOptions().isEmpty());
@@ -159,8 +157,8 @@
     public void testSpacesAtStartAndEndAreTrimmed() throws UnsupportedEncodingException {
         String config = "<?xml version=\"1.0\"?>\n" +
                 "<plugin>\n" +
-                "  <commands>\n" +
-                "    <command type='extends'>\n" +
+                "  <extensions>" +
+                "    <extension>\n" +
                 "      <name>\ntest   \n</name>\n" +
                 "      <bundles>\n" +
                 "        <bundle>\n \t  \nfoo\t \n \n</bundle>\n" +
@@ -170,8 +168,8 @@
                 "      <dependencies>\n\t\n\t \t\t\n" +
                 "        <dependency>\t\t\t  thermostat-foo\n\t\t\n</dependency>\n" +
                 "      </dependencies>\n" +
-                "    </command>\n" +
-                "  </commands>\n" +
+                "    </extension>\n" +
+                "  </extensions>\n" +
                 "</plugin>";
 
         PluginConfiguration result = new PluginConfigurationParser()
@@ -193,24 +191,23 @@
         String config = "<?xml version=\"1.0\"?>\n" +
                 "<plugin>\n" +
                 "  <commands>\n" +
-                "    <command type='provides'>\n" +
+                "    <command>\n" +
                 "      <name>test</name>\n" +
                 "      <description>just a test</description>\n" +
-                "      <usage>test [ -a | -b ] -l &lt;foo&gt;</usage>\n" +
                 "      <options>\n" +
                 "        <group>\n" +
                 "          <required>true</required>\n" +
                 "          <option>\n" +
                 "            <long>exclusive-a</long>\n" +
                 "            <short>a</short>\n" +
-                "            <hasArg>false</hasArg>\n" +
+                "            <argument>false</argument>\n" +
                 "            <required>false</required>\n" +
                 "            <description>exclusive option a</description>\n" +
                 "          </option>\n" +
                 "          <option>\n" +
                 "            <long>exclusive-b</long>\n" +
                 "            <short>b</short>\n" +
-                "            <hasArg>false</hasArg>\n" +
+                "            <argument>false</argument>\n" +
                 "            <required>false</required>\n" +
                 "            <description>exclusive option b</description>\n" +
                 "          </option>\n" +
@@ -218,7 +215,7 @@
                 "        <option>\n" +
                 "          <long>long</long>\n" +
                 "          <short>l</short>\n" +
-                "          <hasArg>true</hasArg>\n" +
+                "          <argument>true</argument>\n" +
                 "          <required>true</required>\n" +
                 "          <description>some required and long option</description>\n" +
                 "        </option>\n" +
@@ -238,7 +235,6 @@
         NewCommand command = newCommands.get(0);
         assertEquals("test", command.getCommandName());
         assertEquals("just a test", command.getDescription());
-        assertEquals("test [ -a | -b ] -l <foo>", command.getUsage());
         Options opts = command.getOptions();
         assertNull(opts.getOption("foobarbaz"));
 
@@ -268,10 +264,9 @@
         String config = "<?xml version=\"1.0\"?>\n" +
                 "<plugin>\n" +
                 "  <commands>\n" +
-                "    <command type='provides'>\n" +
+                "    <command>\n" +
                 "      <name>test</name>\n" +
                 "      <description>just a test</description>\n" +
-                "      <usage>test [ -a | -b ] -l &lt;foo&gt;</usage>\n" +
                 "      <options>\n" +
                 "        <option common=\"true\">\n" +
                 "          <long>dbUrl</long>\n" +
@@ -313,10 +308,9 @@
         String config = "<?xml version=\"1.0\"?>\n" +
                 "<plugin>\n" +
                 "  <commands>\n" +
-                "    <command type='provides'>\n" +
+                "    <command>\n" +
                 "      <name>test</name>\n" +
                 "      <description>just a test</description>\n" +
-                "      <usage>test [ -a | -b ] -l &lt;foo&gt;</usage>\n" +
                 "      <options>\n" +
                 "        <option common=\"true\">\n" +
                 "          <long>foobarbaz</long>\n" +
--- a/numa/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/numa/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,29 +36,31 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-numa-common-${project.version}.jar</bundle>
         <bundle>thermostat-numa-client-core-${project.version}.jar</bundle>
         <bundle>thermostat-numa-client-swing-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>agent</name>
       <bundles>
         <bundle>thermostat-numa-common-${project.version}.jar</bundle>
         <bundle>thermostat-numa-agent-${project.version}.jar</bundle>
       </bundles>
-    </command>
+    </extension>
     <!-- Requires all storage entity classes to be loaded -->
-    <command type="extends">
+    <extension>
       <name>webservice</name>
       <bundles>
         <bundle>thermostat-numa-common-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
-</plugin>
\ No newline at end of file
+    </extension>
+  </extensions>
+</plugin>
--- a/thread/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/thread/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,9 +36,11 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-thread-collector-${project.version}.jar</bundle>
@@ -46,20 +48,20 @@
         <bundle>thermostat-thread-client-controllers-${project.version}.jar</bundle>
         <bundle>thermostat-thread-client-common-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>agent</name>
       <bundles>
         <bundle>thermostat-thread-collector-${project.version}.jar</bundle>
         <bundle>thermostat-thread-harvester-${project.version}.jar</bundle>
       </bundles>
-    </command>
+    </extension>
     <!-- Requires all storage entity classes to be loaded -->
-    <command type="extends">
+    <extension>
       <name>webservice</name>
       <bundles>
         <bundle>thermostat-thread-collector-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
-</plugin>
\ No newline at end of file
+    </extension>
+  </extensions>
+</plugin>
--- a/vm-classstat/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/vm-classstat/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,30 +36,32 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-vm-classstat-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-classstat-client-core-${project.version}.jar</bundle>
         <bundle>thermostat-vm-classstat-client-swing-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>agent</name>
       <bundles>
         <bundle>thermostat-vm-classstat-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-classstat-agent-${project.version}.jar</bundle>
       </bundles>
-    </command>
+    </extension>
     <!-- Requires all storage entity classes to be loaded -->
-    <command type="extends">
+    <extension>
       <name>webservice</name>
       <bundles>
         <bundle>thermostat-vm-classstat-common-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
+    </extension>
+  </extensions>
   <!-- TODO: Need to express dependency on vm-memory-common -->
-</plugin>
\ No newline at end of file
+</plugin>
--- a/vm-cpu/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/vm-cpu/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,36 +36,38 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-vm-cpu-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-cpu-client-core-${project.version}.jar</bundle>
         <bundle>thermostat-vm-cpu-client-swing-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>agent</name>
       <bundles>
         <bundle>thermostat-vm-cpu-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-cpu-agent-${project.version}.jar</bundle>
       </bundles>
-    </command>
+    </extension>
     <!-- Requires all storage entity classes to be loaded -->
-    <command type="extends">
+    <extension>
       <name>webservice</name>
       <bundles>
         <bundle>thermostat-vm-cpu-common-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>vm-stat</name>
       <bundles>
         <bundle>thermostat-vm-cpu-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-cpu-client-cli-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
-</plugin>
\ No newline at end of file
+    </extension>
+  </extensions>
+</plugin>
--- a/vm-gc/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/vm-gc/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,9 +36,11 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-vm-gc-common-${project.version}.jar</bundle>
@@ -48,8 +50,8 @@
         <bundle>thermostat-gc-remote-collector-client-common-${project.version}.jar</bundle>
         <bundle>thermostat-gc-remote-collector-client-swing-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>agent</name>
       <bundles>
         <bundle>thermostat-vm-gc-common-${project.version}.jar</bundle>
@@ -57,14 +59,14 @@
         <bundle>thermostat-gc-remote-collector-common-${project.version}.jar</bundle>
         <bundle>thermostat-gc-remote-collector-command-${project.version}.jar</bundle>
       </bundles>
-    </command>
+    </extension>
     <!-- Requires all storage entity classes to be loaded -->
-    <command type="extends">
+    <extension>
       <name>webservice</name>
       <bundles>
         <bundle>thermostat-vm-gc-common-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
+    </extension>
+  </extensions>
   <!-- TODO: Need to express dependency on vm-memory-common -->
-</plugin>
\ No newline at end of file
+</plugin>
--- a/vm-heap-analysis/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/vm-heap-analysis/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,47 +36,25 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
   <commands>
-    <command type="extends">
-      <name>gui</name>
-      <bundles>
-        <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
-        <bundle>thermostat-vm-heap-analysis-command-${project.version}.jar</bundle>
-        <bundle>thermostat-vm-heap-analysis-client-core-${project.version}.jar</bundle>
-        <bundle>thermostat-vm-heap-analysis-client-swing-${project.version}.jar</bundle>
-      </bundles>
-    </command>
-    <command type="extends">
-      <name>agent</name>
-      <bundles>
-        <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
-        <bundle>thermostat-vm-heap-analysis-agent-${project.version}.jar</bundle>
-      </bundles>
-    </command>
-    <!-- Requires all storage entity classes to be loaded -->
-    <command type="extends">
-      <name>webservice</name>
-      <bundles>
-        <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
-      </bundles>
-    </command>
-    <command type="provides">
+    <command>
       <name>dump-heap</name>
       <description>trigger a heap dump on the VM</description>
-      <usage>dump-heap --hostId &lt;host&gt; --vmId &lt;vm&gt; [-d &lt;url&gt; [-u &lt;user&gt; -p &lt;password&gt;]] [-l &lt;level&gt;]</usage>
       <options>
         <option>
+          <long>hostId</long>
           <short>a</short>
-          <long>hostId</long>
-          <hasArg>true</hasArg>
+          <argument>true</argument>
           <required>true</required>
           <description>the ID of the host to monitor</description>
         </option>
         <option>
+          <long>vmId</long>
           <short>v</short>
-          <long>vmId</long>
-          <hasArg>true</hasArg>
+          <argument>true</argument>
           <required>true</required>
           <description>the ID of the VM to monitor</description>
         </option>
@@ -116,22 +94,21 @@
         <dependency>netty.jar</dependency>
       </dependencies>
     </command>
-    <command type="provides">
+    <command>
       <name>find-objects</name>
       <description>finds objects in a heapdump</description>
-      <usage>find-objects [-d &lt;url&gt; [-u &lt;user&gt; -p &lt;password&gt;]] [-l &lt;level&gt;] --heapId &lt;id&gt; --limit &lt;limit&gt; &lt;pattern&gt;</usage>
       <options>
         <option>
+          <long>heapId</long>
           <short>h</short>
-          <long>heapId</long>
-          <hasArg>true</hasArg>
+          <argument>true</argument>
           <required>true</required>
           <description>the ID of the heapdump to analyze</description>
         </option>
         <option>
-          <short>L</short>
           <long>limit</long>
-          <hasArg>true</hasArg>
+          <short>L</short>          
+          <argument>true</argument>
           <required>false</required>
           <description>limit search to top N results, defaults to 10</description>
         </option>
@@ -171,29 +148,28 @@
         <dependency>netty.jar</dependency>
       </dependencies>
     </command>
-    <command type="provides">
+    <command>
       <name>find-root</name>
       <description>finds the shortest path from an object to a GC root</description>
-      <usage>find-root --heapId &lt;heap&gt; --objectId &lt;object&gt; [-a] [-d &lt;url&gt; [-u &lt;user&gt; -p &lt;password&gt;]] [-l &lt;level&gt;]</usage>
       <options>
         <option>
-          <short>h</short>
           <long>heapId</long>
-          <hasArg>true</hasArg>
+          <short>h</short>          
+          <argument>true</argument>
           <required>true</required>
           <description>the ID of the heapdump to analyze</description>
         </option>
         <option>
-          <short>o</short>
           <long>objectId</long>
-          <hasArg>true</hasArg>
+          <short>o</short>          
+          <argument>true</argument>
           <required>true</required>
           <description>the ID of the object to query</description>
         </option>
         <option>
-          <short>a</short>
           <long>all</long>
-          <hasArg>false</hasArg>
+          <short>a</short>          
+          <argument>false</argument>
           <required>false</required>
           <description>finds all paths to GC roots</description>
         </option>
@@ -233,22 +209,21 @@
         <dependency>netty.jar</dependency>
       </dependencies>
     </command>
-    <command type="provides">
+    <command>
       <name>list-heap-dumps</name>
       <description>list all heap dumps</description>
-      <usage>list-heap-dumps [--hostId &lt;host&gt;] [--vmId &lt;vm&gt;] [-d &lt;url&gt; [-u &lt;user&gt; -p &lt;password&gt;]] [-l &lt;level&gt;]</usage>
       <options>
         <option>
-          <short>a</short>
           <long>hostId</long>
-          <hasArg>true</hasArg>
+          <short>a</short>          
+          <argument>true</argument>
           <required>false</required>
           <description>the ID of the host to monitor</description>
         </option>
         <option>
-          <short>v</short>
           <long>vmId</long>
-          <hasArg>true</hasArg>
+          <short>v</short>          
+          <argument>true</argument>
           <required>false</required>
           <description>the ID of the VM to monitor</description>
         </option>
@@ -288,22 +263,21 @@
         <dependency>netty.jar</dependency>
       </dependencies>
     </command>
-    <command type="provides">
+    <command>
       <name>object-info</name>
       <description>prints information about an object in a heap dump</description>
-      <usage>object-info --heapId &lt;heap&gt; --objectId &lt;object&gt; [-d &lt;url&gt; [-u &lt;user&gt; -p &lt;password&gt;]] [-l &lt;level&gt;]</usage>
       <options>
         <option>
-          <short>h</short>
           <long>heapId</long>
-          <hasArg>true</hasArg>
+          <short>h</short>         
+          <argument>true</argument>
           <required>true</required>
           <description>the ID of the heapdump to analyze</description>
         </option>
         <option>
-          <short>o</short>
           <long>objectId</long>
-          <hasArg>true</hasArg>
+          <short>o</short>          
+          <argument>true</argument>
           <required>true</required>
           <description>the ID of the object to query</description>
         </option>
@@ -343,22 +317,21 @@
         <dependency>netty.jar</dependency>
       </dependencies>
     </command>
-    <command type="provides">
+    <command>
       <name>save-heap-dump-to-file</name>
       <description>saves a heap dump to a local file</description>
-      <usage>save-heap-dump-to-file --heapId &lt;heap&gt; --file &lt;filename&gt; [-d &lt;url&gt; [-u &lt;user&gt; -p &lt;password&gt;]] [-l &lt;level&gt;]</usage>
       <options>
         <option>
-          <short>h</short>
           <long>heapId</long>
-          <hasArg>true</hasArg>
+          <short>h</short>          
+          <argument>true</argument>
           <required>true</required>
           <description>the ID of the heapdump to analyze</description>
         </option>
         <option>
-          <short>f</short>
           <long>file</long>
-          <hasArg>true</hasArg>
+          <short>f</short>          
+          <argument>true</argument>
           <required>true</required>
           <description>the file name to save to</description>
         </option>
@@ -398,15 +371,14 @@
         <dependency>netty.jar</dependency>
       </dependencies>
     </command>
-    <command type="provides">
+    <command>
       <name>show-heap-histogram</name>
       <description>show the heap histogram</description>
-      <usage>show-heap-histogram --heapId &lt;heap&gt; [-d &lt;url&gt; [-u &lt;user&gt; -p &lt;password&gt;]] [-l &lt;level&gt;]</usage>
       <options>
         <option>
-          <short>h</short>
           <long>heapId</long>
-          <hasArg>true</hasArg>
+          <short>h</short>          
+          <argument>true</argument>
           <required>true</required>
           <description>the ID of the heapdump to analyze</description>
         </option>
@@ -447,4 +419,29 @@
       </dependencies>
     </command>
   </commands>
-</plugin>
\ No newline at end of file
+  <extensions>
+    <extension>
+      <name>gui</name>
+      <bundles>
+        <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
+        <bundle>thermostat-vm-heap-analysis-command-${project.version}.jar</bundle>
+        <bundle>thermostat-vm-heap-analysis-client-core-${project.version}.jar</bundle>
+        <bundle>thermostat-vm-heap-analysis-client-swing-${project.version}.jar</bundle>
+      </bundles>
+    </extension>
+    <extension>
+      <name>agent</name>
+      <bundles>
+        <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
+        <bundle>thermostat-vm-heap-analysis-agent-${project.version}.jar</bundle>
+      </bundles>
+    </extension>
+    <!-- Requires all storage entity classes to be loaded -->
+    <extension>
+      <name>webservice</name>
+      <bundles>
+        <bundle>thermostat-vm-heap-analysis-common-${project.version}.jar</bundle>
+      </bundles>
+    </extension>
+  </extensions>
+</plugin>
--- a/vm-memory/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/vm-memory/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,37 +36,39 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-vm-memory-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-memory-client-core-${project.version}.jar</bundle>
         <bundle>thermostat-vm-memory-client-swing-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>agent</name>
       <bundles>
         <bundle>thermostat-vm-memory-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-memory-agent-${project.version}.jar</bundle>
       </bundles>
-    </command>
+    </extension>
     <!-- Requires all storage entity classes to be loaded -->
-    <command type="extends">
+    <extension>
       <name>webservice</name>
       <bundles>
         <bundle>thermostat-vm-memory-common-${project.version}.jar</bundle>
       </bundles>
-    </command>
-    <command type="extends">
+    </extension>
+    <extension>
       <name>vm-stat</name>
       <bundles>
         <bundle>thermostat-vm-memory-common-${project.version}.jar</bundle>
         <bundle>thermostat-vm-memory-client-cli-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
+    </extension>
+  </extensions>
   <!-- TODO: Express dependency on remote GC bundles -->
-</plugin>
\ No newline at end of file
+</plugin>
--- a/vm-overview/distribution/plugin.xml	Mon Apr 08 17:06:45 2013 -0400
+++ b/vm-overview/distribution/plugin.xml	Mon Apr 15 15:45:04 2013 +0200
@@ -36,14 +36,16 @@
  to do so, delete this exception statement from your version.
 
 -->
-<plugin>
-  <commands>
-    <command type="extends">
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0">
+  <extensions>
+    <extension>
       <name>gui</name>
       <bundles>
         <bundle>thermostat-vm-overview-client-core-${project.version}.jar</bundle>
         <bundle>thermostat-vm-overview-client-swing-${project.version}.jar</bundle>
       </bundles>
-    </command>
-  </commands>
-</plugin>
\ No newline at end of file
+    </extension>
+  </extensions>
+</plugin>