changeset 1748:c4d1214d3de0

Add Thermostat Setup GUI Add a GUI alternative to the thermostat-setup script Reviewed-by: jerboaa, omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-July/014460.html PR2581
author Severin Gehwolf <sgehwolf@redhat.com>
date Wed, 02 Sep 2015 11:26:48 +0200
parents 2c681fdcfd33
children e997f60ec4d2
files distribution/assembly/all-plugin-assembly.xml distribution/pom.xml launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java pom.xml setup-command/command/pom.xml setup-command/command/src/main/java/com/redhat/thermostat/setup/command/SetupCommand.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/Activator.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/CredentialFinder.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/MongoUserSetupView.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/MongodbUserSetupException.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupView.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupWindow.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/StartView.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/ThermostatSetup.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/ThermostatSetupImpl.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/UserPropertiesView.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/UserRoles.java setup-command/command/src/main/java/com/redhat/thermostat/setup/command/locale/LocaleResources.java setup-command/command/src/main/resources/com/redhat/thermostat/setup/locale/strings.properties setup-command/command/src/main/resources/thermostat.png setup-command/command/src/test/java/com/redhat/thermostat/setup/command/SetupCommandTest.java setup-command/command/src/test/java/com/redhat/thermostat/setup/command/internal/ActivatorTest.java setup-command/command/src/test/java/com/redhat/thermostat/setup/command/internal/CredentialFinderTest.java setup-command/command/src/test/java/com/redhat/thermostat/setup/command/internal/ThermostatSetupImplTest.java setup-command/command/src/test/java/com/redhat/thermostat/setup/command/locale/LocaleResourcesTest.java setup-command/distribution/pom.xml setup-command/distribution/thermostat-plugin.xml setup-command/pom.xml
diffstat 28 files changed, 3290 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/distribution/assembly/all-plugin-assembly.xml	Tue Sep 01 13:21:43 2015 -0400
+++ b/distribution/assembly/all-plugin-assembly.xml	Wed Sep 02 11:26:48 2015 +0200
@@ -57,6 +57,7 @@
         <include>com.redhat.thermostat:thermostat-storage-profile-distribution</include>
         <include>com.redhat.thermostat:thermostat-thread-distribution</include>
         <include>com.redhat.thermostat:thermostat-validate-distribution</include>
+        <include>com.redhat.thermostat:thermostat-setup-distribution</include>
         <include>com.redhat.thermostat:thermostat-vm-classstat-distribution</include>
         <include>com.redhat.thermostat:thermostat-vm-cpu-distribution</include>
         <include>com.redhat.thermostat:thermostat-vm-gc-distribution</include>
--- a/distribution/pom.xml	Tue Sep 01 13:21:43 2015 -0400
+++ b/distribution/pom.xml	Wed Sep 02 11:26:48 2015 +0200
@@ -425,6 +425,12 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-setup-distribution</artifactId>
+      <version>${project.version}</version>
+      <type>zip</type>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-host-memory-distribution</artifactId>
       <version>${project.version}</version>
       <type>zip</type>
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Tue Sep 01 13:21:43 2015 -0400
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Wed Sep 02 11:26:48 2015 +0200
@@ -88,7 +88,6 @@
 public class LauncherImpl implements Launcher {
 
     private static final String HELP_COMMAND_NAME = "help";
-    private static final String SETUP_SCRIPT_NAME = "thermostat-setup";
 
     private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
     private static final Logger logger = LoggingUtils.getLogger(LauncherImpl.class);
@@ -160,7 +159,12 @@
                 if (isThermostatConfigured()) {
                     runCommandFromArguments(args, listeners, inShell);
                 } else {
-                    printSetupHelpMessage();
+                    if (Arrays.asList(args).contains("--skip-setup")) {
+                        runCommandFromArguments(args, listeners, inShell);
+                    } else {
+                        String[] setupArgs = {"setup"};
+                        runCommandFromArguments(setupArgs, listeners, inShell);
+                    }
                 }
             }
         } catch (NoClassDefFoundError e) {
@@ -185,12 +189,6 @@
         }
     }
 
