changeset 854:0e91d4d47781

Remove tools as bootstrap bundle, rename to client-cli This commit removes the tools bundle from the list of bootstrap bundles as there is nothing left in tools that is required to start Thermostat. Since the tools bundle contains only commands, I am renaming it client-cli (client-command is already taken) and adding this bundle to the appropriate commands' properties files. I have also added a test for the bundle's activator. Reviewed-by: vanaltj Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-December/004697.html
author Elliott Baron <ebaron@redhat.com>
date Thu, 13 Dec 2012 12:12:19 -0500
parents 7b05bcaae364
children fac3b36775fc
files agent/cli/pom.xml agent/core/pom.xml client/cli/pom.xml client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/Activator.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/DisconnectCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ListVMsCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/LocaleResources.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMInfoCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMListFormatter.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java client/cli/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command client/cli/src/main/resources/com/redhat/thermostat/client/cli/strings.properties client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ActivatorTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/DisconnectCommandTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ListVMsCommandTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/LocaleResourcesTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ShellCommandTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/TestTerminal.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VMInfoCommandTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java client/pom.xml distribution/config/commands/connect.properties distribution/config/commands/disconnect.properties distribution/config/commands/list-vms.properties distribution/config/commands/shell.properties distribution/config/commands/vm-info.properties distribution/config/commands/vm-stat.properties distribution/pom.xml distribution/scripts/thermostat killvm/agent/pom.xml main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties pom.xml tools/pom.xml tools/src/main/java/com/redhat/thermostat/tools/Activator.java tools/src/main/java/com/redhat/thermostat/tools/LocaleResources.java tools/src/main/java/com/redhat/thermostat/tools/cli/ConnectCommand.java tools/src/main/java/com/redhat/thermostat/tools/cli/DisconnectCommand.java tools/src/main/java/com/redhat/thermostat/tools/cli/ListVMsCommand.java tools/src/main/java/com/redhat/thermostat/tools/cli/ShellCommand.java tools/src/main/java/com/redhat/thermostat/tools/cli/VMInfoCommand.java tools/src/main/java/com/redhat/thermostat/tools/cli/VMListFormatter.java tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatCommand.java tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatPrinter.java tools/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command tools/src/main/resources/com/redhat/thermostat/tools/strings.properties tools/src/test/java/com/redhat/thermostat/tools/LocaleResourcesTest.java tools/src/test/java/com/redhat/thermostat/tools/cli/ConnectCommandTest.java tools/src/test/java/com/redhat/thermostat/tools/cli/DisconnectCommandTest.java tools/src/test/java/com/redhat/thermostat/tools/cli/ListVMsCommandTest.java tools/src/test/java/com/redhat/thermostat/tools/cli/ShellCommandTest.java tools/src/test/java/com/redhat/thermostat/tools/cli/TestTerminal.java tools/src/test/java/com/redhat/thermostat/tools/cli/VMInfoCommandTest.java tools/src/test/java/com/redhat/thermostat/tools/cli/VmStatCommandTest.java vm-heap-analysis/client-core/pom.xml vm-heap-analysis/client-swing/pom.xml vm-heap-analysis/command/pom.xml vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ActivatorTest.java
diffstat 61 files changed, 2950 insertions(+), 2931 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ b/agent/cli/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -82,6 +82,11 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-osgi-process-handler</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
     </dependency>
--- a/agent/core/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ b/agent/core/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -72,11 +72,6 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-tools</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
     </dependency>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+
