changeset 77:dab60717f61d

Use tycho to build
author Omair Majid <omajid@redhat.com>
date Thu, 16 Jan 2014 11:09:13 -0500
parents 4d2f29046e97
children b788a26c0d4d
files .classpath .hgignore .project .settings/org.eclipse.jdt.core.prefs META-INF/MANIFEST.MF build.properties com.redhat.thermostat.plugin.eclipse.plugin/META-INF/MANIFEST.MF com.redhat.thermostat.plugin.eclipse.plugin/build.properties com.redhat.thermostat.plugin.eclipse.plugin/icons/thermostat.png com.redhat.thermostat.plugin.eclipse.plugin/plugin.xml com.redhat.thermostat.plugin.eclipse.plugin/pom.xml com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/Activator.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/BundleInformationExtractor.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/BaseMasterDetailsBlock.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/CommandEditPage.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/CommandsMasterDetailsBlock.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/CommandsPage.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/ExtensionEditPage.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/ExtensionsMasterDetailsBlock.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/ExtensionsPage.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/MultiPageEditor.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/MultiPageEditorContributor.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/NewBundleDialog.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/NewNameDialog.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/OverviewPage.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Bundle.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Command.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Environments.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Extension.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/ModelObject.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Option.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Plugin.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/PluginModelReaderWriter.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/package-info.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/PluginXmlCreationWizard.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/PluginXmlProjectSelectionPage.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/ThermostatProjectCreationWizard.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/ThermostatProjectCreationWizardPage.java com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/ThermostatProjectCreationWizardPageTwo.java com.redhat.thermostat.plugin.eclipse.plugin/test/com/redhat/thermostat/plugin/eclipse/model/CommandTest.java com.redhat.thermostat.plugin.eclipse.plugin/test/com/redhat/thermostat/plugin/eclipse/model/EnvironmentsTest.java com.redhat.thermostat.plugin.eclipse.plugin/test/com/redhat/thermostat/plugin/eclipse/model/PluginModelReaderWriterTest.java com.redhat.thermostat.plugin.eclipse.plugin/test/com/redhat/thermostat/plugin/eclipse/model/PropertyChangeRecorder.java icons/thermostat.png plugin.xml pom.xml src/com/redhat/thermostat/plugin/eclipse/Activator.java src/com/redhat/thermostat/plugin/eclipse/BundleInformationExtractor.java src/com/redhat/thermostat/plugin/eclipse/editor/BaseMasterDetailsBlock.java src/com/redhat/thermostat/plugin/eclipse/editor/CommandEditPage.java src/com/redhat/thermostat/plugin/eclipse/editor/CommandsMasterDetailsBlock.java src/com/redhat/thermostat/plugin/eclipse/editor/CommandsPage.java src/com/redhat/thermostat/plugin/eclipse/editor/ExtensionEditPage.java src/com/redhat/thermostat/plugin/eclipse/editor/ExtensionsMasterDetailsBlock.java src/com/redhat/thermostat/plugin/eclipse/editor/ExtensionsPage.java src/com/redhat/thermostat/plugin/eclipse/editor/MultiPageEditor.java src/com/redhat/thermostat/plugin/eclipse/editor/MultiPageEditorContributor.java src/com/redhat/thermostat/plugin/eclipse/editor/NewBundleDialog.java src/com/redhat/thermostat/plugin/eclipse/editor/NewNameDialog.java src/com/redhat/thermostat/plugin/eclipse/editor/OverviewPage.java src/com/redhat/thermostat/plugin/eclipse/model/Bundle.java src/com/redhat/thermostat/plugin/eclipse/model/Command.java src/com/redhat/thermostat/plugin/eclipse/model/Environments.java src/com/redhat/thermostat/plugin/eclipse/model/Extension.java src/com/redhat/thermostat/plugin/eclipse/model/ModelObject.java src/com/redhat/thermostat/plugin/eclipse/model/Option.java src/com/redhat/thermostat/plugin/eclipse/model/Plugin.java src/com/redhat/thermostat/plugin/eclipse/model/PluginModelReaderWriter.java src/com/redhat/thermostat/plugin/eclipse/model/package-info.java src/com/redhat/thermostat/plugin/eclipse/wizards/PluginXmlCreationWizard.java src/com/redhat/thermostat/plugin/eclipse/wizards/PluginXmlProjectSelectionPage.java src/com/redhat/thermostat/plugin/eclipse/wizards/ThermostatProjectCreationWizard.java src/com/redhat/thermostat/plugin/eclipse/wizards/ThermostatProjectCreationWizardPage.java src/com/redhat/thermostat/plugin/eclipse/wizards/ThermostatProjectCreationWizardPageTwo.java test/com/redhat/thermostat/plugin/eclipse/model/CommandTest.java test/com/redhat/thermostat/plugin/eclipse/model/EnvironmentsTest.java test/com/redhat/thermostat/plugin/eclipse/model/PluginModelReaderWriterTest.java test/com/redhat/thermostat/plugin/eclipse/model/PropertyChangeRecorder.java
diffstat 78 files changed, 3218 insertions(+), 3163 deletions(-) [+]
line wrap: on
line diff
--- a/.classpath	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
-	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="src" path="test"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>
--- a/.hgignore	Mon Jan 06 18:44:28 2014 -0500
+++ b/.hgignore	Thu Jan 16 11:09:13 2014 -0500
@@ -1,1 +1,1 @@
-bin/
+/target
--- a/.project	Mon Jan 06 18:44:28 2014 -0500
+++ b/.project	Thu Jan 16 11:09:13 2014 -0500
@@ -1,28 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-	<name>eclipse-plugin-thermostat</name>
+	<name>com.redhat.thermostat.plugin.eclipse.parent</name>
 	<comment></comment>
 	<projects>
 	</projects>
 	<buildSpec>
 		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>org.eclipse.pde.ManifestBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>org.eclipse.pde.SchemaBuilder</name>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
 			<arguments>
 			</arguments>
 		</buildCommand>
 	</buildSpec>
 	<natures>
-		<nature>org.eclipse.pde.PluginNature</nature>
-		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
 	</natures>
 </projectDescription>