-    private void printSetupHelpMessage() {
-        String msg = t.localize(LocaleResources.LAUNCHER_FIRST_LAUNCH_MSG, 
-                                SETUP_SCRIPT_NAME).getContents();
-        printAndLogLine(msg);
-    }
-    
     // Log messages might go to a file. Be sure to print to stdout as well.
     private void printAndLogLine(String msg) {
         System.out.println(msg);
@@ -361,7 +359,7 @@
     private CommandContext setupCommandContext(Command cmd, Arguments args) throws CommandException {
 
         CommandContext ctx = cmdCtxFactory.createContext(args);
-        
+
         if (cmd.isStorageRequired()) {
 
             ServiceReference dbServiceReference = context.getServiceReference(DbService.class);
--- a/pom.xml	Tue Sep 01 13:21:43 2015 -0400
+++ b/pom.xml	Wed Sep 02 11:26:48 2015 +0200
@@ -245,6 +245,7 @@
     <module>laf-utils</module>
     <module>thermostat-plugin-validator</module>
     <module>validate-command</module>
+    <module>setup-command</module>
     <module>config</module>
     <!-- development related modules -->
     <module>integration-tests</module>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/pom.xml	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2015 Red Hat, Inc.
+
+ This file is part of Thermostat.
+
+ Thermostat is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ Thermostat is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Thermostat; see the file COPYING.  If not see
+ <http://www.gnu.org/licenses/>.
+
+ Linking this code with other modules is making a combined work
+ based on this code.  Thus, the terms and conditions of the GNU
+ General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this code give
+ you permission to link this code with independent modules to
+ produce an executable, regardless of the license terms of these
+ independent modules, and to copy and distribute the resulting
+ executable under terms of your choice, provided that you also
+ meet, for each linked independent module, the terms and conditions
+ of the license of that module.  An independent module is a module
+ which is not derived from or based on this code.  If you modify
+ this code, you may extend this exception to your version of the
+ library, but you are not obligated to do so.  If you do not wish
+ to do so, delete this exception statement from your version.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat-setup</artifactId>
+    <version>1.3.4-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>thermostat-setup-command</artifactId>
+  <packaging>bundle</packaging>
+  
+  <name>Thermostat Setup Command</name>
+  
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>com.redhat.thermostat.setup.command</Bundle-SymbolicName>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Export-Package />
+            <Private-Package>
+              com.redhat.thermostat.setup.command,
+              com.redhat.thermostat.setup.command.internal,
+              com.redhat.thermostat.setup.command.locale,
+            </Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.setup.command.internal.Activator</Bundle-Activator>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-plugin-validator</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-shared-config</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-swing</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-launcher</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/SetupCommand.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command;
+
+import com.redhat.thermostat.common.cli.AbstractCommand;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.internal.utils.laf.ThemeManager;
+import com.redhat.thermostat.setup.command.internal.SetupWindow;
+import com.redhat.thermostat.setup.command.internal.ThermostatSetup;
+import com.redhat.thermostat.setup.command.internal.ThermostatSetupImpl;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.shared.locale.LocalizedString;
+import org.osgi.framework.BundleContext;
+
+import java.awt.EventQueue;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class SetupCommand extends AbstractCommand {
+    private SetupWindow mainWindow;
+
+    private CommonPaths paths;
+    private BundleContext context;
+    private CountDownLatch pathsAvailable;
+    private ThermostatSetup thermostatSetup;
+    private PrintStream out;
+
+    public SetupCommand(BundleContext context) {
+        this.context = context;
+        pathsAvailable = new CountDownLatch(1);
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        out = ctx.getConsole().getOutput();
+
+        try {
+            setLookAndFeel();
+
+            pathsAvailable.await(1000l, TimeUnit.MILLISECONDS);
+            requireNonNull(paths, new LocalizedString("CommonPaths dependency not available"));
+
+            createMainWindowAndRun();
+        } catch (InterruptedException | InvocationTargetException e) {
+            throw new CommandException(new LocalizedString("SetupCommand failed to run"), e);
+        }
+    }
+
+    public void setPaths(CommonPaths paths) {
+        this.paths = paths;
+        pathsAvailable.countDown();
+    }
+
+    public boolean isStorageRequired() {
+        return false;
+    }
+
+    //package-private for testing
+    void createMainWindowAndRun() {
+        thermostatSetup = new ThermostatSetupImpl(context, paths, out);
+        mainWindow = new SetupWindow(out, thermostatSetup);
+        mainWindow.run();
+    }
+
+    //package-private for testing
+    void setLookAndFeel() throws InvocationTargetException, InterruptedException {
+        EventQueue.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                ThemeManager themeManager = ThemeManager.getInstance();
+                themeManager.setLAF();
+            }
+        });
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/Activator.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import java.util.Map;
+
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.cli.CommandRegistry;
+import com.redhat.thermostat.common.cli.CommandRegistryImpl;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import com.redhat.thermostat.setup.command.SetupCommand;
+
+public class Activator implements BundleActivator {
+
+    private CommandRegistry reg;
+    private MultipleServiceTracker tracker;
+    private SetupCommand setupCommand;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        reg = new CommandRegistryImpl(context);
+        setupCommand = new SetupCommand(context);
+        reg.registerCommand("setup", setupCommand);
+
+        Class<?>[] deps = new Class<?>[] {
+                CommonPaths.class
+        };
+        tracker = new MultipleServiceTracker(context, deps, new MultipleServiceTracker.Action() {
+            @Override
+            public void dependenciesAvailable(Map<String, Object> services) {
+                CommonPaths paths = (CommonPaths) services.get(CommonPaths.class.getName());
+                setupCommand.setPaths(paths);
+            }
+
+            @Override
+            public void dependenciesUnavailable() {
+                reg.unregisterCommands();
+            }
+        });
+        tracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        reg.unregisterCommands();
+        tracker.close();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/CredentialFinder.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import com.redhat.thermostat.shared.config.CommonPaths;
+
+import java.io.File;
+
+public class CredentialFinder {
+
+    private final CommonPaths paths;
+
+    public CredentialFinder(CommonPaths paths) {
+        this.paths = paths;
+    }
+
+    public File getConfiguration(String name) {
+        File systemFile = getConfigurationFile(paths.getSystemConfigurationDirectory(), name);
+        if (isUsable(systemFile)) {
+            return systemFile;
+        }
+        File userFile = getConfigurationFile(paths.getUserConfigurationDirectory(), name);
+        if (isUsable(userFile)) {
+            return userFile;
+        }
+        return null;
+    }
+
+    File getConfigurationFile(File directory, String name) {
+        return new File(directory, name);
+    }
+
+    private boolean isUsable(File file) {
+        return file.isFile() && file.canRead();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/MongoUserSetupView.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import com.redhat.thermostat.setup.command.locale.LocaleResources;
+import com.redhat.thermostat.shared.locale.Translate;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.LayoutManager;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.URL;
+import java.util.Arrays;
+
+public class MongoUserSetupView extends JPanel implements SetupView {
+
+    private JButton backBtn;
+    private JButton defaultSetupBtn;
+    private JButton nextBtn;
+    private JButton cancelBtn;
+
+    private JTextField usernameField;
+    private JPasswordField passwordField1;
+    private JPasswordField passwordField2;
+
+    private JPanel toolbar;
+    private JPanel midPanel;
+    private JPanel detailsPanel;
+    private JPanel messagePanel;
+
+    private JLabel usernameLabel;
+    private JLabel passwordLabel1;
+    private JLabel passwordLabel2;
+    private JLabel passwordMismatchLabel;
+    private JLabel detailsMissingLabel;
+    private JCheckBox showPasswordCheckbox;
+
+    private static final String THERMOSTAT_LOGO = "thermostat.png";
+    private static final String PROGRESS = "Step 2 of 3";
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    public MongoUserSetupView(LayoutManager layout) {
+        super(layout);
+
+        createMidPanel();
+        createToolbarPanel();
+
+        this.add(midPanel, BorderLayout.CENTER);
+        this.add(toolbar, BorderLayout.SOUTH);
+
+        DocumentListener inputValidator = new DocumentListener() {
+            @Override
+            public void insertUpdate(DocumentEvent documentEvent) {
+                validateInput();
+            }
+
+            @Override
+            public void removeUpdate(DocumentEvent documentEvent) {
+                validateInput();
+            }
+
+            @Override
+            public void changedUpdate(DocumentEvent documentEvent) {
+                validateInput();
+            }
+        };
+        usernameField.getDocument().addDocumentListener(inputValidator);
+        passwordField1.getDocument().addDocumentListener(inputValidator);
+        passwordField2.getDocument().addDocumentListener(inputValidator);
+    }
+
+    @Override
+    public void setTitleAndProgress(JLabel title, JLabel progress) {
+        title.setText(translator.localize(LocaleResources.MONGO_SETUP_TITLE).getContents());
+        progress.setText(PROGRESS);
+    }
+
+    private void createMidPanel() {
+        usernameLabel = new JLabel("Username: ");
+        usernameField = new JTextField(30);
+        passwordLabel1 = new JLabel("Password:");
+        passwordField1 = new JPasswordField(30);
+        passwordLabel2 = new JLabel("Verify Password:");
+        passwordField2 = new JPasswordField(30);
+        showPasswordCheckbox = new JCheckBox("Show passwords");
+        showPasswordCheckbox.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                togglePasswords(showPasswordCheckbox.isSelected());
+            }
+        });
+
+        defaultSetupBtn = new JButton("Use Defaults");
+        defaultSetupBtn.setPreferredSize(new Dimension(140, 30));
+        passwordMismatchLabel = new JLabel("Passwords don't match!");
+        passwordMismatchLabel.setForeground(Color.RED);
+        detailsMissingLabel = new JLabel("Please fill in ALL fields");
+        detailsMissingLabel.setForeground(Color.RED);
+        detailsPanel = new JPanel(new GridBagLayout());
+
+        GridBagConstraints c = new GridBagConstraints();
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.gridx = 0;
+        c.gridy = 0;
+        c.gridwidth = 1;
+        c.insets.top = 40;
+        detailsPanel.add(usernameLabel, c);
+        c.gridx = 1;
+        c.gridy = 0;
+        c.gridwidth = 2;
+        detailsPanel.add(usernameField, c);
+        c.gridx = 0;
+        c.gridy = 1;
+        c.gridwidth = 1;
+        c.insets.top = 10;
+        detailsPanel.add(passwordLabel1, c);
+        c.gridx = 1;
+        c.gridy = 1;
+        c.gridwidth = 2;
+        detailsPanel.add(passwordField1, c);
+        c.gridx = 0;
+        c.gridy = 2;
+        c.gridwidth = 1;
+        detailsPanel.add(passwordLabel2, c);
+        c.gridx = 1;
+        c.gridy = 2;
+        c.gridwidth = 2;
+        detailsPanel.add(passwordField2, c);
+        c.gridx = 1;
+        c.gridy = 3;
+        c.gridwidth = 1;
+        detailsPanel.add(showPasswordCheckbox, c);
+
+        c.fill = GridBagConstraints.NONE;
+        c.anchor = GridBagConstraints.LINE_END;
+        c.gridx = 2;
+        c.gridy = 3;
+        c.gridwidth = 1;
+        detailsPanel.add(defaultSetupBtn, c);
+
+        messagePanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
+
+        midPanel = new JPanel(new BorderLayout());
+        midPanel.add(detailsPanel, BorderLayout.NORTH);
+        midPanel.add(messagePanel, BorderLayout.SOUTH);
+    }
+
+    private void createToolbarPanel() {
+        URL logoURL = SetupWindow.class.getClassLoader().getResource(THERMOSTAT_LOGO);
+        JLabel thermostatLogo = new JLabel(new ImageIcon(logoURL));
+
+        backBtn = new JButton(translator.localize(LocaleResources.BACK).getContents());
+        backBtn.setPreferredSize(new Dimension(70, 30));
+        nextBtn = new JButton(translator.localize(LocaleResources.NEXT).getContents());
+        nextBtn.setPreferredSize(new Dimension(70, 30));
+        nextBtn.setEnabled(false);
+        cancelBtn = new JButton(translator.localize(LocaleResources.CANCEL).getContents());
+        cancelBtn.setPreferredSize(new Dimension(70, 30));
+
+        toolbar = new JPanel();
+        toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.LINE_AXIS));
+        toolbar.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
+        toolbar.add(thermostatLogo);
+        toolbar.add(Box.createHorizontalGlue());
+        toolbar.add(backBtn);
+        toolbar.add(nextBtn);
+        toolbar.add(cancelBtn);
+    }
+
+    private void togglePasswords(boolean isVisible) {
+        if (isVisible) {
+            passwordField1.setEchoChar((char) 0);
+            passwordField2.setEchoChar((char) 0);
+        } else {
+            passwordField1.setEchoChar('*');
+            passwordField2.setEchoChar('*');
+        }
+    }
+
+    private void validateInput() {
+        if (usernameField.getText().isEmpty() || passwordField1.getPassword().length == 0 || passwordField2.getPassword().length == 0) {
+            showDetailsMissing();
+            nextBtn.setEnabled(false);
+        } else if (!(Arrays.equals(passwordField1.getPassword(), passwordField2.getPassword()))) {
+            showPasswordMismatch();
+            nextBtn.setEnabled(false);
+        } else {
+            removeErrorMessages();
+            nextBtn.setEnabled(true);
+        }
+    }
+
+    public void enableButtons() {
+        backBtn.setEnabled(true);
+        defaultSetupBtn.setEnabled(true);
+        nextBtn.setEnabled(true);
+    }
+
+    public void disableButtons() {
+        backBtn.setEnabled(false);
+        defaultSetupBtn.setEnabled(false);
+        nextBtn.setEnabled(false);
+    }
+
+    private void showPasswordMismatch() {
+        messagePanel.removeAll();
+        messagePanel.add(passwordMismatchLabel);
+        midPanel.revalidate();
+        midPanel.repaint();
+    }
+
+    private void showDetailsMissing() {
+        messagePanel.removeAll();
+        messagePanel.add(detailsMissingLabel);
+        midPanel.revalidate();
+        midPanel.repaint();
+    }
+
+    private void removeErrorMessages() {
+        messagePanel.removeAll();
+        midPanel.revalidate();
+        midPanel.repaint();
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return this;
+    }
+
+    public JButton getBackBtn() {
+        return backBtn;
+    }
+
+    public JButton getDefaultSetupBtn() {
+        return defaultSetupBtn;
+    }
+
+    public JButton getNextBtn() {
+        return nextBtn;
+    }
+
+    public JButton getCancelBtn() {
+        return cancelBtn;
+    }
+
+    public String getUsername() {
+        return usernameField.getText();
+    }
+
+    public void setUsername(String username) {
+        this.usernameField.setText(username);
+    }
+
+    public char[] getPassword() {
+        return passwordField1.getPassword();
+    }
+
+    public void setPassword(String password) {
+        this.passwordField1.setText(password);
+        this.passwordField2.setText(password);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/MongodbUserSetupException.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+public class MongodbUserSetupException extends Exception {
+
+    public MongodbUserSetupException(String message) {
+        super(message);
+    }
+
+    public MongodbUserSetupException(Throwable cause) {
+        super(cause);
+    }
+
+    public MongodbUserSetupException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupView.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import javax.swing.JLabel;
+import java.awt.Component;
+
+public interface SetupView {
+
+    /**
+     * Sets the title of the current view
+     * and updates the progress
+     *
+     * @param title
+     * @param progress
+     */
+    void setTitleAndProgress(JLabel title, JLabel progress);
+
+    Component getUiComponent();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupWindow.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import com.redhat.thermostat.setup.command.locale.LocaleResources;
+import com.redhat.thermostat.shared.locale.Translate;
+
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.Arrays;
+
+public class SetupWindow {
+    private CountDownLatch shutdown;
+    private JFrame frame;
+    private JPanel mainView;
+    private JPanel topPanel;
+    private JLabel title;
+    private JLabel progress;
+    private StartView startView;
+    private MongoUserSetupView mongoUserSetupView;
+    private UserPropertiesView userPropertiesView;
+    private String username = null;
+    private char[] password = null;
+    private boolean showDetailedBlurb = false;
+    private ThermostatSetup thermostatSetup;
+
+    private static final String defaultUsername = "mongodevuser";
+    private static final String defaultPassword = "mongodevpassword";
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private PrintStream out;
+
+    public SetupWindow(PrintStream out, ThermostatSetup thermostatSetup) {
+        this.out = out;
+        this.thermostatSetup = thermostatSetup;
+        shutdown = new CountDownLatch(1);
+    }
+
+    public void run() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                initialize();
+                addViewListeners();
+                showView(startView);
+                frame.setVisible(true);
+            }
+        });
+
+        try {
+            shutdown.await();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        } finally {
+            cleanup();
+        }
+    }
+
+    private void cleanup() {
+        if (password != null) {
+            Arrays.fill(password, '\0');
+        }
+    }
+
+    private void initialize() {
+        frame = new JFrame(translator.localize(LocaleResources.WINDOW_TITLE).getContents());
+        setLargeFrame(false);
+        frame.addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent e) {
+                shutdown();
+            }
+        });
+        mainView = new JPanel(new BorderLayout());
+        createTopPanel();
+        mainView.add(topPanel, BorderLayout.NORTH);
+        frame.add(mainView);
+
+        startView = new StartView(new BorderLayout());
+        mongoUserSetupView = new MongoUserSetupView(new BorderLayout());
+        userPropertiesView = new UserPropertiesView(new BorderLayout());
+    }
+
+    private void createTopPanel() {
+        title = new JLabel();
+        title.setFont(new Font("Liberation Sans", Font.BOLD, 16));
+        progress = new JLabel();
+
+        topPanel = new JPanel(new GridBagLayout());
+        GridBagConstraints c = new GridBagConstraints();
+        c.insets.left = 10;
+        c.insets.top = 10;
+        c.gridx = 0;
+        c.weightx = 0.5;
+        c.anchor = GridBagConstraints.LINE_START;
+        topPanel.add(progress, c);
+        c.gridx = 1;
+        c.weightx = 1;
+        c.gridwidth = 2;
+        topPanel.add(title, c);
+    }
+
+    private void addViewListeners() {
+        startView.getNextBtn().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                showDetailedBlurb = false;
+                startView.showMoreInfo(showDetailedBlurb);
+                setLargeFrame(showDetailedBlurb);
+
+                mainView.remove(startView);
+                showView(mongoUserSetupView);
+            }
+        });
+        startView.getCancelBtn().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                shutdown();
+            }
+        });
+        startView.getShowMoreInfoBtn().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                showDetailedBlurb = !showDetailedBlurb;
+                startView.showMoreInfo(showDetailedBlurb);
+                setLargeFrame(showDetailedBlurb);
+            }
+        });
+        mongoUserSetupView.getBackBtn().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                mainView.remove(mongoUserSetupView);
+                showView(startView);
+            }
+        });
+        mongoUserSetupView.getDefaultSetupBtn().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                mongoUserSetupView.setUsername(defaultUsername);
+                mongoUserSetupView.setPassword(defaultPassword);
+            }
+        });
+        mongoUserSetupView.getNextBtn().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                username = mongoUserSetupView.getUsername();
+                password = mongoUserSetupView.getPassword();
+                runMongoSetup();
+
+                if (thermostatSetup.isWebAppInstalled()) {
+                    mainView.remove(mongoUserSetupView);
+                    showView(userPropertiesView);
+                }
+            }
+        });
+        mongoUserSetupView.getCancelBtn().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                shutdown();
+            }
+        });
+        userPropertiesView.getFinishBtn().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                runPropertiesSetup();
+            }
+        });
+        userPropertiesView.getCancelBtn().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                shutdown();
+            }
+        });
+    }
+
+    private void setLargeFrame(boolean setLarge) {
+        if (setLarge) {
+            frame.setSize(600, 600);
+        } else {
+            frame.setSize(600, 350);
+        }
+    }
+
+    private void runMongoSetup() {
+        SwingWorker worker = new SwingWorker<Void, Void>() {
+            @Override
+            public Void doInBackground() {
+                mongoUserSetupView.disableButtons();
+                userPropertiesView.disableButtons();
+                try {
+                    thermostatSetup.createMongodbUser(username, password);
+                } catch (MongodbUserSetupException e) {
+                    e.printStackTrace();
+                    shutdown();
+                }
+                return null;
+            }
+
+            @Override
+            public void done() {
+                mongoUserSetupView.enableButtons();
+                userPropertiesView.enableButtons();
+                if (!thermostatSetup.isWebAppInstalled()) {
+                    shutdown();
+                }
+            }
+        };
+        worker.execute();
+    }
+
+    private void runPropertiesSetup() {
+        SwingWorker worker = new SwingWorker<Void, Void>() {
+            @Override
+            public Void doInBackground() {
+                userPropertiesView.disableButtons();
+                try {
+                    String[] agentRoles = null;
+                    String[] clientRoles = null;
+                    if (userPropertiesView.makeAgentUserSelected()) {
+                        agentRoles = new String[] {
+                                UserRoles.CMD_CHANNEL_VERIFY,
+                                UserRoles.LOGIN,
+                                UserRoles.PREPARE_STATEMENT,
+                                UserRoles.PURGE,
+                                UserRoles.REGISTER_CATEGORY,
+                                UserRoles.ACCESS_REALM,
+                                UserRoles.SAVE_FILE,
+                                UserRoles.WRITE,
+                                UserRoles.GRANT_FILES_WRITE_ALL,
+                        };
+                    }
+                    if (userPropertiesView.makeClientAdminSelected()) {
+                        clientRoles = new String[] {
+                                UserRoles.GRANT_AGENTS_READ_ALL,
+                                UserRoles.CMD_CHANNEL_GENERATE,
+                                UserRoles.GRANT_HOSTS_READ_ALL,
+                                UserRoles.LOAD_FILE,
+                                UserRoles.LOGIN,
+                                UserRoles.PREPARE_STATEMENT,
+                                UserRoles.READ,
+                                UserRoles.ACCESS_REALM,
+                                UserRoles.REGISTER_CATEGORY,
+                                UserRoles.GRANT_VMS_READ_BY_USERNAME_ALL,
+                                UserRoles.GRANT_VMS_READ_BY_VM_ID_ALL,
+                                UserRoles.GRANT_FILES_READ_ALL,
+                                UserRoles.WRITE,
+                        };
+                    }
+                    thermostatSetup.createThermostatUser(username, password, agentRoles);
+                    thermostatSetup.createThermostatUser(username, password, clientRoles);
+
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    shutdown();
+                }
+                return null;
+            }
+
+            @Override
+            public void done() {
+                userPropertiesView.enableButtons();
+                shutdown();
+            }
+        };
+        worker.execute();
+    }
+
+    private void showView(SetupView view) {
+        mainView.add(view.getUiComponent(), BorderLayout.CENTER);
+        view.setTitleAndProgress(title, progress);
+        mainView.revalidate();
+        mainView.repaint();
+    }
+
+    private void shutdown() {
+        shutdown.countDown();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/StartView.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import com.redhat.thermostat.common.ApplicationInfo;
+import com.redhat.thermostat.setup.command.locale.LocaleResources;
+import com.redhat.thermostat.shared.locale.Translate;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Desktop;
+import java.awt.Dimension;
+import java.awt.LayoutManager;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+public class StartView extends JPanel implements SetupView {
+
+    private JButton nextBtn;
+    private JButton cancelBtn;
+    private JButton moreInfoBtn;
+
+    private JPanel toolbar;
+    private JEditorPane thermostatBlurb;
+    private JPanel midPanel;
+    private static final String THERMOSTAT_LOGO = "thermostat.png";
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    private static final String SHOW_MORE = "Show More";
+    private static final String SHOW_LESS = "Show Less";
+    private static final String PROGRESS = "Step 1 of 3";
+
+    public StartView(LayoutManager layout) {
+        super(layout);
+
+        createToolbarPanel();
+        createMidPanel();
+    }
+
+    @Override
+    public void setTitleAndProgress(JLabel title, JLabel progress) {
+        title.setText(translator.localize(LocaleResources.WELCOME_SCREEN_TITLE).getContents());
+        progress.setText(PROGRESS);
+    }
+
+    private void createMidPanel() {
+        thermostatBlurb = new JEditorPane();
+        thermostatBlurb.setEditorKit(JEditorPane.createEditorKitForContentType("text/html"));
+        thermostatBlurb.setEditable(false);
+
+        moreInfoBtn = new JButton();
+        moreInfoBtn.setAlignmentX(Component.LEFT_ALIGNMENT);
+        showMoreInfo(false);
+
+        thermostatBlurb.addHyperlinkListener(new HyperlinkListener() {
+            public void hyperlinkUpdate(HyperlinkEvent e) {
+                if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+                    if (Desktop.isDesktopSupported()) {
+                        String userGuideURL = new ApplicationInfo().getUserGuide();
+                        try {
+                            Desktop.getDesktop().browse(new URI(userGuideURL));
+                        } catch (IOException | URISyntaxException e1) {
+                            e1.printStackTrace();
+                        }
+                    }
+                }
+            }
+        });
+        JScrollPane scrollPane = new JScrollPane(thermostatBlurb);
+        scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+        midPanel = new JPanel();
+        midPanel.setLayout(new BoxLayout(midPanel, BoxLayout.Y_AXIS));
+        midPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+        midPanel.add(scrollPane);
+        midPanel.add(moreInfoBtn);
+
+        this.add(midPanel, BorderLayout.CENTER);
+    }
+
+    private void createToolbarPanel() {
+        URL logoURL = SetupWindow.class.getClassLoader().getResource(THERMOSTAT_LOGO);
+        JLabel thermostatLogo = new JLabel(new ImageIcon(logoURL));
+
+        nextBtn = new JButton(translator.localize(LocaleResources.NEXT).getContents());
+        nextBtn.setPreferredSize(new Dimension(70, 30));
+        cancelBtn = new JButton(translator.localize(LocaleResources.CANCEL).getContents());
+        cancelBtn.setPreferredSize(new Dimension(70, 30));
+
+        toolbar = new JPanel();
+        toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.LINE_AXIS));
+        toolbar.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
+        toolbar.add(thermostatLogo);
+        toolbar.add(Box.createHorizontalGlue());
+        toolbar.add(nextBtn);
+        toolbar.add(cancelBtn);
+
+        this.add(toolbar, BorderLayout.SOUTH);
+    }
+
+    public void showMoreInfo(boolean setDetailed) {
+        String userGuideURL = new ApplicationInfo().getUserGuide();
+        StringBuilder text = new StringBuilder();
+
+        text.append("<html>");
+        if(setDetailed) {
+            text.append(translator.localize(LocaleResources.THERMOSTAT_BLURB).getContents());
+            moreInfoBtn.setText(SHOW_LESS);
+        } else {
+            text.append(translator.localize(LocaleResources.THERMOSTAT_BRIEF).getContents());
+            moreInfoBtn.setText(SHOW_MORE);
+        }
+        text.append("<center><a href=\"\">")
+                .append(userGuideURL)
+                .append("</a></center>")
+                .append("</html>").toString();
+
+        thermostatBlurb.setText(text.toString());
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return this;
+    }
+
+    public JButton getShowMoreInfoBtn() {
+        return moreInfoBtn;
+    }
+
+    public JButton getNextBtn() {
+        return nextBtn;
+    }
+
+    public JButton getCancelBtn() {
+        return cancelBtn;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/ThermostatSetup.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import java.io.IOException;
+
+public interface ThermostatSetup {
+
+    /**
+     * Provided a username and password,
+     * creates a MongodbUser
+     *
+     * @param username
+     * @param password
+     * @throws MongodbUserSetupException
+     */
+    void createMongodbUser(String username, char[] password) throws MongodbUserSetupException;
+
+    /**
+     * Creates web.auth file and sets
+     * users.properties and
+     * roles.properties for a user
+     *
+     * @param username
+     * @param password
+     * @param roles
+     * @throws IOException
+     */
+    void createThermostatUser(String username, char[] password, String[] roles) throws IOException;
+
+    /**
+     * Checks if webapp is installed on the system
+     *
+     * @return true if webapp is installed, false otherwise
+     */
+    boolean isWebAppInstalled();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/ThermostatSetupImpl.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,391 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
+import com.redhat.thermostat.common.tools.ApplicationState;
+import com.redhat.thermostat.setup.command.locale.LocaleResources;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.launcher.Launcher;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Properties;
+
+
+public class ThermostatSetupImpl implements ThermostatSetup {
+    private static final String WEB_AUTH_FILE = "web.auth";
+    private static final String USERS_PROPERTIES = "thermostat-users.properties";
+    private static final String ROLES_PROPERTIES = "thermostat-roles.properties";
+    private static final String MONGO_INPUT_SCRIPT = "/tmp/mongo-input.js";
+    private static final String DEFAULT_AGENT_USER = "agent-tester";
+    private static final String DEFAULT_CLIENT_USER = "client-tester";
+    private static final String DEFAULT_USER_PASSWORD = "tester";
+    private static final String THERMOSTAT_AGENT = "thermostat-agent";
+    private static final String THERMOSTAT_CLIENT = "thermostat-client";
+    private static final String THERMOSTAT_CMDC = "thermostat-cmdc";
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    private static final String[] STORAGE_START_ARGS = {"storage", "--start", "--permitLocalhostException"};
+    private static final String[] STORAGE_STOP_ARGS = {"storage", "--stop"};
+
+    private static boolean storageFailed = false;
+    private List<ActionListener<ApplicationState>> listeners;
+    private String setupTmpUnlockContent;
+    private String webApp;
+    private String setupUnlockContentRegular;
+    private String userAgentAuth;
+    private String userDoneFile;
+    private String createUserScript;
+    private PrintStream out;
+    private CredentialFinder finder;
+    private File setupCompleteFile;
+    private Launcher launcher;
+    private Properties roleProps;
+
+    public ThermostatSetupImpl(BundleContext context, CommonPaths paths, PrintStream out) {
+        this.out = out;
+        finder = new CredentialFinder(paths);
+
+        ServiceReference launcherRef = context.getServiceReference(Launcher.class);
+        launcher = (Launcher) context.getService(launcherRef);
+
+        listeners = new ArrayList<>();
+        listeners.add(new StorageListener(out));
+        setThermostatVars(paths);
+    }
+
+    //package-private constructor for testing
+    ThermostatSetupImpl(Launcher launcher, CommonPaths paths, PrintStream out, CredentialFinder finder) {
+        this.launcher = launcher;
+        this.finder = finder;
+        listeners = new ArrayList<>();
+        listeners.add(new StorageListener(out));
+        setThermostatVars(paths);
+    }
+
+    private void setThermostatVars(CommonPaths paths) {
+        //set thermostat environment
+        createUserScript = paths.getSystemThermostatHome().toString() + "/lib/create-user.js";
+        userAgentAuth = paths.getUserAgentAuthConfigFile().toString();
+        userDoneFile = paths.getUserThermostatHome().toString() + "/data/mongodb-user-done.stamp";
+        webApp = paths.getSystemThermostatHome() + "/webapp";
+        String setupCompletePath = paths.getUserThermostatHome().toString() + "/data/setup-complete.stamp";
+        setupCompleteFile = new File(setupCompletePath);
+
+        //set stamp complete vars
+        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss zzz");
+        Date date = new Date();
+        String timestamp = dateFormat.format(date);
+        String programName = "Thermostat Setup";
+        setupTmpUnlockContent = "Temporarily unlocked thermostat via " + programName + " on " + timestamp;
+        setupUnlockContentRegular = "Created by " + programName + " on " + timestamp;
+    }
+
+    @Override
+    public void createMongodbUser(String username, char[] password) throws MongodbUserSetupException {
+        try {
+            unlockThermostat();
+
+            startStorage();
+
+            byte[] encoded = Files.readAllBytes(Paths.get(createUserScript));
+            String mongoInput = new String(encoded);
+            mongoInput = mongoInput.replaceAll("\\$USERNAME", username);
+            mongoInput = mongoInput.replaceAll("\\$PASSWORD", String.valueOf(password));
+
+            File mongoInputFile = new File(MONGO_INPUT_SCRIPT);
+            mongoInputFile.deleteOnExit();
+            Files.write(mongoInputFile.toPath(), mongoInput.getBytes());
+
+            int mongoRetVal = runMongo();
+            if (mongoRetVal != 0) {
+                throw new MongodbUserSetupException("Mongodb user setup failed");
+            }
+
+            stopStorage();
+
+            File userDoneFile = new File(this.userDoneFile);
+            userDoneFile.createNewFile();
+
+            Files.write(setupCompleteFile.toPath(), setupUnlockContentRegular.getBytes());
+        } catch (IOException | InterruptedException e) {
+            removeTempStampFile();
+            throw new MongodbUserSetupException("Error creating Mongodb user", e);
+        }
+    }
+
+    //package-private for testing
+    void unlockThermostat() throws IOException {
+        Files.write(setupCompleteFile.toPath(), setupTmpUnlockContent.getBytes());
+    }
+
+    private void startStorage() throws MongodbUserSetupException {
+        launcher.run(STORAGE_START_ARGS, listeners, false);
+
+        if (storageFailed) {
+            throw new MongodbUserSetupException("Thermostat storage failed to start");
+        }
+    }
+
+    private void stopStorage() throws MongodbUserSetupException {
+        launcher.run(STORAGE_STOP_ARGS, listeners, false);
+
+        if (storageFailed) {
+            throw new MongodbUserSetupException("Thermostat storage failed to stop");
+        }
+    }
+
+    //package-private for testing
+    int runMongo() throws IOException, InterruptedException {
+        ProcessBuilder mongoProcess = new ProcessBuilder("mongo", "127.0.0.1:27518/thermostat", MONGO_INPUT_SCRIPT);
+        return mongoProcess.start().waitFor();
+    }
+
+    private void removeTempStampFile() {
+        if (setupCompleteFile.exists()) {
+            setupCompleteFile.delete();
+        }
+    }
+
+    @Override
+    public void createThermostatUser(String username, char[] password, String[] roles) throws IOException {
+        File credentialsFile = finder.getConfiguration(WEB_AUTH_FILE);
+        try {
+            Properties credentialProps = new Properties();
+            credentialProps.setProperty("storage.username", username);
+            credentialProps.setProperty("storage.password", String.valueOf(password));
+            credentialProps.store(new FileOutputStream(credentialsFile), "Storage Credentials");
+
+            credentialsFile.setReadable(true, false);
+            credentialsFile.setWritable(true, true);
+
+            List<String> rolesList = Arrays.asList(roles);
+
+            if(rolesList.containsAll(Arrays.asList(UserRoles.CLIENT_ROLES))) {
+                createClientUser();
+                setClientRoles(roles);
+            } else if(rolesList.containsAll(Arrays.asList(UserRoles.AGENT_ROLES))) {
+                createAgentUser();
+                setAgentRoles(roles);
+            }
+
+        } catch (IOException e) {
+            throw new IOException("Automatic substitution of file " + WEB_AUTH_FILE + " failed!", e);
+        }
+    }
+
+    private void createAgentUser() throws IOException {
+        Properties userProps = new Properties();
+        FileOutputStream userStream = new FileOutputStream(finder.getConfiguration(USERS_PROPERTIES), true);
+        userProps.setProperty(DEFAULT_AGENT_USER, DEFAULT_USER_PASSWORD);
+        userProps.store(userStream, "Agent User");
+
+        setAgentCredentials();
+    }
+
+    private void setAgentCredentials() throws IOException {
+        Properties agentProps = new Properties();
+        FileOutputStream agentAuthStream = new FileOutputStream(new File(userAgentAuth));
+        agentProps.setProperty("username", DEFAULT_AGENT_USER);
+        agentProps.setProperty("password", DEFAULT_USER_PASSWORD);
+        agentProps.store(agentAuthStream, "Agent Credentials");
+    }
+
+    private void createClientUser() throws IOException {
+        Properties userProps = new Properties();
+        FileOutputStream userStream = new FileOutputStream(finder.getConfiguration(USERS_PROPERTIES), true);
+        userProps.setProperty(DEFAULT_CLIENT_USER, DEFAULT_USER_PASSWORD);
+        userProps.store(userStream, "Client User");
+    }
+
+    private void setAgentRoles(String[] agentRoles) throws IOException {
+        String[] agentUserRoles = new String[] {
+                THERMOSTAT_AGENT
+        };
+        setRoleProperty(DEFAULT_AGENT_USER, agentUserRoles);
+        setRoleProperty(THERMOSTAT_AGENT, agentRoles);
+        FileOutputStream roleStream = new FileOutputStream(finder.getConfiguration(ROLES_PROPERTIES), true);
+        roleProps.store(new PropertiesWriter(roleStream), "Thermostat Agent Roles");
+    }
+
+    private void setClientRoles(String[] clientRoles) throws IOException {
+        String[] clientUserRoles = new String[] {
+                THERMOSTAT_CLIENT,
+                THERMOSTAT_CMDC,
+                UserRoles.PURGE
+        };
+
+        String[] cmdcRoles = new String[]{
+                UserRoles.GRANT_CMD_CHANNEL_GARBAGE_COLLECT,
+                UserRoles.GRANT_CMD_CHANNEL_DUMP_HEAP,
+                UserRoles.GRANT_CMD_CHANNEL_GRANT_THREAD_HARVESTER,
+                UserRoles.GRANT_CMD_CHANNEL_KILLVM,
+                UserRoles.GRANT_CMD_PROFILE_VM,
+                UserRoles.GRANT_CMD_CHANNEL_PING,
+                UserRoles.GRANT_CMD_CHANNEL_JMX_TOGGLE_NOTIFICATION,
+        };
+
+        setRoleProperty(DEFAULT_CLIENT_USER, clientUserRoles);
+        setRoleProperty(THERMOSTAT_CLIENT, clientRoles);
+        setRoleProperty(THERMOSTAT_CMDC, cmdcRoles);
+
+        FileOutputStream roleStream = new FileOutputStream(finder.getConfiguration(ROLES_PROPERTIES), true);
+        roleProps.store(new PropertiesWriter(roleStream), "Thermostat Client Roles");
+    }
+
+    private void setRoleProperty(String attribute, String[] roles) throws IOException {
+        if(roleProps == null) {
+            roleProps = new Properties();
+        }
+        if (roles.length > 0) {
+            StringBuilder rolesBuilder = new StringBuilder();
+            for (int i = 0; i < roles.length - 1; i++) {
+                rolesBuilder.append(roles[i] + ", " + System.getProperty("line.separator"));
+            }
+            rolesBuilder.append(roles[roles.length - 1]);
+            roleProps.setProperty(attribute, rolesBuilder.toString());
+        }
+    }
+
+    @Override
+    public boolean isWebAppInstalled() {
+        Path webAppPath = Paths.get(webApp);
+        if (Files.exists(webAppPath)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * The Properties.store() method doesn't allow for new lines. This
+     * class is used so that when a property key has multiple associated
+     * values, they are written in a readable manner.
+     */
+    public static class PropertiesWriter extends PrintWriter {
+
+        private static final int INDENT_AMOUNT = 4;
+
+        public PropertiesWriter(OutputStream out) {
+            super(out);
+        }
+
+        @Override
+        public void write(char[] line, int startIdx, int len) {
+            for (int i = startIdx; i < len; i++) {
+                // interpret new lines as such
+                if (isNewLine(line, i)) {
+                    i++; // skip 'n' in \n
+                    try {
+                        out.write('\\');
+                        out.write(System.getProperty("line.separator"));
+                        // indent following lines
+                        for (int j = 0; j < INDENT_AMOUNT; j++) {
+                            out.write(' ');
+                        }
+                    } catch (IOException e) {
+                        e.printStackTrace(System.err);
+                    }
+                } else {
+                    try {
+                        out.write(line[i]);
+                    } catch (IOException e) {
+                        e.printStackTrace(System.err);
+                    }
+                }
+            }
+        }
+
+        private boolean isNewLine(char[] line, int j) {
+            if (j + 1 > line.length) {
+                return false;
+            }
+            if (line[j] == '\\' && line[j + 1] == 'n') {
+                return true;
+            }
+            return false;
+        }
+    }
+
+    private static class StorageListener implements ActionListener<ApplicationState> {
+
+        private final PrintStream out;
+
+        private StorageListener(PrintStream out) {
+            this.out = out;
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
+            if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) {
+                AbstractStateNotifyingCommand storage = (AbstractStateNotifyingCommand) actionEvent.getSource();
+                // Implementation detail: there is a single Storage instance registered
+                // as an OSGi service. We remove ourselves as listener so that we don't get
+                // notified in the case that the command is invoked by some other means later.
+                storage.getNotifier().removeActionListener(this);
+
+                switch (actionEvent.getActionId()) {
+                    case START:
+                        storageFailed = false;
+                        break;
+                    case FAIL:
+                        out.println(translator.localize(LocaleResources.STORAGE_FAILED).getContents());
+                        storageFailed = true;
+                        break;
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/UserPropertiesView.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import com.redhat.thermostat.setup.command.locale.LocaleResources;
+import com.redhat.thermostat.shared.locale.Translate;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.LayoutManager;
+import java.net.URL;
+
+public class UserPropertiesView extends JPanel implements SetupView {
+
+    private JButton finishBtn;
+    private JButton backBtn;
+    private JButton cancelBtn;
+
+    private JPanel toolbar;
+    private JPanel midPanel;
+    private JPanel detailsPanel;
+    private JCheckBox makeAgentUserBtn;
+    private JCheckBox makeClientAdminBtn;
+
+    private static final String THERMOSTAT_LOGO = "thermostat.png";
+    private static final String PROGRESS = "Step 3 of 3";
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    public UserPropertiesView(LayoutManager layout) {
+        super(layout);
+
+        createMidPanel();
+        createToolbarPanel();
+
+        this.add(midPanel, BorderLayout.CENTER);
+        this.add(toolbar, BorderLayout.SOUTH);
+    }
+
+    @Override
+    public void setTitleAndProgress(JLabel title, JLabel progress) {
+        title.setText(translator.localize(LocaleResources.USERS_SETUP_TITLE).getContents());
+        progress.setText(PROGRESS);
+    }
+
+    public void createMidPanel() {
+        JLabel agentInfo = new JLabel(translator.localize(LocaleResources.AGENT_INFO).getContents());
+        JLabel clientInfo = new JLabel(translator.localize(LocaleResources.CLIENT_INFO).getContents());
+        makeAgentUserBtn = new JCheckBox(translator.localize(LocaleResources.CREATE_AGENT_USER).getContents());
+        makeAgentUserBtn.setSelected(true);
+        makeClientAdminBtn = new JCheckBox(translator.localize(LocaleResources.CREATE_CLIENT_ADMIN).getContents());
+        makeClientAdminBtn.setSelected(true);
+        detailsPanel = new JPanel(new GridBagLayout());
+
+        GridBagConstraints c = new GridBagConstraints();
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.gridy = 0;
+        c.insets.top = 40;
+        detailsPanel.add(agentInfo, c);
+        c.gridy = 1;
+        c.insets.top = 10;
+        detailsPanel.add(makeAgentUserBtn, c);
+        c.insets.top = 25;
+        c.gridy = 2;
+        detailsPanel.add(clientInfo, c);
+        c.insets.top = 10;
+        c.gridy = 3;
+        detailsPanel.add(makeClientAdminBtn, c);
+
+        midPanel = new JPanel(new BorderLayout());
+        midPanel.add(detailsPanel, BorderLayout.NORTH);
+    }
+
+    private void createToolbarPanel() {
+        URL logoURL = SetupWindow.class.getClassLoader().getResource(THERMOSTAT_LOGO);
+        JLabel thermostatLogo = new JLabel(new ImageIcon(logoURL));
+
+        backBtn = new JButton(translator.localize(LocaleResources.BACK).getContents());
+        backBtn.setPreferredSize(new Dimension(70, 30));
+        backBtn.setEnabled(false);
+        finishBtn = new JButton(translator.localize(LocaleResources.FINISH).getContents());
+        finishBtn.setPreferredSize(new Dimension(70, 30));
+        cancelBtn = new JButton(translator.localize(LocaleResources.CANCEL).getContents());
+        cancelBtn.setPreferredSize(new Dimension(70, 30));
+
+        toolbar = new JPanel();
+        toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.LINE_AXIS));
+        toolbar.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
+        toolbar.add(thermostatLogo);
+        toolbar.add(Box.createHorizontalGlue());
+        toolbar.add(backBtn);
+        toolbar.add(finishBtn);
+        toolbar.add(cancelBtn);
+    }
+
+    public void enableButtons() {
+        makeAgentUserBtn.setEnabled(true);
+        makeClientAdminBtn.setEnabled(true);
+        finishBtn.setEnabled(true);
+    }
+
+    public void disableButtons() {
+        makeAgentUserBtn.setEnabled(false);
+        makeClientAdminBtn.setEnabled(false);
+        finishBtn.setEnabled(false);
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return this;
+    }
+
+    public JButton getFinishBtn() {
+        return finishBtn;
+    }
+
+    public JButton getCancelBtn() {
+        return cancelBtn;
+    }
+
+    public boolean makeAgentUserSelected() {
+        return makeAgentUserBtn.isSelected();
+    }
+
+    public boolean makeClientAdminSelected() {
+        return makeClientAdminBtn.isSelected();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/UserRoles.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+public interface UserRoles {
+
+    /**
+     * Allows for a user to read records tied to any host.
+     */
+    final String GRANT_HOSTS_READ_ALL = "thermostat-hosts-grant-read-hostname-ALL";
+    /**
+     * Allows for a user to read records tied to any JVM id.
+     */
+    final String GRANT_VMS_READ_BY_VM_ID_ALL = "thermostat-vms-grant-read-vmId-ALL";
+    /**
+     * Allows for a user to read records tied to any username the JVM is running as.
+     */
+    final String GRANT_VMS_READ_BY_USERNAME_ALL = "thermostat-vms-grant-read-username-ALL";
+    /**
+     * Allows for a user to read any file from storage.
+     */
+    final String GRANT_FILES_READ_ALL = "thermostat-files-grant-read-filename-ALL";
+    /**
+     * Allows for a user to write any file to storage.
+     */
+    final String GRANT_FILES_WRITE_ALL = "thermostat-files-grant-write-filename-ALL";
+    /**
+     * Allows for a user to see records tied to any agent.
+     */
+    final String GRANT_AGENTS_READ_ALL = "thermostat-agents-grant-read-agentId-ALL";
+
+    final String GRANT_CMD_CHANNEL_GARBAGE_COLLECT = "thermostat-cmdc-grant-garbage-collect";
+    final String GRANT_CMD_CHANNEL_DUMP_HEAP = "thermostat-cmdc-grant-dump-heap";
+    final String GRANT_CMD_CHANNEL_GRANT_THREAD_HARVESTER = "thermostat-cmdc-grant-thread-harvester";
+    final String GRANT_CMD_CHANNEL_KILLVM = "thermostat-cmdc-grant-killvm";
+    final String GRANT_CMD_CHANNEL_PING = "thermostat-cmdc-grant-ping";
+    final String GRANT_CMD_CHANNEL_JMX_TOGGLE_NOTIFICATION = "thermostat-cmdc-grant-jmx-toggle-notifications";
+    final String GRANT_CMD_PROFILE_VM = "thermostat-cmdc-grant-profile-vm";
+
+    final String PREPARE_STATEMENT = "thermostat-prepare-statement";
+    final String READ = "thermostat-query";
+    final String WRITE = "thermostat-write";
+    final String LOAD_FILE = "thermostat-load-file";
+    final String SAVE_FILE = "thermostat-save-file";
+    final String PURGE = "thermostat-purge";
+    final String REGISTER_CATEGORY = "thermostat-register-category";
+    final String CMD_CHANNEL_VERIFY = "thermostat-cmdc-verify";
+    final String CMD_CHANNEL_GENERATE = "thermostat-cmdc-generate";
+    final String LOGIN = "thermostat-login";
+    final String ACCESS_REALM = "thermostat-realm";
+    
+    /**
+     * Basic role memberships for agent users
+     */
+    final String[] AGENT_ROLES = {
+            UserRoles.PREPARE_STATEMENT,
+            UserRoles.WRITE,
+            UserRoles.CMD_CHANNEL_VERIFY,
+            UserRoles.LOGIN,
+            UserRoles.PURGE,
+            UserRoles.REGISTER_CATEGORY,
+            UserRoles.ACCESS_REALM,
+            UserRoles.SAVE_FILE,
+    };
+
+    /**
+     * Basic role memberships for client users
+     */
+    final String[] CLIENT_ROLES = {
+            UserRoles.ACCESS_REALM,
+            UserRoles.LOGIN,
+            UserRoles.READ,
+            UserRoles.PREPARE_STATEMENT,
+            UserRoles.CMD_CHANNEL_GENERATE,
+            UserRoles.LOAD_FILE,
+            UserRoles.REGISTER_CATEGORY
+    };
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/locale/LocaleResources.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.locale;
+
+import com.redhat.thermostat.shared.locale.Translate;
+
+
+public enum LocaleResources {
+
+    WINDOW_TITLE,
+    WELCOME_SCREEN_TITLE,
+    MONGO_SETUP_TITLE,
+    USERS_SETUP_TITLE,
+    NEXT,
+    BACK,
+    CANCEL,
+    FINISH,
+    AGENT_INFO,
+    CLIENT_INFO,
+    THERMOSTAT_BRIEF,
+    THERMOSTAT_BLURB,
+    STORAGE_FAILED,
+    CREATE_AGENT_USER,
+    CREATE_CLIENT_ADMIN,
+    ;
+
+    static final String RESOURCE_BUNDLE =
+            "com.redhat.thermostat.setup.locale.strings";
+
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/main/resources/com/redhat/thermostat/setup/locale/strings.properties	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,64 @@
+WINDOW_TITLE=Thermostat Setup
+
+WELCOME_SCREEN_TITLE=Welcome to the Thermostat Setup Wizard
+
+MONGO_SETUP_TITLE=MongoDB User Setup
+
+USERS_SETUP_TITLE=Thermostat Users Setup
+
+NEXT=Next>
+
+BACK=<Back
+
+CANCEL=Cancel
+
+FINISH=Finish
+
+THERMOSTAT_BRIEF=\
+<p>\
+  Thermostat is a database backed distributed monitoring \
+  solution with support for monitoring multiple JVM instances. \
+</p>\
+<p>\
+    Please see the Thermostat User Guide for more information:\
+<p>
+
+THERMOSTAT_BLURB =\
+<p>\
+    Thermostat is a database backed distributed monitoring \
+    solution with support for monitoring multiple JVM instances. \
+    The system is made up of three (3) components:\
+</p>\
+<ol>\
+    <li>Agents which collect data.</li>\
+    <li>Clients, which allow users to visualize collected data.</li>\
+    <li>Storage layer which connects the above components.</li>\
+</ol>\
+<p>\
+    The storage layer itself is two-tiered. The endpoint agents \
+    and clients communicate with is a web application which uses \
+    Mongodb as a backing database. \
+</p>\
+<p>\
+    This setup wizard helps with a setup where all three components \
+    run on a local system. In particular, it helps with the setup \
+    of the storage layer. First, a user is set up in mongodb which \
+    the web endpoint will use for database connections. Second, \
+    the web endpoint's servlet config is updated so as to use the \
+    credentials of this database user. \
+</p>\
+<p>\
+    Please see the Thermostat User Guide for more information on \
+    how to connect clients and agents to the pre-configured storage \
+    layer:\
+<p>
+
+CREATE_AGENT_USER=Create Agent User
+
+CREATE_CLIENT_ADMIN=Create Client Admin User
+
+STORAGE_FAILED="Thermostat storage failed"
+
+AGENT_INFO=Agents connect to storage and send collected data from JVMs
+
+CLIENT_INFO=Clients connect to storage and retrieve data to display
Binary file setup-command/command/src/main/resources/thermostat.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/SetupCommandTest.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import org.junit.Before;
+
+import com.redhat.thermostat.common.cli.Arguments;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.Console;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+public class SetupCommandTest {
+
+    private SetupCommand cmd;
+    private BundleContext context;
+    private CommandContext ctxt;
+    private Arguments mockArgs;
+    private Console console;
+    private List<String> list = new ArrayList<>();
+    private ByteArrayOutputStream outputBaos, errorBaos;
+    private PrintStream output, error;
+    private CommonPaths paths;
+
+    @Before
+    public void setUp() {
+        paths = mock(CommonPaths.class);
+        context = mock(BundleContext.class);
+        ctxt = mock(CommandContext.class);
+        mockArgs = mock(Arguments.class);
+        console = mock(Console.class);
+
+        outputBaos = new ByteArrayOutputStream();
+        output = new PrintStream(outputBaos);
+
+        errorBaos = new ByteArrayOutputStream();
+        error = new PrintStream(errorBaos);
+
+        when(ctxt.getArguments()).thenReturn(mockArgs);
+        when(ctxt.getConsole()).thenReturn(console);
+        when(console.getError()).thenReturn(error);
+        when(console.getOutput()).thenReturn(output);
+        when(mockArgs.getNonOptionArguments()).thenReturn(list);
+    }
+
+    @Test
+    public void testLookAndFeelIsSet() throws CommandException {
+        final boolean[] isSet = {false};
+        cmd = new SetupCommand(context) {
+            @Override
+            void setLookAndFeel() throws InvocationTargetException, InterruptedException {
+                isSet[0] = true;
+            }
+
+            @Override
+            void createMainWindowAndRun() {
+                //do nothing
+            }
+        };
+
+        cmd.setPaths(paths);
+        cmd.run(ctxt);
+
+        assertTrue(isSet[0]);
+    }
+
+    @Test
+    public void testCreateMainWindowIsCalled() throws CommandException {
+        final boolean[] isSet = {false};
+        cmd = new SetupCommand(context) {
+            @Override
+            void setLookAndFeel() throws InvocationTargetException, InterruptedException {
+                //do nothing
+            }
+
+            @Override
+            void createMainWindowAndRun() {
+                isSet[0] = true;
+            }
+        };
+
+        cmd.setPaths(paths);
+        cmd.run(ctxt);
+
+        assertTrue(isSet[0]);
+    }
+
+    @Test
+    public void testPathsNotSetFailure() {
+        cmd = new SetupCommand(context) {
+            @Override
+            void setLookAndFeel() throws InvocationTargetException, InterruptedException {
+                //do nothing
+            }
+
+            @Override
+            void createMainWindowAndRun() {
+                //do nothing
+            }
+        };
+
+        try {
+            cmd.run(ctxt);
+            fail();
+        } catch (CommandException e) {
+            assertTrue(e.getMessage().contains("CommonPaths dependency not available"));
+        }
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/internal/ActivatorTest.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import static com.redhat.thermostat.testutils.Asserts.assertCommandIsRegistered;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+
+import com.redhat.thermostat.shared.config.CommonPaths;
+import org.junit.Test;
+
+import com.redhat.thermostat.testutils.StubBundleContext;
+import com.redhat.thermostat.setup.command.SetupCommand;
+
+public class ActivatorTest {
+
+    @Test
+    public void testCommandsRegistered() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+
+        CommonPaths paths = mock(CommonPaths.class);
+        ctx.registerService(CommonPaths.class, paths, null);
+
+        Activator activator = new Activator();
+
+        activator.start(ctx);
+
+        assertCommandIsRegistered(ctx, "setup", SetupCommand.class);
+
+        activator.stop(ctx);
+
+        assertEquals(1, ctx.getAllServices().size());
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/internal/CredentialFinderTest.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import com.redhat.thermostat.shared.config.CommonPaths;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class CredentialFinderTest {
+    private File systemConfigDir = mock(File.class);
+    private File userConfigDir = mock(File.class);
+
+    private File realFile1;
+    private File realFile2;
+
+    private CommonPaths paths;
+
+    @Before
+    public void setUp() throws IOException {
+        realFile1 = Files.createTempFile("credentialfinder-unit-test", null).toFile();
+        realFile1.createNewFile();
+
+        realFile2 = Files.createTempFile("credentialfinder-unit-test", null).toFile();
+        realFile2.createNewFile();
+
+        paths = mock(CommonPaths.class);
+        when(paths.getSystemConfigurationDirectory()).thenReturn(systemConfigDir);
+        when(paths.getUserConfigurationDirectory()).thenReturn(userConfigDir);
+    }
+
+    @After
+    public void tearDown() {
+        realFile1.delete();
+        realFile2.delete();
+    }
+
+    @Test
+    public void verifyFileFromUserHomeIsUsedIfSystemHomeIsNotUsable() throws Exception {
+        CredentialFinder finder = new CredentialFinder(paths) {
+            @Override
+            File getConfigurationFile(File directory, String name) {
+                if (directory == systemConfigDir) {
+                    return new File("/does-not-exist/really-it-doesn't");
+                } else if (directory == userConfigDir) {
+                    return realFile1;
+                }
+                throw new AssertionError("Unknown test case");
+            };
+        };
+
+        File config = finder.getConfiguration("web.auth");
+        assertEquals(realFile1, config);
+    }
+
+    @Test
+    public void verifyFileFromSystemHomeIsUsedIfBothAreUsable() throws IOException {
+        final File systemFile = realFile1;
+        final File userFile = realFile2;
+
+        CredentialFinder finder = new CredentialFinder(paths) {
+            @Override
+            File getConfigurationFile(File directory, String name) {
+                if (directory == systemConfigDir) {
+                    return systemFile;
+                } else if (directory == userConfigDir) {
+                    return userFile;
+                }
+                throw new AssertionError("Unknown test case");
+            };
+        };
+
+        File config = finder.getConfiguration("web.auth");
+        assertEquals(systemFile, config);
+    }
+
+    @Test
+    public void verifyFileFromSystemHomeIsUsedIfUserHomeNotUsable() throws IOException {
+        CredentialFinder finder = new CredentialFinder(paths) {
+            @Override
+            File getConfigurationFile(File directory, String name) {
+                if (directory == systemConfigDir) {
+                    return realFile1;
+                } else if (directory == userConfigDir) {
+                    return new File("/does-not-exist/really-it-doesn't");
+                }
+                throw new AssertionError("Unknown test case");
+            };
+        };
+
+        File config = finder.getConfiguration("web.auth");
+        assertEquals(realFile1, config);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/internal/ThermostatSetupImplTest.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,444 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.internal;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
+import com.redhat.thermostat.common.tools.ApplicationState;
+import com.redhat.thermostat.launcher.Launcher;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Properties;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.times;
+
+public class ThermostatSetupImplTest {
+
+    private Path testRoot;
+    private Path thermostatSysHome;
+    private Path thermostatUserHome;
+    private Path sysConfigDir;
+    private Path userConfigDir;
+    private Path userDataDir;
+    private Path userAgentAuth;
+    private Path credentialsFile;
+    private Path userPropertiesFile;
+    private Path rolesPropertiesFile;
+    private static final String username = "mongodevuser";
+    private static final String password = "mongodevpassword";
+    private static final String[] STORAGE_START_ARGS = {"storage", "--start", "--permitLocalhostException"};
+    private static final String[] STORAGE_STOP_ARGS = {"storage", "--stop"};
+    private static final String WEB_AUTH_FILE = "web.auth";
+    private static final String USERS_PROPERTIES = "thermostat-users.properties";
+    private static final String ROLES_PROPERTIES = "thermostat-roles.properties";
+    private static final String THERMOSTAT_AGENT = "thermostat-agent";
+
+    private ThermostatSetupImpl tSetup;
+    private CommonPaths paths;
+    private Launcher mockLauncher;
+    private OutputStream out;
+    private static ActionEvent<ApplicationState> mockActionEvent;
+    private static Collection<ActionListener<ApplicationState>> listeners;
+    private CredentialFinder mockCredentialFinder;
+
+    private void makeTempFilesAndDirectories() throws IOException {
+        testRoot = Files.createTempDirectory("thermostat");
+
+        thermostatSysHome = testRoot.resolve("system");
+        Files.createDirectory(thermostatSysHome);
+        thermostatUserHome = testRoot.resolve("user");
+        Files.createDirectory(thermostatUserHome);
+
+        sysConfigDir = thermostatSysHome.resolve("etc");
+        Files.createDirectories(sysConfigDir);
+        Path sysLibDir = thermostatSysHome.resolve("lib");
+        Files.createDirectories(sysLibDir);
+
+        userConfigDir = thermostatUserHome.resolve("etc");
+        Files.createDirectories(userConfigDir);
+        userDataDir = thermostatUserHome.resolve("data");
+        Files.createDirectories(userDataDir);
+
+        userAgentAuth = userConfigDir.resolve("agent.auth");
+        credentialsFile = sysConfigDir.resolve(WEB_AUTH_FILE);
+        userPropertiesFile = sysConfigDir.resolve(USERS_PROPERTIES);
+        rolesPropertiesFile = sysConfigDir.resolve(ROLES_PROPERTIES);
+
+        //create a dummy create-user.js
+        Path createUserScript = sysLibDir.resolve("create-user.js");
+        Files.write(createUserScript, new byte[]{});
+    }
+
+    @Before
+    public void setup() throws IOException, InterruptedException {
+        makeTempFilesAndDirectories();
+
+        out = new ByteArrayOutputStream();
+
+        paths = mock(CommonPaths.class);
+        when(paths.getSystemThermostatHome()).thenReturn(thermostatSysHome.toFile());
+        when(paths.getUserThermostatHome()).thenReturn(thermostatUserHome.toFile());
+        when(paths.getUserAgentAuthConfigFile()).thenReturn(userAgentAuth.toFile());
+        when(paths.getSystemConfigurationDirectory()).thenReturn(sysConfigDir.toFile());
+        when(paths.getUserConfigurationDirectory()).thenReturn(userConfigDir.toFile());
+
+        mockLauncher = mock(Launcher.class);
+        mockActionEvent = mock(ActionEvent.class);
+        AbstractStateNotifyingCommand mockStorageCommand = mock(AbstractStateNotifyingCommand.class);
+        ActionNotifier<ApplicationState> mockNotifier = mock(ActionNotifier.class);
+        when(mockStorageCommand.getNotifier()).thenReturn(mockNotifier);
+        mockActionEvent = mock(ActionEvent.class);
+        when(mockActionEvent.getSource()).thenReturn(mockStorageCommand);
+        when(mockActionEvent.getPayload()).thenReturn(new String("Test String"));
+        mockCredentialFinder = mock(CredentialFinder.class);
+        when(mockCredentialFinder.getConfiguration(WEB_AUTH_FILE)).thenReturn(credentialsFile.toFile());
+        when(mockCredentialFinder.getConfiguration(USERS_PROPERTIES)).thenReturn(userPropertiesFile.toFile());
+        when(mockCredentialFinder.getConfiguration(ROLES_PROPERTIES)).thenReturn(rolesPropertiesFile.toFile());
+
+        tSetup = new ThermostatSetupImpl(mockLauncher, paths, new PrintStream(out), mockCredentialFinder) {
+            @Override
+            int runMongo() {
+                //instead of running mongo through ProcessBuilder
+                //we need to always return 0 for success in tests
+                return 0;
+            }
+        };
+    }
+
+    @After
+    public void teardown() throws IOException {
+        paths = null;
+        mockLauncher = null;
+
+        Files.walkFileTree(testRoot, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                Files.delete(file);
+                return FileVisitResult.CONTINUE;
+            }
+
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                if (exc == null) {
+                    Files.delete(dir);
+                    return FileVisitResult.CONTINUE;
+                } else {
+                    throw exc;
+                }
+            }
+        });
+    }
+
+    @Test
+    public void testUnlockThermostatUnlockFileCreated() throws IOException {
+        String fileData;
+        File setupCompleteFile = new File(thermostatUserHome + "/data/setup-complete.stamp");
+        Path setupCompleteFilePath = Paths.get(setupCompleteFile.toString());
+
+        Files.createDirectories(setupCompleteFilePath.getParent());
+        tSetup.unlockThermostat();
+        fileData = new String(Files.readAllBytes(setupCompleteFilePath));
+
+        assertTrue(setupCompleteFile.exists());
+        assertTrue(fileData.contains("Temporarily unlocked"));
+    }
+
+    @Test
+    public void testSetupMongodbUser() throws IOException {
+        File userDoneFile = new File(userDataDir.toString() + "/mongodb-user-done.stamp");
+        File setupCompleteFile = new File(userDataDir.toString() + "/setup-complete.stamp");
+
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                listeners = (Collection<ActionListener<ApplicationState>>) args[1];
+
+                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START);
+
+                for (ActionListener<ApplicationState> listener : listeners) {
+                    listener.actionPerformed(mockActionEvent);
+                }
+                return null;
+            }
+        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
+
+        boolean exTriggered = false;
+        try {
+            tSetup.createMongodbUser(username, password.toCharArray());
+        } catch (MongodbUserSetupException e) {
+            exTriggered = true;
+        }
+
+        assertFalse(exTriggered);
+
+        verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
+        verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), isA(Collection.class), anyBoolean());
+        verify(mockActionEvent, times(1)).getActionId();
+
+        assertTrue(userDoneFile.exists());
+        assertTrue(setupCompleteFile.exists());
+        String setupCompleteData = new String(Files.readAllBytes(setupCompleteFile.toPath()));
+        assertTrue(setupCompleteData.contains("Created by Thermostat Setup"));
+    }
+
+    @Test
+    public void testStorageStartFail() {
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                listeners = (Collection<ActionListener<ApplicationState>>) args[1];
+
+                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL);
+
+                for (ActionListener<ApplicationState> listener : listeners) {
+                    listener.actionPerformed(mockActionEvent);
+                }
+                return null;
+            }
+        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
+
+        try {
+            tSetup.createMongodbUser(username, password.toCharArray());
+            //shouldn't get here
+            fail();
+        } catch (MongodbUserSetupException e) {
+            assertTrue(e.getMessage().contains("Thermostat storage failed to start"));
+        }
+    }
+
+    @Test
+    public void testStorageStopFail() {
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                listeners = (Collection<ActionListener<ApplicationState>>) args[1];
+
+                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START);
+
+                for (ActionListener<ApplicationState> listener : listeners) {
+                    listener.actionPerformed(mockActionEvent);
+                }
+                return null;
+            }
+        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
+
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                listeners = (Collection<ActionListener<ApplicationState>>) args[1];
+
+                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL);
+
+                for (ActionListener<ApplicationState> listener : listeners) {
+                    listener.actionPerformed(mockActionEvent);
+                }
+                return null;
+            }
+        }).when(mockLauncher).run(eq(STORAGE_STOP_ARGS), isA(Collection.class), anyBoolean());
+
+        try {
+            tSetup.createMongodbUser(username, password.toCharArray());
+            //shouldn't get here
+            fail();
+        } catch (MongodbUserSetupException e) {
+            assertTrue(e.getMessage().contains("Thermostat storage failed to stop"));
+        }
+    }
+
+    @Test
+    public void testCreateMongodbUserFail() {
+        tSetup = new ThermostatSetupImpl(mockLauncher, paths, new PrintStream(out), mockCredentialFinder) {
+            @Override
+            int runMongo() {
+                //return non-zero val to test failure
+                return 1;
+            }
+        };
+
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                listeners = (Collection<ActionListener<ApplicationState>>) args[1];
+
+                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START);
+
+                for (ActionListener<ApplicationState> listener : listeners) {
+                    listener.actionPerformed(mockActionEvent);
+                }
+                return null;
+            }
+        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
+
+        try {
+            tSetup.createMongodbUser(username, password.toCharArray());
+            //shouldn't get here
+            fail();
+        } catch (MongodbUserSetupException e) {
+            assertTrue(e.getMessage().contains("Mongodb user setup failed"));
+        }
+    }
+
+    @Test
+    public void testSetupThermostatUser() throws IOException {
+        String[] agentRoles = new String[] {
+                    UserRoles.CMD_CHANNEL_VERIFY,
+                    UserRoles.LOGIN,
+                    UserRoles.PREPARE_STATEMENT,
+                    UserRoles.PURGE,
+                    UserRoles.REGISTER_CATEGORY,
+                    UserRoles.ACCESS_REALM,
+                    UserRoles.SAVE_FILE,
+                    UserRoles.WRITE,
+                    UserRoles.GRANT_FILES_WRITE_ALL,
+        };
+        String[] clientRoles = new String[] {
+                    UserRoles.GRANT_AGENTS_READ_ALL,
+                    UserRoles.CMD_CHANNEL_GENERATE,
+                    UserRoles.GRANT_HOSTS_READ_ALL,
+                    UserRoles.LOAD_FILE,
+                    UserRoles.LOGIN,
+                    UserRoles.PREPARE_STATEMENT,
+                    UserRoles.READ,
+                    UserRoles.ACCESS_REALM,
+                    UserRoles.REGISTER_CATEGORY,
+                    UserRoles.GRANT_VMS_READ_BY_USERNAME_ALL,
+                    UserRoles.GRANT_VMS_READ_BY_VM_ID_ALL,
+                    UserRoles.GRANT_FILES_READ_ALL,
+                    UserRoles.WRITE,
+        };
+
+        tSetup.createThermostatUser(username, password.toCharArray(), agentRoles);
+        tSetup.createThermostatUser(username, password.toCharArray(), clientRoles);
+
+        //check credentialsFile
+        assertTrue(credentialsFile.toFile().exists());
+        String credentialsData = new String(Files.readAllBytes(credentialsFile));
+        assertTrue(credentialsData.contains("storage.username=" + username));
+        assertTrue(credentialsData.contains("storage.password=" + password));
+
+        //check agent credentials file
+        assertTrue(userAgentAuth.toFile().exists());
+        String userAgentAuthData = new String(Files.readAllBytes(userAgentAuth));
+        assertTrue(userAgentAuthData.contains("username=agent-tester"));
+        assertTrue(userAgentAuthData.contains("password=tester"));
+
+        //check AgentUser file
+        assertTrue(userPropertiesFile.toFile().exists());
+
+        //check clientAdmin file
+        assertTrue(rolesPropertiesFile.toFile().exists());
+    }
+
+    @Test
+    public void testWebAppInstalledSuccess() throws IOException {
+        Path webAppPath = thermostatSysHome.resolve("webapp");
+        Files.createDirectories(webAppPath);
+        assertTrue(tSetup.isWebAppInstalled());
+    }
+
+    @Test
+    public void testWebAppInstalledFail() throws IOException {
+        //Call isWebAppInstalled() without creating
+        //a THERMOSTAT_SYS_HOME/webapp directory
+        assertFalse(tSetup.isWebAppInstalled());
+    }
+
+    @Test
+    public void testPropertiesWriter() throws IOException {
+        String key = THERMOSTAT_AGENT;
+        String[] roles  = new String[] {
+                UserRoles.LOGIN,
+                UserRoles.PREPARE_STATEMENT,
+                UserRoles.PURGE,
+                UserRoles.REGISTER_CATEGORY,
+        };
+        StringBuilder rolesBuilder = new StringBuilder();
+        for (int i = 0; i < roles.length - 1; i++) {
+            rolesBuilder.append(roles[i] + ", " + System.getProperty("line.separator"));
+        }
+        rolesBuilder.append(roles[roles.length - 1]);
+        String value = rolesBuilder.toString();
+
+        Properties propsToStore = new Properties();
+        propsToStore.setProperty(key, value);
+        FileOutputStream roleStream = new FileOutputStream(rolesPropertiesFile.toFile());
+        propsToStore.store(new ThermostatSetupImpl.PropertiesWriter(roleStream), null);
+
+        Properties propsToLoad = new Properties();
+        propsToLoad.load(new FileInputStream(rolesPropertiesFile.toFile()));
+        String[] loadedRoles = propsToLoad.getProperty(key).split(",\\s+");
+
+        assertTrue(Arrays.asList(roles).containsAll(Arrays.asList(loadedRoles)));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/locale/LocaleResourcesTest.java	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.setup.command.locale;
+
+import com.redhat.thermostat.testutils.AbstractLocaleResourcesTest;
+
+public class LocaleResourcesTest extends AbstractLocaleResourcesTest<LocaleResources> {
+
+    @Override
+    protected Class<LocaleResources> getEnumClass() {
+        return LocaleResources.class;
+    }
+
+    @Override
+    protected String getResourceBundle() {
+        return LocaleResources.RESOURCE_BUNDLE;
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/distribution/pom.xml	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2015 Red Hat, Inc.
+
+ This file is part of Thermostat.
+
+ Thermostat is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ Thermostat is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Thermostat; see the file COPYING.  If not see
+ <http://www.gnu.org/licenses/>.
+
+ Linking this code with other modules is making a combined work
+ based on this code.  Thus, the terms and conditions of the GNU
+ General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this code give
+ you permission to link this code with independent modules to
+ produce an executable, regardless of the license terms of these
+ independent modules, and to copy and distribute the resulting
+ executable under terms of your choice, provided that you also
+ meet, for each linked independent module, the terms and conditions
+ of the license of that module.  An independent module is a module
+ which is not derived from or based on this code.  If you modify
+ this code, you may extend this exception to your version of the
+ library, but you are not obligated to do so.  If you do not wish
+ to do so, delete this exception statement from your version.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat-setup</artifactId>
+    <version>1.3.4-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>thermostat-setup-distribution</artifactId>
+  <packaging>pom</packaging>
+  
+  <name>Thermostat Setup distribution</name>
+  
+  <properties>
+    <thermostat.plugin>setup</thermostat.plugin>
+  </properties>
+  
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <dependencies>
+          <dependency>
+            <groupId>com.redhat.thermostat</groupId>
+            <artifactId>thermostat-assembly</artifactId>
+            <version>${project.version}</version>
+          </dependency>
+        </dependencies>
+        <configuration>
+          <descriptorRefs>
+            <descriptorRef>plugin-assembly</descriptorRef>
+          </descriptorRefs>
+          <appendAssemblyId>false</appendAssemblyId>
+        </configuration>
+        <executions>
+          <execution>
+            <id>assemble-plugin</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  
+  <!-- Explicitly list all plug-in artifacts, transitive dependencies
+       are not included in assembly. -->
+  <dependencies>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-setup-command</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/distribution/thermostat-plugin.xml	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!--
+
+ Copyright 2012-2015 Red Hat, Inc.
+
+ This file is part of Thermostat.
+
+ Thermostat is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ Thermostat is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Thermostat; see the file COPYING.  If not see
+ <http://www.gnu.org/licenses/>.
+
+ Linking this code with other modules is making a combined work
+ based on this code.  Thus, the terms and conditions of the GNU
+ General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this code give
+ you permission to link this code with independent modules to
+ produce an executable, regardless of the license terms of these
+ independent modules, and to copy and distribute the resulting
+ executable under terms of your choice, provided that you also
+ meet, for each linked independent module, the terms and conditions
+ of the license of that module.  An independent module is a module
+ which is not derived from or based on this code.  If you modify
+ this code, you may extend this exception to your version of the
+ library, but you are not obligated to do so.  If you do not wish
+ to do so, delete this exception statement from your version.
+
+-->
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0 thermostat-plugin.xsd">
+  <commands>
+    <command>
+      <name>setup</name>
+      <summary>setup thermostat for first run</summary>
+      <description>setup an initial mongodb user and webapp settings. Optionally create a client admin and agent user.</description>
+      <environments>
+        <environment>cli</environment>
+        <environment>shell</environment>
+      </environments>
+      <bundles>
+        <bundle><symbolic-name>com.redhat.thermostat.setup.command</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.common.core</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.configuration</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.client.swing</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.client.core</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.internal.utils.laf</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.plugin.validator</symbolic-name><version>${project.version}</version></bundle>
+      </bundles>
+    </command>
+  </commands>
+</plugin>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup-command/pom.xml	Wed Sep 02 11:26:48 2015 +0200
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2015 Red Hat, Inc.
+
+ This file is part of Thermostat.
+
+ Thermostat is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ Thermostat is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Thermostat; see the file COPYING.  If not see
+ <http://www.gnu.org/licenses/>.
+
+ Linking this code with other modules is making a combined work
+ based on this code.  Thus, the terms and conditions of the GNU
+ General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this code give
+ you permission to link this code with independent modules to
+ produce an executable, regardless of the license terms of these
+ independent modules, and to copy and distribute the resulting
+ executable under terms of your choice, provided that you also
+ meet, for each linked independent module, the terms and conditions
+ of the license of that module.  An independent module is a module
+ which is not derived from or based on this code.  If you modify
+ this code, you may extend this exception to your version of the
+ library, but you are not obligated to do so.  If you do not wish
+ to do so, delete this exception statement from your version.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat</artifactId>
+    <version>1.3.4-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-setup</artifactId>
+  <packaging>pom</packaging>
+  
+  <name>Thermostat Setup command</name>
+  
+  <description>Initial Setup for thermostat</description>
+  
+  <modules>
+    <module>command</module>
+    <module>distribution</module>
+  </modules>
+</project>
+