+ Copyright 2012 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-client</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-client-cli</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Thermostat CLI Client Commands</name>
+
+  <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>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>jline</groupId>
+      <artifactId>jline</artifactId>
+    </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-launcher</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-osgi-process-handler</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-Activator>com.redhat.thermostat.client.cli.internal.Activator</Bundle-Activator>
+            <Bundle-SymbolicName>com.redhat.thermostat.client.cli</Bundle-SymbolicName>
+            <Private-Package>
+              META_INF.services,
+              com.redhat.thermostat.client.cli.internal,
+            </Private-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/Activator.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import java.util.ServiceLoader;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.common.cli.CommandRegistry;
+import com.redhat.thermostat.common.cli.CommandRegistryImpl;
+
+public class Activator implements BundleActivator {
+
+    private CommandRegistry reg;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        reg = new CommandRegistryImpl(context);
+        ServiceLoader<Command> cmds = ServiceLoader.load(Command.class, getClass().getClassLoader());
+        reg.registerCommands(cmds);
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        reg.unregisterCommands();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import com.redhat.thermostat.common.DbService;
+import com.redhat.thermostat.common.DbServiceFactory;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.config.ClientPreferences;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.launcher.CommonCommandOptions;
+import com.redhat.thermostat.storage.core.ConnectionException;
+import com.redhat.thermostat.storage.core.StorageException;
+import com.redhat.thermostat.utils.keyring.Keyring;
+
+/**
+ * Command in order to persistently connect to a database. Available only in
+ * shell.
+ * 
+ * This commands registers a connection service. If this service is available,
+ * it can be used to retrieve a DB connection.
+ * 
+ */
+public class ConnectCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String NAME = "connect";
+    
+    private ClientPreferences prefs;
+    private DbServiceFactory dbServiceFactory;
+
+    public ConnectCommand() {
+        this(new DbServiceFactory());
+    }
+
+    ConnectCommand(DbServiceFactory dbServiceFactory) {
+        this.dbServiceFactory = dbServiceFactory;
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        DbService service = OSGIUtils.getInstance().getServiceAllowNull(DbService.class);
+        if (service != null) {
+            // Already connected, bail out
+            throw new CommandException(translator.localize(LocaleResources.COMMAND_CONNECT_ALREADY_CONNECTED, service.getConnectionUrl()));
+        }
+        if (prefs == null) {
+            prefs = new ClientPreferences(OSGIUtils.getInstance().getService(Keyring.class));
+        }
+        String dbUrl = ctx.getArguments().getArgument(CommonCommandOptions.DB_URL_ARG);
+        if (dbUrl == null) {
+            dbUrl = prefs.getConnectionUrl();
+        }
+        String username = ctx.getArguments().getArgument(CommonCommandOptions.USERNAME_ARG);
+        String password = ctx.getArguments().getArgument(CommonCommandOptions.PASSWORD_ARG);
+        try {
+            // may throw StorageException if storage url is not supported
+            service = dbServiceFactory.createDbService(username, password, dbUrl);
+            service.connect();
+        } catch (StorageException ex) {
+            throw new CommandException(translator.localize(LocaleResources.COMMAND_CONNECT_INVALID_STORAGE, dbUrl));
+        } catch (ConnectionException ex) {
+            String error = ex.getMessage();
+            String message = ( error == null ? "" : " " + translator.localize(LocaleResources.COMMAND_CONNECT_ERROR, error) );
+            throw new CommandException(translator.localize(LocaleResources.COMMAND_CONNECT_FAILED_TO_CONNECT, dbUrl + message), ex);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+    
+    @Override
+    public boolean isAvailableOutsideShell() {
+        return false;
+    }
+    
+    @Override
+    public boolean isStorageRequired() {
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/DisconnectCommand.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import org.apache.commons.cli.Options;
+
+import com.redhat.thermostat.common.DbService;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.core.ConnectionException;
+
+public class DisconnectCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String NAME = "disconnect";
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        DbService service = OSGIUtils.getInstance().getServiceAllowNull(DbService.class);
+        if (service == null) {
+            // not connected
+            throw new CommandException(translator.localize(LocaleResources.COMMAND_DISCONNECT_NOT_CONNECTED));
+        }
+        try {
+            service.disconnect();
+        } catch (ConnectionException e) {
+            throw new CommandException(translator.localize(LocaleResources.COMMAND_DISCONNECT_ERROR));
+        }
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public Options getOptions() {
+        return new Options();
+    }
+    
+    @Override
+    public boolean isAvailableOutsideShell() {
+        return false;
+    }
+    
+    @Override
+    public boolean isStorageRequired() {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ListVMsCommand.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import java.util.Collection;
+
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.VmInfo;
+
+public class ListVMsCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String NAME = "list-vms";
+
+    private final OSGIUtils serviceProvider;
+
+    public ListVMsCommand() {
+        this(OSGIUtils.getInstance());
+    }
+
+    ListVMsCommand(OSGIUtils serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+
+        HostInfoDAO hostsDAO = serviceProvider.getServiceAllowNull(HostInfoDAO.class);
+        if (hostsDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.HOST_SERVICE_UNAVAILABLE));
+        }
+        Collection<HostRef> hosts = hostsDAO.getHosts();
+        serviceProvider.ungetService(HostInfoDAO.class, hostsDAO);
+
+        VmInfoDAO vmsDAO = serviceProvider.getServiceAllowNull(VmInfoDAO.class);
+        if (vmsDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.VM_SERVICE_UNAVAILABLE));
+        }
+        VMListFormatter formatter = new VMListFormatter();
+        for (HostRef host : hosts) {
+            Collection<VmRef> vms = vmsDAO.getVMs(host);
+            for (VmRef vm : vms) {
+                VmInfo info = vmsDAO.getVmInfo(vm);
+                formatter.addVM(vm, info);
+            }
+        }
+        formatter.format(ctx.getConsole().getOutput());
+
+        serviceProvider.ungetService(VmInfoDAO.class, vmsDAO);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/LocaleResources.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+
+    MISSING_INFO,
+
+    VALUE_AND_UNIT,
+
+    HOST_SERVICE_UNAVAILABLE,
+    VM_SERVICE_UNAVAILABLE,
+    VM_CPU_SERVICE_NOT_AVAILABLE,
+    VM_MEMORY_SERVICE_NOT_AVAILABLE,
+
+    COMMAND_CONNECT_ALREADY_CONNECTED,
+    COMMAND_CONNECT_FAILED_TO_CONNECT,
+    COMMAND_CONNECT_INVALID_STORAGE,
+    COMMAND_CONNECT_ERROR,
+
+    COMMAND_DISCONNECT_NOT_CONNECTED,
+    COMMAND_DISCONNECT_ERROR,
+
+    VM_INFO_PROCESS_ID,
+    VM_INFO_START_TIME,
+    VM_INFO_STOP_TIME,
+    VM_INFO_MAIN_CLASS,
+    VM_INFO_COMMAND_LINE,
+    VM_INFO_JAVA_VERSION,
+    VM_INFO_VIRTUAL_MACHINE,
+    VM_INFO_VM_ARGUMENTS,
+
+    COLUMN_HEADER_HOST_ID,
+    COLUMN_HEADER_HOST,
+    COLUMN_HEADER_VM_ID,
+    COLUMN_HEADER_VM_NAME,
+    COLUMN_HEADER_VM_STATUS,
+    COLUMN_HEADER_TIME,
+    COLUMN_HEADER_CPU_PERCENT,
+    COLUMN_HEADER_MEMORY_PATTERN,
+
+    VM_STOP_TIME_RUNNING,
+    VM_STATUS_ALIVE,
+    VM_STATUS_DEAD,
+    ;
+
+    static final String RESOURCE_BUNDLE = "com.redhat.thermostat.client.cli.strings";
+
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import jline.Terminal;
+import jline.TerminalFactory;
+import jline.console.ConsoleReader;
+import jline.console.history.FileHistory;
+import jline.console.history.History;
+import jline.console.history.PersistentHistory;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.config.ConfigUtils;
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.launcher.Launcher;
+
+public class ShellCommand extends SimpleCommand {
+
+    private static final Logger logger = LoggingUtils.getLogger(ShellCommand.class);
+
+    private static final String[] exitKeywords = { "exit", "quit", "q" };
+
+    private static final String NAME = "shell";
+
+    private static final String PROMPT = "Thermostat > ";
+
+    private HistoryProvider historyProvider;
+
+    private BundleContext bundleContext;
+    
+    static class HistoryProvider {
+        public PersistentHistory get() {
+            PersistentHistory history = null;
+            try {
+                history = new FileHistory(ConfigUtils.getHistoryFile());
+            } catch (InvalidConfigurationException | IOException e) {
+                /* no history available */
+            }
+            return history;
+        }
+    }
+
+    public ShellCommand() {
+        this(FrameworkUtil.getBundle(ShellCommand.class).getBundleContext(), new HistoryProvider());
+    }
+
+    ShellCommand(BundleContext context, HistoryProvider provider) {
+        this.historyProvider = provider;
+        this.bundleContext = context;
+    }
+    
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        Terminal term = TerminalFactory.create();
+        PersistentHistory history = historyProvider.get();
+
+        try {
+            shellMainLoop(ctx, history, term);
+        } catch (IOException ex) {
+            throw new CommandException(ex);
+        } finally {
+            closeTerminal(term);
+            if (history != null) {
+                try {
+                    history.flush();
+                } catch (IOException e) {
+                    logger.log(Level.WARNING, "Unable to save history", e);
+                }
+            }
+        }
+    }
+
+    private void closeTerminal(Terminal term) throws CommandException {
+        try {
+            term.restore();
+        } catch (Exception e) {
+            throw new CommandException(e);
+        }
+    }
+
+    private void shellMainLoop(CommandContext ctx, History history, Terminal term) throws IOException, CommandException {
+        ConsoleReader reader = new ConsoleReader(ctx.getConsole().getInput(), ctx.getConsole().getOutput(), term);
+        if (history != null) {
+            reader.setHistory(history);
+        }
+        while (handleConsoleInput(reader)) { /* no-op; the loop conditional performs the action */ }
+    }
+
+    private boolean handleConsoleInput(ConsoleReader reader) throws IOException, CommandException {
+        String line = reader.readLine(PROMPT);
+        if (line == null) {
+            return false;
+        }
+        line = line.trim();
+        if (line.equals("")) {
+            return true;
+        } else if (Arrays.asList(exitKeywords).contains(line)) {
+            return false;
+        } else {
+            launchCommand(line);
+            return true;
+        }
+    }
+
+    private void launchCommand(String line) throws CommandException {
+        String[] parsed = line.split(" ");
+        ServiceReference launcherRef = bundleContext.getServiceReference(Launcher.class.getName());
+        if (launcherRef != null) {
+            Launcher launcher = (Launcher) bundleContext.getService(launcherRef);
+            launcher.setArgs(parsed);
+            launcher.run();
+        } else {
+            throw new CommandException("Severe: Could not locate launcher");
+        }
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public boolean isStorageRequired() {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMInfoCommand.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.Date;
+
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.HostVMArguments;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.TableRenderer;
+import com.redhat.thermostat.common.dao.DAOException;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.VmInfo;
+
+public class VMInfoCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String NAME = "vm-info";
+    private static final String STILL_ALIVE = translator.localize(LocaleResources.VM_STOP_TIME_RUNNING);
+
+    private OSGIUtils serviceProvider;
+
+    public VMInfoCommand() {
+        this(OSGIUtils.getInstance());
+    }
+
+    /** For tests only */
+    VMInfoCommand(OSGIUtils serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        VmInfoDAO vmsDAO = serviceProvider.getServiceAllowNull(VmInfoDAO.class);
+        if (vmsDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.VM_SERVICE_UNAVAILABLE));
+        }
+
+        HostVMArguments hostVMArgs = new HostVMArguments(ctx.getArguments(), true, false);
+        HostRef host = hostVMArgs.getHost();
+        VmRef vm = hostVMArgs.getVM();
+        try {
+            if (vm != null) {
+                getAndPrintVMInfo(ctx, vmsDAO, vm);
+            } else {
+                getAndPrintAllVMInfo(ctx, vmsDAO, host);
+
+            }
+        } catch (DAOException ex) {
+            ctx.getConsole().getError().println(ex.getMessage());
+        } finally {
+            serviceProvider.ungetService(VmInfoDAO.class, vmsDAO);
+        }
+    }
+
+    private void getAndPrintAllVMInfo(CommandContext ctx, VmInfoDAO vmsDAO, HostRef host) {
+        Collection<VmRef> vms = vmsDAO.getVMs(host);
+        for (VmRef vm : vms) {
+            getAndPrintVMInfo(ctx, vmsDAO, vm);
+        }
+    }
+
+    private void getAndPrintVMInfo(CommandContext ctx, VmInfoDAO vmsDAO, VmRef vm) {
+
+        VmInfo vmInfo = vmsDAO.getVmInfo(vm);
+
+        TableRenderer table = new TableRenderer(2);
+        table.printLine(translator.localize(LocaleResources.VM_INFO_PROCESS_ID), String.valueOf(vmInfo.getVmPid()));
+        table.printLine(translator.localize(LocaleResources.VM_INFO_START_TIME), new Date(vmInfo.getStartTimeStamp()).toString());
+        if (vmInfo.isAlive()) {
+            table.printLine(translator.localize(LocaleResources.VM_INFO_STOP_TIME), STILL_ALIVE);
+        } else {
+            table.printLine(translator.localize(LocaleResources.VM_INFO_STOP_TIME), new Date(vmInfo.getStopTimeStamp()).toString());
+        }
+        table.printLine(translator.localize(LocaleResources.VM_INFO_MAIN_CLASS), vmInfo.getMainClass());
+        table.printLine(translator.localize(LocaleResources.VM_INFO_COMMAND_LINE), vmInfo.getJavaCommandLine());
+        table.printLine(translator.localize(LocaleResources.VM_INFO_JAVA_VERSION), vmInfo.getJavaVersion());
+        table.printLine(translator.localize(LocaleResources.VM_INFO_VIRTUAL_MACHINE), vmInfo.getVmName());
+        table.printLine(translator.localize(LocaleResources.VM_INFO_VM_ARGUMENTS), vmInfo.getVmArguments());
+
+        PrintStream out = ctx.getConsole().getOutput();
+        table.render(out);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMListFormatter.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import java.io.PrintStream;
+
+import com.redhat.thermostat.common.cli.TableRenderer;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.storage.model.VmInfo;
+
+class VMListFormatter {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String HOST_ID = translator.localize(LocaleResources.COLUMN_HEADER_HOST_ID);
+    private static final String HOST = translator.localize(LocaleResources.COLUMN_HEADER_HOST);
+    private static final String VM_ID = translator.localize(LocaleResources.COLUMN_HEADER_VM_ID);
+    private static final String VM_NAME = translator.localize(LocaleResources.COLUMN_HEADER_VM_NAME);
+    private static final String VM_STATUS = translator.localize(LocaleResources.COLUMN_HEADER_VM_STATUS);
+
+    private static final String STATUS_ALIVE = translator.localize(LocaleResources.VM_STATUS_ALIVE);
+    private static final String STATUS_DEAD = translator.localize(LocaleResources.VM_STATUS_DEAD);
+
+    private TableRenderer tableRenderer;
+
+    VMListFormatter() {
+        tableRenderer = new TableRenderer(5);
+        printHeader();
+    }
+
+    void addVM(VmRef vm, VmInfo info) {
+        printVM(vm, info);
+    }
+
+    void format(PrintStream output) {
+        tableRenderer.render(output);
+    }
+
+    private void printHeader() {
+        printLine(HOST_ID, HOST, VM_ID, VM_STATUS, VM_NAME);
+    }
+
+    private void printVM(VmRef vm, VmInfo info) {
+        printLine(vm.getAgent().getAgentId(),
+                  vm.getAgent().getHostName(),
+                  vm.getId().toString(),
+                  info.isAlive() ? STATUS_ALIVE : STATUS_DEAD,
+                  vm.getName());
+    }
+
+    private void printLine(String hostId, String host, String vmId, String status, String vmName) {
+        tableRenderer.printLine(hostId, host, vmId, status, vmName);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.HostVMArguments;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.dao.VmCpuStatDAO;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+public class VMStatCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final Logger log = LoggingUtils.getLogger(VMStatCommand.class);
+
+    private static final String CMD_NAME = "vm-stat";
+
+    private OSGIUtils serviceProvider;
+
+    public VMStatCommand() {
+        this(OSGIUtils.getInstance());
+    }
+
+    VMStatCommand(OSGIUtils serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Override
+    public void run(final CommandContext ctx) throws CommandException {
+        VmCpuStatDAO vmCpuStatDAO = serviceProvider.getServiceAllowNull(VmCpuStatDAO.class);
+        if (vmCpuStatDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.VM_CPU_SERVICE_NOT_AVAILABLE));
+        }
+
+        VmMemoryStatDAO vmMemoryStatDAO = serviceProvider.getServiceAllowNull(VmMemoryStatDAO.class);
+        if (vmMemoryStatDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.VM_MEMORY_SERVICE_NOT_AVAILABLE));
+        }
+
+        HostVMArguments hostVMArgs = new HostVMArguments(ctx.getArguments());
+        VmRef vm = hostVMArgs.getVM();
+        final VMStatPrinter statPrinter = new VMStatPrinter(vm, vmCpuStatDAO, vmMemoryStatDAO, ctx.getConsole().getOutput());
+        statPrinter.printStats();
+        boolean continuous = ctx.getArguments().hasArgument("continuous");
+        if (continuous) {
+            startContinuousStats(ctx, statPrinter);
+        }
+
+        serviceProvider.ungetService(VmMemoryStatDAO.class, vmMemoryStatDAO);
+        serviceProvider.ungetService(VmCpuStatDAO.class, vmCpuStatDAO);
+    }
+
+    private void startContinuousStats(final CommandContext ctx, final VMStatPrinter statPrinter) {
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        ApplicationService appSvc = serviceProvider.getService(ApplicationService.class);
+        Timer timer = appSvc.getTimerFactory().createTimer();
+        timer.setDelay(1);
+        timer.setInitialDelay(1);
+        timer.setSchedulingType(Timer.SchedulingType.FIXED_RATE);
+        timer.setTimeUnit(TimeUnit.SECONDS);
+        timer.setAction(new Runnable() {
+
+            @Override
+            public void run() {
+                statPrinter.printUpdatedStats();
+            }
+        });
+        timer.start();
+        Thread t = new Thread() {
+            public void run() {
+                try {
+                    ctx.getConsole().getInput().read();
+                } catch (IOException e) {
+                    log.log(Level.WARNING, "Unexpected IOException while waiting for user input", e);
+                } finally {
+                    latch.countDown();
+                }
+            }
+        };
+        t.start();
+        try {
+            latch.await();
+            timer.stop();
+        } catch (InterruptedException e) {
+            // Return immediately.
+        }
+    }
+
+    @Override
+    public String getName() {
+        return CMD_NAME;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import com.redhat.thermostat.common.cli.TableRenderer;
+import com.redhat.thermostat.common.dao.VmCpuStatDAO;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.DisplayableValues;
+import com.redhat.thermostat.storage.model.TimeStampedPojo;
+import com.redhat.thermostat.storage.model.TimeStampedPojoComparator;
+import com.redhat.thermostat.storage.model.TimeStampedPojoCorrelator;
+import com.redhat.thermostat.storage.model.VmCpuStat;
+import com.redhat.thermostat.storage.model.VmMemoryStat;
+
+class VMStatPrinter {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String CPU_PERCENT = translator.localize(LocaleResources.COLUMN_HEADER_CPU_PERCENT);
+    private static final String TIME = translator.localize(LocaleResources.COLUMN_HEADER_TIME);
+
+    private VmRef vm;
+    private VmCpuStatDAO vmCpuStatDAO;
+    private VmMemoryStatDAO vmMemoryStatDAO;
+    private PrintStream out;
+    private TimeStampedPojoCorrelator correlator = new TimeStampedPojoCorrelator(2);
+    private TableRenderer table;
+    private int numSpaces;
+
+    private long lastCpuStatTimeStamp = Long.MIN_VALUE;
+    private long lastMemoryStatTimeStamp = Long.MIN_VALUE;
+
+    VMStatPrinter(VmRef vm, VmCpuStatDAO vmCpuStatDAO, VmMemoryStatDAO vmMemoryStatDAO, PrintStream out) {
+        this.vm = vm;
+        this.vmCpuStatDAO = vmCpuStatDAO;
+        this.vmMemoryStatDAO = vmMemoryStatDAO;
+        this.out = out;
+    }
+
+    void printStats() {
+        List<VmCpuStat> cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm, lastCpuStatTimeStamp);
+        List<VmMemoryStat> memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm, lastMemoryStatTimeStamp);
+
+        lastCpuStatTimeStamp = getLatestTimeStamp(lastCpuStatTimeStamp, cpuStats);
+        lastMemoryStatTimeStamp = getLatestTimeStamp(lastMemoryStatTimeStamp, memStats);
+
+        printStats(cpuStats, memStats);
+    }
+
+    void printUpdatedStats() {
+        correlator.clear();
+        List<VmCpuStat> cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm, lastCpuStatTimeStamp);
+        List<VmMemoryStat> memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm, lastMemoryStatTimeStamp);
+
+        lastCpuStatTimeStamp = getLatestTimeStamp(lastCpuStatTimeStamp, cpuStats);
+        lastMemoryStatTimeStamp = getLatestTimeStamp(lastMemoryStatTimeStamp, memStats);
+
+        correlate(cpuStats, memStats);
+        printUpdatedStatsImpl();
+    }
+
+    private long getLatestTimeStamp(long currentTimeStamp, List<? extends TimeStampedPojo> list) {
+        try {
+            return Math.max(currentTimeStamp, Collections.max(list, new TimeStampedPojoComparator<>()).getTimeStamp());
+        } catch (NoSuchElementException listIsEmpty) {
+            return currentTimeStamp;
+        }
+    }
+
+    private void printStats(List<VmCpuStat> cpuStats, List<VmMemoryStat> memStats) {
+        correlate(cpuStats, memStats);
+        numSpaces = getNumSpaces(memStats);
+        int numColumns = numSpaces + 2;
+        table = new TableRenderer(numColumns);
+        printHeaders(memStats, numSpaces, numColumns, table);
+        printUpdatedStatsImpl();
+    }
+
+    private void printStats(int numSpaces, TableRenderer table, Iterator<TimeStampedPojoCorrelator.Correlation> i) {
+
+        TimeStampedPojoCorrelator.Correlation correlation = i.next();
+
+        VmCpuStat cpuStat = (VmCpuStat) correlation.get(0);
+        DecimalFormat format = new DecimalFormat("#0.0");
+        String cpuLoad = cpuStat != null ? format.format(cpuStat.getCpuLoad()) : "";
+
+        DateFormat dateFormat = DateFormat.getTimeInstance();
+        String time = dateFormat.format(new Date(correlation.getTimeStamp()));
+
+        String[] memoryUsage = getMemoryUsage((VmMemoryStat) correlation.get(1), numSpaces);
+
+        String[] line = new String[numSpaces + 2];
+        System.arraycopy(memoryUsage, 0, line, 2, numSpaces);
+        line[0] = time;
+        line[1] = cpuLoad;
+        table.printLine(line);
+    }
+
+    private void printHeaders(List<VmMemoryStat> memStats, int numSpaces, int numColumns, TableRenderer table) {
+        String[] spacesNames = getSpacesNames(memStats, numSpaces);
+        String[] headers = new String[numColumns];
+        headers[0] = TIME;
+        headers[1] = CPU_PERCENT;
+        System.arraycopy(spacesNames, 0, headers, 2, numSpaces);
+        table.printLine(headers);
+    }
+
+    private String[] getMemoryUsage(VmMemoryStat vmMemoryStat, int numSpaces) {
+        String[] memoryUsage = new String[numSpaces];
+        if (vmMemoryStat == null) {
+            Arrays.fill(memoryUsage, "");
+            return memoryUsage;
+        }
+        int i = 0;
+        for (VmMemoryStat.Generation gen : vmMemoryStat.getGenerations()) {
+            for (VmMemoryStat.Space space : gen.getSpaces()) {
+                String[] displayableSize = DisplayableValues.bytes(space.getUsed());
+                memoryUsage[i] = translator.localize(LocaleResources.VALUE_AND_UNIT, displayableSize[0], displayableSize[1]);
+                i++;
+            }
+        }
+        return memoryUsage;
+    }
+
+    private String[] getSpacesNames(List<VmMemoryStat> memStats, int numSpaces) {
+        if (numSpaces < 1) {
+            return new String[0];
+        }
+        String[] spacesNames = new String[numSpaces];
+        VmMemoryStat stat = memStats.get(0);
+        int i = 0;
+        for (VmMemoryStat.Generation gen : stat.getGenerations()) {
+            for (VmMemoryStat.Space space : gen.getSpaces()) {
+                spacesNames[i] = translator.localize(LocaleResources.COLUMN_HEADER_MEMORY_PATTERN, space.getName());
+                i++;
+            }
+        }
+        return spacesNames;
+    }
+
+    private int getNumSpaces(List<VmMemoryStat> memStats) {
+        if (memStats.size() < 1) {
+            return 0;
+        }
+        VmMemoryStat stat = memStats.get(0);
+        int numSpaces = 0;
+        for (VmMemoryStat.Generation gen : stat.getGenerations()) {
+            numSpaces += gen.getSpaces().length;
+        }
+        return numSpaces;
+    }
+
+    private void correlate(List<VmCpuStat> cpuStats, List<VmMemoryStat> memStats) {
+        for(VmCpuStat cpuStat : cpuStats) {
+            correlator.add(0, cpuStat);
+        }
+        for (VmMemoryStat memStat : memStats) {
+            correlator.add(1, memStat);
+        }
+    }
+
+    void printUpdatedStatsImpl() {
+        Iterator<TimeStampedPojoCorrelator.Correlation> iterator = correlator.iterator();
+        while (iterator.hasNext()) {
+            printStats(numSpaces, table, iterator);
+        }
+        table.render(out);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,6 @@
+com.redhat.thermostat.client.cli.internal.ListVMsCommand
+com.redhat.thermostat.client.cli.internal.ShellCommand
+com.redhat.thermostat.client.cli.internal.VMInfoCommand
+com.redhat.thermostat.client.cli.internal.VMStatCommand
+com.redhat.thermostat.client.cli.internal.DisconnectCommand
+com.redhat.thermostat.client.cli.internal.ConnectCommand
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/main/resources/com/redhat/thermostat/client/cli/strings.properties	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,38 @@
+MISSING_INFO = Missing Information
+
+VALUE_AND_UNIT = {0} {1}
+
+HOST_SERVICE_UNAVAILABLE = Unable to get host information (HostInfoDAO is unavailable)
+VM_SERVICE_UNAVAILABLE = Unable to get vm information (VmInfoDAO is unavailable)
+VM_CPU_SERVICE_NOT_AVAILABLE = Unable to access vm cpu information (VmCpuStats not available)
+VM_MEMORY_SERVICE_NOT_AVAILABLE = Unable to access vm memory information (VmCpuStats not available)
+
+COMMAND_CONNECT_ALREADY_CONNECTED = Already connected to storage: URL = {0}\nPlease use disconnect command to disconnect.
+COMMAND_CONNECT_FAILED_TO_CONNECT = Could not connect to db {0}
+COMMAND_CONNECT_INVALID_STORAGE = Unrecognized storage URL {0}
+COMMAND_CONNECT_ERROR = Error: {0}
+
+COMMAND_DISCONNECT_NOT_CONNECTED = Not connected to storage. You may use the connect command for establishing connections.
+COMMAND_DISCONNECT_ERROR = Failed to disconnect from database.
+
+VM_INFO_PROCESS_ID = Process ID:
+VM_INFO_START_TIME = Start time:
+VM_INFO_STOP_TIME = Stop time:
+VM_INFO_MAIN_CLASS = Main class:
+VM_INFO_COMMAND_LINE = Command line:
+VM_INFO_JAVA_VERSION = Java version:
+VM_INFO_VIRTUAL_MACHINE = Virtual machine:
+VM_INFO_VM_ARGUMENTS = VM arguments:
+
+COLUMN_HEADER_HOST_ID = HOST_ID
+COLUMN_HEADER_HOST = HOST
+COLUMN_HEADER_VM_ID  = VM_ID
+COLUMN_HEADER_VM_NAME = VM_NAME
+COLUMN_HEADER_VM_STATUS = STATUS
+COLUMN_HEADER_TIME = TIME
+COLUMN_HEADER_CPU_PERCENT = %CPU
+COLUMN_HEADER_MEMORY_PATTERN = MEM.{0}
+
+VM_STOP_TIME_RUNNING = <Running>
+VM_STATUS_ALIVE = RUNNING
+VM_STATUS_DEAD = EXITED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ActivatorTest.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.test.StubBundleContext;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(FrameworkUtil.class)
+public class ActivatorTest {
+
+    @Test
+    public void testCommandsRegistered() throws Exception {
+        // Need to mock FrameworkUtil to avoid NPE in ShellCommand's no-arg constructor
+        PowerMockito.mockStatic(FrameworkUtil.class);
+        Bundle mockBundle = mock(Bundle.class);
+        when(FrameworkUtil.getBundle(ShellCommand.class)).thenReturn(mockBundle);
+        StubBundleContext ctx = new StubBundleContext();
+        when(mockBundle.getBundleContext()).thenReturn(ctx);
+        
+        Activator activator = new Activator();
+        
+        activator.start(ctx);
+        
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), ConnectCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), DisconnectCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), ListVMsCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), ShellCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), VMInfoCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), VMStatCommand.class));
+        
+        activator.stop(ctx);
+        
+        assertEquals(0, ctx.getAllServices().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.redhat.thermostat.common.DbService;
+import com.redhat.thermostat.common.DbServiceFactory;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.launcher.CommonCommandOptions;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ OSGIUtils.class, DbServiceFactory.class })
+public class ConnectCommandTest {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private ConnectCommand cmd;
+    private TestCommandContextFactory cmdCtxFactory;
+    private BundleContext bundleContext;
+    private DbServiceFactory dbServiceFactory;
+
+    @Before
+    public void setUp() {
+        setupCommandContextFactory();
+
+        dbServiceFactory = mock(DbServiceFactory.class);
+        cmd = new ConnectCommand(dbServiceFactory);
+    }
+
+    private void setupCommandContextFactory() {
+        Bundle sysBundle = mock(Bundle.class);
+        bundleContext = mock(BundleContext.class);
+        when(bundleContext.getBundle(0)).thenReturn(sysBundle);
+        cmdCtxFactory = new TestCommandContextFactory(bundleContext);
+        
+    }
+
+    @After
+    public void tearDown() {
+        cmdCtxFactory = null;
+        cmd = null;
+    }
+
+    @Test
+    public void verifyConnectedThrowsExceptionWithDiagnosticMessage() {
+        String dbUrl = "fluff";
+        DbService dbService = mock(DbService.class);
+        OSGIUtils utils = mock(OSGIUtils.class);
+        PowerMockito.mockStatic(OSGIUtils.class);
+        when(OSGIUtils.getInstance()).thenReturn(utils);
+        when(utils.getServiceAllowNull(DbService.class)).thenReturn(dbService);
+        when(dbService.getConnectionUrl()).thenReturn(dbUrl);
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("--dbUrl", dbUrl);
+        try {
+            cmd.run(cmdCtxFactory.createContext(args));
+        } catch (CommandException e) {
+            assertEquals(translator.localize(LocaleResources.COMMAND_CONNECT_ALREADY_CONNECTED, dbUrl), e.getMessage());
+        }
+    }
+    
+    @Test
+    public void verifyNotConnectedConnects() throws CommandException {
+        OSGIUtils utils = mock(OSGIUtils.class);
+        PowerMockito.mockStatic(OSGIUtils.class);
+        when(OSGIUtils.getInstance()).thenReturn(utils);
+        when(utils.getServiceAllowNull(DbService.class)).thenReturn(null);
+
+        DbService dbService = mock(DbService.class);
+
+        String username = "testuser";
+        String password = "testpassword";
+        String dbUrl = "mongodb://10.23.122.1:12578";
+        when(dbServiceFactory.createDbService(eq(username), eq(password), eq(dbUrl))).thenReturn(dbService);
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("dbUrl", dbUrl);
+        args.addArgument("username", username);
+        args.addArgument("password", password);
+        CommandContext ctx = cmdCtxFactory.createContext(args);
+        cmd.run(ctx);
+        verify(dbService).connect();
+    }
+    
+    @Test
+    public void testIsStorageRequired() {
+        assertFalse(cmd.isStorageRequired());
+    }
+
+    @Test
+    public void testIsNotAvailableOutsideShell() {
+        assertFalse(cmd.isAvailableOutsideShell());
+    }
+    
+    @Test
+    public void testIsAvailableInShell() {
+        assertTrue(cmd.isAvailableInShell());
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("connect", cmd.getName());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Ignore
+    @Test
+    public void testAcceptedArguments() {
+        Options options = cmd.getOptions();
+        assertNotNull(options);
+        assertTrue(options.getOptions().size() == 3);
+
+        assertTrue(options.hasOption(CommonCommandOptions.DB_URL_ARG));
+        Option db = options.getOption(CommonCommandOptions.DB_URL_ARG);
+        assertEquals(CommonCommandOptions.DB_URL_DESC, db.getDescription());
+        assertTrue(db.isRequired());
+        assertTrue(db.hasArg());
+
+        assertTrue(options.hasOption(CommonCommandOptions.USERNAME_ARG));
+        Option user = options.getOption(CommonCommandOptions.USERNAME_ARG);
+        assertEquals(CommonCommandOptions.USERNAME_DESC, user.getDescription());
+        assertFalse(user.isRequired());
+        assertTrue(user.hasArg());
+
+        assertTrue(options.hasOption(CommonCommandOptions.PASSWORD_ARG));
+        Option pass = options.getOption(CommonCommandOptions.PASSWORD_ARG);
+        assertEquals(CommonCommandOptions.PASSWORD_DESC, pass.getDescription());
+        assertFalse(pass.isRequired());
+        assertTrue(pass.hasArg());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/DisconnectCommandTest.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.redhat.thermostat.common.DbService;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ OSGIUtils.class, FrameworkUtil.class })
+public class DisconnectCommandTest {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private DisconnectCommand cmd;
+    private TestCommandContextFactory cmdCtxFactory;
+    private BundleContext bundleContext;
+
+    @Before
+    public void setUp() {
+        setupCommandContextFactory();
+
+        cmd = new DisconnectCommand();
+
+    }
+
+    private void setupCommandContextFactory() {
+        Bundle sysBundle = mock(Bundle.class);
+        bundleContext = mock(BundleContext.class);
+        when(bundleContext.getBundle(0)).thenReturn(sysBundle);
+        cmdCtxFactory = new TestCommandContextFactory(bundleContext);
+    }
+
+    @After
+    public void tearDown() {
+        cmdCtxFactory = null;
+        cmd = null;
+    }
+
+    @Test
+    public void verifyNotConnectedThrowsException() {
+        OSGIUtils utils = mock(OSGIUtils.class);
+        PowerMockito.mockStatic(OSGIUtils.class);
+        when(OSGIUtils.getInstance()).thenReturn(utils);
+        when(utils.getServiceAllowNull(DbService.class)).thenReturn(null);
+
+        try {
+            cmd.run(cmdCtxFactory.createContext(new SimpleArguments()));
+            fail("cmd.run() should have thrown exception.");
+        } catch (CommandException e) {
+            assertEquals(translator.localize(LocaleResources.COMMAND_DISCONNECT_NOT_CONNECTED), e.getMessage());
+        }
+    }
+    
+    @Test
+    public void verifyConnectedDisconnects() throws CommandException {
+        DbService dbService = mock(DbService.class);
+        OSGIUtils utils = mock(OSGIUtils.class);
+        PowerMockito.mockStatic(OSGIUtils.class);
+        when(OSGIUtils.getInstance()).thenReturn(utils);
+        when(utils.getServiceAllowNull(DbService.class)).thenReturn(dbService);
+        
+        CommandContext ctx = cmdCtxFactory.createContext(new SimpleArguments());
+        cmd.run(ctx);
+        verify(dbService).disconnect();
+    }
+
+    @Test
+    public void testIsNotAvailableOutsideShell() {
+        assertFalse(cmd.isAvailableOutsideShell());
+    }
+    
+    @Test
+    public void testIsAvailableInShell() {
+        assertTrue(cmd.isAvailableInShell());
+    }
+    
+    @Test
+    public void testIsStorageRequired() {
+        assertFalse(cmd.isStorageRequired());
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("disconnect", cmd.getName());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Test
+    public void testOptions() {
+        Options options = cmd.getOptions();
+        assertNotNull(options);
+        assertTrue(options.getOptions().size() == 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ListVMsCommandTest.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.VmInfo;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+
+public class ListVMsCommandTest {
+
+    private ListVMsCommand cmd;
+    private TestCommandContextFactory cmdCtxFactory;
+    private HostInfoDAO hostsDAO;
+    private VmInfoDAO vmsDAO;
+    private OSGIUtils serviceProvider;
+
+    @Before
+    public void setUp() {
+        setupCommandContextFactory();
+        serviceProvider = mock(OSGIUtils.class);
+
+        cmd = new ListVMsCommand(serviceProvider);
+
+        hostsDAO = mock(HostInfoDAO.class);
+        vmsDAO = mock(VmInfoDAO.class);
+
+        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostsDAO);
+        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmsDAO);
+    }
+
+    private void setupCommandContextFactory() {
+        cmdCtxFactory = new TestCommandContextFactory();
+    }
+
+    @After
+    public void tearDown() {
+        vmsDAO = null;
+        hostsDAO = null;
+        cmdCtxFactory = null;
+        cmd = null;
+    }
+
+    @Test
+    public void verifyOutputFormatOneLine() throws CommandException {
+
+        HostRef host1 = new HostRef("123", "h1");
+        VmRef vm1 = new VmRef(host1, 1, "n");
+        VmInfo vm1Info = new VmInfo(1, 0, 1, "", "", "", "", "", "", "", "", null, null, null);
+        when(hostsDAO.getHosts()).thenReturn(Arrays.asList(host1));
+        when(vmsDAO.getVMs(host1)).thenReturn(Arrays.asList(vm1));
+        when(vmsDAO.getVmInfo(eq(vm1))).thenReturn(vm1Info);
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("--dbUrl", "fluff");
+        CommandContext ctx = cmdCtxFactory.createContext(args);
+
+        cmd.run(ctx);
+
+        String output = cmdCtxFactory.getOutput();
+        assertEquals("HOST_ID HOST VM_ID STATUS VM_NAME\n" +
+                     "123     h1   1     EXITED n\n", output);
+    }
+
+    @Test
+    public void verifyOutputFormatMultiLines() throws CommandException {
+
+        HostRef host1 = new HostRef("123", "h1");
+        HostRef host2 = new HostRef("456", "longhostname");
+        when(hostsDAO.getHosts()).thenReturn(Arrays.asList(host1, host2));
+
+        VmRef vm1 = new VmRef(host1, 1, "n");
+        VmRef vm2 = new VmRef(host1, 2, "n1");
+        VmRef vm3 = new VmRef(host2, 123456, "longvmname");
+
+        VmInfo vmInfo = new VmInfo(1, 0, 1, "", "", "", "", "", "", "", "", null, null, null);
+
+        when(vmsDAO.getVMs(host1)).thenReturn(Arrays.asList(vm1, vm2));
+        when(vmsDAO.getVMs(host2)).thenReturn(Arrays.asList(vm3));
+
+        when(vmsDAO.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo);
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("--dbUrl", "fluff");
+        CommandContext ctx = cmdCtxFactory.createContext(args);
+
+        cmd.run(ctx);
+
+        String output = cmdCtxFactory.getOutput();
+        assertEquals("HOST_ID HOST         VM_ID  STATUS VM_NAME\n" +
+                     "123     h1           1      EXITED n\n" +
+                     "123     h1           2      EXITED n1\n" +
+                     "456     longhostname 123456 EXITED longvmname\n", output);
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("list-vms", cmd.getName());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Test
+    public void testOptions() {
+        Options options = cmd.getOptions();
+        assertNotNull(options);
+        assertEquals(0, options.getOptions().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/LocaleResourcesTest.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import com.redhat.thermostat.test.locale.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/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ShellCommandTest.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import jline.TerminalFactory;
+import jline.TerminalFactory.Flavor;
+import jline.TerminalFactory.Type;
+import jline.UnixTerminal;
+import jline.console.history.PersistentHistory;
+
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import com.redhat.thermostat.client.cli.internal.ShellCommand.HistoryProvider;
+import com.redhat.thermostat.common.cli.Arguments;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.launcher.Launcher;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+
+public class ShellCommandTest {
+
+    private ShellCommand cmd;
+    private BundleContext bundleContext;
+
+    @Before
+    public void setUp() {
+        bundleContext = mock(BundleContext.class);
+        cmd = new ShellCommand(bundleContext, new HistoryProvider());
+    }
+
+    @After
+    public void tearDown() {
+        cmd = null;
+        bundleContext = null;
+        TerminalFactory.registerFlavor(Flavor.UNIX, UnixTerminal.class);
+        TerminalFactory.reset();
+    }
+
+    @Test
+    public void testBasic() throws CommandException {
+        ServiceReference ref = mock(ServiceReference.class);
+        
+        when(bundleContext.getServiceReference(Launcher.class.getName())).thenReturn(ref);
+        Launcher launcher = mock(Launcher.class);
+        when(bundleContext.getService(ref)).thenReturn(launcher);
+        TestCommandContextFactory ctxFactory = new TestCommandContextFactory(bundleContext);
+        ctxFactory.setInput("help\nexit\n");
+        Arguments args = new SimpleArguments();
+        CommandContext ctx = ctxFactory.createContext(args);
+        cmd.run(ctx);
+        verify(launcher).setArgs(new String[]{"help"});
+        verify(launcher).run();
+    }
+
+    @Test
+    public void testQuitAlsoExits() throws CommandException {
+        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
+        ctxFactory.setInput("quit\n");
+        Arguments args = new SimpleArguments();
+        CommandContext ctx = ctxFactory.createContext(args);
+        cmd.run(ctx);
+        assertEquals("Thermostat > quit\n", ctxFactory.getOutput());
+        assertEquals("", ctxFactory.getError());
+    }
+
+    @Test
+    public void testQAlsoExits() throws CommandException {
+        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
+        ctxFactory.setInput("q\n");
+        Arguments args = new SimpleArguments();
+        CommandContext ctx = ctxFactory.createContext(args);
+        cmd.run(ctx);
+        assertEquals("Thermostat > q\n", ctxFactory.getOutput());
+        assertEquals("", ctxFactory.getError());
+    }
+
+    @Test
+    public void testEofExits() throws CommandException {
+        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
+        ctxFactory.setInput("\u0004"); // EOF
+        Arguments args = new SimpleArguments();
+        CommandContext ctx = ctxFactory.createContext(args);
+        cmd.run(ctx);
+        assertEquals("Thermostat > ", ctxFactory.getOutput());
+        assertEquals("", ctxFactory.getError());
+    }
+
+    @Test
+    public void testDoNothingWithoutInput() throws CommandException {
+        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
+        ctxFactory.setInput("\nexit\n");
+        Arguments args = new SimpleArguments();
+        CommandContext ctx = ctxFactory.createContext(args);
+        cmd.run(ctx);
+        assertEquals("Thermostat > \nThermostat > exit\n", ctxFactory.getOutput());
+    }
+
+    @Test
+    public void testHistoryIsQueried() throws CommandException {
+        PersistentHistory history = mock(PersistentHistory.class);
+        when(history.previous()).thenReturn(true);
+        when(history.current()).thenReturn("old-history-value");
+
+        HistoryProvider provider = mock(HistoryProvider.class);
+        when(provider.get()).thenReturn(history);
+
+        ServiceReference ref = mock(ServiceReference.class);
+        
+        when(bundleContext.getServiceReference(Launcher.class.getName())).thenReturn(ref);
+        Launcher launcher = mock(Launcher.class);
+        when(bundleContext.getService(ref)).thenReturn(launcher);
+        TestCommandContextFactory ctxFactory = new TestCommandContextFactory(bundleContext);
+
+        cmd = new ShellCommand(bundleContext, provider);
+        
+        // "\u001b[A" is the escape code for up-arrow. use xxd -p to generate
+        ctxFactory.setInput("\u001b[A\nexit\n");
+        Arguments args = new SimpleArguments();
+        CommandContext ctx = ctxFactory.createContext(args);
+        cmd.run(ctx);
+
+        assertEquals("Thermostat > old-history-value\nThermostat > exit\n", ctxFactory.getOutput());
+        assertEquals("", ctxFactory.getError());
+
+        verify(launcher).setArgs(new String[] {"old-history-value"});
+        verify(launcher).run();
+    }
+
+    @Test
+    public void testHistoryIsUpdated() throws CommandException, IOException {
+        PersistentHistory mockHistory = mock(PersistentHistory.class);
+        HistoryProvider provider = mock(HistoryProvider.class);
+        when(provider.get()).thenReturn(mockHistory);
+
+        ServiceReference ref = mock(ServiceReference.class);
+        when(bundleContext.getServiceReference(Launcher.class.getName())).thenReturn(ref);
+        Launcher launcher = mock(Launcher.class);
+        when(bundleContext.getService(ref)).thenReturn(launcher);
+        TestCommandContextFactory ctxFactory = new TestCommandContextFactory(bundleContext);
+        
+        cmd = new ShellCommand(bundleContext, provider);
+        
+        ctxFactory.setInput("add-to-history\nexit\n");
+        Arguments args = new SimpleArguments();
+        CommandContext ctx = ctxFactory.createContext(args);
+        cmd.run(ctx);
+
+        verify(launcher).setArgs(new String[] {"add-to-history"});
+        verify(launcher).run();
+        verify(mockHistory).add("add-to-history");
+        verify(mockHistory).flush();
+
+        assertEquals("Thermostat > add-to-history\nThermostat > exit\n", ctxFactory.getOutput());
+        assertEquals("", ctxFactory.getError());
+    }
+
+    @Test(expected=CommandException.class)
+    public void testIOException() throws CommandException {
+        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
+        ctxFactory.setInputThrowsException(new IOException());
+        Arguments args = new SimpleArguments();
+        CommandContext ctx = ctxFactory.createContext(args);
+        cmd.run(ctx);
+    }
+
+    @Test(expected=CommandException.class)
+    public void testTerminalRestoreException() throws CommandException {
+        TerminalFactory.configure(Type.UNIX);
+        TerminalFactory.registerFlavor(Flavor.UNIX, TestTerminal.class);
+        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
+        ctxFactory.setInputThrowsException(new IOException());
+        Arguments args = new SimpleArguments();
+        CommandContext ctx = ctxFactory.createContext(args);
+        cmd.run(ctx);
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("shell", cmd.getName());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Test
+    public void testOptions() {
+        Options options = cmd.getOptions();
+        assertNotNull(options);
+        assertEquals(0, options.getOptions().size());
+    }
+
+    @Test
+    public void testStorageRequired() {
+        assertFalse(cmd.isStorageRequired());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/TestTerminal.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import jline.UnixTerminal;
+
+public class TestTerminal extends UnixTerminal {
+
+    public TestTerminal() throws Exception {
+        super();
+    }
+
+    @Override
+    public void restore() throws Exception {
+        super.restore();
+        throw new Exception();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VMInfoCommandTest.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.TimeZone;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.dao.DAOException;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.VmInfo;
+import com.redhat.thermostat.test.Bug;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+
+public class VMInfoCommandTest {
+
+    private static TimeZone defaultTimezone;
+
+    @BeforeClass
+    public static void setUpClass() {
+        defaultTimezone = TimeZone.getDefault();
+        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        TimeZone.setDefault(defaultTimezone);
+    }
+
+    private VMInfoCommand cmd;
+    private VmInfoDAO vmsDAO;
+    private TestCommandContextFactory cmdCtxFactory;
+    private VmRef vm;
+
+    @Before
+    public void setUp() {
+        setupCommandContextFactory();
+
+        vmsDAO = mock(VmInfoDAO.class);
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmsDAO);
+
+        cmd = new VMInfoCommand(serviceProvider);
+
+        setupDAOs();
+    }
+
+    private void setupCommandContextFactory() {
+        cmdCtxFactory = new TestCommandContextFactory();
+    }
+
+    private void setupDAOs() {
+        HostRef host = new HostRef("123", "dummy");
+        vm = new VmRef(host, 234, "dummy");
+        Calendar start = Calendar.getInstance();
+        start.set(2012, 5, 7, 15, 32, 0);
+        Calendar end = Calendar.getInstance();
+        end.set(2013, 10, 1, 1, 22, 0);
+        VmInfo vmInfo = new VmInfo(234, start.getTimeInMillis(), end.getTimeInMillis(), "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0]);
+        when(vmsDAO.getVmInfo(vm)).thenReturn(vmInfo);
+        when(vmsDAO.getVmInfo(new VmRef(host, 9876, "dummy"))).thenThrow(new DAOException("Unknown VM ID: 9876"));
+        when(vmsDAO.getVMs(host)).thenReturn(Arrays.asList(vm));
+    }
+
+
+    @Test
+    public void testVmInfo() throws CommandException {
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("vmId", "234");
+        args.addArgument("hostId", "123");
+        cmd.run(cmdCtxFactory.createContext(args));
+        String expected = "Process ID:      234\n" +
+                          "Start time:      Thu Jun 07 15:32:00 UTC 2012\n" +
+                          "Stop time:       Fri Nov 01 01:22:00 UTC 2013\n" +
+                          "Main class:      mainClass\n" +
+                          "Command line:    commandLine\n" +
+                          "Java version:    vmVersion\n" +
+                          "Virtual machine: vmName\n" +
+                          "VM arguments:    vmArguments\n";
+        assertEquals(expected, cmdCtxFactory.getOutput());
+    }
+
+    @Test
+    public void testAllVmInfoForHost() throws CommandException {
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("hostId", "123");
+        cmd.run(cmdCtxFactory.createContext(args));
+        String expected = "Process ID:      234\n" +
+                          "Start time:      Thu Jun 07 15:32:00 UTC 2012\n" +
+                          "Stop time:       Fri Nov 01 01:22:00 UTC 2013\n" +
+                          "Main class:      mainClass\n" +
+                          "Command line:    commandLine\n" +
+                          "Java version:    vmVersion\n" +
+                          "Virtual machine: vmName\n" +
+                          "VM arguments:    vmArguments\n";
+        assertEquals(expected, cmdCtxFactory.getOutput());
+    }
+
+    @Test
+    public void testVmInfoUnknownVM() throws CommandException {
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("vmId", "9876");
+        args.addArgument("hostId", "123");
+        cmd.run(cmdCtxFactory.createContext(args));
+        String expected = "Unknown VM ID: 9876\n";
+        assertEquals("", cmdCtxFactory.getOutput());
+        assertEquals(expected, cmdCtxFactory.getError());
+    }
+
+    @Test
+    public void testVmInfoNonNumericalVMID() throws CommandException {
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("vmId", "fluff");
+        args.addArgument("hostId", "123");
+        try {
+            cmd.run(cmdCtxFactory.createContext(args));
+        } catch (CommandException ex) {
+            String expected = "Invalid VM ID: fluff";
+            assertEquals(expected, ex.getMessage());
+        }
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("vm-info", cmd.getName());
+    }
+
+    @Bug(id="1046",
+            summary="CLI vm-info display wrong stop time for living vms",
+            url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1046")
+    @Test
+    public void testStopTime() throws CommandException {
+        Calendar start = Calendar.getInstance();
+        start.set(2012, 5, 7, 15, 32, 0);
+        VmInfo vmInfo = new VmInfo(234, start.getTimeInMillis(), Long.MIN_VALUE, "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0]);
+        when(vmsDAO.getVmInfo(vm)).thenReturn(vmInfo);
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("vmId", "234");
+        args.addArgument("hostId", "123");
+        cmd.run(cmdCtxFactory.createContext(args));
+        String expected = "Process ID:      234\n" +
+                          "Start time:      Thu Jun 07 15:32:00 UTC 2012\n" +
+                          "Stop time:       <Running>\n" +
+                          "Main class:      mainClass\n" +
+                          "Command line:    commandLine\n" +
+                          "Java version:    vmVersion\n" +
+                          "Virtual machine: vmName\n" +
+                          "VM arguments:    vmArguments\n";
+        assertEquals(expected, cmdCtxFactory.getOutput());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Ignore
+    @Test
+    public void testOptions() {
+        Options options = cmd.getOptions();
+        assertNotNull(options);
+        assertEquals(2, options.getOptions().size());
+
+        assertTrue(options.hasOption("vmId"));
+        Option vm = options.getOption("vmId");
+        assertEquals("the ID of the VM to monitor", vm.getDescription());
+        assertFalse(vm.isRequired());
+        assertTrue(vm.hasArg());
+
+        assertTrue(options.hasOption("hostId"));
+        Option host = options.getOption("hostId");
+        assertEquals("the ID of the host to monitor", host.getDescription());
+        assertTrue(host.isRequired());
+        assertTrue(host.hasArg());
+    }
+
+    @Test
+    public void testStorageRequired() {
+        assertTrue(cmd.isStorageRequired());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java	Thu Dec 13 12:12:19 2012 -0500
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2012 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.client.cli.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmCpuStatDAO;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.VmCpuStat;
+import com.redhat.thermostat.storage.model.VmMemoryStat;
+import com.redhat.thermostat.storage.model.VmMemoryStat.Generation;
+import com.redhat.thermostat.storage.model.VmMemoryStat.Space;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+import com.redhat.thermostat.test.TestTimerFactory;
+
+public class VmStatCommandTest {
+
+    private static Locale defaultLocale;
+    private static TimeZone defaultTimeZone;
+
+    @BeforeClass
+    public static void setUpClass() {
+        defaultLocale = Locale.getDefault();
+        Locale.setDefault(Locale.US);
+        defaultTimeZone = TimeZone.getDefault();
+        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        TimeZone.setDefault(defaultTimeZone);
+        Locale.setDefault(defaultLocale);
+    }
+
+    private VMStatCommand cmd;
+    private VmCpuStatDAO vmCpuStatDAO;
+    private TestCommandContextFactory cmdCtxFactory;
+    private VmMemoryStatDAO vmMemoryStatDAO;
+    private TestTimerFactory timerFactory;
+
+    @Before
+    public void setUp() {
+        timerFactory = new TestTimerFactory();
+        ApplicationService appSvc = mock(ApplicationService.class);
+        when(appSvc.getTimerFactory()).thenReturn(timerFactory);
+        setupCommandContextFactory();
+
+        setupDAOs();
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(VmCpuStatDAO.class)).thenReturn(vmCpuStatDAO);
+        when(serviceProvider.getServiceAllowNull(VmMemoryStatDAO.class)).thenReturn(vmMemoryStatDAO);
+        when(serviceProvider.getService(ApplicationService.class)).thenReturn(appSvc);
+
+        cmd = new VMStatCommand(serviceProvider);
+    }
+
+    @After
+    public void tearDown() {
+        vmCpuStatDAO = null;
+        cmdCtxFactory = null;
+        cmd = null;
+        timerFactory = null;
+    }
+
+    private void setupCommandContextFactory() {
+        cmdCtxFactory = new TestCommandContextFactory();
+    }
+
+    private void setupDAOs() {
+        vmCpuStatDAO = mock(VmCpuStatDAO.class);
+        int vmId = 234;
+        HostRef host = new HostRef("123", "dummy");
+        VmRef vm = new VmRef(host, 234, "dummy");
+        VmCpuStat cpustat1 = new VmCpuStat(2, vmId, 65);
+        VmCpuStat cpustat2 = new VmCpuStat(3, vmId, 70);
+        List<VmCpuStat> cpuStats = Arrays.asList(cpustat1, cpustat2);
+        List<VmCpuStat> cpuStats2 = Collections.emptyList();
+        when(vmCpuStatDAO.getLatestVmCpuStats(vm, Long.MIN_VALUE)).thenReturn(cpuStats).thenReturn(cpuStats2);
+
+        VmMemoryStat.Space space1_1_1 = newSpace("space1", 123456, 12345, 1, 0);
+        VmMemoryStat.Space space1_1_2 = newSpace("space2", 123456, 12345, 1, 0);
+        VmMemoryStat.Space[] spaces1_1 = new VmMemoryStat.Space[] { space1_1_1, space1_1_2 };
+        VmMemoryStat.Generation gen1_1 = newGeneration("gen1", "col1", 123456, 12345, spaces1_1);
+
+        VmMemoryStat.Space space1_2_1 = newSpace("space3", 123456, 12345, 1, 0);
+        VmMemoryStat.Space space1_2_2 = newSpace("space4", 123456, 12345, 1, 0);
+        VmMemoryStat.Space[] spaces1_2 = new VmMemoryStat.Space[] { space1_2_1, space1_2_2 };
+        VmMemoryStat.Generation gen1_2 = newGeneration("gen2", "col1", 123456, 12345, spaces1_2);
+
+        VmMemoryStat.Generation[] gens1 = new VmMemoryStat.Generation[] { gen1_1, gen1_2 };
+
+        VmMemoryStat memStat1 = new VmMemoryStat(1, vmId, gens1);
+
+        VmMemoryStat.Space space2_1_1 = newSpace("space1", 123456, 12345, 2, 0);
+        VmMemoryStat.Space space2_1_2 = newSpace("space2", 123456, 12345, 2, 0);
+        VmMemoryStat.Space[] spaces2_1 = new VmMemoryStat.Space[] { space2_1_1, space2_1_2 };
+        VmMemoryStat.Generation gen2_1 = newGeneration("gen1", "col1", 123456, 12345, spaces2_1);
+
+        VmMemoryStat.Space space2_2_1 = newSpace("space3", 123456, 12345, 3, 0);
+        VmMemoryStat.Space space2_2_2 = newSpace("space4", 123456, 12345, 4, 0);
+        VmMemoryStat.Space[] spaces2_2 = new VmMemoryStat.Space[] { space2_2_1, space2_2_2 };
+        VmMemoryStat.Generation gen2_2 = newGeneration("gen2", "col1", 123456, 12345, spaces2_2);
+
+        VmMemoryStat.Generation[] gens2 = new VmMemoryStat.Generation[] { gen2_1, gen2_2 };
+
+        VmMemoryStat memStat2 = new VmMemoryStat(2, vmId, gens2);
+
+        VmMemoryStat.Space space3_1_1 = newSpace("space1", 123456, 12345, 4, 0);
+        VmMemoryStat.Space space3_1_2 = newSpace("space2", 123456, 12345, 5, 0);
+        VmMemoryStat.Space[] spaces3_1 = new VmMemoryStat.Space[] { space3_1_1, space3_1_2 };
+        VmMemoryStat.Generation gen3_1 = newGeneration("gen1", "col1", 123456, 12345, spaces3_1);
+
+        VmMemoryStat.Space space3_2_1 = newSpace("space3", 123456, 12345, 6, 0);
+        VmMemoryStat.Space space3_2_2 = newSpace("space4", 123456, 12345, 7, 0);
+        VmMemoryStat.Space[] spaces3_2 = new VmMemoryStat.Space[] { space3_2_1, space3_2_2 };
+        VmMemoryStat.Generation gen3_2 = newGeneration("gen2", "col1", 123456, 12345, spaces3_2);
+
+        VmMemoryStat.Generation[] gens3 = new VmMemoryStat.Generation[] { gen3_1, gen3_2 };
+
+        VmMemoryStat memStat3 = new VmMemoryStat(3, vmId, gens3);
+
+        VmMemoryStat.Space space4_1_1 = newSpace("space1", 123456, 12345, 8, 0);
+        VmMemoryStat.Space space4_1_2 = newSpace("space2", 123456, 12345, 9, 0);
+        VmMemoryStat.Space[] spaces4_1 = new VmMemoryStat.Space[] { space4_1_1, space4_1_2 };
+        VmMemoryStat.Generation gen4_1 = newGeneration("gen4", "col1", 123456, 12345, spaces4_1);
+
+        VmMemoryStat.Space space4_2_1 = newSpace("space3", 123456, 12345, 10, 0);
+        VmMemoryStat.Space space4_2_2 = newSpace("space4", 123456, 12345, 11, 0);
+        VmMemoryStat.Space[] spaces4_2 = new VmMemoryStat.Space[] { space4_2_1, space4_2_2 };
+        VmMemoryStat.Generation gen4_2 = newGeneration("gen4", "col1", 123456, 12345, spaces4_2);
+
+        VmMemoryStat.Generation[] gens4 = new VmMemoryStat.Generation[] { gen4_1, gen4_2 };
+
+        VmMemoryStat memStat4 = new VmMemoryStat(4, vmId, gens4);
+
+        vmMemoryStatDAO = mock(VmMemoryStatDAO.class);
+        when(vmMemoryStatDAO.getLatestVmMemoryStats(vm, Long.MIN_VALUE))
+            .thenReturn(Arrays.asList(memStat1, memStat2, memStat3));
+
+        when(vmMemoryStatDAO.getLatestVmMemoryStats(vm, memStat3.getTimeStamp())).thenReturn(Arrays.asList(memStat4));
+
+    }
+
+    private Space newSpace(String name, long maxCapacity, long capacity, long used, int index) {
+        VmMemoryStat.Space space = new VmMemoryStat.Space();
+        space.setName(name);
+        space.setMaxCapacity(maxCapacity);
+        space.setCapacity(capacity);
+        space.setUsed(used);
+        space.setIndex(index);
+        return space;
+    }
+
+    private Generation newGeneration(String name, String collector, long maxCapacity, long capacity, Space[] spaces) {
+        VmMemoryStat.Generation gen = new VmMemoryStat.Generation();
+        gen.setName(name);
+        gen.setCollector(collector);
+        gen.setMaxCapacity(capacity);
+        gen.setSpaces(spaces);
+        return gen;
+    }
+
+    @Test
+    public void testBasicCPUMemory() throws CommandException {
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("vmId", "234");
+        args.addArgument("hostId", "123");
+        cmd.run(cmdCtxFactory.createContext(args));
+        String expected = "TIME        %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" +
+                          "12:00:00 AM      1 B        1 B        1 B        1 B\n" +
+                          "12:00:00 AM 65.0 2 B        2 B        3 B        4 B\n" +
+                          "12:00:00 AM 70.0 4 B        5 B        6 B        7 B\n";
+        assertEquals(expected, cmdCtxFactory.getOutput());
+
+    }
+
+    @Test
+    public void testContinuousMode() throws CommandException {
+        
+        Thread t = new Thread() {
+            public void run() {
+                SimpleArguments args = new SimpleArguments();
+                args.addArgument("vmId", "234");
+                args.addArgument("hostId", "123");
+                args.addArgument("continuous", "true");
+                try {
+                    cmd.run(cmdCtxFactory.createContext(args));
+                } catch (CommandException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            }
+        };
+        t.start();
+        try {
+            Thread.sleep(200);
+        } catch (InterruptedException e) {
+            return;
+        }
+        assertTrue(timerFactory.isActive());
+        String expected = "TIME        %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" +
+                          "12:00:00 AM      1 B        1 B        1 B        1 B\n" +
+                          "12:00:00 AM 65.0 2 B        2 B        3 B        4 B\n" +
+                          "12:00:00 AM 70.0 4 B        5 B        6 B        7 B\n";
+        assertEquals(expected, cmdCtxFactory.getOutput());
+        assertEquals(1, timerFactory.getDelay());
+        assertEquals(1, timerFactory.getInitialDelay());
+        assertEquals(TimeUnit.SECONDS, timerFactory.getTimeUnit());
+        assertEquals(Timer.SchedulingType.FIXED_RATE, timerFactory.getSchedulingType());
+
+        timerFactory.getAction().run();
+
+        expected = "TIME        %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" +
+                   "12:00:00 AM      1 B        1 B        1 B        1 B\n" +
+                   "12:00:00 AM 65.0 2 B        2 B        3 B        4 B\n" +
+                   "12:00:00 AM 70.0 4 B        5 B        6 B        7 B\n" +
+                   "12:00:00 AM 70.0 8 B        9 B        10 B       11 B\n";
+        assertEquals(expected, cmdCtxFactory.getOutput());
+        cmdCtxFactory.setInput(" ");
+        try {
+            Thread.sleep(200);
+        } catch (InterruptedException e) {
+            return;
+        }
+        assertFalse(timerFactory.isActive());
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("vm-stat", cmd.getName());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getUsage());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Ignore
+    @Test
+    public void testOptions() {
+        Options options = cmd.getOptions();
+        assertNotNull(options);
+        assertEquals(3, options.getOptions().size());
+
+        assertTrue(options.hasOption("vmId"));
+        Option vm = options.getOption("vmId");
+        assertEquals("the ID of the VM to monitor", vm.getDescription());
+        assertTrue(vm.isRequired());
+        assertTrue(vm.hasArg());
+
+        assertTrue(options.hasOption("hostId"));
+        Option host = options.getOption("hostId");
+        assertEquals("the ID of the host to monitor", host.getDescription());
+        assertTrue(host.isRequired());
+        assertTrue(host.hasArg());
+
+        assertTrue(options.hasOption("continuous"));
+        Option cont = options.getOption("continuous");
+        assertEquals("c", cont.getOpt());
+        assertEquals("print data continuously", cont.getDescription());
+        assertFalse(cont.isRequired());
+        assertFalse(cont.hasArg());
+    }
+
+    @Test
+    public void testStorageRequired() {
+        assertTrue(cmd.isStorageRequired());
+    }
+}
--- a/client/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ b/client/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -60,6 +60,7 @@
 
   <modules>
     <module>core</module>
+    <module>cli</module>
     <module>living-vm-filter</module>
     <module>command</module>
     <module>swing</module>
--- a/distribution/config/commands/connect.properties	Thu Dec 13 09:52:03 2012 -0500
+++ b/distribution/config/commands/connect.properties	Thu Dec 13 12:12:19 2012 -0500
@@ -1,6 +1,6 @@
-# ConnectCommand is provided by the tools bundle, which is a bootstrap bundle.
 # In order to support web storage connections we add web bundles here
-bundles = thermostat-web-common-${project.version}.jar, \
+bundles = thermostat-client-cli-${project.version}.jar, \
+          thermostat-web-common-${project.version}.jar, \
           thermostat-web-client-${project.version}.jar, \
           thermostat-storage-mongodb-${project.version}.jar, \
           mongo.jar, \
--- a/distribution/config/commands/disconnect.properties	Thu Dec 13 09:52:03 2012 -0500
+++ b/distribution/config/commands/disconnect.properties	Thu Dec 13 12:12:19 2012 -0500
@@ -1,5 +1,4 @@
-# DisconnectCommand is provided by the tools bundle, which is a bootstrap bundle, and requires no other bundles.
-bundles =
+bundles = thermostat-client-cli-${project.version}.jar
 
 description = disconnect from the currently used storage
 
--- a/distribution/config/commands/list-vms.properties	Thu Dec 13 09:52:03 2012 -0500
+++ b/distribution/config/commands/list-vms.properties	Thu Dec 13 12:12:19 2012 -0500
@@ -1,5 +1,5 @@
-# ListVmsCommand is provided by tools bundle (a bootstrap bundle), but needs storage impls
-bundles = thermostat-storage-mongodb-${project.version}.jar, \
+bundles = thermostat-client-cli-${project.version}.jar, \
+          thermostat-storage-mongodb-${project.version}.jar, \
           thermostat-web-common-${project.version}.jar, \
           thermostat-web-client-${project.version}.jar, \
           httpcomponents-core.jar, \
--- a/distribution/config/commands/shell.properties	Thu Dec 13 09:52:03 2012 -0500
+++ b/distribution/config/commands/shell.properties	Thu Dec 13 12:12:19 2012 -0500
@@ -1,5 +1,5 @@
 # ShellCommand is provided by the tools bundle, which is a bootstrap bundle, and requires no other bundles.
-bundles =
+bundles = thermostat-client-cli-${project.version}.jar
 
 description = launches the Thermostat interactive shell
 
--- a/distribution/config/commands/vm-info.properties	Thu Dec 13 09:52:03 2012 -0500
+++ b/distribution/config/commands/vm-info.properties	Thu Dec 13 12:12:19 2012 -0500
@@ -1,6 +1,5 @@
-# VMInfoCommand is provided by the tools bundle, a bootstrap bundle.
-# Requires storage impls only.
-bundles = thermostat-storage-mongodb-${project.version}.jar, \
+bundles = thermostat-client-cli-${project.version}.jar, \
+          thermostat-storage-mongodb-${project.version}.jar, \
           thermostat-web-common-${project.version}.jar, \
           thermostat-web-client-${project.version}.jar, \
           httpcomponents-core.jar, \
--- a/distribution/config/commands/vm-stat.properties	Thu Dec 13 09:52:03 2012 -0500
+++ b/distribution/config/commands/vm-stat.properties	Thu Dec 13 12:12:19 2012 -0500
@@ -1,6 +1,5 @@
-# VMStatCommand is provided by tools bundle, a bootstrap bundle.
-# Requires storage impl bundles only.
-bundles = thermostat-storage-mongodb-${project.version}.jar, \
+bundles = thermostat-client-cli-${project.version}.jar, \
+          thermostat-storage-mongodb-${project.version}.jar, \
           thermostat-web-common-${project.version}.jar, \
           thermostat-web-client-${project.version}.jar, \
           httpcomponents-core.jar, \
--- a/distribution/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ b/distribution/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -327,11 +327,6 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-tools</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-launcher</artifactId>
       <version>${project.version}</version>
     </dependency>
@@ -352,6 +347,11 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-cli</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-host-overview-client-core</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/distribution/scripts/thermostat	Thu Dec 13 09:52:03 2012 -0500
+++ b/distribution/scripts/thermostat	Thu Dec 13 12:12:19 2012 -0500
@@ -60,7 +60,7 @@
 
 THERM_DIR=${THERMOSTAT_LIBS}
 
-SERVICE_CLASSPATH="${TOOLS_JAR}:${SERVICE_CLASSPATH}:${THERM_DIR}/thermostat-agent-@project.version@.jar:${THERM_DIR}/thermostat-common-@project.version@.jar:${THERM_DIR}/thermostat-tools-@project.version@.jar"
+SERVICE_CLASSPATH="${TOOLS_JAR}:${SERVICE_CLASSPATH}"
 THERMOSTAT_MAIN="com.redhat.thermostat.main.Thermostat"
 
 # start parsing arguments, we intercept jvm arguments vs thermostat specific
--- a/killvm/agent/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ b/killvm/agent/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -92,6 +92,11 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-osgi-process-handler</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
     </dependency>
--- a/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties	Thu Dec 13 09:52:03 2012 -0500
+++ b/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties	Thu Dec 13 12:12:19 2012 -0500
@@ -2,7 +2,6 @@
         thermostat-storage-core-${project.version}.jar, \
         thermostat-common-core-${project.version}.jar, \
         thermostat-bundles-${project.version}.jar, \
-        thermostat-tools-${project.version}.jar, \
         thermostat-launcher-${project.version}.jar, \
         thermostat-main-${project.version}.jar, \
         jline2.jar, \
--- a/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ b/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -120,7 +120,6 @@
     <module>distribution</module>
     <module>main</module>
     <module>launcher</module>
-    <module>tools</module>
     <module>bundles</module>
     <module>common</module>
     <module>agent</module>
--- a/tools/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-
- Copyright 2012 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>0.5.0-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-tools</artifactId>
-  <packaging>bundle</packaging>
-
-  <name>Thermostat Tools</name>
-
-  <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>org.powermock</groupId>
-      <artifactId>powermock-api-mockito</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.powermock</groupId>
-      <artifactId>powermock-module-junit4</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>jline</groupId>
-      <artifactId>jline</artifactId>
-    </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-launcher</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-osgi-process-handler</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-test</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.core</artifactId>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Bundle-Activator>com.redhat.thermostat.tools.Activator</Bundle-Activator>
-            <Bundle-SymbolicName>com.redhat.thermostat.tools</Bundle-SymbolicName>
-            <Export-Package>
-              com.redhat.thermostat.tools,
-            </Export-Package>
-            <Private-Package>
-              META_INF.services,
-              com.redhat.thermostat.tools.cli,
-            </Private-Package>
-            <!-- Do not autogenerate uses clauses in Manifests -->
-            <_nouses>true</_nouses>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-
-
-</project>
--- a/tools/src/main/java/com/redhat/thermostat/tools/Activator.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright 2012 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.tools;
-
-import java.util.ServiceLoader;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.common.cli.CommandRegistry;
-import com.redhat.thermostat.common.cli.CommandRegistryImpl;
-
-public class Activator implements BundleActivator {
-
-    private CommandRegistry reg;
-
-    @Override
-    public void start(BundleContext context) throws Exception {
-        reg = new CommandRegistryImpl(context);
-        ServiceLoader<Command> cmds = ServiceLoader.load(Command.class, getClass().getClassLoader());
-        reg.registerCommands(cmds);
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        reg.unregisterCommands();
-    }
-
-}
--- a/tools/src/main/java/com/redhat/thermostat/tools/LocaleResources.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * Copyright 2012 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.tools;
-
-import com.redhat.thermostat.common.locale.Translate;
-
-public enum LocaleResources {
-
-    MISSING_INFO,
-
-    VALUE_AND_UNIT,
-
-    HOST_SERVICE_UNAVAILABLE,
-    VM_SERVICE_UNAVAILABLE,
-    VM_CPU_SERVICE_NOT_AVAILABLE,
-    VM_MEMORY_SERVICE_NOT_AVAILABLE,
-
-    COMMAND_CONNECT_ALREADY_CONNECTED,
-    COMMAND_CONNECT_FAILED_TO_CONNECT,
-    COMMAND_CONNECT_INVALID_STORAGE,
-    COMMAND_CONNECT_ERROR,
-
-    COMMAND_DISCONNECT_NOT_CONNECTED,
-    COMMAND_DISCONNECT_ERROR,
-
-    VM_INFO_PROCESS_ID,
-    VM_INFO_START_TIME,
-    VM_INFO_STOP_TIME,
-    VM_INFO_MAIN_CLASS,
-    VM_INFO_COMMAND_LINE,
-    VM_INFO_JAVA_VERSION,
-    VM_INFO_VIRTUAL_MACHINE,
-    VM_INFO_VM_ARGUMENTS,
-
-    COLUMN_HEADER_HOST_ID,
-    COLUMN_HEADER_HOST,
-    COLUMN_HEADER_VM_ID,
-    COLUMN_HEADER_VM_NAME,
-    COLUMN_HEADER_VM_STATUS,
-    COLUMN_HEADER_TIME,
-    COLUMN_HEADER_CPU_PERCENT,
-    COLUMN_HEADER_MEMORY_PATTERN,
-
-    VM_STOP_TIME_RUNNING,
-    VM_STATUS_ALIVE,
-    VM_STATUS_DEAD,
-    ;
-
-    static final String RESOURCE_BUNDLE = "com.redhat.thermostat.tools.strings";
-
-    public static Translate<LocaleResources> createLocalizer() {
-        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
-    }
-}
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/ConnectCommand.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import com.redhat.thermostat.common.DbService;
-import com.redhat.thermostat.common.DbServiceFactory;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.config.ClientPreferences;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.launcher.CommonCommandOptions;
-import com.redhat.thermostat.storage.core.ConnectionException;
-import com.redhat.thermostat.storage.core.StorageException;
-import com.redhat.thermostat.tools.LocaleResources;
-import com.redhat.thermostat.utils.keyring.Keyring;
-
-/**
- * Command in order to persistently connect to a database. Available only in
- * shell.
- * 
- * This commands registers a connection service. If this service is available,
- * it can be used to retrieve a DB connection.
- * 
- */
-public class ConnectCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String NAME = "connect";
-    
-    private ClientPreferences prefs;
-    private DbServiceFactory dbServiceFactory;
-
-    public ConnectCommand() {
-        this(new DbServiceFactory());
-    }
-
-    ConnectCommand(DbServiceFactory dbServiceFactory) {
-        this.dbServiceFactory = dbServiceFactory;
-    }
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        DbService service = OSGIUtils.getInstance().getServiceAllowNull(DbService.class);
-        if (service != null) {
-            // Already connected, bail out
-            throw new CommandException(translator.localize(LocaleResources.COMMAND_CONNECT_ALREADY_CONNECTED, service.getConnectionUrl()));
-        }
-        if (prefs == null) {
-            prefs = new ClientPreferences(OSGIUtils.getInstance().getService(Keyring.class));
-        }
-        String dbUrl = ctx.getArguments().getArgument(CommonCommandOptions.DB_URL_ARG);
-        if (dbUrl == null) {
-            dbUrl = prefs.getConnectionUrl();
-        }
-        String username = ctx.getArguments().getArgument(CommonCommandOptions.USERNAME_ARG);
-        String password = ctx.getArguments().getArgument(CommonCommandOptions.PASSWORD_ARG);
-        try {
-            // may throw StorageException if storage url is not supported
-            service = dbServiceFactory.createDbService(username, password, dbUrl);
-            service.connect();
-        } catch (StorageException ex) {
-            throw new CommandException(translator.localize(LocaleResources.COMMAND_CONNECT_INVALID_STORAGE, dbUrl));
-        } catch (ConnectionException ex) {
-            String error = ex.getMessage();
-            String message = ( error == null ? "" : " " + translator.localize(LocaleResources.COMMAND_CONNECT_ERROR, error) );
-            throw new CommandException(translator.localize(LocaleResources.COMMAND_CONNECT_FAILED_TO_CONNECT, dbUrl + message), ex);
-        }
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-    
-    @Override
-    public boolean isAvailableOutsideShell() {
-        return false;
-    }
-    
-    @Override
-    public boolean isStorageRequired() {
-        return false;
-    }
-}
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/DisconnectCommand.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import org.apache.commons.cli.Options;
-
-import com.redhat.thermostat.common.DbService;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.core.ConnectionException;
-import com.redhat.thermostat.tools.LocaleResources;
-
-public class DisconnectCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String NAME = "disconnect";
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        DbService service = OSGIUtils.getInstance().getServiceAllowNull(DbService.class);
-        if (service == null) {
-            // not connected
-            throw new CommandException(translator.localize(LocaleResources.COMMAND_DISCONNECT_NOT_CONNECTED));
-        }
-        try {
-            service.disconnect();
-        } catch (ConnectionException e) {
-            throw new CommandException(translator.localize(LocaleResources.COMMAND_DISCONNECT_ERROR));
-        }
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-    public Options getOptions() {
-        return new Options();
-    }
-    
-    @Override
-    public boolean isAvailableOutsideShell() {
-        return false;
-    }
-    
-    @Override
-    public boolean isStorageRequired() {
-        return false;
-    }
-
-}
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/ListVMsCommand.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import java.util.Collection;
-
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.dao.HostInfoDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.tools.LocaleResources;
-
-public class ListVMsCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String NAME = "list-vms";
-
-    private final OSGIUtils serviceProvider;
-
-    public ListVMsCommand() {
-        this(OSGIUtils.getInstance());
-    }
-
-    ListVMsCommand(OSGIUtils serviceProvider) {
-        this.serviceProvider = serviceProvider;
-    }
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-
-        HostInfoDAO hostsDAO = serviceProvider.getServiceAllowNull(HostInfoDAO.class);
-        if (hostsDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.HOST_SERVICE_UNAVAILABLE));
-        }
-        Collection<HostRef> hosts = hostsDAO.getHosts();
-        serviceProvider.ungetService(HostInfoDAO.class, hostsDAO);
-
-        VmInfoDAO vmsDAO = serviceProvider.getServiceAllowNull(VmInfoDAO.class);
-        if (vmsDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.VM_SERVICE_UNAVAILABLE));
-        }
-        VMListFormatter formatter = new VMListFormatter();
-        for (HostRef host : hosts) {
-            Collection<VmRef> vms = vmsDAO.getVMs(host);
-            for (VmRef vm : vms) {
-                VmInfo info = vmsDAO.getVmInfo(vm);
-                formatter.addVM(vm, info);
-            }
-        }
-        formatter.format(ctx.getConsole().getOutput());
-
-        serviceProvider.ungetService(VmInfoDAO.class, vmsDAO);
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-}
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/ShellCommand.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,173 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import jline.Terminal;
-import jline.TerminalFactory;
-import jline.console.ConsoleReader;
-import jline.console.history.FileHistory;
-import jline.console.history.History;
-import jline.console.history.PersistentHistory;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.config.ConfigUtils;
-import com.redhat.thermostat.common.config.InvalidConfigurationException;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.launcher.Launcher;
-
-public class ShellCommand extends SimpleCommand {
-
-    private static final Logger logger = LoggingUtils.getLogger(ShellCommand.class);
-
-    private static final String[] exitKeywords = { "exit", "quit", "q" };
-
-    private static final String NAME = "shell";
-
-    private static final String PROMPT = "Thermostat > ";
-
-    private HistoryProvider historyProvider;
-
-    private BundleContext bundleContext;
-    
-    static class HistoryProvider {
-        public PersistentHistory get() {
-            PersistentHistory history = null;
-            try {
-                history = new FileHistory(ConfigUtils.getHistoryFile());
-            } catch (InvalidConfigurationException | IOException e) {
-                /* no history available */
-            }
-            return history;
-        }
-    }
-
-    public ShellCommand() {
-        this(FrameworkUtil.getBundle(ShellCommand.class).getBundleContext(), new HistoryProvider());
-    }
-
-    ShellCommand(BundleContext context, HistoryProvider provider) {
-        this.historyProvider = provider;
-        this.bundleContext = context;
-    }
-    
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        Terminal term = TerminalFactory.create();
-        PersistentHistory history = historyProvider.get();
-
-        try {
-            shellMainLoop(ctx, history, term);
-        } catch (IOException ex) {
-            throw new CommandException(ex);
-        } finally {
-            closeTerminal(term);
-            if (history != null) {
-                try {
-                    history.flush();
-                } catch (IOException e) {
-                    logger.log(Level.WARNING, "Unable to save history", e);
-                }
-            }
-        }
-    }
-
-    private void closeTerminal(Terminal term) throws CommandException {
-        try {
-            term.restore();
-        } catch (Exception e) {
-            throw new CommandException(e);
-        }
-    }
-
-    private void shellMainLoop(CommandContext ctx, History history, Terminal term) throws IOException, CommandException {
-        ConsoleReader reader = new ConsoleReader(ctx.getConsole().getInput(), ctx.getConsole().getOutput(), term);
-        if (history != null) {
-            reader.setHistory(history);
-        }
-        while (handleConsoleInput(reader)) { /* no-op; the loop conditional performs the action */ }
-    }
-
-    private boolean handleConsoleInput(ConsoleReader reader) throws IOException, CommandException {
-        String line = reader.readLine(PROMPT);
-        if (line == null) {
-            return false;
-        }
-        line = line.trim();
-        if (line.equals("")) {
-            return true;
-        } else if (Arrays.asList(exitKeywords).contains(line)) {
-            return false;
-        } else {
-            launchCommand(line);
-            return true;
-        }
-    }
-
-    private void launchCommand(String line) throws CommandException {
-        String[] parsed = line.split(" ");
-        ServiceReference launcherRef = bundleContext.getServiceReference(Launcher.class.getName());
-        if (launcherRef != null) {
-            Launcher launcher = (Launcher) bundleContext.getService(launcherRef);
-            launcher.setArgs(parsed);
-            launcher.run();
-        } else {
-            throw new CommandException("Severe: Could not locate launcher");
-        }
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-    public boolean isStorageRequired() {
-        return false;
-    }
-
-}
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/VMInfoCommand.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import java.io.PrintStream;
-import java.util.Collection;
-import java.util.Date;
-
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.HostVMArguments;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.cli.TableRenderer;
-import com.redhat.thermostat.common.dao.DAOException;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.tools.LocaleResources;
-
-public class VMInfoCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String NAME = "vm-info";
-    private static final String STILL_ALIVE = translator.localize(LocaleResources.VM_STOP_TIME_RUNNING);
-
-    private OSGIUtils serviceProvider;
-
-    public VMInfoCommand() {
-        this(OSGIUtils.getInstance());
-    }
-
-    /** For tests only */
-    VMInfoCommand(OSGIUtils serviceProvider) {
-        this.serviceProvider = serviceProvider;
-    }
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        VmInfoDAO vmsDAO = serviceProvider.getServiceAllowNull(VmInfoDAO.class);
-        if (vmsDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.VM_SERVICE_UNAVAILABLE));
-        }
-
-        HostVMArguments hostVMArgs = new HostVMArguments(ctx.getArguments(), true, false);
-        HostRef host = hostVMArgs.getHost();
-        VmRef vm = hostVMArgs.getVM();
-        try {
-            if (vm != null) {
-                getAndPrintVMInfo(ctx, vmsDAO, vm);
-            } else {
-                getAndPrintAllVMInfo(ctx, vmsDAO, host);
-
-            }
-        } catch (DAOException ex) {
-            ctx.getConsole().getError().println(ex.getMessage());
-        } finally {
-            serviceProvider.ungetService(VmInfoDAO.class, vmsDAO);
-        }
-    }
-
-    private void getAndPrintAllVMInfo(CommandContext ctx, VmInfoDAO vmsDAO, HostRef host) {
-        Collection<VmRef> vms = vmsDAO.getVMs(host);
-        for (VmRef vm : vms) {
-            getAndPrintVMInfo(ctx, vmsDAO, vm);
-        }
-    }
-
-    private void getAndPrintVMInfo(CommandContext ctx, VmInfoDAO vmsDAO, VmRef vm) {
-
-        VmInfo vmInfo = vmsDAO.getVmInfo(vm);
-
-        TableRenderer table = new TableRenderer(2);
-        table.printLine(translator.localize(LocaleResources.VM_INFO_PROCESS_ID), String.valueOf(vmInfo.getVmPid()));
-        table.printLine(translator.localize(LocaleResources.VM_INFO_START_TIME), new Date(vmInfo.getStartTimeStamp()).toString());
-        if (vmInfo.isAlive()) {
-            table.printLine(translator.localize(LocaleResources.VM_INFO_STOP_TIME), STILL_ALIVE);
-        } else {
-            table.printLine(translator.localize(LocaleResources.VM_INFO_STOP_TIME), new Date(vmInfo.getStopTimeStamp()).toString());
-        }
-        table.printLine(translator.localize(LocaleResources.VM_INFO_MAIN_CLASS), vmInfo.getMainClass());
-        table.printLine(translator.localize(LocaleResources.VM_INFO_COMMAND_LINE), vmInfo.getJavaCommandLine());
-        table.printLine(translator.localize(LocaleResources.VM_INFO_JAVA_VERSION), vmInfo.getJavaVersion());
-        table.printLine(translator.localize(LocaleResources.VM_INFO_VIRTUAL_MACHINE), vmInfo.getVmName());
-        table.printLine(translator.localize(LocaleResources.VM_INFO_VM_ARGUMENTS), vmInfo.getVmArguments());
-
-        PrintStream out = ctx.getConsole().getOutput();
-        table.render(out);
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-}
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/VMListFormatter.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import java.io.PrintStream;
-
-import com.redhat.thermostat.common.cli.TableRenderer;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.tools.LocaleResources;
-
-class VMListFormatter {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String HOST_ID = translator.localize(LocaleResources.COLUMN_HEADER_HOST_ID);
-    private static final String HOST = translator.localize(LocaleResources.COLUMN_HEADER_HOST);
-    private static final String VM_ID = translator.localize(LocaleResources.COLUMN_HEADER_VM_ID);
-    private static final String VM_NAME = translator.localize(LocaleResources.COLUMN_HEADER_VM_NAME);
-    private static final String VM_STATUS = translator.localize(LocaleResources.COLUMN_HEADER_VM_STATUS);
-
-    private static final String STATUS_ALIVE = translator.localize(LocaleResources.VM_STATUS_ALIVE);
-    private static final String STATUS_DEAD = translator.localize(LocaleResources.VM_STATUS_DEAD);
-
-    private TableRenderer tableRenderer;
-
-    VMListFormatter() {
-        tableRenderer = new TableRenderer(5);
-        printHeader();
-    }
-
-    void addVM(VmRef vm, VmInfo info) {
-        printVM(vm, info);
-    }
-
-    void format(PrintStream output) {
-        tableRenderer.render(output);
-    }
-
-    private void printHeader() {
-        printLine(HOST_ID, HOST, VM_ID, VM_STATUS, VM_NAME);
-    }
-
-    private void printVM(VmRef vm, VmInfo info) {
-        printLine(vm.getAgent().getAgentId(),
-                  vm.getAgent().getHostName(),
-                  vm.getId().toString(),
-                  info.isAlive() ? STATUS_ALIVE : STATUS_DEAD,
-                  vm.getName());
-    }
-
-    private void printLine(String hostId, String host, String vmId, String status, String vmName) {
-        tableRenderer.printLine(hostId, host, vmId, status, vmName);
-    }
-
-}
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatCommand.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.HostVMArguments;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.dao.VmCpuStatDAO;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.tools.LocaleResources;
-
-public class VMStatCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final Logger log = LoggingUtils.getLogger(VMStatCommand.class);
-
-    private static final String CMD_NAME = "vm-stat";
-
-    private OSGIUtils serviceProvider;
-
-    public VMStatCommand() {
-        this(OSGIUtils.getInstance());
-    }
-
-    VMStatCommand(OSGIUtils serviceProvider) {
-        this.serviceProvider = serviceProvider;
-    }
-
-    @Override
-    public void run(final CommandContext ctx) throws CommandException {
-        VmCpuStatDAO vmCpuStatDAO = serviceProvider.getServiceAllowNull(VmCpuStatDAO.class);
-        if (vmCpuStatDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.VM_CPU_SERVICE_NOT_AVAILABLE));
-        }
-
-        VmMemoryStatDAO vmMemoryStatDAO = serviceProvider.getServiceAllowNull(VmMemoryStatDAO.class);
-        if (vmMemoryStatDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.VM_MEMORY_SERVICE_NOT_AVAILABLE));
-        }
-
-        HostVMArguments hostVMArgs = new HostVMArguments(ctx.getArguments());
-        VmRef vm = hostVMArgs.getVM();
-        final VMStatPrinter statPrinter = new VMStatPrinter(vm, vmCpuStatDAO, vmMemoryStatDAO, ctx.getConsole().getOutput());
-        statPrinter.printStats();
-        boolean continuous = ctx.getArguments().hasArgument("continuous");
-        if (continuous) {
-            startContinuousStats(ctx, statPrinter);
-        }
-
-        serviceProvider.ungetService(VmMemoryStatDAO.class, vmMemoryStatDAO);
-        serviceProvider.ungetService(VmCpuStatDAO.class, vmCpuStatDAO);
-    }
-
-    private void startContinuousStats(final CommandContext ctx, final VMStatPrinter statPrinter) {
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        ApplicationService appSvc = serviceProvider.getService(ApplicationService.class);
-        Timer timer = appSvc.getTimerFactory().createTimer();
-        timer.setDelay(1);
-        timer.setInitialDelay(1);
-        timer.setSchedulingType(Timer.SchedulingType.FIXED_RATE);
-        timer.setTimeUnit(TimeUnit.SECONDS);
-        timer.setAction(new Runnable() {
-
-            @Override
-            public void run() {
-                statPrinter.printUpdatedStats();
-            }
-        });
-        timer.start();
-        Thread t = new Thread() {
-            public void run() {
-                try {
-                    ctx.getConsole().getInput().read();
-                } catch (IOException e) {
-                    log.log(Level.WARNING, "Unexpected IOException while waiting for user input", e);
-                } finally {
-                    latch.countDown();
-                }
-            }
-        };
-        t.start();
-        try {
-            latch.await();
-            timer.stop();
-        } catch (InterruptedException e) {
-            // Return immediately.
-        }
-    }
-
-    @Override
-    public String getName() {
-        return CMD_NAME;
-    }
-}
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatPrinter.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,217 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import java.io.PrintStream;
-import java.text.DateFormat;
-import java.text.DecimalFormat;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import com.redhat.thermostat.common.cli.TableRenderer;
-import com.redhat.thermostat.common.dao.VmCpuStatDAO;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.DisplayableValues;
-import com.redhat.thermostat.storage.model.TimeStampedPojo;
-import com.redhat.thermostat.storage.model.TimeStampedPojoComparator;
-import com.redhat.thermostat.storage.model.TimeStampedPojoCorrelator;
-import com.redhat.thermostat.storage.model.VmCpuStat;
-import com.redhat.thermostat.storage.model.VmMemoryStat;
-import com.redhat.thermostat.tools.LocaleResources;
-
-class VMStatPrinter {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String CPU_PERCENT = translator.localize(LocaleResources.COLUMN_HEADER_CPU_PERCENT);
-    private static final String TIME = translator.localize(LocaleResources.COLUMN_HEADER_TIME);
-
-    private VmRef vm;
-    private VmCpuStatDAO vmCpuStatDAO;
-    private VmMemoryStatDAO vmMemoryStatDAO;
-    private PrintStream out;
-    private TimeStampedPojoCorrelator correlator = new TimeStampedPojoCorrelator(2);
-    private TableRenderer table;
-    private int numSpaces;
-
-    private long lastCpuStatTimeStamp = Long.MIN_VALUE;
-    private long lastMemoryStatTimeStamp = Long.MIN_VALUE;
-
-    VMStatPrinter(VmRef vm, VmCpuStatDAO vmCpuStatDAO, VmMemoryStatDAO vmMemoryStatDAO, PrintStream out) {
-        this.vm = vm;
-        this.vmCpuStatDAO = vmCpuStatDAO;
-        this.vmMemoryStatDAO = vmMemoryStatDAO;
-        this.out = out;
-    }
-
-    void printStats() {
-        List<VmCpuStat> cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm, lastCpuStatTimeStamp);
-        List<VmMemoryStat> memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm, lastMemoryStatTimeStamp);
-
-        lastCpuStatTimeStamp = getLatestTimeStamp(lastCpuStatTimeStamp, cpuStats);
-        lastMemoryStatTimeStamp = getLatestTimeStamp(lastMemoryStatTimeStamp, memStats);
-
-        printStats(cpuStats, memStats);
-    }
-
-    void printUpdatedStats() {
-        correlator.clear();
-        List<VmCpuStat> cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm, lastCpuStatTimeStamp);
-        List<VmMemoryStat> memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm, lastMemoryStatTimeStamp);
-
-        lastCpuStatTimeStamp = getLatestTimeStamp(lastCpuStatTimeStamp, cpuStats);
-        lastMemoryStatTimeStamp = getLatestTimeStamp(lastMemoryStatTimeStamp, memStats);
-
-        correlate(cpuStats, memStats);
-        printUpdatedStatsImpl();
-    }
-
-    private long getLatestTimeStamp(long currentTimeStamp, List<? extends TimeStampedPojo> list) {
-        try {
-            return Math.max(currentTimeStamp, Collections.max(list, new TimeStampedPojoComparator<>()).getTimeStamp());
-        } catch (NoSuchElementException listIsEmpty) {
-            return currentTimeStamp;
-        }
-    }
-
-    private void printStats(List<VmCpuStat> cpuStats, List<VmMemoryStat> memStats) {
-        correlate(cpuStats, memStats);
-        numSpaces = getNumSpaces(memStats);
-        int numColumns = numSpaces + 2;
-        table = new TableRenderer(numColumns);
-        printHeaders(memStats, numSpaces, numColumns, table);
-        printUpdatedStatsImpl();
-    }
-
-    private void printStats(int numSpaces, TableRenderer table, Iterator<TimeStampedPojoCorrelator.Correlation> i) {
-
-        TimeStampedPojoCorrelator.Correlation correlation = i.next();
-
-        VmCpuStat cpuStat = (VmCpuStat) correlation.get(0);
-        DecimalFormat format = new DecimalFormat("#0.0");
-        String cpuLoad = cpuStat != null ? format.format(cpuStat.getCpuLoad()) : "";
-
-        DateFormat dateFormat = DateFormat.getTimeInstance();
-        String time = dateFormat.format(new Date(correlation.getTimeStamp()));
-
-        String[] memoryUsage = getMemoryUsage((VmMemoryStat) correlation.get(1), numSpaces);
-
-        String[] line = new String[numSpaces + 2];
-        System.arraycopy(memoryUsage, 0, line, 2, numSpaces);
-        line[0] = time;
-        line[1] = cpuLoad;
-        table.printLine(line);
-    }
-
-    private void printHeaders(List<VmMemoryStat> memStats, int numSpaces, int numColumns, TableRenderer table) {
-        String[] spacesNames = getSpacesNames(memStats, numSpaces);
-        String[] headers = new String[numColumns];
-        headers[0] = TIME;
-        headers[1] = CPU_PERCENT;
-        System.arraycopy(spacesNames, 0, headers, 2, numSpaces);
-        table.printLine(headers);
-    }
-
-    private String[] getMemoryUsage(VmMemoryStat vmMemoryStat, int numSpaces) {
-        String[] memoryUsage = new String[numSpaces];
-        if (vmMemoryStat == null) {
-            Arrays.fill(memoryUsage, "");
-            return memoryUsage;
-        }
-        int i = 0;
-        for (VmMemoryStat.Generation gen : vmMemoryStat.getGenerations()) {
-            for (VmMemoryStat.Space space : gen.getSpaces()) {
-                String[] displayableSize = DisplayableValues.bytes(space.getUsed());
-                memoryUsage[i] = translator.localize(LocaleResources.VALUE_AND_UNIT, displayableSize[0], displayableSize[1]);
-                i++;
-            }
-        }
-        return memoryUsage;
-    }
-
-    private String[] getSpacesNames(List<VmMemoryStat> memStats, int numSpaces) {
-        if (numSpaces < 1) {
-            return new String[0];
-        }
-        String[] spacesNames = new String[numSpaces];
-        VmMemoryStat stat = memStats.get(0);
-        int i = 0;
-        for (VmMemoryStat.Generation gen : stat.getGenerations()) {
-            for (VmMemoryStat.Space space : gen.getSpaces()) {
-                spacesNames[i] = translator.localize(LocaleResources.COLUMN_HEADER_MEMORY_PATTERN, space.getName());
-                i++;
-            }
-        }
-        return spacesNames;
-    }
-
-    private int getNumSpaces(List<VmMemoryStat> memStats) {
-        if (memStats.size() < 1) {
-            return 0;
-        }
-        VmMemoryStat stat = memStats.get(0);
-        int numSpaces = 0;
-        for (VmMemoryStat.Generation gen : stat.getGenerations()) {
-            numSpaces += gen.getSpaces().length;
-        }
-        return numSpaces;
-    }
-
-    private void correlate(List<VmCpuStat> cpuStats, List<VmMemoryStat> memStats) {
-        for(VmCpuStat cpuStat : cpuStats) {
-            correlator.add(0, cpuStat);
-        }
-        for (VmMemoryStat memStat : memStats) {
-            correlator.add(1, memStat);
-        }
-    }
-
-    void printUpdatedStatsImpl() {
-        Iterator<TimeStampedPojoCorrelator.Correlation> iterator = correlator.iterator();
-        while (iterator.hasNext()) {
-            printStats(numSpaces, table, iterator);
-        }
-        table.render(out);
-    }
-
-}
--- a/tools/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-com.redhat.thermostat.tools.cli.ListVMsCommand
-com.redhat.thermostat.tools.cli.ShellCommand
-com.redhat.thermostat.tools.cli.VMInfoCommand
-com.redhat.thermostat.tools.cli.VMStatCommand
-com.redhat.thermostat.tools.cli.DisconnectCommand
-com.redhat.thermostat.tools.cli.ConnectCommand
\ No newline at end of file
--- a/tools/src/main/resources/com/redhat/thermostat/tools/strings.properties	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-MISSING_INFO = Missing Information
-
-VALUE_AND_UNIT = {0} {1}
-
-HOST_SERVICE_UNAVAILABLE = Unable to get host information (HostInfoDAO is unavailable)
-VM_SERVICE_UNAVAILABLE = Unable to get vm information (VmInfoDAO is unavailable)
-VM_CPU_SERVICE_NOT_AVAILABLE = Unable to access vm cpu information (VmCpuStats not available)
-VM_MEMORY_SERVICE_NOT_AVAILABLE = Unable to access vm memory information (VmCpuStats not available)
-
-COMMAND_CONNECT_ALREADY_CONNECTED = Already connected to storage: URL = {0}\nPlease use disconnect command to disconnect.
-COMMAND_CONNECT_FAILED_TO_CONNECT = Could not connect to db {0}
-COMMAND_CONNECT_INVALID_STORAGE = Unrecognized storage URL {0}
-COMMAND_CONNECT_ERROR = Error: {0}
-
-COMMAND_DISCONNECT_NOT_CONNECTED = Not connected to storage. You may use the connect command for establishing connections.
-COMMAND_DISCONNECT_ERROR = Failed to disconnect from database.
-
-VM_INFO_PROCESS_ID = Process ID:
-VM_INFO_START_TIME = Start time:
-VM_INFO_STOP_TIME = Stop time:
-VM_INFO_MAIN_CLASS = Main class:
-VM_INFO_COMMAND_LINE = Command line:
-VM_INFO_JAVA_VERSION = Java version:
-VM_INFO_VIRTUAL_MACHINE = Virtual machine:
-VM_INFO_VM_ARGUMENTS = VM arguments:
-
-COLUMN_HEADER_HOST_ID = HOST_ID
-COLUMN_HEADER_HOST = HOST
-COLUMN_HEADER_VM_ID  = VM_ID
-COLUMN_HEADER_VM_NAME = VM_NAME
-COLUMN_HEADER_VM_STATUS = STATUS
-COLUMN_HEADER_TIME = TIME
-COLUMN_HEADER_CPU_PERCENT = %CPU
-COLUMN_HEADER_MEMORY_PATTERN = MEM.{0}
-
-VM_STOP_TIME_RUNNING = <Running>
-VM_STATUS_ALIVE = RUNNING
-VM_STATUS_DEAD = EXITED
--- a/tools/src/test/java/com/redhat/thermostat/tools/LocaleResourcesTest.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012 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.tools;
-
-import java.io.IOException;
-import java.util.Properties;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-
-public class LocaleResourcesTest {
-
-    @Test
-    public void testLocalizedStringsArePresent() throws IOException {
-
-        String stringsResource = "/" + LocaleResources.RESOURCE_BUNDLE.replace(".", "/") + ".properties";
-
-        Properties props = new Properties();
-        props.load(getClass().getResourceAsStream(stringsResource));
-
-        Assert.assertEquals(LocaleResources.values().length, props.values().size());
-        for (LocaleResources resource : LocaleResources.values()) {
-            Assert.assertTrue("missing property from resource bound file: " + resource,
-                              props.containsKey(resource.name()));
-        }
-    }
-}
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/ConnectCommandTest.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-import com.redhat.thermostat.common.DbService;
-import com.redhat.thermostat.common.DbServiceFactory;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.launcher.CommonCommandOptions;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-import com.redhat.thermostat.tools.LocaleResources;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({ OSGIUtils.class, DbServiceFactory.class })
-public class ConnectCommandTest {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private ConnectCommand cmd;
-    private TestCommandContextFactory cmdCtxFactory;
-    private BundleContext bundleContext;
-    private DbServiceFactory dbServiceFactory;
-
-    @Before
-    public void setUp() {
-        setupCommandContextFactory();
-
-        dbServiceFactory = mock(DbServiceFactory.class);
-        cmd = new ConnectCommand(dbServiceFactory);
-    }
-
-    private void setupCommandContextFactory() {
-        Bundle sysBundle = mock(Bundle.class);
-        bundleContext = mock(BundleContext.class);
-        when(bundleContext.getBundle(0)).thenReturn(sysBundle);
-        cmdCtxFactory = new TestCommandContextFactory(bundleContext);
-        
-    }
-
-    @After
-    public void tearDown() {
-        cmdCtxFactory = null;
-        cmd = null;
-    }
-
-    @Test
-    public void verifyConnectedThrowsExceptionWithDiagnosticMessage() {
-        String dbUrl = "fluff";
-        DbService dbService = mock(DbService.class);
-        OSGIUtils utils = mock(OSGIUtils.class);
-        PowerMockito.mockStatic(OSGIUtils.class);
-        when(OSGIUtils.getInstance()).thenReturn(utils);
-        when(utils.getServiceAllowNull(DbService.class)).thenReturn(dbService);
-        when(dbService.getConnectionUrl()).thenReturn(dbUrl);
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("--dbUrl", dbUrl);
-        try {
-            cmd.run(cmdCtxFactory.createContext(args));
-        } catch (CommandException e) {
-            assertEquals(translator.localize(LocaleResources.COMMAND_CONNECT_ALREADY_CONNECTED, dbUrl), e.getMessage());
-        }
-    }
-    
-    @Test
-    public void verifyNotConnectedConnects() throws CommandException {
-        OSGIUtils utils = mock(OSGIUtils.class);
-        PowerMockito.mockStatic(OSGIUtils.class);
-        when(OSGIUtils.getInstance()).thenReturn(utils);
-        when(utils.getServiceAllowNull(DbService.class)).thenReturn(null);
-
-        DbService dbService = mock(DbService.class);
-
-        String username = "testuser";
-        String password = "testpassword";
-        String dbUrl = "mongodb://10.23.122.1:12578";
-        when(dbServiceFactory.createDbService(eq(username), eq(password), eq(dbUrl))).thenReturn(dbService);
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("dbUrl", dbUrl);
-        args.addArgument("username", username);
-        args.addArgument("password", password);
-        CommandContext ctx = cmdCtxFactory.createContext(args);
-        cmd.run(ctx);
-        verify(dbService).connect();
-    }
-    
-    @Test
-    public void testIsStorageRequired() {
-        assertFalse(cmd.isStorageRequired());
-    }
-
-    @Test
-    public void testIsNotAvailableOutsideShell() {
-        assertFalse(cmd.isAvailableOutsideShell());
-    }
-    
-    @Test
-    public void testIsAvailableInShell() {
-        assertTrue(cmd.isAvailableInShell());
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("connect", cmd.getName());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Ignore
-    @Test
-    public void testAcceptedArguments() {
-        Options options = cmd.getOptions();
-        assertNotNull(options);
-        assertTrue(options.getOptions().size() == 3);
-
-        assertTrue(options.hasOption(CommonCommandOptions.DB_URL_ARG));
-        Option db = options.getOption(CommonCommandOptions.DB_URL_ARG);
-        assertEquals(CommonCommandOptions.DB_URL_DESC, db.getDescription());
-        assertTrue(db.isRequired());
-        assertTrue(db.hasArg());
-
-        assertTrue(options.hasOption(CommonCommandOptions.USERNAME_ARG));
-        Option user = options.getOption(CommonCommandOptions.USERNAME_ARG);
-        assertEquals(CommonCommandOptions.USERNAME_DESC, user.getDescription());
-        assertFalse(user.isRequired());
-        assertTrue(user.hasArg());
-
-        assertTrue(options.hasOption(CommonCommandOptions.PASSWORD_ARG));
-        Option pass = options.getOption(CommonCommandOptions.PASSWORD_ARG);
-        assertEquals(CommonCommandOptions.PASSWORD_DESC, pass.getDescription());
-        assertFalse(pass.isRequired());
-        assertTrue(pass.hasArg());
-    }
-}
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/DisconnectCommandTest.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-import com.redhat.thermostat.common.DbService;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-import com.redhat.thermostat.tools.LocaleResources;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({ OSGIUtils.class, FrameworkUtil.class })
-public class DisconnectCommandTest {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private DisconnectCommand cmd;
-    private TestCommandContextFactory cmdCtxFactory;
-    private BundleContext bundleContext;
-
-    @Before
-    public void setUp() {
-        setupCommandContextFactory();
-
-        cmd = new DisconnectCommand();
-
-    }
-
-    private void setupCommandContextFactory() {
-        Bundle sysBundle = mock(Bundle.class);
-        bundleContext = mock(BundleContext.class);
-        when(bundleContext.getBundle(0)).thenReturn(sysBundle);
-        cmdCtxFactory = new TestCommandContextFactory(bundleContext);
-    }
-
-    @After
-    public void tearDown() {
-        cmdCtxFactory = null;
-        cmd = null;
-    }
-
-    @Test
-    public void verifyNotConnectedThrowsException() {
-        OSGIUtils utils = mock(OSGIUtils.class);
-        PowerMockito.mockStatic(OSGIUtils.class);
-        when(OSGIUtils.getInstance()).thenReturn(utils);
-        when(utils.getServiceAllowNull(DbService.class)).thenReturn(null);
-
-        try {
-            cmd.run(cmdCtxFactory.createContext(new SimpleArguments()));
-            fail("cmd.run() should have thrown exception.");
-        } catch (CommandException e) {
-            assertEquals(translator.localize(LocaleResources.COMMAND_DISCONNECT_NOT_CONNECTED), e.getMessage());
-        }
-    }
-    
-    @Test
-    public void verifyConnectedDisconnects() throws CommandException {
-        DbService dbService = mock(DbService.class);
-        OSGIUtils utils = mock(OSGIUtils.class);
-        PowerMockito.mockStatic(OSGIUtils.class);
-        when(OSGIUtils.getInstance()).thenReturn(utils);
-        when(utils.getServiceAllowNull(DbService.class)).thenReturn(dbService);
-        
-        CommandContext ctx = cmdCtxFactory.createContext(new SimpleArguments());
-        cmd.run(ctx);
-        verify(dbService).disconnect();
-    }
-
-    @Test
-    public void testIsNotAvailableOutsideShell() {
-        assertFalse(cmd.isAvailableOutsideShell());
-    }
-    
-    @Test
-    public void testIsAvailableInShell() {
-        assertTrue(cmd.isAvailableInShell());
-    }
-    
-    @Test
-    public void testIsStorageRequired() {
-        assertFalse(cmd.isStorageRequired());
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("disconnect", cmd.getName());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Test
-    public void testOptions() {
-        Options options = cmd.getOptions();
-        assertNotNull(options);
-        assertTrue(options.getOptions().size() == 0);
-    }
-}
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/ListVMsCommandTest.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.HostInfoDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-
-public class ListVMsCommandTest {
-
-    private ListVMsCommand cmd;
-    private TestCommandContextFactory cmdCtxFactory;
-    private HostInfoDAO hostsDAO;
-    private VmInfoDAO vmsDAO;
-    private OSGIUtils serviceProvider;
-
-    @Before
-    public void setUp() {
-        setupCommandContextFactory();
-        serviceProvider = mock(OSGIUtils.class);
-
-        cmd = new ListVMsCommand(serviceProvider);
-
-        hostsDAO = mock(HostInfoDAO.class);
-        vmsDAO = mock(VmInfoDAO.class);
-
-        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostsDAO);
-        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmsDAO);
-    }
-
-    private void setupCommandContextFactory() {
-        cmdCtxFactory = new TestCommandContextFactory();
-    }
-
-    @After
-    public void tearDown() {
-        vmsDAO = null;
-        hostsDAO = null;
-        cmdCtxFactory = null;
-        cmd = null;
-    }
-
-    @Test
-    public void verifyOutputFormatOneLine() throws CommandException {
-
-        HostRef host1 = new HostRef("123", "h1");
-        VmRef vm1 = new VmRef(host1, 1, "n");
-        VmInfo vm1Info = new VmInfo(1, 0, 1, "", "", "", "", "", "", "", "", null, null, null);
-        when(hostsDAO.getHosts()).thenReturn(Arrays.asList(host1));
-        when(vmsDAO.getVMs(host1)).thenReturn(Arrays.asList(vm1));
-        when(vmsDAO.getVmInfo(eq(vm1))).thenReturn(vm1Info);
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("--dbUrl", "fluff");
-        CommandContext ctx = cmdCtxFactory.createContext(args);
-
-        cmd.run(ctx);
-
-        String output = cmdCtxFactory.getOutput();
-        assertEquals("HOST_ID HOST VM_ID STATUS VM_NAME\n" +
-                     "123     h1   1     EXITED n\n", output);
-    }
-
-    @Test
-    public void verifyOutputFormatMultiLines() throws CommandException {
-
-        HostRef host1 = new HostRef("123", "h1");
-        HostRef host2 = new HostRef("456", "longhostname");
-        when(hostsDAO.getHosts()).thenReturn(Arrays.asList(host1, host2));
-
-        VmRef vm1 = new VmRef(host1, 1, "n");
-        VmRef vm2 = new VmRef(host1, 2, "n1");
-        VmRef vm3 = new VmRef(host2, 123456, "longvmname");
-
-        VmInfo vmInfo = new VmInfo(1, 0, 1, "", "", "", "", "", "", "", "", null, null, null);
-
-        when(vmsDAO.getVMs(host1)).thenReturn(Arrays.asList(vm1, vm2));
-        when(vmsDAO.getVMs(host2)).thenReturn(Arrays.asList(vm3));
-
-        when(vmsDAO.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo);
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("--dbUrl", "fluff");
-        CommandContext ctx = cmdCtxFactory.createContext(args);
-
-        cmd.run(ctx);
-
-        String output = cmdCtxFactory.getOutput();
-        assertEquals("HOST_ID HOST         VM_ID  STATUS VM_NAME\n" +
-                     "123     h1           1      EXITED n\n" +
-                     "123     h1           2      EXITED n1\n" +
-                     "456     longhostname 123456 EXITED longvmname\n", output);
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("list-vms", cmd.getName());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Test
-    public void testOptions() {
-        Options options = cmd.getOptions();
-        assertNotNull(options);
-        assertEquals(0, options.getOptions().size());
-    }
-}
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/ShellCommandTest.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,248 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-
-import jline.TerminalFactory;
-import jline.TerminalFactory.Flavor;
-import jline.TerminalFactory.Type;
-import jline.UnixTerminal;
-import jline.console.history.PersistentHistory;
-
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-
-import com.redhat.thermostat.common.cli.Arguments;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.launcher.Launcher;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-import com.redhat.thermostat.tools.cli.ShellCommand.HistoryProvider;
-
-public class ShellCommandTest {
-
-    private ShellCommand cmd;
-    private BundleContext bundleContext;
-
-    @Before
-    public void setUp() {
-        bundleContext = mock(BundleContext.class);
-        cmd = new ShellCommand(bundleContext, new HistoryProvider());
-    }
-
-    @After
-    public void tearDown() {
-        cmd = null;
-        bundleContext = null;
-        TerminalFactory.registerFlavor(Flavor.UNIX, UnixTerminal.class);
-        TerminalFactory.reset();
-    }
-
-    @Test
-    public void testBasic() throws CommandException {
-        ServiceReference ref = mock(ServiceReference.class);
-        
-        when(bundleContext.getServiceReference(Launcher.class.getName())).thenReturn(ref);
-        Launcher launcher = mock(Launcher.class);
-        when(bundleContext.getService(ref)).thenReturn(launcher);
-        TestCommandContextFactory ctxFactory = new TestCommandContextFactory(bundleContext);
-        ctxFactory.setInput("help\nexit\n");
-        Arguments args = new SimpleArguments();
-        CommandContext ctx = ctxFactory.createContext(args);
-        cmd.run(ctx);
-        verify(launcher).setArgs(new String[]{"help"});
-        verify(launcher).run();
-    }
-
-    @Test
-    public void testQuitAlsoExits() throws CommandException {
-        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
-        ctxFactory.setInput("quit\n");
-        Arguments args = new SimpleArguments();
-        CommandContext ctx = ctxFactory.createContext(args);
-        cmd.run(ctx);
-        assertEquals("Thermostat > quit\n", ctxFactory.getOutput());
-        assertEquals("", ctxFactory.getError());
-    }
-
-    @Test
-    public void testQAlsoExits() throws CommandException {
-        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
-        ctxFactory.setInput("q\n");
-        Arguments args = new SimpleArguments();
-        CommandContext ctx = ctxFactory.createContext(args);
-        cmd.run(ctx);
-        assertEquals("Thermostat > q\n", ctxFactory.getOutput());
-        assertEquals("", ctxFactory.getError());
-    }
-
-    @Test
-    public void testEofExits() throws CommandException {
-        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
-        ctxFactory.setInput("\u0004"); // EOF
-        Arguments args = new SimpleArguments();
-        CommandContext ctx = ctxFactory.createContext(args);
-        cmd.run(ctx);
-        assertEquals("Thermostat > ", ctxFactory.getOutput());
-        assertEquals("", ctxFactory.getError());
-    }
-
-    @Test
-    public void testDoNothingWithoutInput() throws CommandException {
-        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
-        ctxFactory.setInput("\nexit\n");
-        Arguments args = new SimpleArguments();
-        CommandContext ctx = ctxFactory.createContext(args);
-        cmd.run(ctx);
-        assertEquals("Thermostat > \nThermostat > exit\n", ctxFactory.getOutput());
-    }
-
-    @Test
-    public void testHistoryIsQueried() throws CommandException {
-        PersistentHistory history = mock(PersistentHistory.class);
-        when(history.previous()).thenReturn(true);
-        when(history.current()).thenReturn("old-history-value");
-
-        HistoryProvider provider = mock(HistoryProvider.class);
-        when(provider.get()).thenReturn(history);
-
-        ServiceReference ref = mock(ServiceReference.class);
-        
-        when(bundleContext.getServiceReference(Launcher.class.getName())).thenReturn(ref);
-        Launcher launcher = mock(Launcher.class);
-        when(bundleContext.getService(ref)).thenReturn(launcher);
-        TestCommandContextFactory ctxFactory = new TestCommandContextFactory(bundleContext);
-
-        cmd = new ShellCommand(bundleContext, provider);
-        
-        // "\u001b[A" is the escape code for up-arrow. use xxd -p to generate
-        ctxFactory.setInput("\u001b[A\nexit\n");
-        Arguments args = new SimpleArguments();
-        CommandContext ctx = ctxFactory.createContext(args);
-        cmd.run(ctx);
-
-        assertEquals("Thermostat > old-history-value\nThermostat > exit\n", ctxFactory.getOutput());
-        assertEquals("", ctxFactory.getError());
-
-        verify(launcher).setArgs(new String[] {"old-history-value"});
-        verify(launcher).run();
-    }
-
-    @Test
-    public void testHistoryIsUpdated() throws CommandException, IOException {
-        PersistentHistory mockHistory = mock(PersistentHistory.class);
-        HistoryProvider provider = mock(HistoryProvider.class);
-        when(provider.get()).thenReturn(mockHistory);
-
-        ServiceReference ref = mock(ServiceReference.class);
-        when(bundleContext.getServiceReference(Launcher.class.getName())).thenReturn(ref);
-        Launcher launcher = mock(Launcher.class);
-        when(bundleContext.getService(ref)).thenReturn(launcher);
-        TestCommandContextFactory ctxFactory = new TestCommandContextFactory(bundleContext);
-        
-        cmd = new ShellCommand(bundleContext, provider);
-        
-        ctxFactory.setInput("add-to-history\nexit\n");
-        Arguments args = new SimpleArguments();
-        CommandContext ctx = ctxFactory.createContext(args);
-        cmd.run(ctx);
-
-        verify(launcher).setArgs(new String[] {"add-to-history"});
-        verify(launcher).run();
-        verify(mockHistory).add("add-to-history");
-        verify(mockHistory).flush();
-
-        assertEquals("Thermostat > add-to-history\nThermostat > exit\n", ctxFactory.getOutput());
-        assertEquals("", ctxFactory.getError());
-    }
-
-    @Test(expected=CommandException.class)
-    public void testIOException() throws CommandException {
-        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
-        ctxFactory.setInputThrowsException(new IOException());
-        Arguments args = new SimpleArguments();
-        CommandContext ctx = ctxFactory.createContext(args);
-        cmd.run(ctx);
-    }
-
-    @Test(expected=CommandException.class)
-    public void testTerminalRestoreException() throws CommandException {
-        TerminalFactory.configure(Type.UNIX);
-        TerminalFactory.registerFlavor(Flavor.UNIX, TestTerminal.class);
-        TestCommandContextFactory ctxFactory = new TestCommandContextFactory();
-        ctxFactory.setInputThrowsException(new IOException());
-        Arguments args = new SimpleArguments();
-        CommandContext ctx = ctxFactory.createContext(args);
-        cmd.run(ctx);
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("shell", cmd.getName());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Test
-    public void testOptions() {
-        Options options = cmd.getOptions();
-        assertNotNull(options);
-        assertEquals(0, options.getOptions().size());
-    }
-
-    @Test
-    public void testStorageRequired() {
-        assertFalse(cmd.isStorageRequired());
-    }
-}
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/TestTerminal.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import jline.UnixTerminal;
-
-public class TestTerminal extends UnixTerminal {
-
-    public TestTerminal() throws Exception {
-        super();
-    }
-
-    @Override
-    public void restore() throws Exception {
-        super.restore();
-        throw new Exception();
-    }
-
-}
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/VMInfoCommandTest.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,239 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.TimeZone;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.DAOException;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.test.Bug;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-
-public class VMInfoCommandTest {
-
-    private static TimeZone defaultTimezone;
-
-    @BeforeClass
-    public static void setUpClass() {
-        defaultTimezone = TimeZone.getDefault();
-        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
-    }
-
-    @AfterClass
-    public static void tearDownClass() {
-        TimeZone.setDefault(defaultTimezone);
-    }
-
-    private VMInfoCommand cmd;
-    private VmInfoDAO vmsDAO;
-    private TestCommandContextFactory cmdCtxFactory;
-    private VmRef vm;
-
-    @Before
-    public void setUp() {
-        setupCommandContextFactory();
-
-        vmsDAO = mock(VmInfoDAO.class);
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmsDAO);
-
-        cmd = new VMInfoCommand(serviceProvider);
-
-        setupDAOs();
-    }
-
-    private void setupCommandContextFactory() {
-        cmdCtxFactory = new TestCommandContextFactory();
-    }
-
-    private void setupDAOs() {
-        HostRef host = new HostRef("123", "dummy");
-        vm = new VmRef(host, 234, "dummy");
-        Calendar start = Calendar.getInstance();
-        start.set(2012, 5, 7, 15, 32, 0);
-        Calendar end = Calendar.getInstance();
-        end.set(2013, 10, 1, 1, 22, 0);
-        VmInfo vmInfo = new VmInfo(234, start.getTimeInMillis(), end.getTimeInMillis(), "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0]);
-        when(vmsDAO.getVmInfo(vm)).thenReturn(vmInfo);
-        when(vmsDAO.getVmInfo(new VmRef(host, 9876, "dummy"))).thenThrow(new DAOException("Unknown VM ID: 9876"));
-        when(vmsDAO.getVMs(host)).thenReturn(Arrays.asList(vm));
-    }
-
-
-    @Test
-    public void testVmInfo() throws CommandException {
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("vmId", "234");
-        args.addArgument("hostId", "123");
-        cmd.run(cmdCtxFactory.createContext(args));
-        String expected = "Process ID:      234\n" +
-                          "Start time:      Thu Jun 07 15:32:00 UTC 2012\n" +
-                          "Stop time:       Fri Nov 01 01:22:00 UTC 2013\n" +
-                          "Main class:      mainClass\n" +
-                          "Command line:    commandLine\n" +
-                          "Java version:    vmVersion\n" +
-                          "Virtual machine: vmName\n" +
-                          "VM arguments:    vmArguments\n";
-        assertEquals(expected, cmdCtxFactory.getOutput());
-    }
-
-    @Test
-    public void testAllVmInfoForHost() throws CommandException {
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("hostId", "123");
-        cmd.run(cmdCtxFactory.createContext(args));
-        String expected = "Process ID:      234\n" +
-                          "Start time:      Thu Jun 07 15:32:00 UTC 2012\n" +
-                          "Stop time:       Fri Nov 01 01:22:00 UTC 2013\n" +
-                          "Main class:      mainClass\n" +
-                          "Command line:    commandLine\n" +
-                          "Java version:    vmVersion\n" +
-                          "Virtual machine: vmName\n" +
-                          "VM arguments:    vmArguments\n";
-        assertEquals(expected, cmdCtxFactory.getOutput());
-    }
-
-    @Test
-    public void testVmInfoUnknownVM() throws CommandException {
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("vmId", "9876");
-        args.addArgument("hostId", "123");
-        cmd.run(cmdCtxFactory.createContext(args));
-        String expected = "Unknown VM ID: 9876\n";
-        assertEquals("", cmdCtxFactory.getOutput());
-        assertEquals(expected, cmdCtxFactory.getError());
-    }
-
-    @Test
-    public void testVmInfoNonNumericalVMID() throws CommandException {
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("vmId", "fluff");
-        args.addArgument("hostId", "123");
-        try {
-            cmd.run(cmdCtxFactory.createContext(args));
-        } catch (CommandException ex) {
-            String expected = "Invalid VM ID: fluff";
-            assertEquals(expected, ex.getMessage());
-        }
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("vm-info", cmd.getName());
-    }
-
-    @Bug(id="1046",
-            summary="CLI vm-info display wrong stop time for living vms",
-            url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1046")
-    @Test
-    public void testStopTime() throws CommandException {
-        Calendar start = Calendar.getInstance();
-        start.set(2012, 5, 7, 15, 32, 0);
-        VmInfo vmInfo = new VmInfo(234, start.getTimeInMillis(), Long.MIN_VALUE, "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0]);
-        when(vmsDAO.getVmInfo(vm)).thenReturn(vmInfo);
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("vmId", "234");
-        args.addArgument("hostId", "123");
-        cmd.run(cmdCtxFactory.createContext(args));
-        String expected = "Process ID:      234\n" +
-                          "Start time:      Thu Jun 07 15:32:00 UTC 2012\n" +
-                          "Stop time:       <Running>\n" +
-                          "Main class:      mainClass\n" +
-                          "Command line:    commandLine\n" +
-                          "Java version:    vmVersion\n" +
-                          "Virtual machine: vmName\n" +
-                          "VM arguments:    vmArguments\n";
-        assertEquals(expected, cmdCtxFactory.getOutput());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Ignore
-    @Test
-    public void testOptions() {
-        Options options = cmd.getOptions();
-        assertNotNull(options);
-        assertEquals(2, options.getOptions().size());
-
-        assertTrue(options.hasOption("vmId"));
-        Option vm = options.getOption("vmId");
-        assertEquals("the ID of the VM to monitor", vm.getDescription());
-        assertFalse(vm.isRequired());
-        assertTrue(vm.hasArg());
-
-        assertTrue(options.hasOption("hostId"));
-        Option host = options.getOption("hostId");
-        assertEquals("the ID of the host to monitor", host.getDescription());
-        assertTrue(host.isRequired());
-        assertTrue(host.hasArg());
-    }
-
-    @Test
-    public void testStorageRequired() {
-        assertTrue(cmd.isStorageRequired());
-    }
-}
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/VmStatCommandTest.java	Thu Dec 13 09:52:03 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,333 +0,0 @@
-/*
- * Copyright 2012 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.tools.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.TimeZone;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.VmCpuStatDAO;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.VmCpuStat;
-import com.redhat.thermostat.storage.model.VmMemoryStat;
-import com.redhat.thermostat.storage.model.VmMemoryStat.Generation;
-import com.redhat.thermostat.storage.model.VmMemoryStat.Space;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-import com.redhat.thermostat.test.TestTimerFactory;
-
-public class VmStatCommandTest {
-
-    private static Locale defaultLocale;
-    private static TimeZone defaultTimeZone;
-
-    @BeforeClass
-    public static void setUpClass() {
-        defaultLocale = Locale.getDefault();
-        Locale.setDefault(Locale.US);
-        defaultTimeZone = TimeZone.getDefault();
-        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
-    }
-
-    @AfterClass
-    public static void tearDownClass() {
-        TimeZone.setDefault(defaultTimeZone);
-        Locale.setDefault(defaultLocale);
-    }
-
-    private VMStatCommand cmd;
-    private VmCpuStatDAO vmCpuStatDAO;
-    private TestCommandContextFactory cmdCtxFactory;
-    private VmMemoryStatDAO vmMemoryStatDAO;
-    private TestTimerFactory timerFactory;
-
-    @Before
-    public void setUp() {
-        timerFactory = new TestTimerFactory();
-        ApplicationService appSvc = mock(ApplicationService.class);
-        when(appSvc.getTimerFactory()).thenReturn(timerFactory);
-        setupCommandContextFactory();
-
-        setupDAOs();
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(VmCpuStatDAO.class)).thenReturn(vmCpuStatDAO);
-        when(serviceProvider.getServiceAllowNull(VmMemoryStatDAO.class)).thenReturn(vmMemoryStatDAO);
-        when(serviceProvider.getService(ApplicationService.class)).thenReturn(appSvc);
-
-        cmd = new VMStatCommand(serviceProvider);
-    }
-
-    @After
-    public void tearDown() {
-        vmCpuStatDAO = null;
-        cmdCtxFactory = null;
-        cmd = null;
-        timerFactory = null;
-    }
-
-    private void setupCommandContextFactory() {
-        cmdCtxFactory = new TestCommandContextFactory();
-    }
-
-    private void setupDAOs() {
-        vmCpuStatDAO = mock(VmCpuStatDAO.class);
-        int vmId = 234;
-        HostRef host = new HostRef("123", "dummy");
-        VmRef vm = new VmRef(host, 234, "dummy");
-        VmCpuStat cpustat1 = new VmCpuStat(2, vmId, 65);
-        VmCpuStat cpustat2 = new VmCpuStat(3, vmId, 70);
-        List<VmCpuStat> cpuStats = Arrays.asList(cpustat1, cpustat2);
-        List<VmCpuStat> cpuStats2 = Collections.emptyList();
-        when(vmCpuStatDAO.getLatestVmCpuStats(vm, Long.MIN_VALUE)).thenReturn(cpuStats).thenReturn(cpuStats2);
-
-        VmMemoryStat.Space space1_1_1 = newSpace("space1", 123456, 12345, 1, 0);
-        VmMemoryStat.Space space1_1_2 = newSpace("space2", 123456, 12345, 1, 0);
-        VmMemoryStat.Space[] spaces1_1 = new VmMemoryStat.Space[] { space1_1_1, space1_1_2 };
-        VmMemoryStat.Generation gen1_1 = newGeneration("gen1", "col1", 123456, 12345, spaces1_1);
-
-        VmMemoryStat.Space space1_2_1 = newSpace("space3", 123456, 12345, 1, 0);
-        VmMemoryStat.Space space1_2_2 = newSpace("space4", 123456, 12345, 1, 0);
-        VmMemoryStat.Space[] spaces1_2 = new VmMemoryStat.Space[] { space1_2_1, space1_2_2 };
-        VmMemoryStat.Generation gen1_2 = newGeneration("gen2", "col1", 123456, 12345, spaces1_2);
-
-        VmMemoryStat.Generation[] gens1 = new VmMemoryStat.Generation[] { gen1_1, gen1_2 };
-
-        VmMemoryStat memStat1 = new VmMemoryStat(1, vmId, gens1);
-
-        VmMemoryStat.Space space2_1_1 = newSpace("space1", 123456, 12345, 2, 0);
-        VmMemoryStat.Space space2_1_2 = newSpace("space2", 123456, 12345, 2, 0);
-        VmMemoryStat.Space[] spaces2_1 = new VmMemoryStat.Space[] { space2_1_1, space2_1_2 };
-        VmMemoryStat.Generation gen2_1 = newGeneration("gen1", "col1", 123456, 12345, spaces2_1);
-
-        VmMemoryStat.Space space2_2_1 = newSpace("space3", 123456, 12345, 3, 0);
-        VmMemoryStat.Space space2_2_2 = newSpace("space4", 123456, 12345, 4, 0);
-        VmMemoryStat.Space[] spaces2_2 = new VmMemoryStat.Space[] { space2_2_1, space2_2_2 };
-        VmMemoryStat.Generation gen2_2 = newGeneration("gen2", "col1", 123456, 12345, spaces2_2);
-
-        VmMemoryStat.Generation[] gens2 = new VmMemoryStat.Generation[] { gen2_1, gen2_2 };
-
-        VmMemoryStat memStat2 = new VmMemoryStat(2, vmId, gens2);
-
-        VmMemoryStat.Space space3_1_1 = newSpace("space1", 123456, 12345, 4, 0);
-        VmMemoryStat.Space space3_1_2 = newSpace("space2", 123456, 12345, 5, 0);
-        VmMemoryStat.Space[] spaces3_1 = new VmMemoryStat.Space[] { space3_1_1, space3_1_2 };
-        VmMemoryStat.Generation gen3_1 = newGeneration("gen1", "col1", 123456, 12345, spaces3_1);
-
-        VmMemoryStat.Space space3_2_1 = newSpace("space3", 123456, 12345, 6, 0);
-        VmMemoryStat.Space space3_2_2 = newSpace("space4", 123456, 12345, 7, 0);
-        VmMemoryStat.Space[] spaces3_2 = new VmMemoryStat.Space[] { space3_2_1, space3_2_2 };
-        VmMemoryStat.Generation gen3_2 = newGeneration("gen2", "col1", 123456, 12345, spaces3_2);
-
-        VmMemoryStat.Generation[] gens3 = new VmMemoryStat.Generation[] { gen3_1, gen3_2 };
-
-        VmMemoryStat memStat3 = new VmMemoryStat(3, vmId, gens3);
-
-        VmMemoryStat.Space space4_1_1 = newSpace("space1", 123456, 12345, 8, 0);
-        VmMemoryStat.Space space4_1_2 = newSpace("space2", 123456, 12345, 9, 0);
-        VmMemoryStat.Space[] spaces4_1 = new VmMemoryStat.Space[] { space4_1_1, space4_1_2 };
-        VmMemoryStat.Generation gen4_1 = newGeneration("gen4", "col1", 123456, 12345, spaces4_1);
-
-        VmMemoryStat.Space space4_2_1 = newSpace("space3", 123456, 12345, 10, 0);
-        VmMemoryStat.Space space4_2_2 = newSpace("space4", 123456, 12345, 11, 0);
-        VmMemoryStat.Space[] spaces4_2 = new VmMemoryStat.Space[] { space4_2_1, space4_2_2 };
-        VmMemoryStat.Generation gen4_2 = newGeneration("gen4", "col1", 123456, 12345, spaces4_2);
-
-        VmMemoryStat.Generation[] gens4 = new VmMemoryStat.Generation[] { gen4_1, gen4_2 };
-
-        VmMemoryStat memStat4 = new VmMemoryStat(4, vmId, gens4);
-
-        vmMemoryStatDAO = mock(VmMemoryStatDAO.class);
-        when(vmMemoryStatDAO.getLatestVmMemoryStats(vm, Long.MIN_VALUE))
-            .thenReturn(Arrays.asList(memStat1, memStat2, memStat3));
-
-        when(vmMemoryStatDAO.getLatestVmMemoryStats(vm, memStat3.getTimeStamp())).thenReturn(Arrays.asList(memStat4));
-
-    }
-
-    private Space newSpace(String name, long maxCapacity, long capacity, long used, int index) {
-        VmMemoryStat.Space space = new VmMemoryStat.Space();
-        space.setName(name);
-        space.setMaxCapacity(maxCapacity);
-        space.setCapacity(capacity);
-        space.setUsed(used);
-        space.setIndex(index);
-        return space;
-    }
-
-    private Generation newGeneration(String name, String collector, long maxCapacity, long capacity, Space[] spaces) {
-        VmMemoryStat.Generation gen = new VmMemoryStat.Generation();
-        gen.setName(name);
-        gen.setCollector(collector);
-        gen.setMaxCapacity(capacity);
-        gen.setSpaces(spaces);
-        return gen;
-    }
-
-    @Test
-    public void testBasicCPUMemory() throws CommandException {
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("vmId", "234");
-        args.addArgument("hostId", "123");
-        cmd.run(cmdCtxFactory.createContext(args));
-        String expected = "TIME        %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" +
-                          "12:00:00 AM      1 B        1 B        1 B        1 B\n" +
-                          "12:00:00 AM 65.0 2 B        2 B        3 B        4 B\n" +
-                          "12:00:00 AM 70.0 4 B        5 B        6 B        7 B\n";
-        assertEquals(expected, cmdCtxFactory.getOutput());
-
-    }
-
-    @Test
-    public void testContinuousMode() throws CommandException {
-        
-        Thread t = new Thread() {
-            public void run() {
-                SimpleArguments args = new SimpleArguments();
-                args.addArgument("vmId", "234");
-                args.addArgument("hostId", "123");
-                args.addArgument("continuous", "true");
-                try {
-                    cmd.run(cmdCtxFactory.createContext(args));
-                } catch (CommandException e) {
-                    // TODO Auto-generated catch block
-                    e.printStackTrace();
-                }
-            }
-        };
-        t.start();
-        try {
-            Thread.sleep(200);
-        } catch (InterruptedException e) {
-            return;
-        }
-        assertTrue(timerFactory.isActive());
-        String expected = "TIME        %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" +
-                          "12:00:00 AM      1 B        1 B        1 B        1 B\n" +
-                          "12:00:00 AM 65.0 2 B        2 B        3 B        4 B\n" +
-                          "12:00:00 AM 70.0 4 B        5 B        6 B        7 B\n";
-        assertEquals(expected, cmdCtxFactory.getOutput());
-        assertEquals(1, timerFactory.getDelay());
-        assertEquals(1, timerFactory.getInitialDelay());
-        assertEquals(TimeUnit.SECONDS, timerFactory.getTimeUnit());
-        assertEquals(Timer.SchedulingType.FIXED_RATE, timerFactory.getSchedulingType());
-
-        timerFactory.getAction().run();
-
-        expected = "TIME        %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" +
-                   "12:00:00 AM      1 B        1 B        1 B        1 B\n" +
-                   "12:00:00 AM 65.0 2 B        2 B        3 B        4 B\n" +
-                   "12:00:00 AM 70.0 4 B        5 B        6 B        7 B\n" +
-                   "12:00:00 AM 70.0 8 B        9 B        10 B       11 B\n";
-        assertEquals(expected, cmdCtxFactory.getOutput());
-        cmdCtxFactory.setInput(" ");
-        try {
-            Thread.sleep(200);
-        } catch (InterruptedException e) {
-            return;
-        }
-        assertFalse(timerFactory.isActive());
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("vm-stat", cmd.getName());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getUsage());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Ignore
-    @Test
-    public void testOptions() {
-        Options options = cmd.getOptions();
-        assertNotNull(options);
-        assertEquals(3, options.getOptions().size());
-
-        assertTrue(options.hasOption("vmId"));
-        Option vm = options.getOption("vmId");
-        assertEquals("the ID of the VM to monitor", vm.getDescription());
-        assertTrue(vm.isRequired());
-        assertTrue(vm.hasArg());
-
-        assertTrue(options.hasOption("hostId"));
-        Option host = options.getOption("hostId");
-        assertEquals("the ID of the host to monitor", host.getDescription());
-        assertTrue(host.isRequired());
-        assertTrue(host.hasArg());
-
-        assertTrue(options.hasOption("continuous"));
-        Option cont = options.getOption("continuous");
-        assertEquals("c", cont.getOpt());
-        assertEquals("print data continuously", cont.getDescription());
-        assertFalse(cont.isRequired());
-        assertFalse(cont.hasArg());
-    }
-
-    @Test
-    public void testStorageRequired() {
-        assertTrue(cmd.isStorageRequired());
-    }
-}
--- a/vm-heap-analysis/client-core/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ b/vm-heap-analysis/client-core/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -116,11 +116,6 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-tools</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-client-command</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/vm-heap-analysis/client-swing/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ b/vm-heap-analysis/client-swing/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -112,12 +112,6 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-tools</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-vm-heap-analysis-common</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/vm-heap-analysis/command/pom.xml	Thu Dec 13 09:52:03 2012 -0500
+++ b/vm-heap-analysis/command/pom.xml	Thu Dec 13 12:12:19 2012 -0500
@@ -83,16 +83,6 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.powermock</groupId>
-      <artifactId>powermock-api-mockito</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.powermock</groupId>
-      <artifactId>powermock-module-junit4</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
       <scope>provided</scope>
@@ -115,12 +105,6 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-tools</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-common-test</artifactId>
       <version>${project.version}</version>
       <scope>test</scope>
--- a/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ActivatorTest.java	Thu Dec 13 09:52:03 2012 -0500
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ActivatorTest.java	Thu Dec 13 12:12:19 2012 -0500
@@ -36,40 +36,19 @@
 
 package com.redhat.thermostat.vm.heap.analysis.command.internal;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
 import com.redhat.thermostat.common.cli.Command;
 import com.redhat.thermostat.test.StubBundleContext;
-import com.redhat.thermostat.tools.cli.ShellCommand;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(FrameworkUtil.class)
 public class ActivatorTest {
 
     @Test
     public void testCommandsRegistered() throws Exception {
-        /*
-         * ServiceLoader pulls in all commands from bundles on the classpath.
-         * During maven builds the tools bundle is on the classpath which uses
-         * the no-arg constructor of ShellCommand. That in turn uses
-         * FrameworkUtil. We need to mock FrameworkUtil here in order to avoid
-         * that throwing NPEs.
-         */
-        PowerMockito.mockStatic(FrameworkUtil.class);
-        Bundle mockBundle = mock(Bundle.class);
-        when(FrameworkUtil.getBundle(ShellCommand.class)).thenReturn(mockBundle);
         StubBundleContext ctx = new StubBundleContext();
-        when(mockBundle.getBundleContext()).thenReturn(ctx);
         Activator activator = new Activator();
         
         activator.start(ctx);
@@ -81,5 +60,9 @@
         assertTrue(ctx.isServiceRegistered(Command.class.getName(), ObjectInfoCommand.class));
         assertTrue(ctx.isServiceRegistered(Command.class.getName(), SaveHeapDumpToFileCommand.class));
         assertTrue(ctx.isServiceRegistered(Command.class.getName(), ShowHeapHistogramCommand.class));
+        
+        activator.stop(ctx);
+        
+        assertEquals(0, ctx.getAllServices().size());
     }
 }