--- a/.settings/org.eclipse.jdt.core.prefs	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
-org.eclipse.jdt.core.compiler.compliance=1.7
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.7
--- a/META-INF/MANIFEST.MF	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-Manifest-Version: 1.0
-Bundle-ManifestVersion: 2
-Bundle-Name: com.redhat.thermostat.plugin.eclipse
-Bundle-SymbolicName: com.redhat.thermostat.plugin.eclipse;
- singleton:=true
-Bundle-Version: 1.0.0.qualifier
-Bundle-Activator: com.redhat.thermostat.plugin.eclipse.Activator
-Require-Bundle: org.eclipse.ui,
- org.eclipse.core.runtime,
- org.eclipse.jface.text,
- org.eclipse.ui.editors,
- org.eclipse.core.resources,
- org.eclipse.ui.ide,
- org.eclipse.jdt;bundle-version="3.9.0",
- org.eclipse.jdt.launching,
- org.eclipse.jdt.core;bundle-version="3.9.0",
- org.eclipse.ui.forms;bundle-version="3.6.0",
- org.eclipse.wst.sse.ui;bundle-version="1.3.200",
- org.junit;bundle-version="4.10.0",
- org.eclipse.core.databinding,
- org.eclipse.core.databinding.beans,
- org.eclipse.core.databinding.observable,
- org.eclipse.core.databinding.property,
- org.eclipse.jface.databinding,
- com.ibm.icu
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Bundle-ActivationPolicy: lazy
--- a/build.properties	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = plugin.xml,\
-               META-INF/,\
-               .,\
-               icons/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/META-INF/MANIFEST.MF	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,27 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: com.redhat.thermostat.plugin.eclipse.plugin
+Bundle-SymbolicName: com.redhat.thermostat.plugin.eclipse.plugin;
+ singleton:=true
+Bundle-Version: 0.1.0.qualifier
+Bundle-Activator: com.redhat.thermostat.plugin.eclipse.plugin.Activator
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.jface.text,
+ org.eclipse.ui.editors,
+ org.eclipse.core.resources,
+ org.eclipse.ui.ide,
+ org.eclipse.jdt;bundle-version="3.9.0",
+ org.eclipse.jdt.launching,
+ org.eclipse.jdt.core;bundle-version="3.9.0",
+ org.eclipse.ui.forms;bundle-version="3.6.0",
+ org.eclipse.wst.sse.ui;bundle-version="1.3.200",
+ org.junit;bundle-version="4.10.0",
+ org.eclipse.core.databinding,
+ org.eclipse.core.databinding.beans,
+ org.eclipse.core.databinding.observable,
+ org.eclipse.core.databinding.property,
+ org.eclipse.jface.databinding,
+ com.ibm.icu
+Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-ActivationPolicy: lazy
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/build.properties	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = plugin.xml,\
+               META-INF/,\
+               .,\
+               icons/
Binary file com.redhat.thermostat.plugin.eclipse.plugin/icons/thermostat.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/plugin.xml	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+   <extension
+         point="org.eclipse.ui.editors">
+      <editor
+            class="com.redhat.thermostat.plugin.eclipse.plugin.editor.MultiPageEditor"
+            contributorClass="com.redhat.thermostat.plugin.eclipse.plugin.editor.MultiPageEditorContributor"
+            extensions="xml"
+            icon="icons/thermostat.png"
+            id="thermostatplugin.editors.MultiPageEditor"
+            name="Thermostat Plugin Editor">
+         <contentTypeBinding
+               contentTypeId="com.redhat.thermostat.plugin.eclipse.plugin.xml">
+         </contentTypeBinding>
+      </editor>
+   </extension>
+   
+   <extension
+         point="org.eclipse.ui.newWizards">
+      <category
+            name="Thermostat"
+            id="com.redhat.thermostat.plugin.eclipse.plugin">
+      </category>
+      <wizard
+            name="Thermostat Plugin Projects"
+            icon="icons/thermostat.png"
+            category="com.redhat.thermostat.plugin.eclipse.plugin"
+            class="com.redhat.thermostat.plugin.eclipse.plugin.wizards.ThermostatProjectCreationWizard"
+            id="thermostatplugin.wizards.CreateNewThermostatPluginWizard">
+      </wizard>
+      <wizard
+            category="com.redhat.thermostat.plugin.eclipse.plugin"
+            class="com.redhat.thermostat.plugin.eclipse.plugin.wizards.PluginXmlCreationWizard"
+            icon="icons/thermostat.png"
+            id="com.redhat.thermostat.plugin.eclipse.plugin.wizards.PluginXmlCreationWizard"
+            name="Thermostat Plugin Descriptor"
+            project="false">
+      </wizard>
+   </extension>
+   <extension
+         id="com.redhat.thermostat.eclipse.plugin.contenttypes"
+         point="org.eclipse.core.contenttype.contentTypes">
+      <content-type
+            base-type="org.eclipse.core.runtime.xml"
+            file-names="thermostat-plugin.xml"
+            id="com.redhat.thermostat.plugin.eclipse.plugin.xml"
+            name="Thermostat Plugin XML"
+            priority="high">
+         <describer
+               class="org.eclipse.core.runtime.content.XMLRootElementContentDescriber2">
+            <parameter
+                  name="element"
+                  value="{http://icedtea.classpath.org/thermostat/plugins/v1.0}plugin">
+            </parameter>
+         </describer>
+      </content-type>
+   </extension>
+
+</plugin>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/pom.xml	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+			http://maven.apache.org/xsd/maven-4.0.0.xsd"
+    xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.redhat.thermostat.plugin.eclipse</groupId>
+    <artifactId>com.redhat.thermostat.plugin.eclipse.parent</artifactId>
+    <version>0.1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>com.redhat.thermostat.plugin.eclipse.plugin</artifactId>
+  <packaging>eclipse-plugin</packaging>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/Activator.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,61 @@
+package com.redhat.thermostat.plugin.eclipse.plugin;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+    // The plug-in ID
+    public static final String PLUGIN_ID = "com.redhat.thermostat.plugin.eclipse.plugin"; //$NON-NLS-1$
+
+    // The shared instance
+    private static Activator plugin;
+    
+    /**
+     * The constructor
+     */
+    public Activator() {
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+     */
+    public void start(BundleContext context) throws Exception {
+        super.start(context);
+        plugin = this;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+     */
+    public void stop(BundleContext context) throws Exception {
+        plugin = null;
+        super.stop(context);
+    }
+
+    /**
+     * Returns the shared instance
+     *
+     * @return the shared instance
+     */
+    public static Activator getDefault() {
+        return plugin;
+    }
+
+    /**
+     * Returns an image descriptor for the image file at the given
+     * plug-in relative path
+     *
+     * @param path the path
+     * @return the image descriptor
+     */
+    public static ImageDescriptor getImageDescriptor(String path) {
+        return imageDescriptorFromPlugin(PLUGIN_ID, path);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/BundleInformationExtractor.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,24 @@
+package com.redhat.thermostat.plugin.eclipse.plugin;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Bundle;
+
+public class BundleInformationExtractor {
+
+    public Bundle extract(String path) throws FileNotFoundException, IOException {
+
+        try (JarInputStream in = new JarInputStream(new FileInputStream(path))) {
+            Attributes attr = in.getManifest().getMainAttributes();
+            String name = attr.getValue("Bundle-SymbolicName");
+            String version = attr.getValue("Bundle-Version");
+
+            return new Bundle(name, version);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/BaseMasterDetailsBlock.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,116 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.MasterDetailsBlock;
+import org.eclipse.ui.forms.SectionPart;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Section;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Plugin;
+
+public abstract class BaseMasterDetailsBlock extends MasterDetailsBlock {
+
+    protected Plugin model;
+
+    public void setModel(Plugin model) {
+        this.model = model;
+    }
+
+    @Override
+    protected void createToolBarActions(IManagedForm managedForm) {
+        // no-op
+    }
+
+    @Override
+    protected void createMasterPart(final IManagedForm managedForm, final Composite parent) {
+        FormToolkit toolkit = managedForm.getToolkit();
+        final Section section = toolkit.createSection(parent, Section.TITLE_BAR);
+        section.setText(getSectionTitle());
+
+        final SectionPart sectionPart = new SectionPart(section);
+
+        Composite sectionContents = toolkit.createComposite(section);
+        GridLayout layout = new GridLayout(2, false);
+        sectionContents.setLayout(layout);
+
+        section.setClient(sectionContents);
+
+        Table list = toolkit.createTable(sectionContents, SWT.BORDER | SWT.V_SCROLL);
+        list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        final TableViewer viewer = new TableViewer(list);
+        viewer.addSelectionChangedListener(new ISelectionChangedListener() {
+            @Override
+            public void selectionChanged(SelectionChangedEvent event) {
+                managedForm.fireSelectionChanged(sectionPart, event.getSelection());
+            }
+        });
+        IStructuredContentProvider contentProvider = ArrayContentProvider.getInstance();
+        viewer.setContentProvider(contentProvider);
+        viewer.setInput(getListViewModel());
+        model.addPropertyChangeListener(new PropertyChangeListener() {
+            @Override
+            public void propertyChange(PropertyChangeEvent arg0) {
+                viewer.setInput(getListViewModel());
+                viewer.refresh();
+            }
+        });
+
+        Composite buttons = toolkit.createComposite(sectionContents);
+        GridData buttonCompositeLayoutData = new GridData(SWT.FILL, SWT.FILL, false, true);
+        buttonCompositeLayoutData.verticalAlignment = SWT.BEGINNING;
+        buttons.setLayoutData(buttonCompositeLayoutData);
+
+        buttons.setLayout(new GridLayout(1, false));
+        GridData buttonLayoutData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
+
+        Button add = toolkit.createButton(buttons, "Add", SWT.NONE);
+        add.setLayoutData(buttonLayoutData);
+        add.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                addButtonSelected(parent.getShell());
+
+                Object lastElement = viewer.getElementAt(viewer.getTable().getItemCount() - 1);
+                viewer.setSelection(new StructuredSelection(lastElement));
+            }
+
+        });
+
+        Button remove = toolkit.createButton(buttons, "Remove", SWT.NONE);
+        remove.setLayoutData(buttonLayoutData);
+        remove.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                Object selectedItem = ((IStructuredSelection)viewer.getSelection()).getFirstElement();
+                removeButtonSelected(selectedItem);
+            }
+        });
+    }
+
+    abstract String getSectionTitle();
+
+    abstract Object[] getListViewModel();
+
+    abstract void addButtonSelected(Shell shell);
+
+    abstract void removeButtonSelected(Object selectedItem);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/CommandEditPage.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,274 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.IDetailsPage;
+import org.eclipse.ui.forms.IFormPart;
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.editor.FormPage;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Section;
+import org.eclipse.ui.forms.widgets.TableWrapData;
+import org.eclipse.ui.forms.widgets.TableWrapLayout;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Bundle;
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Command;
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Environments;
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Plugin;
+
+class CommandEditPage implements IDetailsPage {
+
+    private FormToolkit toolkit;
+    private Plugin model;
+    private boolean isStale = false;
+
+    private Command commandModel;
+
+    private Text commandName;
+    private Text commandUsage;
+    private Text commandDescription;
+    private Button cli;
+    private Button shell;
+
+    // uses a List<Bundle> as the backing model
+    private TableViewer bundlesTableViewer;
+
+    private DataBindingContext bindingContext;
+
+    private FormPage form;
+
+    public CommandEditPage(FormPage formPage) {
+        this.form = formPage;
+    }
+
+    public void setModel(Plugin model) {
+        this.model = model;
+    }
+
+    @Override
+    public void initialize(IManagedForm form) {
+        toolkit = form.getToolkit();
+    }
+
+    @Override
+    public void dispose() {
+        if (bindingContext != null) {
+            bindingContext.dispose();
+        }
+    }
+
+    @Override
+    public boolean isDirty() {
+        if (commandModel == null) {
+            return false;
+        }
+
+        Command latestCommandInModel = model.getCommand(commandModel.getName());
+        if (latestCommandInModel == null) {
+            return false;
+        }
+
+        // TODO convert is-command-different into is-command-dirty operation
+        return !latestCommandInModel.equals(commandModel);
+    }
+
+    @Override
+    public void commit(boolean onSave) {
+        // no op
+    }
+
+    @Override
+    public boolean setFormInput(Object input) {
+        // TODO fix this
+        return false;
+    }
+
+    @Override
+    public void setFocus() {
+        // TODO what is this?
+    }
+
+    @Override
+    public boolean isStale() {
+        // FIXME check from model?
+        return false;
+    }
+
+    @Override
+    public void refresh() {
+        // no-op
+    }
+
+    @Override
+    public void selectionChanged(IFormPart part, ISelection selection) {
+        if (bindingContext != null) {
+            bindingContext.dispose();
+        }
+
+        String commandName = (String) ((IStructuredSelection)selection).getFirstElement();
+        commandModel = model.getCommand(commandName);
+        if (commandModel == null) {
+            return;
+        }
+
+        bindingContext = initDataBindings();
+    }
+
+    @Override
+    public void createContents(Composite parent) {
+        TableWrapLayout parentLayout = new TableWrapLayout();
+        parentLayout.topMargin = 0;
+        parentLayout.bottomMargin = 0;
+        parentLayout.leftMargin = 0;
+        parentLayout.rightMargin = 0;
+        parent.setLayout(parentLayout);
+
+        Section section = toolkit.createSection(parent, Section.TITLE_BAR);
+
+        TableWrapData tableData = new TableWrapData(TableWrapData.FILL, TableWrapData.TOP);
+        tableData.grabHorizontal = true;
+
+        section.setLayoutData(tableData);
+
+        section.setText("Command details");
+
+        Composite sectionContents = toolkit.createComposite(section);
+        section.setClient(sectionContents);
+
+        sectionContents.setLayout(new GridLayout());
+
+        createBasicSection(sectionContents);
+        createArgumentsAndOptionsSection(sectionContents);
+        createBundlesSection(sectionContents);
+    }
+
+    private void createBasicSection(Composite sectionContents) {
+        Section basics = toolkit.createSection(sectionContents, Section.TITLE_BAR);
+        basics.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+        basics.setText("Basics");
+
+        Composite basicContents = toolkit.createComposite(basics);
+        basics.setClient(basicContents);
+        basicContents.setLayout(new GridLayout(2, false));
+
+        toolkit.createLabel(basicContents, "Name:");
+        commandName = toolkit.createText(basicContents, "<command name here>");
+        commandName.setEditable(false);
+        commandName.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+
+        toolkit.createLabel(basicContents, "Usage:");
+        commandUsage = toolkit.createText(basicContents, "<usage>");
+        commandUsage.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+
+        toolkit.createLabel(basicContents, "Description:");
+        commandDescription = toolkit.createText(basicContents, "<description>");
+        commandDescription.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+
+        toolkit.createLabel(basicContents, "Environments");
+        Composite environmentsComposite = toolkit.createComposite(basicContents);
+        environmentsComposite.setLayout(new RowLayout());
+        cli = toolkit.createButton(environmentsComposite, "CLI", SWT.CHECK);
+        shell = toolkit.createButton(environmentsComposite, "Shell", SWT.CHECK);
+    }
+
+    private void createArgumentsAndOptionsSection(Composite sectionContents) {
+        // TODO Auto-generated method stub
+    }
+
+    private void createBundlesSection(final Composite sectionContents) {
+        Section bundles = toolkit.createSection(sectionContents, Section.TITLE_BAR);
+        bundles.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+        bundles.setText("Bundles to load");
+
+        Composite bundleContents = toolkit.createComposite(bundles);
+        bundles.setClient(bundleContents);
+        bundleContents.setLayout(new GridLayout(2, false));
+
+        Table list = toolkit.createTable(bundleContents, SWT.BORDER | SWT.V_SCROLL);
+        list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        bundlesTableViewer = new TableViewer(list);
+        IStructuredContentProvider contentProvider = ArrayContentProvider.getInstance();
+        bundlesTableViewer.setContentProvider(contentProvider);
+
+        Composite buttonComposite = toolkit.createComposite(bundleContents);
+        buttonComposite.setLayout(new GridLayout(1, false));
+
+        Button add = toolkit.createButton(buttonComposite, "Add", SWT.NONE);
+        add.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+        add.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                NewBundleDialog dialog = new NewBundleDialog(sectionContents.getShell());
+                dialog.create();
+                if (dialog.open() == Window.OK) {
+                    commandModel.addBundle(dialog.getBundle());
+                }
+            }
+        });
+
+        Button remove = toolkit.createButton(buttonComposite, "Remove", SWT.NONE);
+        remove.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+        remove.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                Bundle selectedItem = (Bundle)
+                        ((IStructuredSelection)bundlesTableViewer.getSelection()).getFirstElement();
+                commandModel.removeBundle(selectedItem);
+            }
+        });
+    }
+
+    private DataBindingContext initDataBindings() {
+        DataBindingContext bindingContext = new DataBindingContext();
+
+        IObservableValue nameWidgetValue = WidgetProperties.text(SWT.Modify).observe(commandName);
+        IObservableValue nameModelValue = BeanProperties.value(Command.class, "name").observe(commandModel);
+        bindingContext.bindValue(nameWidgetValue, nameModelValue);
+
+        IObservableValue usageWidgetValue = WidgetProperties.text(SWT.Modify).observe(commandUsage);
+        IObservableValue usageModelValue = BeanProperties.value(Command.class, "usage").observe(commandModel);
+        bindingContext.bindValue(usageWidgetValue, usageModelValue);
+
+        IObservableValue descriptionWidgetValue = WidgetProperties.text(SWT.Modify).observe(commandDescription);
+        IObservableValue descriptionModelValue = BeanProperties.value(Command.class, "description").observe(commandModel);
+        bindingContext.bindValue(descriptionWidgetValue, descriptionModelValue);
+
+        IObservableValue environmentsModelValue = BeanProperties.value(Command.class, "environments").observe(commandModel);
+
+        IObservableValue cliWidgetValue = WidgetProperties.selection().observe(cli);
+        IObservableValue cliModelValue = BeanProperties.value(Environments.class, "cli").observeDetail(environmentsModelValue);
+        bindingContext.bindValue(cliWidgetValue, cliModelValue);
+
+        IObservableValue shellWidgetValue = WidgetProperties.selection().observe(shell);
+        IObservableValue shellModelValue = BeanProperties.value(Environments.class, "shell").observeDetail(environmentsModelValue);
+        bindingContext.bindValue(shellWidgetValue, shellModelValue);
+
+        ObservableListContentProvider listContentProvider = new ObservableListContentProvider();
+        bundlesTableViewer.setContentProvider(listContentProvider);
+
+        IObservableList bundlesModel = BeanProperties.list(Command.class, "bundles").observe(commandModel);
+        bundlesTableViewer.setInput(bundlesModel);
+
+        return bindingContext;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/CommandsMasterDetailsBlock.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,56 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.forms.DetailsPart;
+import org.eclipse.ui.forms.editor.FormPage;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Command;
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Plugin;
+
+public class CommandsMasterDetailsBlock extends BaseMasterDetailsBlock {
+
+    private CommandEditPage editPage;
+
+    public CommandsMasterDetailsBlock(FormPage formPage) {
+        editPage = new CommandEditPage(formPage);
+    }
+
+    public void setModel(Plugin model) {
+        super.setModel(model);
+
+        editPage.setModel(model);
+    }
+
+    @Override
+    protected void registerPages(DetailsPart detailsPart) {
+        detailsPart.registerPage(String.class, editPage);
+    }
+
+    @Override
+    String getSectionTitle() {
+        return "Commands provided by the plugin";
+    }
+
+    @Override
+    Object[] getListViewModel() {
+        return model.getCommandNames().toArray();
+    }
+
+    @Override
+    void addButtonSelected(Shell shell) {
+        NewNameDialog dialog = new NewNameDialog(shell);
+        dialog.create();
+        if (dialog.open() == Window.OK) {
+            Command command = new Command();
+            command.setName(dialog.getName());
+            model.addCommand(command);
+        }
+    }
+
+    @Override
+    void removeButtonSelected(Object selectedItem) {
+        model.removeCommand((String) selectedItem);
+        
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/CommandsPage.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,36 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.editor.FormEditor;
+import org.eclipse.ui.forms.editor.FormPage;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.forms.widgets.TableWrapLayout;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Plugin;
+
+public class CommandsPage extends FormPage {
+
+    static final String ID = "com.redhat.thermostat.plugin.eclipse.plugin.editor.CommandsPage";
+    static final String TITLE = "Commands";
+
+    private Plugin model;
+
+    public CommandsPage(FormEditor editor, Plugin model) {
+        super(editor, ID, TITLE);
+
+        this.model = model;
+    }
+
+    @Override
+    protected void createFormContent(IManagedForm managedForm) {
+        ScrolledForm form = managedForm.getForm();
+
+        form.setText("Commands");
+        form.getBody().setLayout(new TableWrapLayout());
+
+        CommandsMasterDetailsBlock masterAndDetails = new CommandsMasterDetailsBlock(this);
+        masterAndDetails.setModel(model);
+        masterAndDetails.createContent(managedForm);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/ExtensionEditPage.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,202 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import java.util.Objects;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.ui.forms.IDetailsPage;
+import org.eclipse.ui.forms.IFormPart;
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.editor.FormPage;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Section;
+import org.eclipse.ui.forms.widgets.TableWrapData;
+import org.eclipse.ui.forms.widgets.TableWrapLayout;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Bundle;
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Extension;
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Plugin;
+
+public class ExtensionEditPage implements IDetailsPage {
+
+    private FormToolkit toolkit;
+    private Plugin model;
+    private TableViewer bundlesTableViewer;
+
+    private Extension extensionModel;
+
+    private DataBindingContext bindingContext;
+
+    private FormPage formPage;
+
+    public ExtensionEditPage(FormPage parent) {
+        this.formPage = parent;
+    }
+
+    public void setModel(Plugin model) {
+        this.model = model;
+    }
+
+    @Override
+    public void initialize(IManagedForm form) {
+        toolkit = form.getToolkit();
+    }
+
+    @Override
+    public void dispose() {
+        if (bindingContext != null) {
+            bindingContext.dispose();
+        }
+    }
+
+    @Override
+    public boolean isDirty() {
+        if (extensionModel == null) {
+            return false;
+        }
+
+        Extension extensionInMasterModel = model.getExtension(extensionModel.getName());
+        if (extensionInMasterModel == null) {
+            return false;
+        }
+
+        // TODO change this is-content-different into is-content-dirty
+        return !extensionInMasterModel.equals(extensionModel);
+    }
+
+    @Override
+    public void commit(boolean onSave) {
+        // nothing to do
+    }
+
+    @Override
+    public boolean setFormInput(Object input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public void setFocus() {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public boolean isStale() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public void refresh() {
+        // no-op
+    }
+
+    @Override
+    public void selectionChanged(IFormPart part, ISelection selection) {
+        if (bindingContext != null) {
+            bindingContext.dispose();
+        }
+
+        String extensionName = (String) ((IStructuredSelection)selection).getFirstElement();
+        extensionModel = model.getExtension(extensionName);
+
+        bindingContext = initDataBindings();
+    }
+
+    @Override
+    public void createContents(Composite parent) {
+        TableWrapLayout parentLayout = new TableWrapLayout();
+        parentLayout.topMargin = 0;
+        parentLayout.bottomMargin = 0;
+        parentLayout.leftMargin = 0;
+        parentLayout.rightMargin = 0;
+        parent.setLayout(parentLayout);
+
+        Section section = toolkit.createSection(parent, Section.TITLE_BAR);
+
+        TableWrapData tableData = new TableWrapData(TableWrapData.FILL, TableWrapData.TOP);
+        tableData.grabHorizontal = true;
+
+        section.setLayoutData(tableData);
+
+        section.setText("Extension details");
+
+        Composite sectionContents = toolkit.createComposite(section);
+        section.setClient(sectionContents);
+
+        sectionContents.setLayout(new GridLayout());
+
+        createBundlesSection(sectionContents);
+    }
+
+    private void createBundlesSection(final Composite sectionContents) {
+        Section bundles = toolkit.createSection(sectionContents, Section.TITLE_BAR);
+        bundles.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+        bundles.setText("Bundles to load");
+
+        Composite bundleContents = toolkit.createComposite(bundles);
+        bundles.setClient(bundleContents);
+        bundleContents.setLayout(new GridLayout(2, false));
+
+        Table bundlesTable = toolkit.createTable(bundleContents, SWT.BORDER | SWT.V_SCROLL);
+        bundlesTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+        bundlesTableViewer = new TableViewer(bundlesTable);
+
+        Composite buttonComposite = toolkit.createComposite(bundleContents);
+        buttonComposite.setLayout(new GridLayout(1, false));
+
+        Button add = toolkit.createButton(buttonComposite, "Add", SWT.NONE);
+        add.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+        add.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                NewBundleDialog dialog = new NewBundleDialog(sectionContents.getShell());
+                dialog.create();
+                if (dialog.open() == Window.OK) {
+                    Bundle newBundle = dialog.getBundle();
+                    extensionModel.addBundle(newBundle);
+                }
+            }
+        });
+
+        Button remove = toolkit.createButton(buttonComposite, "Remove", SWT.NONE);
+        remove.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+        remove.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                Bundle selectedItem = (Bundle)
+                        ((IStructuredSelection)bundlesTableViewer.getSelection()).getFirstElement();
+                extensionModel.removeBundle(selectedItem);
+            }
+        });
+
+    }
+
+    private DataBindingContext initDataBindings() {
+        DataBindingContext bindingContext = new DataBindingContext();
+
+        ObservableListContentProvider listContentProvider = new ObservableListContentProvider();
+        bundlesTableViewer.setContentProvider(listContentProvider);
+
+        IObservableList bundlesModel = BeanProperties.list(Extension.class, "bundles").observe(extensionModel);
+        bundlesTableViewer.setInput(bundlesModel);
+
+        return bindingContext;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/ExtensionsMasterDetailsBlock.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,59 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.forms.DetailsPart;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Extension;
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Plugin;
+
+public class ExtensionsMasterDetailsBlock extends BaseMasterDetailsBlock {
+
+    private ExtensionEditPage editPage;
+
+    public ExtensionsMasterDetailsBlock(ExtensionsPage extensionsPage) {
+        editPage = new ExtensionEditPage(extensionsPage);
+    }
+
+    public void setModel(Plugin model) {
+        super.setModel(model);
+
+        editPage.setModel(model);
+    }
+
+    @Override
+    protected void registerPages(DetailsPart detailsPart) {
+        detailsPart.registerPage(String.class, editPage);
+    }
+
+    @Override
+    String getSectionTitle() {
+        return "Commands extended by the plugin";
+    }
+
+    @Override
+    Object[] getListViewModel() {
+        return model.getExtensionNames().toArray();
+    }
+
+    @Override
+    void addButtonSelected(Shell shell) {
+        NewNameDialog dialog = new NewNameDialog(shell);
+        dialog.create();
+        if (dialog.open() == Window.OK) {
+            Extension newExtension = new Extension();
+            newExtension.setName(dialog.getName());
+            model.addExtension(newExtension);
+        }
+    }
+
+    @Override
+    void removeButtonSelected(Object selectedItem) {
+        if (selectedItem == null) {
+            return;
+        }
+
+        model.removeExtension((String) selectedItem);
+    };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/ExtensionsPage.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,39 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.editor.FormEditor;
+import org.eclipse.ui.forms.editor.FormPage;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Plugin;
+
+
+public class ExtensionsPage extends FormPage {
+
+    static final String ID = "com.redhat.thermostat.plugin.eclipse.plugin.editor.ExtensionsPage";
+    static final String TITLE = "Extensions";
+
+    private Plugin model;
+
+    public ExtensionsPage(FormEditor editor, Plugin model) {
+        super(editor, ID, TITLE);
+
+        this.model = model;
+    }
+
+    @Override
+    protected void createFormContent(IManagedForm managedForm) {
+        ScrolledForm form = managedForm.getForm();
+        form.setText("Extensions");
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 2;
+        layout.makeColumnsEqualWidth = true;
+        form.getBody().setLayout(layout);
+
+        ExtensionsMasterDetailsBlock masterAndDetails = new ExtensionsMasterDetailsBlock(this);
+        masterAndDetails.setModel(model);
+        masterAndDetails.createContent(managedForm);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/MultiPageEditor.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,189 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentListener;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.forms.editor.FormEditor;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.wst.sse.ui.StructuredTextEditor;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Plugin;
+import com.redhat.thermostat.plugin.eclipse.plugin.model.PluginModelReaderWriter;
+
+public class MultiPageEditor extends FormEditor implements IResourceChangeListener {
+
+    private static final int INDEX_SOURCE = 3;
+
+    private StructuredTextEditor editor;
+    private boolean editorIsDirty = false;
+
+    private PluginModelReaderWriter modelHelper;
+    private Plugin model;
+
+    private int oldPage = -1;
+
+    public MultiPageEditor() {
+        super();
+        ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
+    }
+
+    @Override
+    public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException {
+        if (!(editorInput instanceof IFileEditorInput))
+            throw new PartInitException("Invalid Input: Must be IFileEditorInput");
+        super.init(site, editorInput);
+
+        try {
+            IFile file = ((IFileEditorInput)getEditorInput()).getFile();
+            modelHelper = new PluginModelReaderWriter(file);
+            model = modelHelper.loadModel(file.getContents());
+            Objects.requireNonNull(model);
+        } catch (CoreException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    @Override
+    protected void addPages() {
+        try {
+            OverviewPage overview = new OverviewPage(this, modelHelper.getPluginName());
+            addPage(overview);
+
+            CommandsPage commandsPage = new CommandsPage(this, model);
+            addPage(commandsPage);
+
+            ExtensionsPage extensionsPage = new ExtensionsPage(this, model);
+            addPage(extensionsPage);
+
+            createSourcePage();
+        } catch (PartInitException pie) {
+            throw new RuntimeException(pie);
+            // ErrorDialog.openError(getSite().getShell(),
+            //     "Error creating nested text editor", null, e.getStatus());
+
+        }
+    }
+
+    void createSourcePage() throws PartInitException {
+        editor = new StructuredTextEditor();
+        addPage(editor, getEditorInput());
+        setPageText(INDEX_SOURCE, editor.getTitle());
+
+        getDocument().addDocumentListener(new IDocumentListener() {
+
+            @Override
+            public void documentChanged(DocumentEvent event) {
+                editorIsDirty = true;
+            }
+
+            @Override
+            public void documentAboutToBeChanged(DocumentEvent event) {
+                // nothing to do
+            }
+        });
+    }
+
+    @Override
+    public void dispose() {
+        ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
+        super.dispose();
+    }
+
+    @Override
+    protected void pageChange(int newPageIndex) {
+        if (oldPage != -1) {
+            if (oldPage == INDEX_SOURCE && editorIsDirty) {
+                updateModelFromSource();
+            } else if (newPageIndex == INDEX_SOURCE) {
+                updateSourceFromModel();
+            }
+        }
+
+        super.pageChange(newPageIndex);
+
+        oldPage = newPageIndex;
+    }
+
+    @Override
+    public void doSave(IProgressMonitor monitor) {
+        if (getActivePage() != INDEX_SOURCE) {
+            updateSourceFromModel();
+        }
+
+        editor.doSave(monitor);
+    }
+
+    @Override
+    public boolean isSaveAsAllowed() {
+        return false;
+    }
+
+    @Override
+    public void doSaveAs() {
+        throw new AssertionError("SaveAs is not allowed");
+    }
+
+    private void updateSourceFromModel() {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        modelHelper.saveModel(model, baos);
+        String modelSource = new String(baos.toByteArray(), StandardCharsets.UTF_8);
+
+        if (!getDocument().get().equals(modelSource)) {
+            getDocument().set(modelSource);
+        }
+
+        editorIsDirty = false;
+    }
+
+    private void updateModelFromSource() {
+        model = modelHelper.loadModel(getDocument().get());
+
+        editorIsDirty = false;
+    }
+
+    private IDocument getDocument() {
+        return editor.getDocumentProvider().getDocument(editor.getEditorInput());
+    }
+
+    /**
+     * Closes all project files on project close.
+     */
+    public void resourceChanged(final IResourceChangeEvent event) {
+        if (event.getType() == IResourceChangeEvent.PRE_CLOSE) {
+            Display.getDefault().asyncExec(new Runnable() {
+                public void run() {
+                    IWorkbenchPage[] pages = getSite().getWorkbenchWindow()
+                            .getPages();
+                    for (int i = 0; i < pages.length; i++) {
+                        if (((FileEditorInput) editor.getEditorInput())
+                                .getFile().getProject()
+                                .equals(event.getResource())) {
+                            IEditorPart editorPart = pages[i].findEditor(editor
+                                    .getEditorInput());
+                            pages[i].closeEditor(editorPart, true);
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/MultiPageEditorContributor.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,77 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.ide.IDEActionFactory;
+import org.eclipse.ui.part.MultiPageEditorActionBarContributor;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.ITextEditorActionConstants;
+
+/**
+ * Manages the installation/deinstallation of global actions for multi-page editors.
+ * Responsible for the redirection of global actions to the active editor.
+ * Multi-page contributor replaces the contributors for the individual editors in the multi-page editor.
+ */
+public class MultiPageEditorContributor extends MultiPageEditorActionBarContributor {
+	private IEditorPart activeEditorPart;
+
+	/**
+	 * Creates a multi-page contributor.
+	 */
+	public MultiPageEditorContributor() {
+		super();
+	}
+	/**
+	 * Returns the action registed with the given text editor.
+	 * @return IAction or null if editor is null.
+	 */
+	protected IAction getAction(ITextEditor editor, String actionID) {
+		return (editor == null ? null : editor.getAction(actionID));
+	}
+
+	public void setActivePage(IEditorPart part) {
+		if (activeEditorPart == part)
+			return;
+
+		activeEditorPart = part;
+
+		IActionBars actionBars = getActionBars();
+		if (actionBars != null) {
+
+			ITextEditor editor = (part instanceof ITextEditor) ? (ITextEditor) part : null;
+
+			actionBars.setGlobalActionHandler(
+				ActionFactory.DELETE.getId(),
+				getAction(editor, ITextEditorActionConstants.DELETE));
+			actionBars.setGlobalActionHandler(
+				ActionFactory.UNDO.getId(),
+				getAction(editor, ITextEditorActionConstants.UNDO));
+			actionBars.setGlobalActionHandler(
+				ActionFactory.REDO.getId(),
+				getAction(editor, ITextEditorActionConstants.REDO));
+			actionBars.setGlobalActionHandler(
+				ActionFactory.CUT.getId(),
+				getAction(editor, ITextEditorActionConstants.CUT));
+			actionBars.setGlobalActionHandler(
+				ActionFactory.COPY.getId(),
+				getAction(editor, ITextEditorActionConstants.COPY));
+			actionBars.setGlobalActionHandler(
+				ActionFactory.PASTE.getId(),
+				getAction(editor, ITextEditorActionConstants.PASTE));
+			actionBars.setGlobalActionHandler(
+				ActionFactory.SELECT_ALL.getId(),
+				getAction(editor, ITextEditorActionConstants.SELECT_ALL));
+			actionBars.setGlobalActionHandler(
+				ActionFactory.FIND.getId(),
+				getAction(editor, ITextEditorActionConstants.FIND));
+			actionBars.setGlobalActionHandler(
+				IDEActionFactory.BOOKMARK.getId(),
+				getAction(editor, IDEActionFactory.BOOKMARK.getId()));
+			actionBars.updateActionBars();
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/NewBundleDialog.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,161 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import java.io.IOException;
+
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.BundleInformationExtractor;
+import com.redhat.thermostat.plugin.eclipse.plugin.model.Bundle;
+
+/**
+ * Prompt the user to enter or select a bundle name/version.
+ *
+ * Used by the command edit page.
+ */
+public class NewBundleDialog extends TitleAreaDialog {
+
+    private Bundle bundleInfo;
+
+    private Button manualSelectionButton;
+    private Text nameText;
+    private Text versionText;
+
+    private Button fromJarButton;
+    private Text fileLocationText;
+    private Button btnFromFile;
+
+    public NewBundleDialog(Shell parentShell) {
+        super(parentShell);
+    }
+
+    @Override
+    public void create() {
+        super.create();
+
+        setTitle("Add a new new bundle");
+        setMessage("Use this bundle with this plugin");
+    }
+
+    @Override
+    protected Control createDialogArea(Composite parent) {
+        Composite area = (Composite) super.createDialogArea(parent);
+
+        Composite container = new Composite(area, SWT.NONE);
+        container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,true));
+
+        GridLayout containerLayout = new GridLayout(3, false);
+        containerLayout.marginTop = 5;
+        containerLayout.marginRight = 5;
+        containerLayout.marginLeft = 5;
+        container.setLayout(containerLayout);
+
+        manualSelectionButton = new Button(container, SWT.RADIO);
+        manualSelectionButton.setSelection(true);
+        manualSelectionButton.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                nameText.setEnabled(true);
+                versionText.setEnabled(true);
+
+                fileLocationText.setEnabled(false);
+                btnFromFile.setEnabled(false);
+            }
+        });
+        manualSelectionButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+        manualSelectionButton.setText("Specify Manually");
+
+        Label nameLabel = new Label(container, SWT.None);
+        nameLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+        nameLabel.setText("Symbolic Name:");
+        nameText = new Text(container, SWT.None);
+        GridData nameTextLayoutData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
+        nameTextLayoutData.horizontalSpan = 2;
+        nameText.setLayoutData(nameTextLayoutData);
+
+        Label versionLabel = new Label(container, SWT.None);
+        versionLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+        versionLabel.setText("Version:");
+        versionText = new Text(container, SWT.None);
+        GridData versionTextLayoutData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
+        versionTextLayoutData.horizontalSpan = 2;
+        versionText.setLayoutData(versionTextLayoutData);
+
+        fromJarButton = new Button(container, SWT.RADIO);
+        fromJarButton.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                nameText.setEnabled(false);
+                versionText.setEnabled(false);
+
+                fileLocationText.setEnabled(true);
+                btnFromFile.setEnabled(true);
+            }
+        });
+        fromJarButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+        fromJarButton.setText("Extract from Jar/Bundle on disk");
+
+        Label locationLabel = new Label(container, SWT.NONE);
+        locationLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+        locationLabel.setText("Location:");
+
+        fileLocationText = new Text(container, SWT.BORDER);
+        fileLocationText.setEnabled(false);
+        fileLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+        btnFromFile = new Button(container, SWT.NONE);
+        btnFromFile.setText("...");
+        btnFromFile.setEnabled(false);
+        btnFromFile.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
+                dialog.setFilterExtensions(new String[] { "*.jar" });
+                String result = dialog.open();
+                if (result != null) {
+                    fileLocationText.setText(result);
+                }
+            }
+        });
+
+        // TODO implement extracting data from bundle/jar on disk
+
+        return area;
+    }
+
+    @Override
+    protected void okPressed() {
+        saveInput();
+        super.okPressed();
+    }
+
+    private void saveInput() {
+        if (manualSelectionButton.getSelection()) {
+            bundleInfo = new Bundle(nameText.getText(), versionText.getText());
+        } else {
+            try {
+                BundleInformationExtractor extractor = new BundleInformationExtractor();
+                bundleInfo = extractor.extract(fileLocationText.getText());
+            } catch (IOException e) {
+                // FIXME doing something saner with this exception
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public Bundle getBundle() {
+        return bundleInfo;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/NewNameDialog.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,63 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/** Asks the name for a new command/extension */
+public class NewNameDialog extends TitleAreaDialog {
+
+    private String name;
+    private Text nameText;
+
+    public NewNameDialog(Shell parentShell) {
+        super(parentShell);
+
+    }
+
+    @Override
+    public void create() {
+        super.create();
+
+        setTitle("Enter the name for the new command");
+        setMessage("This is the command users will use to trigger your plugin");
+    }
+
+    @Override
+    protected Control createDialogArea(Composite parent) {
+        Composite area = (Composite) super.createDialogArea(parent);
+
+        Composite container = new Composite(area, SWT.NONE);
+        container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,true));
+
+        container.setLayout(new GridLayout(2, false));
+
+        Label label = new Label(container, SWT.None);
+        label.setText("Name:");
+        nameText = new Text(container, SWT.None);
+        nameText.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+
+        return area;
+    }
+
+    @Override
+    protected void okPressed() {
+        saveInput();
+        super.okPressed();
+    }
+
+    private void saveInput() {
+        name = nameText.getText();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/editor/OverviewPage.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,114 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.editor;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.editor.FormEditor;
+import org.eclipse.ui.forms.editor.FormPage;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.FormText;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.forms.widgets.Section;
+import org.eclipse.ui.forms.widgets.TableWrapLayout;
+
+public class OverviewPage extends FormPage {
+
+    static final String ID = "com.redhat.thermostat.plugin.eclipse.plugin.editor.OverviewPage";
+    static final String TITLE = "Overview";
+
+    private String pluginName;
+
+    public OverviewPage(FormEditor editor, String pluginName) {
+        super(editor, ID, TITLE);
+
+        this.pluginName = pluginName;
+    }
+
+    @Override
+    protected void createFormContent(IManagedForm managedForm) {
+        ScrolledForm form = managedForm.getForm();
+        form.setText("Overview: " + pluginName);
+        TableWrapLayout layout = new TableWrapLayout();
+        form.getBody().setLayout(layout);
+
+        createOverviewSection(form.getBody());
+
+        createEditCommandsAndExtensionsSection(form.getBody());
+    }
+
+
+    private void createOverviewSection(Composite parent) {
+        FormToolkit toolkit = getManagedForm().getToolkit();
+        Section section = toolkit.createSection(parent, Section.TITLE_BAR);
+        section.setText("General Information");
+
+        Composite sectionData = toolkit.createComposite(section);
+        sectionData.setLayout(new TableWrapLayout());
+        FormText helpText = toolkit.createFormText(sectionData, false);
+        String onlineHelp = "<form>"
+                + "<p>For more information about thermostat see "
+                + "<a href=\"http://icedtea.classpath.org/thermostat\">the homepage</a>. "
+                + "Additional information about plugins is available "
+                + "<a href=\"http://icedtea.classpath.org/wiki/Thermostat/ExtensionTutorial\">here</a>."
+                + "</p>"
+                + "</form>";
+        helpText.setText(onlineHelp, true, false);
+        helpText.addHyperlinkListener(new HyperlinkAdapter() {
+            @Override
+            public void linkActivated(HyperlinkEvent e) {
+                String href = (String) e.getHref();
+                try {
+                    PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(new URL(href));
+                } catch (PartInitException | MalformedURLException e1) {
+                    e1.printStackTrace();
+                }
+            }
+        });
+
+        section.setClient(sectionData);
+    }
+
+    private void createEditCommandsAndExtensionsSection(Composite parent) {
+        FormToolkit toolkit = getManagedForm().getToolkit();
+        Section section = toolkit.createSection(parent, Section.TITLE_BAR);
+        section.setText("Commands and Extensions");
+
+        Composite sectionData = toolkit.createComposite(section);
+        sectionData.setLayout(new TableWrapLayout());
+
+        FormText commandAndExtensionsForm = toolkit.createFormText(sectionData, false);
+        String formContents = ""
+                + "<form>"
+                + "<p>Plugins provide new commands or extend existing ones.</p>"
+                + "<li><a href=\"commands\">Commands</a>: declares new commands provided by this plugin</li>"
+                + "<li><a href=\"extensions\">Extensions</a>: declares which commands provided by other plugins or thermostat itself should be extended</li>"
+                + "</form>";
+        commandAndExtensionsForm.setText(formContents, true, false);
+
+        commandAndExtensionsForm.addHyperlinkListener(new HyperlinkAdapter() {
+            @Override
+            public void linkActivated(HyperlinkEvent e) {
+                String href = (String) e.getHref();
+                String id = null;
+                switch(href) {
+                    case "commands":
+                        id = CommandsPage.ID;
+                        break;
+                    case "extensions":
+                        id = ExtensionsPage.ID;
+                        break;
+                }
+                OverviewPage.this.getEditor().setActivePage(id);
+            }
+        });
+
+        section.setClient(sectionData);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Bundle.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,59 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import java.util.Objects;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name="bundle")
+public class Bundle {
+
+    private String name;
+    private String version;
+
+    public Bundle() {
+        name = null;
+        version = null;
+    }
+
+    public Bundle(String name, String version) {
+        this.name = name;
+        this.version = version;
+    }
+
+    @XmlElement(name="symbolic-name")
+    public String getSymbolicName() {
+        return this.name;
+    }
+
+    public void setSymbolicName(String name) {
+        this.name = name;
+    }
+
+    @XmlElement(name="version")
+    public String getVersion() {
+        return this.version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String toString() {
+        return this.name + " (" + this.version + ")";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Bundle)) {
+            return false;
+        }
+        Bundle other = (Bundle) obj;
+        return Objects.equals(this.name, other.name) && Objects.equals(this.version, other.version);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.name, this.version);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Command.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,143 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(propOrder = {
+        "name", "description", "usage",
+        "arguments", "options",
+        "environments",
+        "bundles"})
+public class Command extends ModelObject {
+
+    private String name;
+    private String description;
+    private String usage;
+    private List<String> arguments = new ArrayList<>();
+    private List<Option> options = new ArrayList<>();
+    private Environments environments = new Environments();
+    private List<Bundle> bundles = new ArrayList<>();
+
+    public Command() {
+        // no-arg java bean constructor
+    }
+
+    public Command(String name, String description, String usage,
+            List<String> arguments, List<Option> options,
+            Environments environments, List<Bundle> bundles) {
+        this.name = name;
+        this.description = description;
+        this.usage = usage;
+
+        this.arguments = arguments;
+        this.options = options;
+        this.environments = environments;
+        this.bundles = bundles;
+    }
+
+    @XmlElement(name="name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        firePropertyChange("name", this.name, this.name = name);
+    }
+
+    @XmlElement(name="description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        firePropertyChange("description", this.description, this.description = description);
+    }
+
+    @XmlElement(name="usage")
+    public String getUsage() {
+        return usage;
+    }
+
+    public void setUsage(String usage) {
+        firePropertyChange("usage", this.usage, this.usage = usage);
+    }
+
+    @XmlElementWrapper(name="arguments")
+    @XmlElement(name="argument")
+    public List<String> getArguments() {
+        return arguments;
+    }
+
+    public void setArguments(List<String> arguments) {
+        firePropertyChange("arguments", this.arguments, this.arguments = arguments);
+    }
+
+    public void addArgument(String argument) {
+        this.arguments.add(argument);
+        firePropertyChange("arguments", null, this.arguments);
+    }
+
+    public void removeArgument(String argument) {
+        this.arguments.remove(argument);
+        firePropertyChange("arguments", null, this.arguments);
+    }
+
+    @XmlElementWrapper(name="options")
+    @XmlElement(name="option")
+    public List<Option> getOptions() {
+        return options;
+    }
+
+    public void setOptions(List<Option> options) {
+        firePropertyChange("options", this.options, this.options = options);
+    }
+
+    @XmlElement(name="environments")
+    public Environments getEnvironments() {
+        return environments;
+    }
+
+    public void setEnvironments(Environments environments) {
+        firePropertyChange("environments", this.environments, this.environments = environments);
+    }
+
+    @XmlElementWrapper(name="bundles")
+    @XmlElement(name="bundle")
+    public List<Bundle> getBundles() {
+        return bundles;
+    }
+
+    public void setBundles(List<Bundle> bundles) {
+        this.bundles = bundles;
+    }
+
+    public void addBundle(Bundle bundle) {
+        this.bundles.add(bundle);
+        firePropertyChange("bundles", null, this.bundles);
+    }
+
+    public void removeBundle(Bundle bundle) {
+        this.bundles.remove(bundle);
+        firePropertyChange("bundles", null, this.bundles);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Command)) {
+            return false;
+        }
+        Command other = (Command) obj;
+        return Objects.equals(this.name, other.name) &&
+                Objects.equals(this.description, other.description) &&
+                Objects.equals(this.usage, other.usage) &&
+                Objects.equals(this.arguments, other.arguments) &&
+                Objects.equals(this.options, other.options) &&
+                Objects.equals(this.environments, other.environments) &&
+                Objects.equals(this.bundles, other.bundles);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Environments.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,61 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+@XmlAccessorType(XmlAccessType.NONE)
+public class Environments extends ModelObject {
+
+    private static final String CLI = "cli";
+    private static final String SHELL = "shell";
+
+    private List<String> environments;
+
+    public Environments() {
+        environments = new ArrayList<String>();
+    }
+
+    @XmlElement(name="environment")
+    public List<String> getEnvironments() {
+        return environments;
+    }
+
+    public boolean isCli() {
+        return environments.contains(CLI);
+    }
+
+    public void setCli(boolean newValue) {
+        addOrRemoveEnvironment(CLI, newValue);
+    }
+
+    public boolean isShell() {
+        return environments.contains(SHELL);
+    }
+
+    public void setShell(boolean newValue) {
+        addOrRemoveEnvironment(SHELL, newValue);
+    }
+
+    private void addOrRemoveEnvironment(String name, boolean add) {
+        if (add) {
+            if (environments.indexOf(name) == -1) {
+                environments.add(name);
+                firePropertyChange(name, false, true);
+            }
+        } else { // remove
+            if (environments.indexOf(name) != -1) {
+                environments.remove(name);
+                firePropertyChange(name, true, false);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Environments: " + environments.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Extension.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,66 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(propOrder = {"name", "bundles"})
+public class Extension extends ModelObject {
+
+    private String name;
+
+    private List<Bundle> bundles;
+
+    public Extension() {
+        bundles = new ArrayList<>();
+    }
+
+    public Extension(String name, List<Bundle> bundles) {
+        this.name = name;
+        this.bundles = bundles;
+    }
+
+    @XmlElement(name="name")
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        firePropertyChange("name", this.name, this.name = name);
+    }
+
+    /** Do not modify the returned list */
+    @XmlElementWrapper(name="bundles")
+    @XmlElement(name="bundle")
+    public List<Bundle> getBundles() {
+        return this.bundles;
+    }
+
+    public void setBundles(List<Bundle> bundles) {
+        firePropertyChange("bundles", this.bundles, this.bundles = bundles);
+    }
+
+    public void addBundle(Bundle bundle) {
+        bundles.add(bundle);
+        firePropertyChange("bundles", null, bundles);
+    }
+
+    public void removeBundle(Bundle bundle) {
+        bundles.remove(bundle);
+        firePropertyChange("bundles", null, bundles);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Extension)) {
+            return false;
+        }
+        Extension other = (Extension) obj;
+        return Objects.equals(this.name, other.name) && Objects.equals(this.bundles, other.bundles);
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/ModelObject.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,29 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+public class ModelObject {
+
+    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
+
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        changeSupport.addPropertyChangeListener(listener);
+    }
+
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        changeSupport.removePropertyChangeListener(listener);
+    }
+
+    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+        changeSupport.addPropertyChangeListener(propertyName, listener);
+    }
+
+    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+        changeSupport.removePropertyChangeListener(propertyName, listener);
+    }
+
+    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
+        changeSupport.firePropertyChange(propertyName, oldValue, newValue);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Option.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,25 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import javax.xml.bind.annotation.XmlElement;
+
+public class Option {
+
+    private String name;
+
+    public Option() {
+        this.name = null;
+    }
+
+    public Option(String name) {
+        this.name = name;
+    }
+
+    @XmlElement(name="long")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/Plugin.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,103 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name="plugin")
+@XmlAccessorType(XmlAccessType.NONE)
+public class Plugin extends ModelObject {
+
+    private List<Command> commands;
+
+    private List<Extension> extensions;
+
+    public Plugin() {
+        commands = new ArrayList<>();
+        extensions = new ArrayList<>();
+    }
+
+    @XmlElementWrapper(name="commands")
+    @XmlElement(name="command")
+    public List<Command> getCommands() {
+        return this.commands;
+    }
+
+    public void addCommand(Command command) {
+        this.commands.add(command);
+        firePropertyChange("commands", null, this.commands);
+    }
+
+    public Command getCommand(String name) {
+        for (Command command : commands) {
+            if (command.getName().equals(name)) {
+                return command;
+            }
+        }
+        return null;
+    }
+
+    public List<String> getCommandNames() {
+        List<String> result = new ArrayList<>();
+        for (Command command : commands) {
+            result.add(command.getName());
+        }
+        return result;
+    }
+
+    public void removeCommand(String name) {
+        for (int i = 0; i < commands.size(); i++) {
+            Command command = commands.get(i);
+            if (command.getName().equals(name)) {
+                commands.remove(i);
+                firePropertyChange("commands", null, this.commands);
+                return;
+            }
+        }
+    }
+
+    @XmlElementWrapper(name="extensions")
+    @XmlElement(name="extension")
+    public List<Extension> getExtensions() {
+        return this.extensions;
+    }
+
+    public void addExtension(Extension extension) {
+        this.extensions.add(extension);
+        firePropertyChange("extensions", null, this.extensions);
+    }
+
+    public Extension getExtension(String name) {
+        for (Extension extension : extensions) {
+            if (extension.getName().equals(name)) {
+                return extension;
+            }
+        }
+        return null;
+    }
+
+    public List<String> getExtensionNames() {
+        List<String> result = new ArrayList<>();
+        for (Extension extension : extensions) {
+            result.add(extension.getName());
+        }
+        return result;
+    }
+
+    public void removeExtension(String name) {
+        for (int i = 0; i < extensions.size(); i++) {
+            Extension extension = extensions.get(i);
+            if (extension.getName().equals(name)) {
+                extensions.remove(i);
+                firePropertyChange("extensions", null, this.extensions);
+                return;
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/PluginModelReaderWriter.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,78 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Reads and writes the plugin model to/from input streams.
+ */
+public class PluginModelReaderWriter {
+
+    private String name;
+    private IFile file;
+
+    public PluginModelReaderWriter(IFile file) throws CoreException {
+        this(file, file.getFullPath().makeAbsolute().removeLastSegments(1).lastSegment());
+    }
+
+    public PluginModelReaderWriter(IFile file, String name) {
+        this.file = file;
+        this.name = name;
+    }
+
+    public String getPluginName() {
+        return name;
+    }
+
+    public Plugin loadModel(String contents) {
+        return loadModel(new StringReader(contents));
+    }
+
+
+    public Plugin loadModel(InputStream inputStream) {
+        JAXBContext context;
+        try {
+            context = JAXBContext.newInstance(Plugin.class);
+            Unmarshaller um = context.createUnmarshaller();
+            Plugin plugin = (Plugin) um.unmarshal(inputStream);
+            return plugin;
+        } catch (JAXBException e) {
+            throw new RuntimeException("Unable to load model", e);
+        }
+    }
+
+    public Plugin loadModel(Reader reader) {
+        JAXBContext context;
+        try {
+            context = JAXBContext.newInstance(Plugin.class);
+            Unmarshaller um = context.createUnmarshaller();
+            Plugin plugin = (Plugin) um.unmarshal(reader);
+            return plugin;
+        } catch (JAXBException e) {
+            throw new RuntimeException("Unable to load model", e);
+        }
+    }
+
+    public void saveModel(Plugin plugin, OutputStream out) {
+        try {
+            JAXBContext context = JAXBContext.newInstance(Plugin.class);
+            Marshaller m = context.createMarshaller();
+            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+
+            m.marshal(plugin, out);
+        } catch (JAXBException e) {
+            throw new RuntimeException("Error saving file", e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/model/package-info.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,8 @@
+/**
+ * Contains model classes that represents XML elements of the
+ * {@code thermostat-plugin.xml} file.
+ */
+@javax.xml.bind.annotation.XmlSchema(
+        namespace="http://icedtea.classpath.org/thermostat/plugins/v1.0",
+        elementFormDefault=javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/PluginXmlCreationWizard.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,132 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.wizards;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.operation.*;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+
+import java.io.*;
+
+import org.eclipse.ui.*;
+import org.eclipse.ui.ide.IDE;
+
+import com.redhat.thermostat.plugin.eclipse.plugin.Activator;
+
+public class PluginXmlCreationWizard extends Wizard implements INewWizard {
+
+    private PluginXmlProjectSelectionPage page;
+    private ISelection selection;
+
+    public PluginXmlCreationWizard() {
+        super();
+        setNeedsProgressMonitor(true);
+    }
+
+    @Override
+    public void addPages() {
+        setWindowTitle("Create Themrostat Plugin");
+        page = new PluginXmlProjectSelectionPage(selection);
+        addPage(page);
+    }
+
+    /**
+     * This method is called when 'Finish' button is pressed in the wizard. We
+     * will create an operation and run it using wizard as execution context.
+     */
+    @Override
+    public boolean performFinish() {
+        final String containerName = page.getContainerName();
+        final String fileName = "thermostat-plugin.xml";
+        IRunnableWithProgress op = new IRunnableWithProgress() {
+            public void run(IProgressMonitor monitor)
+                    throws InvocationTargetException {
+                try {
+                    doFinish(containerName, fileName, monitor);
+                } catch (CoreException e) {
+                    throw new InvocationTargetException(e);
+                } finally {
+                    monitor.done();
+                }
+            }
+        };
+        try {
+            getContainer().run(true, false, op);
+        } catch (InterruptedException e) {
+            return false;
+        } catch (InvocationTargetException e) {
+            Throwable realException = e.getTargetException();
+            MessageDialog.openError(getShell(), "Error",
+                    realException.getMessage());
+            return false;
+        }
+        return true;
+    }
+
+    private void doFinish(String containerName, String fileName,
+            IProgressMonitor monitor) throws CoreException {
+        // create a sample file
+        monitor.beginTask("Creating " + fileName, 2);
+        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+        IResource resource = root.findMember(new Path(containerName));
+        if (!resource.exists() || !(resource instanceof IContainer)) {
+            throwCoreException("Container \"" + containerName
+                    + "\" does not exist.");
+        }
+        IContainer container = (IContainer) resource;
+        final IFile file = container.getFile(new Path(fileName));
+        try {
+            InputStream stream = getInitialContentStream();
+            if (file.exists()) {
+                // TODO dont replace file without confirming
+                file.setContents(stream, true, true, monitor);
+            } else {
+                file.create(stream, true, monitor);
+            }
+            stream.close();
+        } catch (IOException e) {
+        }
+        monitor.worked(1);
+        monitor.setTaskName("Opening file for editing...");
+        getShell().getDisplay().asyncExec(new Runnable() {
+            public void run() {
+                IWorkbenchPage page = PlatformUI.getWorkbench()
+                        .getActiveWorkbenchWindow().getActivePage();
+                try {
+                    IDE.openEditor(page, file, true);
+                } catch (PartInitException e) {
+                }
+            }
+        });
+        monitor.worked(1);
+    }
+
+    private InputStream getInitialContentStream() {
+        String contents = "<?xml version=\"1.0\"?>\n"
+                + "<plugin xmlns=\"http://icedtea.classpath.org/thermostat/plugins/v1.0\"\n"
+                + "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+                + "\txsi:schemaLocation=\"http://icedtea.classpath.org/thermostat/plugins/v1.0 thermostat-plugin.xsd\">\n"
+                + "</plugin>";
+
+        return new ByteArrayInputStream(contents.getBytes());
+    }
+
+    private void throwCoreException(String message) throws CoreException {
+        IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+                IStatus.OK, message, null);
+        throw new CoreException(status);
+    }
+
+    @Override
+    public void init(IWorkbench workbench, IStructuredSelection selection) {
+        this.selection = selection;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/PluginXmlProjectSelectionPage.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,152 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.wizards;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.SimpleContentProposalProvider;
+import org.eclipse.jface.fieldassist.TextContentAdapter;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ContainerSelectionDialog;
+
+public class PluginXmlProjectSelectionPage extends WizardPage {
+    private Text containerText;
+
+    private ISelection selection;
+
+    public PluginXmlProjectSelectionPage(ISelection selection) {
+        super("wizardPage");
+        setTitle("Thermostat Wizard");
+        setDescription("This wizard creates a new Thermostat Plugin.");
+        this.selection = selection;
+    }
+
+    public void createControl(Composite parent) {
+        Composite container = new Composite(parent, SWT.NULL);
+        GridLayout layout = new GridLayout();
+        container.setLayout(layout);
+        layout.numColumns = 3;
+        layout.verticalSpacing = 9;
+        Label label = new Label(container, SWT.NULL);
+        label.setText("&Project:");
+
+        containerText = new Text(container, SWT.BORDER | SWT.SINGLE);
+        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+        containerText.setLayoutData(gd);
+        containerText.addModifyListener(new ModifyListener() {
+            public void modifyText(ModifyEvent e) {
+                dialogChanged();
+            }
+        });
+
+        String[] proposals = getOpenProjectNames().toArray(new String[0]);
+        SimpleContentProposalProvider projectProposalProvider = new SimpleContentProposalProvider(proposals);
+        TextContentAdapter contentAdapter = new TextContentAdapter();
+        ContentProposalAdapter proposalAdapter = new ContentProposalAdapter(containerText, contentAdapter, projectProposalProvider, null, null);
+        proposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
+
+        Button button = new Button(container, SWT.PUSH);
+        button.setText("Browse...");
+        button.addSelectionListener(new SelectionAdapter() {
+            public void widgetSelected(SelectionEvent e) {
+                handleBrowse();
+            }
+        });
+        initialize();
+        dialogChanged();
+
+        setControl(container);
+    }
+
+    private void initialize() {
+        if (selection != null && selection.isEmpty() == false
+                && selection instanceof IStructuredSelection) {
+            IStructuredSelection ssel = (IStructuredSelection) selection;
+            if (ssel.size() > 1)
+                return;
+            Object obj = ssel.getFirstElement();
+
+            if (obj instanceof IAdaptable) {
+                IProject container = (IProject)((IAdaptable)obj).getAdapter(IProject.class);
+
+                containerText.setText(container.getName().toString());
+            }
+        }
+    }
+
+    private void handleBrowse() {
+        ContainerSelectionDialog dialog = new ContainerSelectionDialog(
+                getShell(), ResourcesPlugin.getWorkspace().getRoot(), false,
+                "Select new file container");
+        if (dialog.open() == ContainerSelectionDialog.OK) {
+            Object[] result = dialog.getResult();
+            if (result.length == 1) {
+                containerText.setText(((Path) result[0]).toString());
+            }
+        }
+    }
+
+    private void dialogChanged() {
+        String containerName = getContainerName();
+
+        if (containerName.length() == 0) {
+            updateStatus("File container must be specified");
+            return;
+        }
+
+        IResource container = ResourcesPlugin.getWorkspace().getRoot()
+                .findMember(new Path(containerName));
+
+        if (container == null
+                || (container.getType() & (IResource.PROJECT | IResource.FOLDER)) == 0) {
+            updateStatus("File container must exist");
+            return;
+        }
+        if (!container.isAccessible()) {
+            updateStatus("Project must be writable");
+            return;
+        }
+        updateStatus(null);
+    }
+
+    private void updateStatus(String message) {
+        setErrorMessage(message);
+        setPageComplete(message == null);
+    }
+
+    public String getContainerName() {
+        return containerText.getText();
+    }
+
+    private List<String> getOpenProjectNames() {
+        List<String> result = new ArrayList<>();
+
+        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+        for (IProject project : projects) {
+           if (project.isOpen()) {
+               result.add(project.getName());
+           }
+        }
+
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/ThermostatProjectCreationWizard.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,174 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.wizards;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.launching.IVMInstall;
+import org.eclipse.jdt.launching.JavaRuntime;
+import org.eclipse.jdt.launching.LibraryLocation;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWizard;
+
+public class ThermostatProjectCreationWizard extends Wizard implements
+        INewWizard {
+    private ThermostatProjectCreationWizardPage page;
+    private ThermostatProjectCreationWizardPageTwo pageTwo;
+    private HashMap<String, Boolean> selectedComponents;
+
+    public ThermostatProjectCreationWizard() {
+        super();
+        setNeedsProgressMonitor(true);
+    }
+
+    public void addPages() {
+        setWindowTitle("Create New Thermostat Plugin");
+        page = new ThermostatProjectCreationWizardPage();
+        addPage(page);
+        pageTwo = new ThermostatProjectCreationWizardPageTwo();
+        addPage(pageTwo);
+    }
+
+    public boolean performFinish() {
+        try {
+            selectedComponents = page.getSelectedComponents();
+
+            createProject(page.getProjectName());
+            for (Entry<String, Boolean> temp : selectedComponents.entrySet()) {
+                if (temp.getValue()) {
+                    createProject(page.getProjectName() + "-" + temp.getKey());
+                }
+            }
+        } catch (CoreException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        return true;
+    }
+
+    private void createProject(String projectTitle) throws CoreException {
+        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+        IProject project = root.getProject(projectTitle);
+        if (project.exists()) {
+            project.delete(true, null);
+        }
+        try {
+            project.create(null);
+            project.open(null);
+        } catch (CoreException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        // Set the Java nature to created project
+        IProjectDescription description = project.getDescription();
+        description.setNatureIds(new String[] { JavaCore.NATURE_ID });
+        project.setDescription(description, null);
+
+        // Create Java project
+        IJavaProject javaProject = JavaCore.create(project);
+
+        // Add bin/ouput folder
+        IFolder binFolder = project.getFolder("bin");
+        binFolder.create(false, true, null);
+        javaProject.setOutputLocation(binFolder.getFullPath(), null);
+
+        // Add libs to project class path
+        List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
+        IVMInstall vmInstall = JavaRuntime.getDefaultVMInstall();
+        LibraryLocation[] locations = JavaRuntime
+                .getLibraryLocations(vmInstall);
+        for (LibraryLocation element : locations) {
+            entries.add(JavaCore.newLibraryEntry(
+                    element.getSystemLibraryPath(), null, null));
+        }
+
+        javaProject.setRawClasspath(
+                entries.toArray(new IClasspathEntry[entries.size()]), null);
+
+        // If root then folder create sub directories corresponding components
+        if (page.getProjectName().equals(projectTitle)) {
+            for (Entry<String, Boolean> currentComponent : selectedComponents
+                    .entrySet()) {
+                if (currentComponent.getValue()) {
+                    IFolder componentFolder = project.getFolder(currentComponent
+                            .getKey());
+                    componentFolder.create(false, true, null);
+                }
+            }
+        }
+
+        // Create src folder
+        IFolder srcFolder = project.getFolder("src");
+        srcFolder.create(false, true, null);
+
+        IFolder srcMainFolder = srcFolder.getFolder("main");
+        srcMainFolder.create(true, true, null);
+
+        IFolder srcMainJavaFolder = srcMainFolder.getFolder("java");
+        srcMainJavaFolder.create(true, true, null);
+
+        IPackageFragmentRoot packageFragmentRoot = javaProject
+                .getPackageFragmentRoot(srcMainJavaFolder);
+        IClasspathEntry[] oldEntries = javaProject.getRawClasspath();
+        IClasspathEntry[] newEntries = new IClasspathEntry[oldEntries.length + 1];
+        System.arraycopy(oldEntries, 0, newEntries, 0, oldEntries.length);
+        newEntries[oldEntries.length] = JavaCore
+                .newSourceEntry(packageFragmentRoot.getPath());
+        javaProject.setRawClasspath(newEntries, null);
+
+        IPackageFragment pack = javaProject.getPackageFragmentRoot(
+                srcMainJavaFolder).createPackageFragment(pageTwo.getPackageName(),
+                false, null);
+
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("package " + pack.getElementName() + ";\n");
+        buffer.append("\n");
+        // Empty file for testing
+        ICompilationUnit cu = pack.createCompilationUnit(
+                "ThermostatPlugin.java", buffer.toString(), false, null);
+
+        // Create thermostat-plugin.xml in the main project
+        if (page.getProjectName().equals(projectTitle)) {
+            final IFile file = project.getFile("thermostat-plugin.xml");
+            try {
+                InputStream stream = openContentStream();
+                if (file.exists()) {
+                    file.setContents(stream, true, true, null);
+                } else {
+                    file.create(stream, true, null);
+                }
+                stream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private InputStream openContentStream() {
+        String contents = "<--!Welcome to Thermostat-->"; // Sample content
+        return new ByteArrayInputStream(contents.getBytes());
+    }
+    public void init(IWorkbench workbench, IStructuredSelection selection) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/ThermostatProjectCreationWizardPage.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,155 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.wizards;
+
+import java.util.HashMap;
+
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+public class ThermostatProjectCreationWizardPage extends WizardPage {
+    private Text projectText;
+
+    private boolean agentSelected = false;
+    private boolean clientSelected = false;
+    private boolean commonSelected = false;
+    private boolean distributionSelected = false;
+
+    public ThermostatProjectCreationWizardPage() {
+        super("wizardPage");
+        setTitle("Thermostat Wizard");
+        setDescription("This wizard creates a new Thermostat Plugin.");
+    }
+
+    public void createControl(Composite parent) {
+        Composite container = new Composite(parent, SWT.NULL);
+        GridLayout layout = new GridLayout();
+        container.setLayout(layout);
+        
+        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+        Label projectNameLabel = new Label(container, SWT.NULL);
+        projectNameLabel.setText("&Project name:");
+        
+        projectText = new Text(container, SWT.BORDER | SWT.SINGLE);
+        gd = new GridData(GridData.FILL_HORIZONTAL);
+        projectText.setLayoutData(gd);
+        projectText.addModifyListener(new ModifyListener() {
+            public void modifyText(ModifyEvent e) {
+                dialogChanged();
+            }
+        });
+        
+        Label componentLabel = new Label(container, SWT.NULL);
+        componentLabel.setText("&Select components you would like to include in the project: ");
+        
+        Button agentButton = new Button(container, SWT.CHECK);
+        agentButton.setText("Agent");
+        agentButton.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e){
+                Button button = (Button) e.widget;
+                if (button.getSelection()) {
+                    agentSelected = true;
+                } else {
+                    agentSelected = false;
+                }
+            }
+        });
+        
+        Button clientButton = new Button(container, SWT.CHECK);
+        clientButton.setText("Client");
+        clientButton.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e){
+                Button button = (Button) e.widget;
+                if (button.getSelection()) {
+                    clientSelected = true;
+                } else {
+                    clientSelected = false;
+                }
+            }
+        });
+        
+        Button commonButton = new Button(container, SWT.CHECK);
+        commonButton.setText("Common");
+        commonButton.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e){
+                Button button = (Button) e.widget;
+                if (button.getSelection()) {
+                    commonSelected = true;
+                } else {
+                    commonSelected = false;
+                }
+            }
+        });
+        
+        Button distributionButton = new Button(container, SWT.CHECK);
+        distributionButton.setText("Distribution");
+        distributionButton.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e){
+                Button button = (Button) e.widget;
+                if (button.getSelection()) {
+                    distributionSelected = true;
+                } else {
+                    distributionSelected = false;
+                }
+            }
+        });
+        
+        initialize();
+        dialogChanged();
+
+        setControl(container);
+    }
+
+    private void initialize() {
+        projectText.setText("Thermostat-Plugin-Project");
+    }
+
+    private void dialogChanged() {
+        String projectName = getProjectName();
+        if (projectName.length() == 0) {
+            updateStatus("Project name must be specified");
+            return;
+        }
+        if (projectName.replace('\\', '/').indexOf('/', 1) > 0) {
+            updateStatus("Project name must be valid");
+            return;
+        }
+        if (projectName.contains(" ")) {
+            updateStatus("Project name must be valid");
+            return;
+        }
+        updateStatus(null);
+    }
+
+    private void updateStatus(String message) {
+        setErrorMessage(message);
+        setPageComplete(message == null);
+    }
+
+    public String getProjectName() {
+        return projectText.getText();
+    }
+
+    public HashMap<String, Boolean> getSelectedComponents() {
+        HashMap<String, Boolean> selectedComponentBoxes = new HashMap<String, Boolean>();
+        
+        selectedComponentBoxes.put("agent", agentSelected);
+        selectedComponentBoxes.put("client", clientSelected);
+        selectedComponentBoxes.put("common", commonSelected);
+        selectedComponentBoxes.put("distribution", distributionSelected);
+        
+        return selectedComponentBoxes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/src/com/redhat/thermostat/plugin/eclipse/plugin/wizards/ThermostatProjectCreationWizardPageTwo.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,71 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.wizards;
+
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+public class ThermostatProjectCreationWizardPageTwo extends WizardPage {
+    private Text packageText;
+
+    public ThermostatProjectCreationWizardPageTwo() {
+        super("wizardPage");
+        setTitle("Thermostat Wizard");
+        setDescription("This wizard creates a new Thermostat Plugin.");
+    }
+
+    public void createControl(Composite parent) {
+        Composite container = new Composite(parent, SWT.NULL);
+        GridLayout layout = new GridLayout();
+        container.setLayout(layout);
+        
+        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+        Label packageNameLabel = new Label(container, SWT.NULL);
+        packageNameLabel.setText("&Package name:");
+        
+        packageText = new Text(container, SWT.BORDER | SWT.SINGLE);
+        gd = new GridData(GridData.FILL_HORIZONTAL);
+        packageText.setLayoutData(gd);
+        packageText.addModifyListener(new ModifyListener() {
+            public void modifyText(ModifyEvent e) {
+                dialogChanged();
+            }
+        });
+        
+        initialize();
+        dialogChanged(); 
+
+        setControl(container);
+    }
+
+    private void initialize() {
+        packageText.setText("com.redhat.thermostat.plugin");
+    }
+
+    private void dialogChanged() {
+        String packageName = getPackageName();
+        if (packageName.length() == 0) {
+            updateStatus("Package name must be specified");
+            return;
+        }
+        if (packageName.contains(" ")) {
+            updateStatus("Package name must be valid");
+            return;
+        }
+        updateStatus(null);
+    }
+
+    private void updateStatus(String message) {
+        setErrorMessage(message);
+        setPageComplete(message == null);
+    }
+
+    public String getPackageName() {
+        return packageText.getText();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/test/com/redhat/thermostat/plugin/eclipse/model/CommandTest.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,122 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.beans.PropertyChangeListener;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class CommandTest {
+
+    private CustomListener listener;
+    private Command command;
+
+    @Before
+    public void setUp() {
+        command = new Command();
+
+        listener = new CustomListener();
+    }
+
+    @Test
+    public void testConstruction() {
+        Command command = new Command("name", "description", "usage",
+                Collections.<String> emptyList(),
+                Collections.<Option> emptyList(),
+                new Environments(),
+                Collections.<Bundle> emptyList());
+
+        assertNotNull(command);
+
+        assertEquals("name", command.getName());
+        assertEquals("description", command.getDescription());
+        assertEquals("usage", command.getUsage());
+    }
+
+    @Test
+    public void testNameChange() {
+        command.setName("old");
+        command.addPropertyChangeListener("name", listener);
+
+        command.setName("new");
+
+        assertPropertyChanged(listener, "name", "old", "new");
+    }
+
+    @Test
+    public void testDescriptionChange() {
+        command.setDescription("old");
+        command.addPropertyChangeListener("description", listener);
+
+        command.setDescription("new");
+
+        assertPropertyChanged(listener, "description", "old", "new");
+    }
+
+    @Test
+    public void testUsageChange() {
+        command.setUsage("old");
+        command.addPropertyChangeListener("usage", listener);
+
+        command.setUsage("new");
+
+        assertPropertyChanged(listener, "usage", "old", "new");
+    }
+
+    @Test
+    public void testArgumentsChange() {
+        command.setArguments(Arrays.asList(new String[] { "old" }));
+        command.addPropertyChangeListener("arguments", listener);
+
+        command.setArguments(Arrays.asList(new String[] { "new" }));
+
+        assertPropertyChanged(listener, "arguments",
+                Arrays.asList(new String[] { "old" }), Arrays.asList(new String[] { "new" }));
+    }
+
+    private static void assertPropertyChanged(CustomListener listener,
+            String propertyName, Object oldValue, Object newValue) {
+
+        assertTrue(listener.getInvoked());
+        assertEquals(propertyName, listener.getPropertyName());
+        assertEquals(oldValue, listener.getOldValue());
+        assertEquals(newValue, listener.getNewValue());
+    }
+
+    static class CustomListener implements PropertyChangeListener {
+
+        private boolean invoked = false;
+        private String propertyName;
+        private Object oldValue;
+        private Object newValue;
+
+        public void propertyChange(java.beans.PropertyChangeEvent evt) {
+            this.invoked = true;
+            this.propertyName = evt.getPropertyName();
+            this.oldValue = evt.getOldValue();
+            this.newValue = evt.getNewValue();
+        };
+
+        public boolean getInvoked() {
+            return invoked;
+        }
+
+        public String getPropertyName() {
+            return propertyName;
+        }
+
+        public Object getOldValue() {
+            return oldValue;
+        }
+
+        public Object getNewValue() {
+            return newValue;
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/test/com/redhat/thermostat/plugin/eclipse/model/EnvironmentsTest.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,52 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static com.redhat.thermostat.plugin.eclipse.plugin.model.PropertyChangeRecorder.assertPropertyChanged;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class EnvironmentsTest {
+
+    private Environments environments;
+    private PropertyChangeRecorder recorder;
+
+    @Before
+    public void setUp() {
+        environments = new Environments();
+        recorder = new PropertyChangeRecorder();
+        environments.addPropertyChangeListener(recorder);
+    }
+
+    @Test
+    public void testCli() {
+        assertFalse(environments.isCli());
+
+        environments.setCli(true);
+
+        assertTrue(environments.isCli());
+        assertPropertyChanged(recorder, environments, "cli", false, true);
+
+        environments.setCli(false);
+
+        assertFalse(environments.isCli());
+        assertPropertyChanged(recorder, environments, "cli", true, false);
+    }
+
+    @Test
+    public void testShell() {
+        assertFalse(environments.isShell());
+
+        environments.setShell(true);
+
+        assertTrue(environments.isShell());
+        assertPropertyChanged(recorder, environments, "shell", false, true);
+
+        environments.setShell(false);
+
+        assertFalse(environments.isShell());
+        assertPropertyChanged(recorder, environments, "shell", true, false);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/test/com/redhat/thermostat/plugin/eclipse/model/PluginModelReaderWriterTest.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,86 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+public class PluginModelReaderWriterTest {
+
+    @Test
+    public void testParsingCommand() {
+        String document = "<?xml version='1.0'?>\n"
+                + "<plugin>\n"
+                + "  <commands>\n"
+                + "    <command>\n"
+                + "      <name>foo</name>\n"
+                + "      <usage>foo bar</usage>\n"
+                + "      <description>foos the bar if possible</description>\n"
+                + "      <arguments>\n"
+                + "        <argument>bar</argument>\n"
+                + "      </arguments>\n"
+                + "      <options>\n"
+                + "        <option>\n"
+                + "        </option>\n"
+                + "      </options>\n"
+                + "      <environments>\n"
+                + "        <environment>cli</environment>\n"
+                + "      </environments>\n"
+                + "      <bundles>\n"
+                + "        <bundle><symbolic-name>foo</symbolic-name><version>1</version></bundle>\n"
+                + "      </bundles>\n"
+                + "    </command>\n"
+                + "  </commands>\n"
+                + "</plugin>\n";
+
+        PluginModelReaderWriter pluginModel = new PluginModelReaderWriter(null, "<stdin>");
+        Plugin model = pluginModel.loadModel(document);
+
+        pluginModel.saveModel(model, System.out);
+
+        Command foo = model.getCommands().get(0);
+
+        assertNotNull(foo);
+
+        assertEquals("foo", foo.getName());
+        assertEquals("foo bar", foo.getUsage());
+        assertEquals("foos the bar if possible", foo.getDescription());
+
+        assertTrue(foo.getEnvironments().isCli());
+        assertFalse(foo.getEnvironments().isShell());
+
+        List<Bundle> bundles = foo.getBundles();
+        assertEquals(1, bundles.size());
+
+        Bundle bundle = bundles.get(0);
+        assertEquals("foo", bundle.getSymbolicName());
+        assertEquals("1", bundle.getVersion());
+    }
+
+    @Test
+    public void testBinding() {
+        String document = "<?xml version='1.0'?>\n"
+                + "<plugin>\n"
+                + "  <extensions>\n"
+                + "    <extension>\n"
+                + "      <name>foo</name>\n"
+                + "      <bundles>\n"
+                + "        <bundle><symbolic-name>foo</symbolic-name><version>1</version></bundle>\n"
+                + "      </bundles>\n"
+                + "    </extension>\n"
+                + "  </extensions>\n"
+                + "</plugin>\n";
+
+        PluginModelReaderWriter model = new PluginModelReaderWriter(null, "stdin");
+        Plugin plugin = model.loadModel(document);
+
+        List<Extension> extensions = plugin.getExtensions();
+        assertEquals(1, extensions.size());
+
+        model.saveModel(plugin, System.out);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/com.redhat.thermostat.plugin.eclipse.plugin/test/com/redhat/thermostat/plugin/eclipse/model/PropertyChangeRecorder.java	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,56 @@
+package com.redhat.thermostat.plugin.eclipse.plugin.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+public class PropertyChangeRecorder implements PropertyChangeListener {
+
+    private boolean invoked = false;
+    private Object source;
+    private String propertyName;
+    private Object oldValue;
+    private Object newValue;
+
+    public boolean getInvoked() {
+        return invoked;
+    }
+
+    public Object getSource() {
+        return source;
+    }
+
+    public String getPropertyName() {
+        return propertyName;
+    }
+
+    public Object getOldValue() {
+        return oldValue;
+    }
+
+    public Object getNewValue() {
+        return newValue;
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent evt) {
+        invoked = true;
+
+        source = evt.getSource();
+        propertyName = evt.getPropertyName();
+        oldValue = evt.getOldValue();
+        newValue = evt.getNewValue();
+    }
+
+    public static void assertPropertyChanged(PropertyChangeRecorder recorder,
+            Object source, String propertyName, Object oldValue, Object newValue) {
+
+        assertTrue(recorder.getInvoked());
+        assertEquals(source, recorder.getSource());
+        assertEquals(propertyName, recorder.getPropertyName());
+        assertEquals(oldValue, recorder.getOldValue());
+        assertEquals(newValue, recorder.getNewValue());
+    }
+}
Binary file icons/thermostat.png has changed
--- a/plugin.xml	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?eclipse version="3.4"?>
-<plugin>
-
-   <extension
-         point="org.eclipse.ui.editors">
-      <editor
-            class="com.redhat.thermostat.plugin.eclipse.editor.MultiPageEditor"
-            contributorClass="com.redhat.thermostat.plugin.eclipse.editor.MultiPageEditorContributor"
-            extensions="xml"
-            icon="icons/thermostat.png"
-            id="thermostatplugin.editors.MultiPageEditor"
-            name="Thermostat Plugin Editor">
-         <contentTypeBinding
-               contentTypeId="com.redhat.thermostat.plugin.eclipse.xml">
-         </contentTypeBinding>
-      </editor>
-   </extension>
-   
-   <extension
-         point="org.eclipse.ui.newWizards">
-      <category
-            name="Thermostat"
-            id="com.redhat.thermostat.plugin.eclipse">
-      </category>
-      <wizard
-            name="Thermostat Plugin Projects"
-            icon="icons/thermostat.png"
-            category="com.redhat.thermostat.plugin.eclipse"
-            class="com.redhat.thermostat.plugin.eclipse.wizards.ThermostatProjectCreationWizard"
-            id="thermostatplugin.wizards.CreateNewThermostatPluginWizard">
-      </wizard>
-      <wizard
-            category="com.redhat.thermostat.plugin.eclipse"
-            class="com.redhat.thermostat.plugin.eclipse.wizards.PluginXmlCreationWizard"
-            icon="icons/thermostat.png"
-            id="com.redhat.thermostat.plugin.eclipse.wizards.PluginXmlCreationWizard"
-            name="Thermostat Plugin Descriptor"
-            project="false">
-      </wizard>
-   </extension>
-   <extension
-         id="com.redhat.thermostat.eclipse.plugin.contenttypes"
-         point="org.eclipse.core.contenttype.contentTypes">
-      <content-type
-            base-type="org.eclipse.core.runtime.xml"
-            file-names="thermostat-plugin.xml"
-            id="com.redhat.thermostat.plugin.eclipse.xml"
-            name="Thermostat Plugin XML"
-            priority="high">
-         <describer
-               class="org.eclipse.core.runtime.content.XMLRootElementContentDescriber2">
-            <parameter
-                  name="element"
-                  value="{http://icedtea.classpath.org/thermostat/plugins/v1.0}plugin">
-            </parameter>
-         </describer>
-      </content-type>
-   </extension>
-
-</plugin>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pom.xml	Thu Jan 16 11:09:13 2014 -0500
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+			http://maven.apache.org/xsd/maven-4.0.0.xsd"
+    xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.redhat.thermostat.plugin.eclipse</groupId>
+  <artifactId>com.redhat.thermostat.plugin.eclipse.parent</artifactId>
+  <version>0.1.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>com.redhat.thermostat.plugin.eclipse.plugin</module>
+  </modules>
+
+  <properties>
+    <tycho-version>0.19.0</tycho-version>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <repositories>
+   <repository>
+     <id>kepler</id>
+     <layout>p2</layout>
+     <url>http://download.eclipse.org/releases/kepler</url>
+   </repository>
+  </repositories>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.eclipse.tycho</groupId>
+        <artifactId>tycho-maven-plugin</artifactId>
+        <version>${tycho-version}</version>
+        <extensions>true</extensions>
+      </plugin>
+      <plugin>
+        <groupId>org.eclipse.tycho</groupId>
+        <artifactId>target-platform-configuration</artifactId>
+        <version>${tycho-version}</version>
+        <configuration>
+          <environments>
+            <environment>
+              <os>linux</os>
+              <ws>gtk</ws>
+              <arch>x86</arch>
+            </environment>
+            <environment>
+              <os>linux</os>
+              <ws>gtk</ws>
+              <arch>x86_64</arch>
+            </environment>
+          </environments>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
--- a/src/com/redhat/thermostat/plugin/eclipse/Activator.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse;
-
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.ui.plugin.AbstractUIPlugin;
-import org.osgi.framework.BundleContext;
-
-/**
- * The activator class controls the plug-in life cycle
- */
-public class Activator extends AbstractUIPlugin {
-
-    // The plug-in ID
-    public static final String PLUGIN_ID = "com.redhat.thermostat.plugin.eclipse"; //$NON-NLS-1$
-
-    // The shared instance
-    private static Activator plugin;
-    
-    /**
-     * The constructor
-     */
-    public Activator() {
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
-     */
-    public void start(BundleContext context) throws Exception {
-        super.start(context);
-        plugin = this;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
-     */
-    public void stop(BundleContext context) throws Exception {
-        plugin = null;
-        super.stop(context);
-    }
-
-    /**
-     * Returns the shared instance
-     *
-     * @return the shared instance
-     */
-    public static Activator getDefault() {
-        return plugin;
-    }
-
-    /**
-     * Returns an image descriptor for the image file at the given
-     * plug-in relative path
-     *
-     * @param path the path
-     * @return the image descriptor
-     */
-    public static ImageDescriptor getImageDescriptor(String path) {
-        return imageDescriptorFromPlugin(PLUGIN_ID, path);
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/BundleInformationExtractor.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.jar.Attributes;
-import java.util.jar.JarInputStream;
-
-import com.redhat.thermostat.plugin.eclipse.model.Bundle;
-
-public class BundleInformationExtractor {
-
-    public Bundle extract(String path) throws FileNotFoundException, IOException {
-
-        try (JarInputStream in = new JarInputStream(new FileInputStream(path))) {
-            Attributes attr = in.getManifest().getMainAttributes();
-            String name = attr.getValue("Bundle-SymbolicName");
-            String version = attr.getValue("Bundle-Version");
-
-            return new Bundle(name, version);
-        }
-    }
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/BaseMasterDetailsBlock.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-import org.eclipse.jface.viewers.ArrayContentProvider;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.ui.forms.IManagedForm;
-import org.eclipse.ui.forms.MasterDetailsBlock;
-import org.eclipse.ui.forms.SectionPart;
-import org.eclipse.ui.forms.widgets.FormToolkit;
-import org.eclipse.ui.forms.widgets.Section;
-
-import com.redhat.thermostat.plugin.eclipse.model.Plugin;
-
-public abstract class BaseMasterDetailsBlock extends MasterDetailsBlock {
-
-    protected Plugin model;
-
-    public void setModel(Plugin model) {
-        this.model = model;
-    }
-
-    @Override
-    protected void createToolBarActions(IManagedForm managedForm) {
-        // no-op
-    }
-
-    @Override
-    protected void createMasterPart(final IManagedForm managedForm, final Composite parent) {
-        FormToolkit toolkit = managedForm.getToolkit();
-        final Section section = toolkit.createSection(parent, Section.TITLE_BAR);
-        section.setText(getSectionTitle());
-
-        final SectionPart sectionPart = new SectionPart(section);
-
-        Composite sectionContents = toolkit.createComposite(section);
-        GridLayout layout = new GridLayout(2, false);
-        sectionContents.setLayout(layout);
-
-        section.setClient(sectionContents);
-
-        Table list = toolkit.createTable(sectionContents, SWT.BORDER | SWT.V_SCROLL);
-        list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-        final TableViewer viewer = new TableViewer(list);
-        viewer.addSelectionChangedListener(new ISelectionChangedListener() {
-            @Override
-            public void selectionChanged(SelectionChangedEvent event) {
-                managedForm.fireSelectionChanged(sectionPart, event.getSelection());
-            }
-        });
-        IStructuredContentProvider contentProvider = ArrayContentProvider.getInstance();
-        viewer.setContentProvider(contentProvider);
-        viewer.setInput(getListViewModel());
-        model.addPropertyChangeListener(new PropertyChangeListener() {
-            @Override
-            public void propertyChange(PropertyChangeEvent arg0) {
-                viewer.setInput(getListViewModel());
-                viewer.refresh();
-            }
-        });
-
-        Composite buttons = toolkit.createComposite(sectionContents);
-        GridData buttonCompositeLayoutData = new GridData(SWT.FILL, SWT.FILL, false, true);
-        buttonCompositeLayoutData.verticalAlignment = SWT.BEGINNING;
-        buttons.setLayoutData(buttonCompositeLayoutData);
-
-        buttons.setLayout(new GridLayout(1, false));
-        GridData buttonLayoutData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
-
-        Button add = toolkit.createButton(buttons, "Add", SWT.NONE);
-        add.setLayoutData(buttonLayoutData);
-        add.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                addButtonSelected(parent.getShell());
-
-                Object lastElement = viewer.getElementAt(viewer.getTable().getItemCount() - 1);
-                viewer.setSelection(new StructuredSelection(lastElement));
-            }
-
-        });
-
-        Button remove = toolkit.createButton(buttons, "Remove", SWT.NONE);
-        remove.setLayoutData(buttonLayoutData);
-        remove.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                Object selectedItem = ((IStructuredSelection)viewer.getSelection()).getFirstElement();
-                removeButtonSelected(selectedItem);
-            }
-        });
-    }
-
-    abstract String getSectionTitle();
-
-    abstract Object[] getListViewModel();
-
-    abstract void addButtonSelected(Shell shell);
-
-    abstract void removeButtonSelected(Object selectedItem);
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/CommandEditPage.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,274 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import org.eclipse.core.databinding.DataBindingContext;
-import org.eclipse.core.databinding.beans.BeanProperties;
-import org.eclipse.core.databinding.observable.list.IObservableList;
-import org.eclipse.core.databinding.observable.value.IObservableValue;
-import org.eclipse.jface.databinding.swt.WidgetProperties;
-import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
-import org.eclipse.jface.viewers.ArrayContentProvider;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.ui.forms.IDetailsPage;
-import org.eclipse.ui.forms.IFormPart;
-import org.eclipse.ui.forms.IManagedForm;
-import org.eclipse.ui.forms.editor.FormPage;
-import org.eclipse.ui.forms.widgets.FormToolkit;
-import org.eclipse.ui.forms.widgets.Section;
-import org.eclipse.ui.forms.widgets.TableWrapData;
-import org.eclipse.ui.forms.widgets.TableWrapLayout;
-
-import com.redhat.thermostat.plugin.eclipse.model.Bundle;
-import com.redhat.thermostat.plugin.eclipse.model.Command;
-import com.redhat.thermostat.plugin.eclipse.model.Environments;
-import com.redhat.thermostat.plugin.eclipse.model.Plugin;
-
-class CommandEditPage implements IDetailsPage {
-
-    private FormToolkit toolkit;
-    private Plugin model;
-    private boolean isStale = false;
-
-    private Command commandModel;
-
-    private Text commandName;
-    private Text commandUsage;
-    private Text commandDescription;
-    private Button cli;
-    private Button shell;
-
-    // uses a List<Bundle> as the backing model
-    private TableViewer bundlesTableViewer;
-
-    private DataBindingContext bindingContext;
-
-    private FormPage form;
-
-    public CommandEditPage(FormPage formPage) {
-        this.form = formPage;
-    }
-
-    public void setModel(Plugin model) {
-        this.model = model;
-    }
-
-    @Override
-    public void initialize(IManagedForm form) {
-        toolkit = form.getToolkit();
-    }
-
-    @Override
-    public void dispose() {
-        if (bindingContext != null) {
-            bindingContext.dispose();
-        }
-    }
-
-    @Override
-    public boolean isDirty() {
-        if (commandModel == null) {
-            return false;
-        }
-
-        Command latestCommandInModel = model.getCommand(commandModel.getName());
-        if (latestCommandInModel == null) {
-            return false;
-        }
-
-        // TODO convert is-command-different into is-command-dirty operation
-        return !latestCommandInModel.equals(commandModel);
-    }
-
-    @Override
-    public void commit(boolean onSave) {
-        // no op
-    }
-
-    @Override
-    public boolean setFormInput(Object input) {
-        // TODO fix this
-        return false;
-    }
-
-    @Override
-    public void setFocus() {
-        // TODO what is this?
-    }
-
-    @Override
-    public boolean isStale() {
-        // FIXME check from model?
-        return false;
-    }
-
-    @Override
-    public void refresh() {
-        // no-op
-    }
-
-    @Override
-    public void selectionChanged(IFormPart part, ISelection selection) {
-        if (bindingContext != null) {
-            bindingContext.dispose();
-        }
-
-        String commandName = (String) ((IStructuredSelection)selection).getFirstElement();
-        commandModel = model.getCommand(commandName);
-        if (commandModel == null) {
-            return;
-        }
-
-        bindingContext = initDataBindings();
-    }
-
-    @Override
-    public void createContents(Composite parent) {
-        TableWrapLayout parentLayout = new TableWrapLayout();
-        parentLayout.topMargin = 0;
-        parentLayout.bottomMargin = 0;
-        parentLayout.leftMargin = 0;
-        parentLayout.rightMargin = 0;
-        parent.setLayout(parentLayout);
-
-        Section section = toolkit.createSection(parent, Section.TITLE_BAR);
-
-        TableWrapData tableData = new TableWrapData(TableWrapData.FILL, TableWrapData.TOP);
-        tableData.grabHorizontal = true;
-
-        section.setLayoutData(tableData);
-
-        section.setText("Command details");
-
-        Composite sectionContents = toolkit.createComposite(section);
-        section.setClient(sectionContents);
-
-        sectionContents.setLayout(new GridLayout());
-
-        createBasicSection(sectionContents);
-        createArgumentsAndOptionsSection(sectionContents);
-        createBundlesSection(sectionContents);
-    }
-
-    private void createBasicSection(Composite sectionContents) {
-        Section basics = toolkit.createSection(sectionContents, Section.TITLE_BAR);
-        basics.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-        basics.setText("Basics");
-
-        Composite basicContents = toolkit.createComposite(basics);
-        basics.setClient(basicContents);
-        basicContents.setLayout(new GridLayout(2, false));
-
-        toolkit.createLabel(basicContents, "Name:");
-        commandName = toolkit.createText(basicContents, "<command name here>");
-        commandName.setEditable(false);
-        commandName.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
-
-        toolkit.createLabel(basicContents, "Usage:");
-        commandUsage = toolkit.createText(basicContents, "<usage>");
-        commandUsage.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
-
-        toolkit.createLabel(basicContents, "Description:");
-        commandDescription = toolkit.createText(basicContents, "<description>");
-        commandDescription.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
-
-        toolkit.createLabel(basicContents, "Environments");
-        Composite environmentsComposite = toolkit.createComposite(basicContents);
-        environmentsComposite.setLayout(new RowLayout());
-        cli = toolkit.createButton(environmentsComposite, "CLI", SWT.CHECK);
-        shell = toolkit.createButton(environmentsComposite, "Shell", SWT.CHECK);
-    }
-
-    private void createArgumentsAndOptionsSection(Composite sectionContents) {
-        // TODO Auto-generated method stub
-    }
-
-    private void createBundlesSection(final Composite sectionContents) {
-        Section bundles = toolkit.createSection(sectionContents, Section.TITLE_BAR);
-        bundles.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-        bundles.setText("Bundles to load");
-
-        Composite bundleContents = toolkit.createComposite(bundles);
-        bundles.setClient(bundleContents);
-        bundleContents.setLayout(new GridLayout(2, false));
-
-        Table list = toolkit.createTable(bundleContents, SWT.BORDER | SWT.V_SCROLL);
-        list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-        bundlesTableViewer = new TableViewer(list);
-        IStructuredContentProvider contentProvider = ArrayContentProvider.getInstance();
-        bundlesTableViewer.setContentProvider(contentProvider);
-
-        Composite buttonComposite = toolkit.createComposite(bundleContents);
-        buttonComposite.setLayout(new GridLayout(1, false));
-
-        Button add = toolkit.createButton(buttonComposite, "Add", SWT.NONE);
-        add.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
-        add.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                NewBundleDialog dialog = new NewBundleDialog(sectionContents.getShell());
-                dialog.create();
-                if (dialog.open() == Window.OK) {
-                    commandModel.addBundle(dialog.getBundle());
-                }
-            }
-        });
-
-        Button remove = toolkit.createButton(buttonComposite, "Remove", SWT.NONE);
-        remove.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
-        remove.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                Bundle selectedItem = (Bundle)
-                        ((IStructuredSelection)bundlesTableViewer.getSelection()).getFirstElement();
-                commandModel.removeBundle(selectedItem);
-            }
-        });
-    }
-
-    private DataBindingContext initDataBindings() {
-        DataBindingContext bindingContext = new DataBindingContext();
-
-        IObservableValue nameWidgetValue = WidgetProperties.text(SWT.Modify).observe(commandName);
-        IObservableValue nameModelValue = BeanProperties.value(Command.class, "name").observe(commandModel);
-        bindingContext.bindValue(nameWidgetValue, nameModelValue);
-
-        IObservableValue usageWidgetValue = WidgetProperties.text(SWT.Modify).observe(commandUsage);
-        IObservableValue usageModelValue = BeanProperties.value(Command.class, "usage").observe(commandModel);
-        bindingContext.bindValue(usageWidgetValue, usageModelValue);
-
-        IObservableValue descriptionWidgetValue = WidgetProperties.text(SWT.Modify).observe(commandDescription);
-        IObservableValue descriptionModelValue = BeanProperties.value(Command.class, "description").observe(commandModel);
-        bindingContext.bindValue(descriptionWidgetValue, descriptionModelValue);
-
-        IObservableValue environmentsModelValue = BeanProperties.value(Command.class, "environments").observe(commandModel);
-
-        IObservableValue cliWidgetValue = WidgetProperties.selection().observe(cli);
-        IObservableValue cliModelValue = BeanProperties.value(Environments.class, "cli").observeDetail(environmentsModelValue);
-        bindingContext.bindValue(cliWidgetValue, cliModelValue);
-
-        IObservableValue shellWidgetValue = WidgetProperties.selection().observe(shell);
-        IObservableValue shellModelValue = BeanProperties.value(Environments.class, "shell").observeDetail(environmentsModelValue);
-        bindingContext.bindValue(shellWidgetValue, shellModelValue);
-
-        ObservableListContentProvider listContentProvider = new ObservableListContentProvider();
-        bundlesTableViewer.setContentProvider(listContentProvider);
-
-        IObservableList bundlesModel = BeanProperties.list(Command.class, "bundles").observe(commandModel);
-        bundlesTableViewer.setInput(bundlesModel);
-
-        return bindingContext;
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/CommandsMasterDetailsBlock.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.forms.DetailsPart;
-import org.eclipse.ui.forms.editor.FormPage;
-
-import com.redhat.thermostat.plugin.eclipse.model.Command;
-import com.redhat.thermostat.plugin.eclipse.model.Plugin;
-
-public class CommandsMasterDetailsBlock extends BaseMasterDetailsBlock {
-
-    private CommandEditPage editPage;
-
-    public CommandsMasterDetailsBlock(FormPage formPage) {
-        editPage = new CommandEditPage(formPage);
-    }
-
-    public void setModel(Plugin model) {
-        super.setModel(model);
-
-        editPage.setModel(model);
-    }
-
-    @Override
-    protected void registerPages(DetailsPart detailsPart) {
-        detailsPart.registerPage(String.class, editPage);
-    }
-
-    @Override
-    String getSectionTitle() {
-        return "Commands provided by the plugin";
-    }
-
-    @Override
-    Object[] getListViewModel() {
-        return model.getCommandNames().toArray();
-    }
-
-    @Override
-    void addButtonSelected(Shell shell) {
-        NewNameDialog dialog = new NewNameDialog(shell);
-        dialog.create();
-        if (dialog.open() == Window.OK) {
-            Command command = new Command();
-            command.setName(dialog.getName());
-            model.addCommand(command);
-        }
-    }
-
-    @Override
-    void removeButtonSelected(Object selectedItem) {
-        model.removeCommand((String) selectedItem);
-        
-    };
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/CommandsPage.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import org.eclipse.ui.forms.IManagedForm;
-import org.eclipse.ui.forms.editor.FormEditor;
-import org.eclipse.ui.forms.editor.FormPage;
-import org.eclipse.ui.forms.widgets.ScrolledForm;
-import org.eclipse.ui.forms.widgets.TableWrapLayout;
-
-import com.redhat.thermostat.plugin.eclipse.model.Plugin;
-
-public class CommandsPage extends FormPage {
-
-    static final String ID = "com.redhat.thermostat.plugin.eclipse.editor.CommandsPage";
-    static final String TITLE = "Commands";
-
-    private Plugin model;
-
-    public CommandsPage(FormEditor editor, Plugin model) {
-        super(editor, ID, TITLE);
-
-        this.model = model;
-    }
-
-    @Override
-    protected void createFormContent(IManagedForm managedForm) {
-        ScrolledForm form = managedForm.getForm();
-
-        form.setText("Commands");
-        form.getBody().setLayout(new TableWrapLayout());
-
-        CommandsMasterDetailsBlock masterAndDetails = new CommandsMasterDetailsBlock(this);
-        masterAndDetails.setModel(model);
-        masterAndDetails.createContent(managedForm);
-    }
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/ExtensionEditPage.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import java.util.Objects;
-
-import org.eclipse.core.databinding.DataBindingContext;
-import org.eclipse.core.databinding.beans.BeanProperties;
-import org.eclipse.core.databinding.observable.list.IObservableList;
-import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.ui.forms.IDetailsPage;
-import org.eclipse.ui.forms.IFormPart;
-import org.eclipse.ui.forms.IManagedForm;
-import org.eclipse.ui.forms.editor.FormPage;
-import org.eclipse.ui.forms.widgets.FormToolkit;
-import org.eclipse.ui.forms.widgets.Section;
-import org.eclipse.ui.forms.widgets.TableWrapData;
-import org.eclipse.ui.forms.widgets.TableWrapLayout;
-
-import com.redhat.thermostat.plugin.eclipse.model.Bundle;
-import com.redhat.thermostat.plugin.eclipse.model.Extension;
-import com.redhat.thermostat.plugin.eclipse.model.Plugin;
-
-public class ExtensionEditPage implements IDetailsPage {
-
-    private FormToolkit toolkit;
-    private Plugin model;
-    private TableViewer bundlesTableViewer;
-
-    private Extension extensionModel;
-
-    private DataBindingContext bindingContext;
-
-    private FormPage formPage;
-
-    public ExtensionEditPage(FormPage parent) {
-        this.formPage = parent;
-    }
-
-    public void setModel(Plugin model) {
-        this.model = model;
-    }
-
-    @Override
-    public void initialize(IManagedForm form) {
-        toolkit = form.getToolkit();
-    }
-
-    @Override
-    public void dispose() {
-        if (bindingContext != null) {
-            bindingContext.dispose();
-        }
-    }
-
-    @Override
-    public boolean isDirty() {
-        if (extensionModel == null) {
-            return false;
-        }
-
-        Extension extensionInMasterModel = model.getExtension(extensionModel.getName());
-        if (extensionInMasterModel == null) {
-            return false;
-        }
-
-        // TODO change this is-content-different into is-content-dirty
-        return !extensionInMasterModel.equals(extensionModel);
-    }
-
-    @Override
-    public void commit(boolean onSave) {
-        // nothing to do
-    }
-
-    @Override
-    public boolean setFormInput(Object input) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public void setFocus() {
-        // TODO Auto-generated method stub
-        
-    }
-
-    @Override
-    public boolean isStale() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public void refresh() {
-        // no-op
-    }
-
-    @Override
-    public void selectionChanged(IFormPart part, ISelection selection) {
-        if (bindingContext != null) {
-            bindingContext.dispose();
-        }
-
-        String extensionName = (String) ((IStructuredSelection)selection).getFirstElement();
-        extensionModel = model.getExtension(extensionName);
-
-        bindingContext = initDataBindings();
-    }
-
-    @Override
-    public void createContents(Composite parent) {
-        TableWrapLayout parentLayout = new TableWrapLayout();
-        parentLayout.topMargin = 0;
-        parentLayout.bottomMargin = 0;
-        parentLayout.leftMargin = 0;
-        parentLayout.rightMargin = 0;
-        parent.setLayout(parentLayout);
-
-        Section section = toolkit.createSection(parent, Section.TITLE_BAR);
-
-        TableWrapData tableData = new TableWrapData(TableWrapData.FILL, TableWrapData.TOP);
-        tableData.grabHorizontal = true;
-
-        section.setLayoutData(tableData);
-
-        section.setText("Extension details");
-
-        Composite sectionContents = toolkit.createComposite(section);
-        section.setClient(sectionContents);
-
-        sectionContents.setLayout(new GridLayout());
-
-        createBundlesSection(sectionContents);
-    }
-
-    private void createBundlesSection(final Composite sectionContents) {
-        Section bundles = toolkit.createSection(sectionContents, Section.TITLE_BAR);
-        bundles.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-        bundles.setText("Bundles to load");
-
-        Composite bundleContents = toolkit.createComposite(bundles);
-        bundles.setClient(bundleContents);
-        bundleContents.setLayout(new GridLayout(2, false));
-
-        Table bundlesTable = toolkit.createTable(bundleContents, SWT.BORDER | SWT.V_SCROLL);
-        bundlesTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
-        bundlesTableViewer = new TableViewer(bundlesTable);
-
-        Composite buttonComposite = toolkit.createComposite(bundleContents);
-        buttonComposite.setLayout(new GridLayout(1, false));
-
-        Button add = toolkit.createButton(buttonComposite, "Add", SWT.NONE);
-        add.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
-        add.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                NewBundleDialog dialog = new NewBundleDialog(sectionContents.getShell());
-                dialog.create();
-                if (dialog.open() == Window.OK) {
-                    Bundle newBundle = dialog.getBundle();
-                    extensionModel.addBundle(newBundle);
-                }
-            }
-        });
-
-        Button remove = toolkit.createButton(buttonComposite, "Remove", SWT.NONE);
-        remove.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
-        remove.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                Bundle selectedItem = (Bundle)
-                        ((IStructuredSelection)bundlesTableViewer.getSelection()).getFirstElement();
-                extensionModel.removeBundle(selectedItem);
-            }
-        });
-
-    }
-
-    private DataBindingContext initDataBindings() {
-        DataBindingContext bindingContext = new DataBindingContext();
-
-        ObservableListContentProvider listContentProvider = new ObservableListContentProvider();
-        bundlesTableViewer.setContentProvider(listContentProvider);
-
-        IObservableList bundlesModel = BeanProperties.list(Extension.class, "bundles").observe(extensionModel);
-        bundlesTableViewer.setInput(bundlesModel);
-
-        return bindingContext;
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/ExtensionsMasterDetailsBlock.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.forms.DetailsPart;
-
-import com.redhat.thermostat.plugin.eclipse.model.Extension;
-import com.redhat.thermostat.plugin.eclipse.model.Plugin;
-
-public class ExtensionsMasterDetailsBlock extends BaseMasterDetailsBlock {
-
-    private ExtensionEditPage editPage;
-
-    public ExtensionsMasterDetailsBlock(ExtensionsPage extensionsPage) {
-        editPage = new ExtensionEditPage(extensionsPage);
-    }
-
-    public void setModel(Plugin model) {
-        super.setModel(model);
-
-        editPage.setModel(model);
-    }
-
-    @Override
-    protected void registerPages(DetailsPart detailsPart) {
-        detailsPart.registerPage(String.class, editPage);
-    }
-
-    @Override
-    String getSectionTitle() {
-        return "Commands extended by the plugin";
-    }
-
-    @Override
-    Object[] getListViewModel() {
-        return model.getExtensionNames().toArray();
-    }
-
-    @Override
-    void addButtonSelected(Shell shell) {
-        NewNameDialog dialog = new NewNameDialog(shell);
-        dialog.create();
-        if (dialog.open() == Window.OK) {
-            Extension newExtension = new Extension();
-            newExtension.setName(dialog.getName());
-            model.addExtension(newExtension);
-        }
-    }
-
-    @Override
-    void removeButtonSelected(Object selectedItem) {
-        if (selectedItem == null) {
-            return;
-        }
-
-        model.removeExtension((String) selectedItem);
-    };
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/ExtensionsPage.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.ui.forms.IManagedForm;
-import org.eclipse.ui.forms.editor.FormEditor;
-import org.eclipse.ui.forms.editor.FormPage;
-import org.eclipse.ui.forms.widgets.ScrolledForm;
-
-import com.redhat.thermostat.plugin.eclipse.model.Plugin;
-
-
-public class ExtensionsPage extends FormPage {
-
-    static final String ID = "com.redhat.thermostat.plugin.eclipse.editor.ExtensionsPage";
-    static final String TITLE = "Extensions";
-
-    private Plugin model;
-
-    public ExtensionsPage(FormEditor editor, Plugin model) {
-        super(editor, ID, TITLE);
-
-        this.model = model;
-    }
-
-    @Override
-    protected void createFormContent(IManagedForm managedForm) {
-        ScrolledForm form = managedForm.getForm();
-        form.setText("Extensions");
-        GridLayout layout = new GridLayout();
-        layout.numColumns = 2;
-        layout.makeColumnsEqualWidth = true;
-        form.getBody().setLayout(layout);
-
-        ExtensionsMasterDetailsBlock masterAndDetails = new ExtensionsMasterDetailsBlock(this);
-        masterAndDetails.setModel(model);
-        masterAndDetails.createContent(managedForm);
-    }
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/MultiPageEditor.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import java.io.ByteArrayOutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Objects;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IResourceChangeEvent;
-import org.eclipse.core.resources.IResourceChangeListener;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jface.text.DocumentEvent;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IDocumentListener;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorSite;
-import org.eclipse.ui.IFileEditorInput;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.forms.editor.FormEditor;
-import org.eclipse.ui.part.FileEditorInput;
-import org.eclipse.wst.sse.ui.StructuredTextEditor;
-
-import com.redhat.thermostat.plugin.eclipse.model.Plugin;
-import com.redhat.thermostat.plugin.eclipse.model.PluginModelReaderWriter;
-
-public class MultiPageEditor extends FormEditor implements IResourceChangeListener {
-
-    private static final int INDEX_SOURCE = 3;
-
-    private StructuredTextEditor editor;
-    private boolean editorIsDirty = false;
-
-    private PluginModelReaderWriter modelHelper;
-    private Plugin model;
-
-    private int oldPage = -1;
-
-    public MultiPageEditor() {
-        super();
-        ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
-    }
-
-    @Override
-    public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException {
-        if (!(editorInput instanceof IFileEditorInput))
-            throw new PartInitException("Invalid Input: Must be IFileEditorInput");
-        super.init(site, editorInput);
-
-        try {
-            IFile file = ((IFileEditorInput)getEditorInput()).getFile();
-            modelHelper = new PluginModelReaderWriter(file);
-            model = modelHelper.loadModel(file.getContents());
-            Objects.requireNonNull(model);
-        } catch (CoreException e) {
-            e.printStackTrace();
-        }
-
-    }
-
-    @Override
-    protected void addPages() {
-        try {
-            OverviewPage overview = new OverviewPage(this, modelHelper.getPluginName());
-            addPage(overview);
-
-            CommandsPage commandsPage = new CommandsPage(this, model);
-            addPage(commandsPage);
-
-            ExtensionsPage extensionsPage = new ExtensionsPage(this, model);
-            addPage(extensionsPage);
-
-            createSourcePage();
-        } catch (PartInitException pie) {
-            throw new RuntimeException(pie);
-            // ErrorDialog.openError(getSite().getShell(),
-            //     "Error creating nested text editor", null, e.getStatus());
-
-        }
-    }
-
-    void createSourcePage() throws PartInitException {
-        editor = new StructuredTextEditor();
-        addPage(editor, getEditorInput());
-        setPageText(INDEX_SOURCE, editor.getTitle());
-
-        getDocument().addDocumentListener(new IDocumentListener() {
-
-            @Override
-            public void documentChanged(DocumentEvent event) {
-                editorIsDirty = true;
-            }
-
-            @Override
-            public void documentAboutToBeChanged(DocumentEvent event) {
-                // nothing to do
-            }
-        });
-    }
-
-    @Override
-    public void dispose() {
-        ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
-        super.dispose();
-    }
-
-    @Override
-    protected void pageChange(int newPageIndex) {
-        if (oldPage != -1) {
-            if (oldPage == INDEX_SOURCE && editorIsDirty) {
-                updateModelFromSource();
-            } else if (newPageIndex == INDEX_SOURCE) {
-                updateSourceFromModel();
-            }
-        }
-
-        super.pageChange(newPageIndex);
-
-        oldPage = newPageIndex;
-    }
-
-    @Override
-    public void doSave(IProgressMonitor monitor) {
-        if (getActivePage() != INDEX_SOURCE) {
-            updateSourceFromModel();
-        }
-
-        editor.doSave(monitor);
-    }
-
-    @Override
-    public boolean isSaveAsAllowed() {
-        return false;
-    }
-
-    @Override
-    public void doSaveAs() {
-        throw new AssertionError("SaveAs is not allowed");
-    }
-
-    private void updateSourceFromModel() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        modelHelper.saveModel(model, baos);
-        String modelSource = new String(baos.toByteArray(), StandardCharsets.UTF_8);
-
-        if (!getDocument().get().equals(modelSource)) {
-            getDocument().set(modelSource);
-        }
-
-        editorIsDirty = false;
-    }
-
-    private void updateModelFromSource() {
-        model = modelHelper.loadModel(getDocument().get());
-
-        editorIsDirty = false;
-    }
-
-    private IDocument getDocument() {
-        return editor.getDocumentProvider().getDocument(editor.getEditorInput());
-    }
-
-    /**
-     * Closes all project files on project close.
-     */
-    public void resourceChanged(final IResourceChangeEvent event) {
-        if (event.getType() == IResourceChangeEvent.PRE_CLOSE) {
-            Display.getDefault().asyncExec(new Runnable() {
-                public void run() {
-                    IWorkbenchPage[] pages = getSite().getWorkbenchWindow()
-                            .getPages();
-                    for (int i = 0; i < pages.length; i++) {
-                        if (((FileEditorInput) editor.getEditorInput())
-                                .getFile().getProject()
-                                .equals(event.getResource())) {
-                            IEditorPart editorPart = pages[i].findEditor(editor
-                                    .getEditorInput());
-                            pages[i].closeEditor(editorPart, true);
-                        }
-                    }
-                }
-            });
-        }
-    }
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/MultiPageEditorContributor.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.ui.IActionBars;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.actions.ActionFactory;
-import org.eclipse.ui.ide.IDEActionFactory;
-import org.eclipse.ui.part.MultiPageEditorActionBarContributor;
-import org.eclipse.ui.texteditor.ITextEditor;
-import org.eclipse.ui.texteditor.ITextEditorActionConstants;
-
-/**
- * Manages the installation/deinstallation of global actions for multi-page editors.
- * Responsible for the redirection of global actions to the active editor.
- * Multi-page contributor replaces the contributors for the individual editors in the multi-page editor.
- */
-public class MultiPageEditorContributor extends MultiPageEditorActionBarContributor {
-	private IEditorPart activeEditorPart;
-
-	/**
-	 * Creates a multi-page contributor.
-	 */
-	public MultiPageEditorContributor() {
-		super();
-	}
-	/**
-	 * Returns the action registed with the given text editor.
-	 * @return IAction or null if editor is null.
-	 */
-	protected IAction getAction(ITextEditor editor, String actionID) {
-		return (editor == null ? null : editor.getAction(actionID));
-	}
-
-	public void setActivePage(IEditorPart part) {
-		if (activeEditorPart == part)
-			return;
-
-		activeEditorPart = part;
-
-		IActionBars actionBars = getActionBars();
-		if (actionBars != null) {
-
-			ITextEditor editor = (part instanceof ITextEditor) ? (ITextEditor) part : null;
-
-			actionBars.setGlobalActionHandler(
-				ActionFactory.DELETE.getId(),
-				getAction(editor, ITextEditorActionConstants.DELETE));
-			actionBars.setGlobalActionHandler(
-				ActionFactory.UNDO.getId(),
-				getAction(editor, ITextEditorActionConstants.UNDO));
-			actionBars.setGlobalActionHandler(
-				ActionFactory.REDO.getId(),
-				getAction(editor, ITextEditorActionConstants.REDO));
-			actionBars.setGlobalActionHandler(
-				ActionFactory.CUT.getId(),
-				getAction(editor, ITextEditorActionConstants.CUT));
-			actionBars.setGlobalActionHandler(
-				ActionFactory.COPY.getId(),
-				getAction(editor, ITextEditorActionConstants.COPY));
-			actionBars.setGlobalActionHandler(
-				ActionFactory.PASTE.getId(),
-				getAction(editor, ITextEditorActionConstants.PASTE));
-			actionBars.setGlobalActionHandler(
-				ActionFactory.SELECT_ALL.getId(),
-				getAction(editor, ITextEditorActionConstants.SELECT_ALL));
-			actionBars.setGlobalActionHandler(
-				ActionFactory.FIND.getId(),
-				getAction(editor, ITextEditorActionConstants.FIND));
-			actionBars.setGlobalActionHandler(
-				IDEActionFactory.BOOKMARK.getId(),
-				getAction(editor, IDEActionFactory.BOOKMARK.getId()));
-			actionBars.updateActionBars();
-		}
-	}
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/NewBundleDialog.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import java.io.IOException;
-
-import org.eclipse.jface.dialogs.TitleAreaDialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-import com.redhat.thermostat.plugin.eclipse.BundleInformationExtractor;
-import com.redhat.thermostat.plugin.eclipse.model.Bundle;
-
-/**
- * Prompt the user to enter or select a bundle name/version.
- *
- * Used by the command edit page.
- */
-public class NewBundleDialog extends TitleAreaDialog {
-
-    private Bundle bundleInfo;
-
-    private Button manualSelectionButton;
-    private Text nameText;
-    private Text versionText;
-
-    private Button fromJarButton;
-    private Text fileLocationText;
-    private Button btnFromFile;
-
-    public NewBundleDialog(Shell parentShell) {
-        super(parentShell);
-    }
-
-    @Override
-    public void create() {
-        super.create();
-
-        setTitle("Add a new new bundle");
-        setMessage("Use this bundle with this plugin");
-    }
-
-    @Override
-    protected Control createDialogArea(Composite parent) {
-        Composite area = (Composite) super.createDialogArea(parent);
-
-        Composite container = new Composite(area, SWT.NONE);
-        container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,true));
-
-        GridLayout containerLayout = new GridLayout(3, false);
-        containerLayout.marginTop = 5;
-        containerLayout.marginRight = 5;
-        containerLayout.marginLeft = 5;
-        container.setLayout(containerLayout);
-
-        manualSelectionButton = new Button(container, SWT.RADIO);
-        manualSelectionButton.setSelection(true);
-        manualSelectionButton.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                nameText.setEnabled(true);
-                versionText.setEnabled(true);
-
-                fileLocationText.setEnabled(false);
-                btnFromFile.setEnabled(false);
-            }
-        });
-        manualSelectionButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
-        manualSelectionButton.setText("Specify Manually");
-
-        Label nameLabel = new Label(container, SWT.None);
-        nameLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
-        nameLabel.setText("Symbolic Name:");
-        nameText = new Text(container, SWT.None);
-        GridData nameTextLayoutData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
-        nameTextLayoutData.horizontalSpan = 2;
-        nameText.setLayoutData(nameTextLayoutData);
-
-        Label versionLabel = new Label(container, SWT.None);
-        versionLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
-        versionLabel.setText("Version:");
-        versionText = new Text(container, SWT.None);
-        GridData versionTextLayoutData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
-        versionTextLayoutData.horizontalSpan = 2;
-        versionText.setLayoutData(versionTextLayoutData);
-
-        fromJarButton = new Button(container, SWT.RADIO);
-        fromJarButton.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                nameText.setEnabled(false);
-                versionText.setEnabled(false);
-
-                fileLocationText.setEnabled(true);
-                btnFromFile.setEnabled(true);
-            }
-        });
-        fromJarButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
-        fromJarButton.setText("Extract from Jar/Bundle on disk");
-
-        Label locationLabel = new Label(container, SWT.NONE);
-        locationLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
-        locationLabel.setText("Location:");
-
-        fileLocationText = new Text(container, SWT.BORDER);
-        fileLocationText.setEnabled(false);
-        fileLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
-
-        btnFromFile = new Button(container, SWT.NONE);
-        btnFromFile.setText("...");
-        btnFromFile.setEnabled(false);
-        btnFromFile.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
-                dialog.setFilterExtensions(new String[] { "*.jar" });
-                String result = dialog.open();
-                if (result != null) {
-                    fileLocationText.setText(result);
-                }
-            }
-        });
-
-        // TODO implement extracting data from bundle/jar on disk
-
-        return area;
-    }
-
-    @Override
-    protected void okPressed() {
-        saveInput();
-        super.okPressed();
-    }
-
-    private void saveInput() {
-        if (manualSelectionButton.getSelection()) {
-            bundleInfo = new Bundle(nameText.getText(), versionText.getText());
-        } else {
-            try {
-                BundleInformationExtractor extractor = new BundleInformationExtractor();
-                bundleInfo = extractor.extract(fileLocationText.getText());
-            } catch (IOException e) {
-                // FIXME doing something saner with this exception
-                e.printStackTrace();
-            }
-        }
-    }
-
-    public Bundle getBundle() {
-        return bundleInfo;
-    }
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/NewNameDialog.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import org.eclipse.jface.dialogs.TitleAreaDialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-/** Asks the name for a new command/extension */
-public class NewNameDialog extends TitleAreaDialog {
-
-    private String name;
-    private Text nameText;
-
-    public NewNameDialog(Shell parentShell) {
-        super(parentShell);
-
-    }
-
-    @Override
-    public void create() {
-        super.create();
-
-        setTitle("Enter the name for the new command");
-        setMessage("This is the command users will use to trigger your plugin");
-    }
-
-    @Override
-    protected Control createDialogArea(Composite parent) {
-        Composite area = (Composite) super.createDialogArea(parent);
-
-        Composite container = new Composite(area, SWT.NONE);
-        container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,true));
-
-        container.setLayout(new GridLayout(2, false));
-
-        Label label = new Label(container, SWT.None);
-        label.setText("Name:");
-        nameText = new Text(container, SWT.None);
-        nameText.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
-
-        return area;
-    }
-
-    @Override
-    protected void okPressed() {
-        saveInput();
-        super.okPressed();
-    }
-
-    private void saveInput() {
-        name = nameText.getText();
-    }
-
-    public String getName() {
-        return name;
-    }
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/OverviewPage.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.editor;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.forms.IManagedForm;
-import org.eclipse.ui.forms.editor.FormEditor;
-import org.eclipse.ui.forms.editor.FormPage;
-import org.eclipse.ui.forms.events.HyperlinkAdapter;
-import org.eclipse.ui.forms.events.HyperlinkEvent;
-import org.eclipse.ui.forms.widgets.FormText;
-import org.eclipse.ui.forms.widgets.FormToolkit;
-import org.eclipse.ui.forms.widgets.ScrolledForm;
-import org.eclipse.ui.forms.widgets.Section;
-import org.eclipse.ui.forms.widgets.TableWrapLayout;
-
-public class OverviewPage extends FormPage {
-
-    static final String ID = "com.redhat.thermostat.plugin.eclipse.editor.OverviewPage";
-    static final String TITLE = "Overview";
-
-    private String pluginName;
-
-    public OverviewPage(FormEditor editor, String pluginName) {
-        super(editor, ID, TITLE);
-
-        this.pluginName = pluginName;
-    }
-
-    @Override
-    protected void createFormContent(IManagedForm managedForm) {
-        ScrolledForm form = managedForm.getForm();
-        form.setText("Overview: " + pluginName);
-        TableWrapLayout layout = new TableWrapLayout();
-        form.getBody().setLayout(layout);
-
-        createOverviewSection(form.getBody());
-
-        createEditCommandsAndExtensionsSection(form.getBody());
-    }
-
-
-    private void createOverviewSection(Composite parent) {
-        FormToolkit toolkit = getManagedForm().getToolkit();
-        Section section = toolkit.createSection(parent, Section.TITLE_BAR);
-        section.setText("General Information");
-
-        Composite sectionData = toolkit.createComposite(section);
-        sectionData.setLayout(new TableWrapLayout());
-        FormText helpText = toolkit.createFormText(sectionData, false);
-        String onlineHelp = "<form>"
-                + "<p>For more information about thermostat see "
-                + "<a href=\"http://icedtea.classpath.org/thermostat\">the homepage</a>. "
-                + "Additional information about plugins is available "
-                + "<a href=\"http://icedtea.classpath.org/wiki/Thermostat/ExtensionTutorial\">here</a>."
-                + "</p>"
-                + "</form>";
-        helpText.setText(onlineHelp, true, false);
-        helpText.addHyperlinkListener(new HyperlinkAdapter() {
-            @Override
-            public void linkActivated(HyperlinkEvent e) {
-                String href = (String) e.getHref();
-                try {
-                    PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(new URL(href));
-                } catch (PartInitException | MalformedURLException e1) {
-                    e1.printStackTrace();
-                }
-            }
-        });
-
-        section.setClient(sectionData);
-    }
-
-    private void createEditCommandsAndExtensionsSection(Composite parent) {
-        FormToolkit toolkit = getManagedForm().getToolkit();
-        Section section = toolkit.createSection(parent, Section.TITLE_BAR);
-        section.setText("Commands and Extensions");
-
-        Composite sectionData = toolkit.createComposite(section);
-        sectionData.setLayout(new TableWrapLayout());
-
-        FormText commandAndExtensionsForm = toolkit.createFormText(sectionData, false);
-        String formContents = ""
-                + "<form>"
-                + "<p>Plugins provide new commands or extend existing ones.</p>"
-                + "<li><a href=\"commands\">Commands</a>: declares new commands provided by this plugin</li>"
-                + "<li><a href=\"extensions\">Extensions</a>: declares which commands provided by other plugins or thermostat itself should be extended</li>"
-                + "</form>";
-        commandAndExtensionsForm.setText(formContents, true, false);
-
-        commandAndExtensionsForm.addHyperlinkListener(new HyperlinkAdapter() {
-            @Override
-            public void linkActivated(HyperlinkEvent e) {
-                String href = (String) e.getHref();
-                String id = null;
-                switch(href) {
-                    case "commands":
-                        id = CommandsPage.ID;
-                        break;
-                    case "extensions":
-                        id = ExtensionsPage.ID;
-                        break;
-                }
-                OverviewPage.this.getEditor().setActivePage(id);
-            }
-        });
-
-        section.setClient(sectionData);
-    }
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/model/Bundle.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import java.util.Objects;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-
-@XmlRootElement(name="bundle")
-public class Bundle {
-
-    private String name;
-    private String version;
-
-    public Bundle() {
-        name = null;
-        version = null;
-    }
-
-    public Bundle(String name, String version) {
-        this.name = name;
-        this.version = version;
-    }
-
-    @XmlElement(name="symbolic-name")
-    public String getSymbolicName() {
-        return this.name;
-    }
-
-    public void setSymbolicName(String name) {
-        this.name = name;
-    }
-
-    @XmlElement(name="version")
-    public String getVersion() {
-        return this.version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-    public String toString() {
-        return this.name + " (" + this.version + ")";
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Bundle)) {
-            return false;
-        }
-        Bundle other = (Bundle) obj;
-        return Objects.equals(this.name, other.name) && Objects.equals(this.version, other.version);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(this.name, this.version);
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/model/Command.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlType(propOrder = {
-        "name", "description", "usage",
-        "arguments", "options",
-        "environments",
-        "bundles"})
-public class Command extends ModelObject {
-
-    private String name;
-    private String description;
-    private String usage;
-    private List<String> arguments = new ArrayList<>();
-    private List<Option> options = new ArrayList<>();
-    private Environments environments = new Environments();
-    private List<Bundle> bundles = new ArrayList<>();
-
-    public Command() {
-        // no-arg java bean constructor
-    }
-
-    public Command(String name, String description, String usage,
-            List<String> arguments, List<Option> options,
-            Environments environments, List<Bundle> bundles) {
-        this.name = name;
-        this.description = description;
-        this.usage = usage;
-
-        this.arguments = arguments;
-        this.options = options;
-        this.environments = environments;
-        this.bundles = bundles;
-    }
-
-    @XmlElement(name="name")
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        firePropertyChange("name", this.name, this.name = name);
-    }
-
-    @XmlElement(name="description")
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(String description) {
-        firePropertyChange("description", this.description, this.description = description);
-    }
-
-    @XmlElement(name="usage")
-    public String getUsage() {
-        return usage;
-    }
-
-    public void setUsage(String usage) {
-        firePropertyChange("usage", this.usage, this.usage = usage);
-    }
-
-    @XmlElementWrapper(name="arguments")
-    @XmlElement(name="argument")
-    public List<String> getArguments() {
-        return arguments;
-    }
-
-    public void setArguments(List<String> arguments) {
-        firePropertyChange("arguments", this.arguments, this.arguments = arguments);
-    }
-
-    public void addArgument(String argument) {
-        this.arguments.add(argument);
-        firePropertyChange("arguments", null, this.arguments);
-    }
-
-    public void removeArgument(String argument) {
-        this.arguments.remove(argument);
-        firePropertyChange("arguments", null, this.arguments);
-    }
-
-    @XmlElementWrapper(name="options")
-    @XmlElement(name="option")
-    public List<Option> getOptions() {
-        return options;
-    }
-
-    public void setOptions(List<Option> options) {
-        firePropertyChange("options", this.options, this.options = options);
-    }
-
-    @XmlElement(name="environments")
-    public Environments getEnvironments() {
-        return environments;
-    }
-
-    public void setEnvironments(Environments environments) {
-        firePropertyChange("environments", this.environments, this.environments = environments);
-    }
-
-    @XmlElementWrapper(name="bundles")
-    @XmlElement(name="bundle")
-    public List<Bundle> getBundles() {
-        return bundles;
-    }
-
-    public void setBundles(List<Bundle> bundles) {
-        this.bundles = bundles;
-    }
-
-    public void addBundle(Bundle bundle) {
-        this.bundles.add(bundle);
-        firePropertyChange("bundles", null, this.bundles);
-    }
-
-    public void removeBundle(Bundle bundle) {
-        this.bundles.remove(bundle);
-        firePropertyChange("bundles", null, this.bundles);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Command)) {
-            return false;
-        }
-        Command other = (Command) obj;
-        return Objects.equals(this.name, other.name) &&
-                Objects.equals(this.description, other.description) &&
-                Objects.equals(this.usage, other.usage) &&
-                Objects.equals(this.arguments, other.arguments) &&
-                Objects.equals(this.options, other.options) &&
-                Objects.equals(this.environments, other.environments) &&
-                Objects.equals(this.bundles, other.bundles);
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/model/Environments.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-
-@XmlAccessorType(XmlAccessType.NONE)
-public class Environments extends ModelObject {
-
-    private static final String CLI = "cli";
-    private static final String SHELL = "shell";
-
-    private List<String> environments;
-
-    public Environments() {
-        environments = new ArrayList<String>();
-    }
-
-    @XmlElement(name="environment")
-    public List<String> getEnvironments() {
-        return environments;
-    }
-
-    public boolean isCli() {
-        return environments.contains(CLI);
-    }
-
-    public void setCli(boolean newValue) {
-        addOrRemoveEnvironment(CLI, newValue);
-    }
-
-    public boolean isShell() {
-        return environments.contains(SHELL);
-    }
-
-    public void setShell(boolean newValue) {
-        addOrRemoveEnvironment(SHELL, newValue);
-    }
-
-    private void addOrRemoveEnvironment(String name, boolean add) {
-        if (add) {
-            if (environments.indexOf(name) == -1) {
-                environments.add(name);
-                firePropertyChange(name, false, true);
-            }
-        } else { // remove
-            if (environments.indexOf(name) != -1) {
-                environments.remove(name);
-                firePropertyChange(name, true, false);
-            }
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "Environments: " + environments.toString();
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/model/Extension.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlType(propOrder = {"name", "bundles"})
-public class Extension extends ModelObject {
-
-    private String name;
-
-    private List<Bundle> bundles;
-
-    public Extension() {
-        bundles = new ArrayList<>();
-    }
-
-    public Extension(String name, List<Bundle> bundles) {
-        this.name = name;
-        this.bundles = bundles;
-    }
-
-    @XmlElement(name="name")
-    public String getName() {
-        return this.name;
-    }
-
-    public void setName(String name) {
-        firePropertyChange("name", this.name, this.name = name);
-    }
-
-    /** Do not modify the returned list */
-    @XmlElementWrapper(name="bundles")
-    @XmlElement(name="bundle")
-    public List<Bundle> getBundles() {
-        return this.bundles;
-    }
-
-    public void setBundles(List<Bundle> bundles) {
-        firePropertyChange("bundles", this.bundles, this.bundles = bundles);
-    }
-
-    public void addBundle(Bundle bundle) {
-        bundles.add(bundle);
-        firePropertyChange("bundles", null, bundles);
-    }
-
-    public void removeBundle(Bundle bundle) {
-        bundles.remove(bundle);
-        firePropertyChange("bundles", null, bundles);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Extension)) {
-            return false;
-        }
-        Extension other = (Extension) obj;
-        return Objects.equals(this.name, other.name) && Objects.equals(this.bundles, other.bundles);
-    }
-
-}
\ No newline at end of file
--- a/src/com/redhat/thermostat/plugin/eclipse/model/ModelObject.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import java.beans.PropertyChangeListener;
-import java.beans.PropertyChangeSupport;
-
-public class ModelObject {
-
-    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
-
-    public void addPropertyChangeListener(PropertyChangeListener listener) {
-        changeSupport.addPropertyChangeListener(listener);
-    }
-
-    public void removePropertyChangeListener(PropertyChangeListener listener) {
-        changeSupport.removePropertyChangeListener(listener);
-    }
-
-    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
-        changeSupport.addPropertyChangeListener(propertyName, listener);
-    }
-
-    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
-        changeSupport.removePropertyChangeListener(propertyName, listener);
-    }
-
-    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
-        changeSupport.firePropertyChange(propertyName, oldValue, newValue);
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/model/Option.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import javax.xml.bind.annotation.XmlElement;
-
-public class Option {
-
-    private String name;
-
-    public Option() {
-        this.name = null;
-    }
-
-    public Option(String name) {
-        this.name = name;
-    }
-
-    @XmlElement(name="long")
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-}
\ No newline at end of file
--- a/src/com/redhat/thermostat/plugin/eclipse/model/Plugin.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlRootElement;
-
-@XmlRootElement(name="plugin")
-@XmlAccessorType(XmlAccessType.NONE)
-public class Plugin extends ModelObject {
-
-    private List<Command> commands;
-
-    private List<Extension> extensions;
-
-    public Plugin() {
-        commands = new ArrayList<>();
-        extensions = new ArrayList<>();
-    }
-
-    @XmlElementWrapper(name="commands")
-    @XmlElement(name="command")
-    public List<Command> getCommands() {
-        return this.commands;
-    }
-
-    public void addCommand(Command command) {
-        this.commands.add(command);
-        firePropertyChange("commands", null, this.commands);
-    }
-
-    public Command getCommand(String name) {
-        for (Command command : commands) {
-            if (command.getName().equals(name)) {
-                return command;
-            }
-        }
-        return null;
-    }
-
-    public List<String> getCommandNames() {
-        List<String> result = new ArrayList<>();
-        for (Command command : commands) {
-            result.add(command.getName());
-        }
-        return result;
-    }
-
-    public void removeCommand(String name) {
-        for (int i = 0; i < commands.size(); i++) {
-            Command command = commands.get(i);
-            if (command.getName().equals(name)) {
-                commands.remove(i);
-                firePropertyChange("commands", null, this.commands);
-                return;
-            }
-        }
-    }
-
-    @XmlElementWrapper(name="extensions")
-    @XmlElement(name="extension")
-    public List<Extension> getExtensions() {
-        return this.extensions;
-    }
-
-    public void addExtension(Extension extension) {
-        this.extensions.add(extension);
-        firePropertyChange("extensions", null, this.extensions);
-    }
-
-    public Extension getExtension(String name) {
-        for (Extension extension : extensions) {
-            if (extension.getName().equals(name)) {
-                return extension;
-            }
-        }
-        return null;
-    }
-
-    public List<String> getExtensionNames() {
-        List<String> result = new ArrayList<>();
-        for (Extension extension : extensions) {
-            result.add(extension.getName());
-        }
-        return result;
-    }
-
-    public void removeExtension(String name) {
-        for (int i = 0; i < extensions.size(); i++) {
-            Extension extension = extensions.get(i);
-            if (extension.getName().equals(name)) {
-                extensions.remove(i);
-                firePropertyChange("extensions", null, this.extensions);
-                return;
-            }
-        }
-    }
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/model/PluginModelReaderWriter.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.StringReader;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-import javax.xml.bind.Unmarshaller;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.CoreException;
-
-/**
- * Reads and writes the plugin model to/from input streams.
- */
-public class PluginModelReaderWriter {
-
-    private String name;
-    private IFile file;
-
-    public PluginModelReaderWriter(IFile file) throws CoreException {
-        this(file, file.getFullPath().makeAbsolute().removeLastSegments(1).lastSegment());
-    }
-
-    public PluginModelReaderWriter(IFile file, String name) {
-        this.file = file;
-        this.name = name;
-    }
-
-    public String getPluginName() {
-        return name;
-    }
-
-    public Plugin loadModel(String contents) {
-        return loadModel(new StringReader(contents));
-    }
-
-
-    public Plugin loadModel(InputStream inputStream) {
-        JAXBContext context;
-        try {
-            context = JAXBContext.newInstance(Plugin.class);
-            Unmarshaller um = context.createUnmarshaller();
-            Plugin plugin = (Plugin) um.unmarshal(inputStream);
-            return plugin;
-        } catch (JAXBException e) {
-            throw new RuntimeException("Unable to load model", e);
-        }
-    }
-
-    public Plugin loadModel(Reader reader) {
-        JAXBContext context;
-        try {
-            context = JAXBContext.newInstance(Plugin.class);
-            Unmarshaller um = context.createUnmarshaller();
-            Plugin plugin = (Plugin) um.unmarshal(reader);
-            return plugin;
-        } catch (JAXBException e) {
-            throw new RuntimeException("Unable to load model", e);
-        }
-    }
-
-    public void saveModel(Plugin plugin, OutputStream out) {
-        try {
-            JAXBContext context = JAXBContext.newInstance(Plugin.class);
-            Marshaller m = context.createMarshaller();
-            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
-
-            m.marshal(plugin, out);
-        } catch (JAXBException e) {
-            throw new RuntimeException("Error saving file", e);
-        }
-    }
-
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/model/package-info.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-/**
- * Contains model classes that represents XML elements of the
- * {@code thermostat-plugin.xml} file.
- */
-@javax.xml.bind.annotation.XmlSchema(
-        namespace="http://icedtea.classpath.org/thermostat/plugins/v1.0",
-        elementFormDefault=javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
-package com.redhat.thermostat.plugin.eclipse.model;
--- a/src/com/redhat/thermostat/plugin/eclipse/wizards/PluginXmlCreationWizard.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.wizards;
-
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.ui.INewWizard;
-import org.eclipse.ui.IWorkbench;
-import org.eclipse.core.runtime.*;
-import org.eclipse.jface.operation.*;
-import java.lang.reflect.InvocationTargetException;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.CoreException;
-import java.io.*;
-import org.eclipse.ui.*;
-import org.eclipse.ui.ide.IDE;
-
-import com.redhat.thermostat.plugin.eclipse.Activator;
-
-public class PluginXmlCreationWizard extends Wizard implements INewWizard {
-
-    private PluginXmlProjectSelectionPage page;
-    private ISelection selection;
-
-    public PluginXmlCreationWizard() {
-        super();
-        setNeedsProgressMonitor(true);
-    }
-
-    @Override
-    public void addPages() {
-        setWindowTitle("Create Themrostat Plugin");
-        page = new PluginXmlProjectSelectionPage(selection);
-        addPage(page);
-    }
-
-    /**
-     * This method is called when 'Finish' button is pressed in the wizard. We
-     * will create an operation and run it using wizard as execution context.
-     */
-    @Override
-    public boolean performFinish() {
-        final String containerName = page.getContainerName();
-        final String fileName = "thermostat-plugin.xml";
-        IRunnableWithProgress op = new IRunnableWithProgress() {
-            public void run(IProgressMonitor monitor)
-                    throws InvocationTargetException {
-                try {
-                    doFinish(containerName, fileName, monitor);
-                } catch (CoreException e) {
-                    throw new InvocationTargetException(e);
-                } finally {
-                    monitor.done();
-                }
-            }
-        };
-        try {
-            getContainer().run(true, false, op);
-        } catch (InterruptedException e) {
-            return false;
-        } catch (InvocationTargetException e) {
-            Throwable realException = e.getTargetException();
-            MessageDialog.openError(getShell(), "Error",
-                    realException.getMessage());
-            return false;
-        }
-        return true;
-    }
-
-    private void doFinish(String containerName, String fileName,
-            IProgressMonitor monitor) throws CoreException {
-        // create a sample file
-        monitor.beginTask("Creating " + fileName, 2);
-        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-        IResource resource = root.findMember(new Path(containerName));
-        if (!resource.exists() || !(resource instanceof IContainer)) {
-            throwCoreException("Container \"" + containerName
-                    + "\" does not exist.");
-        }
-        IContainer container = (IContainer) resource;
-        final IFile file = container.getFile(new Path(fileName));
-        try {
-            InputStream stream = getInitialContentStream();
-            if (file.exists()) {
-                // TODO dont replace file without confirming
-                file.setContents(stream, true, true, monitor);
-            } else {
-                file.create(stream, true, monitor);
-            }
-            stream.close();
-        } catch (IOException e) {
-        }
-        monitor.worked(1);
-        monitor.setTaskName("Opening file for editing...");
-        getShell().getDisplay().asyncExec(new Runnable() {
-            public void run() {
-                IWorkbenchPage page = PlatformUI.getWorkbench()
-                        .getActiveWorkbenchWindow().getActivePage();
-                try {
-                    IDE.openEditor(page, file, true);
-                } catch (PartInitException e) {
-                }
-            }
-        });
-        monitor.worked(1);
-    }
-
-    private InputStream getInitialContentStream() {
-        String contents = "<?xml version=\"1.0\"?>\n"
-                + "<plugin xmlns=\"http://icedtea.classpath.org/thermostat/plugins/v1.0\"\n"
-                + "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
-                + "\txsi:schemaLocation=\"http://icedtea.classpath.org/thermostat/plugins/v1.0 thermostat-plugin.xsd\">\n"
-                + "</plugin>";
-
-        return new ByteArrayInputStream(contents.getBytes());
-    }
-
-    private void throwCoreException(String message) throws CoreException {
-        IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID,
-                IStatus.OK, message, null);
-        throw new CoreException(status);
-    }
-
-    @Override
-    public void init(IWorkbench workbench, IStructuredSelection selection) {
-        this.selection = selection;
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/wizards/PluginXmlProjectSelectionPage.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.wizards;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.jface.bindings.keys.KeyStroke;
-import org.eclipse.jface.fieldassist.ContentProposalAdapter;
-import org.eclipse.jface.fieldassist.SimpleContentProposalProvider;
-import org.eclipse.jface.fieldassist.TextContentAdapter;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.ui.dialogs.ContainerSelectionDialog;
-
-public class PluginXmlProjectSelectionPage extends WizardPage {
-    private Text containerText;
-
-    private ISelection selection;
-
-    public PluginXmlProjectSelectionPage(ISelection selection) {
-        super("wizardPage");
-        setTitle("Thermostat Wizard");
-        setDescription("This wizard creates a new Thermostat Plugin.");
-        this.selection = selection;
-    }
-
-    public void createControl(Composite parent) {
-        Composite container = new Composite(parent, SWT.NULL);
-        GridLayout layout = new GridLayout();
-        container.setLayout(layout);
-        layout.numColumns = 3;
-        layout.verticalSpacing = 9;
-        Label label = new Label(container, SWT.NULL);
-        label.setText("&Project:");
-
-        containerText = new Text(container, SWT.BORDER | SWT.SINGLE);
-        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
-        containerText.setLayoutData(gd);
-        containerText.addModifyListener(new ModifyListener() {
-            public void modifyText(ModifyEvent e) {
-                dialogChanged();
-            }
-        });
-
-        String[] proposals = getOpenProjectNames().toArray(new String[0]);
-        SimpleContentProposalProvider projectProposalProvider = new SimpleContentProposalProvider(proposals);
-        TextContentAdapter contentAdapter = new TextContentAdapter();
-        ContentProposalAdapter proposalAdapter = new ContentProposalAdapter(containerText, contentAdapter, projectProposalProvider, null, null);
-        proposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
-
-        Button button = new Button(container, SWT.PUSH);
-        button.setText("Browse...");
-        button.addSelectionListener(new SelectionAdapter() {
-            public void widgetSelected(SelectionEvent e) {
-                handleBrowse();
-            }
-        });
-        initialize();
-        dialogChanged();
-
-        setControl(container);
-    }
-
-    private void initialize() {
-        if (selection != null && selection.isEmpty() == false
-                && selection instanceof IStructuredSelection) {
-            IStructuredSelection ssel = (IStructuredSelection) selection;
-            if (ssel.size() > 1)
-                return;
-            Object obj = ssel.getFirstElement();
-
-            if (obj instanceof IAdaptable) {
-                IProject container = (IProject)((IAdaptable)obj).getAdapter(IProject.class);
-
-                containerText.setText(container.getName().toString());
-            }
-        }
-    }
-
-    private void handleBrowse() {
-        ContainerSelectionDialog dialog = new ContainerSelectionDialog(
-                getShell(), ResourcesPlugin.getWorkspace().getRoot(), false,
-                "Select new file container");
-        if (dialog.open() == ContainerSelectionDialog.OK) {
-            Object[] result = dialog.getResult();
-            if (result.length == 1) {
-                containerText.setText(((Path) result[0]).toString());
-            }
-        }
-    }
-
-    private void dialogChanged() {
-        String containerName = getContainerName();
-
-        if (containerName.length() == 0) {
-            updateStatus("File container must be specified");
-            return;
-        }
-
-        IResource container = ResourcesPlugin.getWorkspace().getRoot()
-                .findMember(new Path(containerName));
-
-        if (container == null
-                || (container.getType() & (IResource.PROJECT | IResource.FOLDER)) == 0) {
-            updateStatus("File container must exist");
-            return;
-        }
-        if (!container.isAccessible()) {
-            updateStatus("Project must be writable");
-            return;
-        }
-        updateStatus(null);
-    }
-
-    private void updateStatus(String message) {
-        setErrorMessage(message);
-        setPageComplete(message == null);
-    }
-
-    public String getContainerName() {
-        return containerText.getText();
-    }
-
-    private List<String> getOpenProjectNames() {
-        List<String> result = new ArrayList<>();
-
-        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
-        for (IProject project : projects) {
-           if (project.isOpen()) {
-               result.add(project.getName());
-           }
-        }
-
-        return result;
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/wizards/ThermostatProjectCreationWizard.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,174 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.wizards;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map.Entry;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IProjectDescription;
-import org.eclipse.core.resources.IWorkspaceRoot;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.core.IClasspathEntry;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IPackageFragment;
-import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.launching.IVMInstall;
-import org.eclipse.jdt.launching.JavaRuntime;
-import org.eclipse.jdt.launching.LibraryLocation;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.ui.INewWizard;
-import org.eclipse.ui.IWorkbench;
-import org.eclipse.ui.IWorkbenchWizard;
-
-public class ThermostatProjectCreationWizard extends Wizard implements
-        INewWizard {
-    private ThermostatProjectCreationWizardPage page;
-    private ThermostatProjectCreationWizardPageTwo pageTwo;
-    private HashMap<String, Boolean> selectedComponents;
-
-    public ThermostatProjectCreationWizard() {
-        super();
-        setNeedsProgressMonitor(true);
-    }
-
-    public void addPages() {
-        setWindowTitle("Create New Thermostat Plugin");
-        page = new ThermostatProjectCreationWizardPage();
-        addPage(page);
-        pageTwo = new ThermostatProjectCreationWizardPageTwo();
-        addPage(pageTwo);
-    }
-
-    public boolean performFinish() {
-        try {
-            selectedComponents = page.getSelectedComponents();
-
-            createProject(page.getProjectName());
-            for (Entry<String, Boolean> temp : selectedComponents.entrySet()) {
-                if (temp.getValue()) {
-                    createProject(page.getProjectName() + "-" + temp.getKey());
-                }
-            }
-        } catch (CoreException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-        return true;
-    }
-
-    private void createProject(String projectTitle) throws CoreException {
-        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-        IProject project = root.getProject(projectTitle);
-        if (project.exists()) {
-            project.delete(true, null);
-        }
-        try {
-            project.create(null);
-            project.open(null);
-        } catch (CoreException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-        // Set the Java nature to created project
-        IProjectDescription description = project.getDescription();
-        description.setNatureIds(new String[] { JavaCore.NATURE_ID });
-        project.setDescription(description, null);
-
-        // Create Java project
-        IJavaProject javaProject = JavaCore.create(project);
-
-        // Add bin/ouput folder
-        IFolder binFolder = project.getFolder("bin");
-        binFolder.create(false, true, null);
-        javaProject.setOutputLocation(binFolder.getFullPath(), null);
-
-        // Add libs to project class path
-        List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
-        IVMInstall vmInstall = JavaRuntime.getDefaultVMInstall();
-        LibraryLocation[] locations = JavaRuntime
-                .getLibraryLocations(vmInstall);
-        for (LibraryLocation element : locations) {
-            entries.add(JavaCore.newLibraryEntry(
-                    element.getSystemLibraryPath(), null, null));
-        }
-
-        javaProject.setRawClasspath(
-                entries.toArray(new IClasspathEntry[entries.size()]), null);
-
-        // If root then folder create sub directories corresponding components
-        if (page.getProjectName().equals(projectTitle)) {
-            for (Entry<String, Boolean> currentComponent : selectedComponents
-                    .entrySet()) {
-                if (currentComponent.getValue()) {
-                    IFolder componentFolder = project.getFolder(currentComponent
-                            .getKey());
-                    componentFolder.create(false, true, null);
-                }
-            }
-        }
-
-        // Create src folder
-        IFolder srcFolder = project.getFolder("src");
-        srcFolder.create(false, true, null);
-
-        IFolder srcMainFolder = srcFolder.getFolder("main");
-        srcMainFolder.create(true, true, null);
-
-        IFolder srcMainJavaFolder = srcMainFolder.getFolder("java");
-        srcMainJavaFolder.create(true, true, null);
-
-        IPackageFragmentRoot packageFragmentRoot = javaProject
-                .getPackageFragmentRoot(srcMainJavaFolder);
-        IClasspathEntry[] oldEntries = javaProject.getRawClasspath();
-        IClasspathEntry[] newEntries = new IClasspathEntry[oldEntries.length + 1];
-        System.arraycopy(oldEntries, 0, newEntries, 0, oldEntries.length);
-        newEntries[oldEntries.length] = JavaCore
-                .newSourceEntry(packageFragmentRoot.getPath());
-        javaProject.setRawClasspath(newEntries, null);
-
-        IPackageFragment pack = javaProject.getPackageFragmentRoot(
-                srcMainJavaFolder).createPackageFragment(pageTwo.getPackageName(),
-                false, null);
-
-        StringBuffer buffer = new StringBuffer();
-        buffer.append("package " + pack.getElementName() + ";\n");
-        buffer.append("\n");
-        // Empty file for testing
-        ICompilationUnit cu = pack.createCompilationUnit(
-                "ThermostatPlugin.java", buffer.toString(), false, null);
-
-        // Create thermostat-plugin.xml in the main project
-        if (page.getProjectName().equals(projectTitle)) {
-            final IFile file = project.getFile("thermostat-plugin.xml");
-            try {
-                InputStream stream = openContentStream();
-                if (file.exists()) {
-                    file.setContents(stream, true, true, null);
-                } else {
-                    file.create(stream, true, null);
-                }
-                stream.close();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    private InputStream openContentStream() {
-        String contents = "<--!Welcome to Thermostat-->"; // Sample content
-        return new ByteArrayInputStream(contents.getBytes());
-    }
-    public void init(IWorkbench workbench, IStructuredSelection selection) {
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/wizards/ThermostatProjectCreationWizardPage.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.wizards;
-
-import java.util.HashMap;
-
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-public class ThermostatProjectCreationWizardPage extends WizardPage {
-    private Text projectText;
-
-    private boolean agentSelected = false;
-    private boolean clientSelected = false;
-    private boolean commonSelected = false;
-    private boolean distributionSelected = false;
-
-    public ThermostatProjectCreationWizardPage() {
-        super("wizardPage");
-        setTitle("Thermostat Wizard");
-        setDescription("This wizard creates a new Thermostat Plugin.");
-    }
-
-    public void createControl(Composite parent) {
-        Composite container = new Composite(parent, SWT.NULL);
-        GridLayout layout = new GridLayout();
-        container.setLayout(layout);
-        
-        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
-        Label projectNameLabel = new Label(container, SWT.NULL);
-        projectNameLabel.setText("&Project name:");
-        
-        projectText = new Text(container, SWT.BORDER | SWT.SINGLE);
-        gd = new GridData(GridData.FILL_HORIZONTAL);
-        projectText.setLayoutData(gd);
-        projectText.addModifyListener(new ModifyListener() {
-            public void modifyText(ModifyEvent e) {
-                dialogChanged();
-            }
-        });
-        
-        Label componentLabel = new Label(container, SWT.NULL);
-        componentLabel.setText("&Select components you would like to include in the project: ");
-        
-        Button agentButton = new Button(container, SWT.CHECK);
-        agentButton.setText("Agent");
-        agentButton.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e){
-                Button button = (Button) e.widget;
-                if (button.getSelection()) {
-                    agentSelected = true;
-                } else {
-                    agentSelected = false;
-                }
-            }
-        });
-        
-        Button clientButton = new Button(container, SWT.CHECK);
-        clientButton.setText("Client");
-        clientButton.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e){
-                Button button = (Button) e.widget;
-                if (button.getSelection()) {
-                    clientSelected = true;
-                } else {
-                    clientSelected = false;
-                }
-            }
-        });
-        
-        Button commonButton = new Button(container, SWT.CHECK);
-        commonButton.setText("Common");
-        commonButton.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e){
-                Button button = (Button) e.widget;
-                if (button.getSelection()) {
-                    commonSelected = true;
-                } else {
-                    commonSelected = false;
-                }
-            }
-        });
-        
-        Button distributionButton = new Button(container, SWT.CHECK);
-        distributionButton.setText("Distribution");
-        distributionButton.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e){
-                Button button = (Button) e.widget;
-                if (button.getSelection()) {
-                    distributionSelected = true;
-                } else {
-                    distributionSelected = false;
-                }
-            }
-        });
-        
-        initialize();
-        dialogChanged();
-
-        setControl(container);
-    }
-
-    private void initialize() {
-        projectText.setText("Thermostat-Plugin-Project");
-    }
-
-    private void dialogChanged() {
-        String projectName = getProjectName();
-        if (projectName.length() == 0) {
-            updateStatus("Project name must be specified");
-            return;
-        }
-        if (projectName.replace('\\', '/').indexOf('/', 1) > 0) {
-            updateStatus("Project name must be valid");
-            return;
-        }
-        if (projectName.contains(" ")) {
-            updateStatus("Project name must be valid");
-            return;
-        }
-        updateStatus(null);
-    }
-
-    private void updateStatus(String message) {
-        setErrorMessage(message);
-        setPageComplete(message == null);
-    }
-
-    public String getProjectName() {
-        return projectText.getText();
-    }
-
-    public HashMap<String, Boolean> getSelectedComponents() {
-        HashMap<String, Boolean> selectedComponentBoxes = new HashMap<String, Boolean>();
-        
-        selectedComponentBoxes.put("agent", agentSelected);
-        selectedComponentBoxes.put("client", clientSelected);
-        selectedComponentBoxes.put("common", commonSelected);
-        selectedComponentBoxes.put("distribution", distributionSelected);
-        
-        return selectedComponentBoxes;
-    }
-}
--- a/src/com/redhat/thermostat/plugin/eclipse/wizards/ThermostatProjectCreationWizardPageTwo.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.wizards;
-
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-public class ThermostatProjectCreationWizardPageTwo extends WizardPage {
-    private Text packageText;
-
-    public ThermostatProjectCreationWizardPageTwo() {
-        super("wizardPage");
-        setTitle("Thermostat Wizard");
-        setDescription("This wizard creates a new Thermostat Plugin.");
-    }
-
-    public void createControl(Composite parent) {
-        Composite container = new Composite(parent, SWT.NULL);
-        GridLayout layout = new GridLayout();
-        container.setLayout(layout);
-        
-        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
-        Label packageNameLabel = new Label(container, SWT.NULL);
-        packageNameLabel.setText("&Package name:");
-        
-        packageText = new Text(container, SWT.BORDER | SWT.SINGLE);
-        gd = new GridData(GridData.FILL_HORIZONTAL);
-        packageText.setLayoutData(gd);
-        packageText.addModifyListener(new ModifyListener() {
-            public void modifyText(ModifyEvent e) {
-                dialogChanged();
-            }
-        });
-        
-        initialize();
-        dialogChanged(); 
-
-        setControl(container);
-    }
-
-    private void initialize() {
-        packageText.setText("com.redhat.thermostat.plugin");
-    }
-
-    private void dialogChanged() {
-        String packageName = getPackageName();
-        if (packageName.length() == 0) {
-            updateStatus("Package name must be specified");
-            return;
-        }
-        if (packageName.contains(" ")) {
-            updateStatus("Package name must be valid");
-            return;
-        }
-        updateStatus(null);
-    }
-
-    private void updateStatus(String message) {
-        setErrorMessage(message);
-        setPageComplete(message == null);
-    }
-
-    public String getPackageName() {
-        return packageText.getText();
-    }
-}
--- a/test/com/redhat/thermostat/plugin/eclipse/model/CommandTest.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.beans.PropertyChangeListener;
-import java.util.Arrays;
-import java.util.Collections;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class CommandTest {
-
-    private CustomListener listener;
-    private Command command;
-
-    @Before
-    public void setUp() {
-        command = new Command();
-
-        listener = new CustomListener();
-    }
-
-    @Test
-    public void testConstruction() {
-        Command command = new Command("name", "description", "usage",
-                Collections.<String> emptyList(),
-                Collections.<Option> emptyList(),
-                new Environments(),
-                Collections.<Bundle> emptyList());
-
-        assertNotNull(command);
-
-        assertEquals("name", command.getName());
-        assertEquals("description", command.getDescription());
-        assertEquals("usage", command.getUsage());
-    }
-
-    @Test
-    public void testNameChange() {
-        command.setName("old");
-        command.addPropertyChangeListener("name", listener);
-
-        command.setName("new");
-
-        assertPropertyChanged(listener, "name", "old", "new");
-    }
-
-    @Test
-    public void testDescriptionChange() {
-        command.setDescription("old");
-        command.addPropertyChangeListener("description", listener);
-
-        command.setDescription("new");
-
-        assertPropertyChanged(listener, "description", "old", "new");
-    }
-
-    @Test
-    public void testUsageChange() {
-        command.setUsage("old");
-        command.addPropertyChangeListener("usage", listener);
-
-        command.setUsage("new");
-
-        assertPropertyChanged(listener, "usage", "old", "new");
-    }
-
-    @Test
-    public void testArgumentsChange() {
-        command.setArguments(Arrays.asList(new String[] { "old" }));
-        command.addPropertyChangeListener("arguments", listener);
-
-        command.setArguments(Arrays.asList(new String[] { "new" }));
-
-        assertPropertyChanged(listener, "arguments",
-                Arrays.asList(new String[] { "old" }), Arrays.asList(new String[] { "new" }));
-    }
-
-    private static void assertPropertyChanged(CustomListener listener,
-            String propertyName, Object oldValue, Object newValue) {
-
-        assertTrue(listener.getInvoked());
-        assertEquals(propertyName, listener.getPropertyName());
-        assertEquals(oldValue, listener.getOldValue());
-        assertEquals(newValue, listener.getNewValue());
-    }
-
-    static class CustomListener implements PropertyChangeListener {
-
-        private boolean invoked = false;
-        private String propertyName;
-        private Object oldValue;
-        private Object newValue;
-
-        public void propertyChange(java.beans.PropertyChangeEvent evt) {
-            this.invoked = true;
-            this.propertyName = evt.getPropertyName();
-            this.oldValue = evt.getOldValue();
-            this.newValue = evt.getNewValue();
-        };
-
-        public boolean getInvoked() {
-            return invoked;
-        }
-
-        public String getPropertyName() {
-            return propertyName;
-        }
-
-        public Object getOldValue() {
-            return oldValue;
-        }
-
-        public Object getNewValue() {
-            return newValue;
-        }
-
-    }
-}
--- a/test/com/redhat/thermostat/plugin/eclipse/model/EnvironmentsTest.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static com.redhat.thermostat.plugin.eclipse.model.PropertyChangeRecorder.assertPropertyChanged;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class EnvironmentsTest {
-
-    private Environments environments;
-    private PropertyChangeRecorder recorder;
-
-    @Before
-    public void setUp() {
-        environments = new Environments();
-        recorder = new PropertyChangeRecorder();
-        environments.addPropertyChangeListener(recorder);
-    }
-
-    @Test
-    public void testCli() {
-        assertFalse(environments.isCli());
-
-        environments.setCli(true);
-
-        assertTrue(environments.isCli());
-        assertPropertyChanged(recorder, environments, "cli", false, true);
-
-        environments.setCli(false);
-
-        assertFalse(environments.isCli());
-        assertPropertyChanged(recorder, environments, "cli", true, false);
-    }
-
-    @Test
-    public void testShell() {
-        assertFalse(environments.isShell());
-
-        environments.setShell(true);
-
-        assertTrue(environments.isShell());
-        assertPropertyChanged(recorder, environments, "shell", false, true);
-
-        environments.setShell(false);
-
-        assertFalse(environments.isShell());
-        assertPropertyChanged(recorder, environments, "shell", true, false);
-    }
-
-}
--- a/test/com/redhat/thermostat/plugin/eclipse/model/PluginModelReaderWriterTest.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.List;
-
-import org.junit.Test;
-
-public class PluginModelReaderWriterTest {
-
-    @Test
-    public void testParsingCommand() {
-        String document = "<?xml version='1.0'?>\n"
-                + "<plugin>\n"
-                + "  <commands>\n"
-                + "    <command>\n"
-                + "      <name>foo</name>\n"
-                + "      <usage>foo bar</usage>\n"
-                + "      <description>foos the bar if possible</description>\n"
-                + "      <arguments>\n"
-                + "        <argument>bar</argument>\n"
-                + "      </arguments>\n"
-                + "      <options>\n"
-                + "        <option>\n"
-                + "        </option>\n"
-                + "      </options>\n"
-                + "      <environments>\n"
-                + "        <environment>cli</environment>\n"
-                + "      </environments>\n"
-                + "      <bundles>\n"
-                + "        <bundle><symbolic-name>foo</symbolic-name><version>1</version></bundle>\n"
-                + "      </bundles>\n"
-                + "    </command>\n"
-                + "  </commands>\n"
-                + "</plugin>\n";
-
-        PluginModelReaderWriter pluginModel = new PluginModelReaderWriter(null, "<stdin>");
-        Plugin model = pluginModel.loadModel(document);
-
-        pluginModel.saveModel(model, System.out);
-
-        Command foo = model.getCommands().get(0);
-
-        assertNotNull(foo);
-
-        assertEquals("foo", foo.getName());
-        assertEquals("foo bar", foo.getUsage());
-        assertEquals("foos the bar if possible", foo.getDescription());
-
-        assertTrue(foo.getEnvironments().isCli());
-        assertFalse(foo.getEnvironments().isShell());
-
-        List<Bundle> bundles = foo.getBundles();
-        assertEquals(1, bundles.size());
-
-        Bundle bundle = bundles.get(0);
-        assertEquals("foo", bundle.getSymbolicName());
-        assertEquals("1", bundle.getVersion());
-    }
-
-    @Test
-    public void testBinding() {
-        String document = "<?xml version='1.0'?>\n"
-                + "<plugin>\n"
-                + "  <extensions>\n"
-                + "    <extension>\n"
-                + "      <name>foo</name>\n"
-                + "      <bundles>\n"
-                + "        <bundle><symbolic-name>foo</symbolic-name><version>1</version></bundle>\n"
-                + "      </bundles>\n"
-                + "    </extension>\n"
-                + "  </extensions>\n"
-                + "</plugin>\n";
-
-        PluginModelReaderWriter model = new PluginModelReaderWriter(null, "stdin");
-        Plugin plugin = model.loadModel(document);
-
-        List<Extension> extensions = plugin.getExtensions();
-        assertEquals(1, extensions.size());
-
-        model.saveModel(plugin, System.out);
-    }
-}
--- a/test/com/redhat/thermostat/plugin/eclipse/model/PropertyChangeRecorder.java	Mon Jan 06 18:44:28 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-package com.redhat.thermostat.plugin.eclipse.model;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-public class PropertyChangeRecorder implements PropertyChangeListener {
-
-    private boolean invoked = false;
-    private Object source;
-    private String propertyName;
-    private Object oldValue;
-    private Object newValue;
-
-    public boolean getInvoked() {
-        return invoked;
-    }
-
-    public Object getSource() {
-        return source;
-    }
-
-    public String getPropertyName() {
-        return propertyName;
-    }
-
-    public Object getOldValue() {
-        return oldValue;
-    }
-
-    public Object getNewValue() {
-        return newValue;
-    }
-
-    @Override
-    public void propertyChange(PropertyChangeEvent evt) {
-        invoked = true;
-
-        source = evt.getSource();
-        propertyName = evt.getPropertyName();
-        oldValue = evt.getOldValue();
-        newValue = evt.getNewValue();
-    }
-
-    public static void assertPropertyChanged(PropertyChangeRecorder recorder,
-            Object source, String propertyName, Object oldValue, Object newValue) {
-
-        assertTrue(recorder.getInvoked());
-        assertEquals(source, recorder.getSource());
-        assertEquals(propertyName, recorder.getPropertyName());
-        assertEquals(oldValue, recorder.getOldValue());
-        assertEquals(newValue, recorder.getNewValue());
-    }
-}