changeset 210:088b33902d21

Move CLI framework to common module. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-April/000722.html
author Roman Kennke <rkennke@redhat.com>
date Tue, 10 Apr 2012 21:27:33 +0200
parents 2f13d4668028
children d951bf8be570
files cli/pom.xml cli/src/main/java/com/redhat/thermostat/cli/Command.java cli/src/main/java/com/redhat/thermostat/cli/CommandContext.java cli/src/main/java/com/redhat/thermostat/cli/CommandContextFactory.java cli/src/main/java/com/redhat/thermostat/cli/CommandContextImpl.java cli/src/main/java/com/redhat/thermostat/cli/CommandRegistry.java cli/src/main/java/com/redhat/thermostat/cli/Console.java cli/src/main/java/com/redhat/thermostat/cli/HelpCommand.java cli/src/main/java/com/redhat/thermostat/cli/Main.java cli/src/main/java/com/redhat/thermostat/cli/SystemConsole.java cli/src/main/resources/META-INF/services/com.redhat.thermostat.cli.Command cli/src/test/java/com/redhat/thermostat/cli/CLITestEnvironment.java cli/src/test/java/com/redhat/thermostat/cli/CommandContextFactoryTest.java cli/src/test/java/com/redhat/thermostat/cli/CommandRegistryTest.java cli/src/test/java/com/redhat/thermostat/cli/HelpCommandTest.java cli/src/test/java/com/redhat/thermostat/cli/MainTest.java cli/src/test/java/com/redhat/thermostat/cli/TestCommand.java cli/src/test/java/com/redhat/thermostat/cli/TestCommandContextFactory.java common/src/main/java/com/redhat/thermostat/cli/Command.java common/src/main/java/com/redhat/thermostat/cli/CommandContext.java common/src/main/java/com/redhat/thermostat/cli/CommandContextFactory.java common/src/main/java/com/redhat/thermostat/cli/CommandContextImpl.java common/src/main/java/com/redhat/thermostat/cli/CommandRegistry.java common/src/main/java/com/redhat/thermostat/cli/Console.java common/src/main/java/com/redhat/thermostat/cli/HelpCommand.java common/src/main/java/com/redhat/thermostat/cli/Main.java common/src/main/java/com/redhat/thermostat/cli/SystemConsole.java common/src/test/java/com/redhat/thermostat/cli/CLITestEnvironment.java common/src/test/java/com/redhat/thermostat/cli/CommandContextFactoryTest.java common/src/test/java/com/redhat/thermostat/cli/CommandRegistryTest.java common/src/test/java/com/redhat/thermostat/cli/HelpCommandTest.java common/src/test/java/com/redhat/thermostat/cli/MainTest.java common/src/test/java/com/redhat/thermostat/cli/TestCommand.java common/src/test/java/com/redhat/thermostat/cli/TestCommandContextFactory.java
diffstat 34 files changed, 1265 insertions(+), 1340 deletions(-) [+]
line wrap: on
line diff
--- a/cli/pom.xml	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +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.2-SNAPSHOT</version>
-    <relativePath>..</relativePath>
-  </parent>
-
-  <artifactId>thermostat-cli</artifactId>
-  <packaging>jar</packaging>
-
-  <name>Thermostat CLI</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>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-  </dependencies>
-
-</project>
--- a/cli/src/main/java/com/redhat/thermostat/cli/Command.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +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.cli;
-
-interface Command {
-
-    void run(CommandContext ctx);
-
-    String getName();
-
-    String getDescription();
-
-    String getUsage();
-}
--- a/cli/src/main/java/com/redhat/thermostat/cli/CommandContext.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +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.cli;
-
-interface CommandContext {
-
-    Console getConsole();
-
-    String[] getArguments();
-
-    CommandRegistry getCommandRegistry();
-
-}
--- a/cli/src/main/java/com/redhat/thermostat/cli/CommandContextFactory.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +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.cli;
-
-class CommandContextFactory {
-
-    private static CommandContextFactory instance = new CommandContextFactory();
-
-    static CommandContextFactory getInstance() {
-        return instance;
-    }
-
-    static void setInstance(CommandContextFactory ctxFactory) {
-        instance = ctxFactory;
-    }
-
-    private CommandRegistry commandRegistry = new CommandRegistry();
-
-    CommandContext createContext(final String[] args) {
-        return new CommandContextImpl(args, commandRegistry);
-    }
-
-    CommandRegistry getCommandRegistry() {
-        return commandRegistry;
-    }
-
-}
--- a/cli/src/main/java/com/redhat/thermostat/cli/CommandContextImpl.java	Thu Apr 05 14:30:19 2012 +0200
+++ /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.cli;
-
-class CommandContextImpl implements CommandContext {
-
-    private String[] arguments;
-    private CommandRegistry commandRegistry;
-
-    CommandContextImpl(String[] args, CommandRegistry cmdReg) {
-        arguments = args;
-        commandRegistry = cmdReg;
-    }
-
-    @Override
-    public Console getConsole() {
-        return new SystemConsole();
-    }
-
-    @Override
-    public String[] getArguments() {
-        return arguments;
-    }
-
-    @Override
-    public CommandRegistry getCommandRegistry() {
-        return commandRegistry;
-    }
-
-}
--- a/cli/src/main/java/com/redhat/thermostat/cli/CommandRegistry.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +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.cli;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-class CommandRegistry {
-
-    private Map<String,Command> commands;
-
-    CommandRegistry() {
-        commands = new HashMap<>();
-    }
-
-    private void registerCommand(Command cmd) {
-        commands.put(cmd.getName(), cmd);
-    }
-
-    void registerCommands(Iterable<? extends Command> cmds) {
-        for (Command cmd : cmds) {
-            registerCommand(cmd);
-        }
-    }
-
-    Command getCommand(String name) {
-        return commands.get(name);
-    }
-
-    Collection<Command> getRegisteredCommands() {
-        return Collections.unmodifiableCollection(commands.values());
-    }
-
-}
--- a/cli/src/main/java/com/redhat/thermostat/cli/Console.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +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.cli;
-
-import java.io.InputStream;
-import java.io.PrintStream;
-
-public interface Console {
-
-    PrintStream getOutput();
-
-    PrintStream getError();
-
-    InputStream getInput();
-
-}
--- a/cli/src/main/java/com/redhat/thermostat/cli/HelpCommand.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +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.cli;
-
-import java.util.Collection;
-
-public class HelpCommand implements Command {
-
-    private static final String NAME = "help";
-    private static final String DESCRIPTION = "show help for a given command or help overview";
-    private static final String USAGE = "help [COMMAND]\n\n"
-            + DESCRIPTION + "\n\n"
-            + "    With no arguments, print a list of commands with short help messages.\n\n"
-            + "    Given a command, print help for that command.";
-
-    @Override
-    public void run(CommandContext ctx) {
-        String[] args = ctx.getArguments();
-        if (args.length == 0) {
-            printCommandSummaries(ctx);
-        } else {
-            printCommandUsage(ctx, args[0]);
-        }
-    }
-
-    private void printCommandSummaries(CommandContext ctx) {
-        CommandRegistry cmdRegistry = ctx.getCommandRegistry();
-
-        StringBuilder out = new StringBuilder();
-        out.append("list of commands:\n\n");
-
-        Collection<Command> commands = cmdRegistry.getRegisteredCommands();
-        for (Command cmd : commands) {
-            printCommandSummary(out, cmd);
-        }
-        ctx.getConsole().getOutput().print(out);
-    }
-
-    private void printCommandSummary(StringBuilder out, Command cmd) {
-        out.append(" ");
-        out.append(cmd.getName());
-        out.append("\t\t");
-        out.append(cmd.getDescription());
-        out.append("\n");
-    }
-
-    private void printCommandUsage(CommandContext ctx, String cmdName) {
-        Command cmd = ctx.getCommandRegistry().getCommand(cmdName);
-        if (cmd != null) {
-            ctx.getConsole().getOutput().print(cmd.getUsage());
-        } else {
-            printCommandSummaries(ctx);
-        }
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-    public String getDescription() {
-        return DESCRIPTION;
-    }
-
-    @Override
-    public String getUsage() {
-        return USAGE;
-    }
-
-}
--- a/cli/src/main/java/com/redhat/thermostat/cli/Main.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +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.cli;
-
-import java.util.Arrays;
-import java.util.ServiceLoader;
-
-public class Main {
-
-    public static void main(String[] args) {
-        new Main(args).run();
-    }
-
-    private Main(String[] args) {
-        this.args = args;
-    }
-
-    private String[] args;
-
-    private void run() {
-        registerDefaultCommands();
-        if (hasNoArguments()) {
-            runHelpCommand();
-        } else {
-            runCommandFromArguments();
-        }
-    }
-
-    private boolean hasNoArguments() {
-        return args.length == 0;
-    }
-
-    private void runHelpCommand() {
-        runCommand("help", new String[0]);
-    }
-
-    private void runCommandFromArguments() {
-        runCommand(args[0], Arrays.copyOfRange(args, 1, args.length));
-    }
-
-    private void runCommand(String cmdName, String[] cmdArgs) {
-        CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance();
-        CommandRegistry registry = cmdCtxFactory.getCommandRegistry();
-        Command cmd = registry.getCommand(cmdName);
-        CommandContext ctx = cmdCtxFactory.createContext(cmdArgs);
-        cmd.run(ctx);
-    }
-
-    private void registerDefaultCommands() {
-        CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance();
-        CommandRegistry registry = cmdCtxFactory.getCommandRegistry();
-        ServiceLoader<Command> cmds = ServiceLoader.load(Command.class);
-        registry.registerCommands(cmds);
-    }
-}
--- a/cli/src/main/java/com/redhat/thermostat/cli/SystemConsole.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +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.cli;
-
-import java.io.InputStream;
-import java.io.PrintStream;
-
-class SystemConsole implements Console {
-
-    @Override
-    public PrintStream getOutput() {
-        return System.out;
-    }
-
-    @Override
-    public PrintStream getError() {
-        return System.err;
-    }
-
-    @Override
-    public InputStream getInput() {
-        return System.in;
-    }
-
-}
--- a/cli/src/main/resources/META-INF/services/com.redhat.thermostat.cli.Command	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-com.redhat.thermostat.cli.HelpCommand
--- a/cli/src/test/java/com/redhat/thermostat/cli/CLITestEnvironment.java	Thu Apr 05 14:30:19 2012 +0200
+++ /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.cli;
-
-public class CLITestEnvironment {
-
-    public static void setUp() {
-        reset();
-    }
-
-    public static void tearDown() {
-        reset();
-    }
-
-    private static void reset() {
-        CommandContextFactory.setInstance(new CommandContextFactory());
-    }
-
-}
--- a/cli/src/test/java/com/redhat/thermostat/cli/CommandContextFactoryTest.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +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.cli;
-
-import static org.junit.Assert.*;
-
-import org.junit.Test;
-
-public class CommandContextFactoryTest {
-
-    @Test
-    public void testDefaultInstance() {
-        CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance();
-        CommandContext ctx = cmdCtxFactory.createContext(new String[] {"arg1", "arg2"});
-        assertSame(System.out, ctx.getConsole().getOutput());
-        assertSame(System.err, ctx.getConsole().getError());
-        assertSame(System.in, ctx.getConsole().getInput());
-        assertArrayEquals(new String[] {"arg1", "arg2"}, ctx.getArguments());
-        assertNotNull(cmdCtxFactory.getCommandRegistry());
-        assertNotNull(ctx.getCommandRegistry());
-        assertSame(cmdCtxFactory.getCommandRegistry(), ctx.getCommandRegistry());
-    }
-
-}
--- a/cli/src/test/java/com/redhat/thermostat/cli/CommandRegistryTest.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +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.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class CommandRegistryTest {
-
-    private CommandRegistry registry;
-    private Command cmd1;
-    private Command cmd2;
-
-    @Before
-    public void setUp() {
-        registry = new CommandRegistry();
-        cmd1 = createCommand("test1");
-        cmd2 = createCommand("test2");
-        registry.registerCommands(Arrays.asList(cmd1, cmd2));
-    }
-
-    @After
-    public void tearDown() {
-        cmd2 = null;
-        cmd1 = null;
-        registry = null;
-    }
-
-    private Command createCommand(String name) {
-        Command cmd = mock(Command.class);
-        when(cmd.getName()).thenReturn(name);
-        return cmd;
-    }
-
-    @Test
-    public void testRegisterCommands() {
-        runAndVerifyCommand("test1", cmd1);
-        runAndVerifyCommand("test2", cmd2);
-    }
-
-    private void runAndVerifyCommand(String name, Command cmd) {
-        Command actualCmd = registry.getCommand(name);
-        TestCommandContextFactory cf = new TestCommandContextFactory();
-        CommandContext ctx = cf.createContext(new String[0]);
-        actualCmd.run(ctx);
-        verify(cmd).run(ctx);
-    }
-
-    @Test
-    public void testGetCommands() {
-        Collection<Command> cmds = registry.getRegisteredCommands();
-        assertTrue(cmds.contains(cmd1));
-        assertTrue(cmds.contains(cmd2));
-        assertEquals(2, cmds.size());
-    }
-}
--- a/cli/src/test/java/com/redhat/thermostat/cli/HelpCommandTest.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +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.cli;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.Arrays;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class HelpCommandTest {
-
-    private TestCommandContextFactory  ctxFactory;
-
-    @Before
-    public void setUp() {
-
-        CLITestEnvironment.setUp();
-        ctxFactory = new TestCommandContextFactory();
-        CommandContextFactory.setInstance(ctxFactory);
-
-
-    }
-
-    @After
-    public void tearDown() {
-        CLITestEnvironment.tearDown();
-    }
-
-    @Test
-    public void testName() {
-        HelpCommand cmd = new HelpCommand();
-        assertEquals("help", cmd.getName());
-    }
-
-    @Test
-    public void verifyHelpNoArgPrintsListOfCommandsNoCommands() {
-
-        HelpCommand cmd = new HelpCommand();
-        cmd.run(ctxFactory.createContext(new String[0]));
-        String expected = "list of commands:\n\n";
-        String actual = ctxFactory.getOutput();
-        assertEquals(expected, actual);
-    }
-
-    @Test
-    public void verifyHelpNoArgPrintsListOfCommands2Commands() {
-
-        TestCommand cmd1 = new TestCommand("test1");
-        cmd1.setDescription("test command 1");
-        TestCommand cmd2 = new TestCommand("test2");
-        cmd2.setDescription("test command 2");
-        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1, cmd2));
-
-        HelpCommand cmd = new HelpCommand();
-        cmd.run(ctxFactory.createContext(new String[0]));
-        String expected = "list of commands:\n\n"
-                          + " test1\t\ttest command 1\n"
-                          + " test2\t\ttest command 2\n";
-        String actual = ctxFactory.getOutput();
-        assertEquals(expected, actual);
-    }
-
-    @Test
-    public void verifyHelpKnownCmdPrintsCommandUsage() {
-        TestCommand cmd1 = new TestCommand("test1");
-        String usage = "test usage command 1";
-        cmd1.setUsage(usage);
-        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1));
-
-        HelpCommand cmd = new HelpCommand();
-        cmd.run(ctxFactory.createContext(new String[] { "test1" }));
-
-        String actual = ctxFactory.getOutput();
-        assertEquals(usage, actual);
-    }
-
-    @Test
-    public void verifyHelpUnknownCmdPrintsSummaries() {
-        TestCommand cmd1 = new TestCommand("test1");
-        cmd1.setUsage("test usage command 1");
-        cmd1.setDescription("test command 1");
-        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1));
-
-        HelpCommand cmd = new HelpCommand();
-        cmd.run(ctxFactory.createContext(new String[] { "test12" }));
-
-        String expected = "list of commands:\n\n"
-                + " test1\t\ttest command 1\n";
-        String actual = ctxFactory.getOutput();
-        assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testDescription() {
-        HelpCommand cmd = new HelpCommand();
-        assertEquals("show help for a given command or help overview", cmd.getDescription());
-    }
-
-    @Test
-    public void testUsage() {
-        HelpCommand cmd = new HelpCommand();
-        String expected = "help [COMMAND]\n\n"
-                          + "show help for a given command or help overview\n\n"
-                          + "    With no arguments, print a list of commands with short help messages.\n\n"
-                          + "    Given a command, print help for that command.";
-
-        assertEquals(expected, cmd.getUsage());
-    }
-}
--- a/cli/src/test/java/com/redhat/thermostat/cli/MainTest.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +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.cli;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.Arrays;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class MainTest {
-
-    private static class TestCmd1 implements TestCommand.Handle {
-
-        @Override
-        public void run(CommandContext ctx) {
-            ctx.getConsole().getOutput().print(ctx.getArguments()[0] + ", " + ctx.getArguments()[1]);
-        }
-
-    }
-
-    private static class TestCmd2 implements TestCommand.Handle {
-        @Override
-        public void run(CommandContext ctx) {
-            ctx.getConsole().getOutput().print(ctx.getArguments()[1] + ": " + ctx.getArguments()[0]);
-        }
-    }
-
-    private TestCommandContextFactory  ctxFactory;
-
-    @Before
-    public void setUp() {
-
-        CLITestEnvironment.setUp();
-        ctxFactory = new TestCommandContextFactory();
-        CommandContextFactory.setInstance(ctxFactory);
-
-        TestCommand cmd1 = new TestCommand("test1", new TestCmd1());
-        cmd1.setDescription("description 1");
-        TestCommand cmd2 = new TestCommand("test2", new TestCmd2());
-        cmd2.setDescription("description 2");
-        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1, cmd2));
-
-    }
-
-    @After
-    public void tearDown() {
-        CLITestEnvironment.tearDown();
-    }
-
-    @Test
-    public void testMain() {
-        runAndVerifyCommand(new String[] {"test1", "Hello", "World"}, "Hello, World");
-
-        ctxFactory.reset();
-
-        runAndVerifyCommand(new String[] {"test2", "Hello", "World"}, "World: Hello");
-    }
-
-    @Test
-    public void testMainNoArgs() {
-        String expected = "list of commands:\n\n"
-                          + " help\t\tshow help for a given command or help overview\n"
-                          + " test1\t\tdescription 1\n"
-                          + " test2\t\tdescription 2\n";
-        runAndVerifyCommand(new String[0], expected);
-    }
-
-    private void runAndVerifyCommand(String[] args, String expected) {
-        Main.main(args);
-        assertEquals(expected, ctxFactory.getOutput());
-    }
-}
--- a/cli/src/test/java/com/redhat/thermostat/cli/TestCommand.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +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.cli;
-
-
-class TestCommand implements Command {
-
-    private String name;
-    private Handle handle;
-    private String description;
-    private String usage;
-
-    static interface Handle {
-        public void run(CommandContext ctx);
-    }
-
-    TestCommand(String name) {
-        this(name, null);
-    }
-
-    TestCommand(String name, Handle r) {
-        this.name = name;
-        this.handle = r;
-    }
-
-    @Override
-    public void run(CommandContext ctx) {
-        handle.run(ctx);
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public String getDescription() {
-        return description;
-    }
-
-    void setDescription(String desc) {
-        description = desc;
-    }
-
-    @Override
-    public String getUsage() {
-        return usage;
-    }
-
-    void setUsage(String usage) {
-        this.usage = usage;
-    }
-}
--- a/cli/src/test/java/com/redhat/thermostat/cli/TestCommandContextFactory.java	Thu Apr 05 14:30:19 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +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.cli;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.PrintStream;
-
-class TestCommandContextFactory extends CommandContextFactory {
-
-    private ByteArrayOutputStream out;
-    private ByteArrayOutputStream err;
-    private ByteArrayInputStream in;
-
-    TestCommandContextFactory() {
-        reset();
-    }
-
-    private CommandRegistry commandRegistry = new CommandRegistry();
-
-    private class TestConsole implements Console {
-
-        @Override
-        public PrintStream getOutput() {
-            return new PrintStream(out);
-        }
-
-        @Override
-        public PrintStream getError() {
-            return new PrintStream(err);
-        }
-
-        @Override
-        public InputStream getInput() {
-            return in;
-        }
-        
-    }
-
-    @Override
-    CommandContext createContext(final String[] args) {
-        return new CommandContext() {
-
-            @Override
-            public Console getConsole() {
-                return new TestConsole();
-            }
-
-            @Override
-            public String[] getArguments() {
-                return args;
-            }
-
-            @Override
-            public CommandRegistry getCommandRegistry() {
-                return commandRegistry;
-            }
-            
-        };
-    }
-
-    @Override
-    CommandRegistry getCommandRegistry() {
-        return commandRegistry;
-    }
-
-    String getOutput() {
-        return new String(out.toByteArray());
-    }
-
-    void setInput(String input) {
-        in = new ByteArrayInputStream(input.getBytes());
-    }
-
-    Object getError() {
-        return new String(err.toByteArray());
-    }
-
-    void reset() {
-        out = new ByteArrayOutputStream();
-        err = new ByteArrayOutputStream();
-        in = new ByteArrayInputStream(new byte[0]);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/cli/Command.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,48 @@
+/*
+ * 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.cli;
+
+interface Command {
+
+    void run(CommandContext ctx);
+
+    String getName();
+
+    String getDescription();
+
+    String getUsage();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/cli/CommandContext.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.cli;
+
+interface CommandContext {
+
+    Console getConsole();
+
+    String[] getArguments();
+
+    CommandRegistry getCommandRegistry();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/cli/CommandContextFactory.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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.cli;
+
+class CommandContextFactory {
+
+    private static CommandContextFactory instance = new CommandContextFactory();
+
+    static CommandContextFactory getInstance() {
+        return instance;
+    }
+
+    static void setInstance(CommandContextFactory ctxFactory) {
+        instance = ctxFactory;
+    }
+
+    private CommandRegistry commandRegistry = new CommandRegistry();
+
+    CommandContext createContext(final String[] args) {
+        return new CommandContextImpl(args, commandRegistry);
+    }
+
+    CommandRegistry getCommandRegistry() {
+        return commandRegistry;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/cli/CommandContextImpl.java	Tue Apr 10 21:27:33 2012 +0200
@@ -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.cli;
+
+class CommandContextImpl implements CommandContext {
+
+    private String[] arguments;
+    private CommandRegistry commandRegistry;
+
+    CommandContextImpl(String[] args, CommandRegistry cmdReg) {
+        arguments = args;
+        commandRegistry = cmdReg;
+    }
+
+    @Override
+    public Console getConsole() {
+        return new SystemConsole();
+    }
+
+    @Override
+    public String[] getArguments() {
+        return arguments;
+    }
+
+    @Override
+    public CommandRegistry getCommandRegistry() {
+        return commandRegistry;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/cli/CommandRegistry.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.cli;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+class CommandRegistry {
+
+    private Map<String,Command> commands;
+
+    CommandRegistry() {
+        commands = new HashMap<>();
+    }
+
+    private void registerCommand(Command cmd) {
+        commands.put(cmd.getName(), cmd);
+    }
+
+    void registerCommands(Iterable<? extends Command> cmds) {
+        for (Command cmd : cmds) {
+            registerCommand(cmd);
+        }
+    }
+
+    Command getCommand(String name) {
+        return commands.get(name);
+    }
+
+    Collection<Command> getRegisteredCommands() {
+        return Collections.unmodifiableCollection(commands.values());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/cli/Console.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,50 @@
+/*
+ * 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.cli;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+
+public interface Console {
+
+    PrintStream getOutput();
+
+    PrintStream getError();
+
+    InputStream getInput();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/cli/HelpCommand.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,105 @@
+/*
+ * 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.cli;
+
+import java.util.Collection;
+
+public class HelpCommand implements Command {
+
+    private static final String NAME = "help";
+    private static final String DESCRIPTION = "show help for a given command or help overview";
+    private static final String USAGE = "help [COMMAND]\n\n"
+            + DESCRIPTION + "\n\n"
+            + "    With no arguments, print a list of commands with short help messages.\n\n"
+            + "    Given a command, print help for that command.";
+
+    @Override
+    public void run(CommandContext ctx) {
+        String[] args = ctx.getArguments();
+        if (args.length == 0) {
+            printCommandSummaries(ctx);
+        } else {
+            printCommandUsage(ctx, args[0]);
+        }
+    }
+
+    private void printCommandSummaries(CommandContext ctx) {
+        CommandRegistry cmdRegistry = ctx.getCommandRegistry();
+
+        StringBuilder out = new StringBuilder();
+        out.append("list of commands:\n\n");
+
+        Collection<Command> commands = cmdRegistry.getRegisteredCommands();
+        for (Command cmd : commands) {
+            printCommandSummary(out, cmd);
+        }
+        ctx.getConsole().getOutput().print(out);
+    }
+
+    private void printCommandSummary(StringBuilder out, Command cmd) {
+        out.append(" ");
+        out.append(cmd.getName());
+        out.append("\t\t");
+        out.append(cmd.getDescription());
+        out.append("\n");
+    }
+
+    private void printCommandUsage(CommandContext ctx, String cmdName) {
+        Command cmd = ctx.getCommandRegistry().getCommand(cmdName);
+        if (cmd != null) {
+            ctx.getConsole().getOutput().print(cmd.getUsage());
+        } else {
+            printCommandSummaries(ctx);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public String getDescription() {
+        return DESCRIPTION;
+    }
+
+    @Override
+    public String getUsage() {
+        return USAGE;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/cli/Main.java	Tue Apr 10 21:27:33 2012 +0200
@@ -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.cli;
+
+import java.util.Arrays;
+import java.util.ServiceLoader;
+
+public class Main {
+
+    public static void main(String[] args) {
+        new Main(args).run();
+    }
+
+    private Main(String[] args) {
+        this.args = args;
+    }
+
+    private String[] args;
+
+    private void run() {
+        registerDefaultCommands();
+        if (hasNoArguments()) {
+            runHelpCommand();
+        } else {
+            runCommandFromArguments();
+        }
+    }
+
+    private boolean hasNoArguments() {
+        return args.length == 0;
+    }
+
+    private void runHelpCommand() {
+        runCommand("help", new String[0]);
+    }
+
+    private void runCommandFromArguments() {
+        runCommand(args[0], Arrays.copyOfRange(args, 1, args.length));
+    }
+
+    private void runCommand(String cmdName, String[] cmdArgs) {
+        CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance();
+        CommandRegistry registry = cmdCtxFactory.getCommandRegistry();
+        Command cmd = registry.getCommand(cmdName);
+        CommandContext ctx = cmdCtxFactory.createContext(cmdArgs);
+        cmd.run(ctx);
+    }
+
+    private void registerDefaultCommands() {
+        CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance();
+        CommandRegistry registry = cmdCtxFactory.getCommandRegistry();
+        ServiceLoader<Command> cmds = ServiceLoader.load(Command.class);
+        registry.registerCommands(cmds);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/cli/SystemConsole.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.cli;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+
+class SystemConsole implements Console {
+
+    @Override
+    public PrintStream getOutput() {
+        return System.out;
+    }
+
+    @Override
+    public PrintStream getError() {
+        return System.err;
+    }
+
+    @Override
+    public InputStream getInput() {
+        return System.in;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/cli/CLITestEnvironment.java	Tue Apr 10 21:27:33 2012 +0200
@@ -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.cli;
+
+public class CLITestEnvironment {
+
+    public static void setUp() {
+        reset();
+    }
+
+    public static void tearDown() {
+        reset();
+    }
+
+    private static void reset() {
+        CommandContextFactory.setInstance(new CommandContextFactory());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/cli/CommandContextFactoryTest.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.cli;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class CommandContextFactoryTest {
+
+    @Test
+    public void testDefaultInstance() {
+        CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance();
+        CommandContext ctx = cmdCtxFactory.createContext(new String[] {"arg1", "arg2"});
+        assertSame(System.out, ctx.getConsole().getOutput());
+        assertSame(System.err, ctx.getConsole().getError());
+        assertSame(System.in, ctx.getConsole().getInput());
+        assertArrayEquals(new String[] {"arg1", "arg2"}, ctx.getArguments());
+        assertNotNull(cmdCtxFactory.getCommandRegistry());
+        assertNotNull(ctx.getCommandRegistry());
+        assertSame(cmdCtxFactory.getCommandRegistry(), ctx.getCommandRegistry());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/cli/CommandRegistryTest.java	Tue Apr 10 21:27:33 2012 +0200
@@ -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.cli;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CommandRegistryTest {
+
+    private CommandRegistry registry;
+    private Command cmd1;
+    private Command cmd2;
+
+    @Before
+    public void setUp() {
+        registry = new CommandRegistry();
+        cmd1 = createCommand("test1");
+        cmd2 = createCommand("test2");
+        registry.registerCommands(Arrays.asList(cmd1, cmd2));
+    }
+
+    @After
+    public void tearDown() {
+        cmd2 = null;
+        cmd1 = null;
+        registry = null;
+    }
+
+    private Command createCommand(String name) {
+        Command cmd = mock(Command.class);
+        when(cmd.getName()).thenReturn(name);
+        return cmd;
+    }
+
+    @Test
+    public void testRegisterCommands() {
+        runAndVerifyCommand("test1", cmd1);
+        runAndVerifyCommand("test2", cmd2);
+    }
+
+    private void runAndVerifyCommand(String name, Command cmd) {
+        Command actualCmd = registry.getCommand(name);
+        TestCommandContextFactory cf = new TestCommandContextFactory();
+        CommandContext ctx = cf.createContext(new String[0]);
+        actualCmd.run(ctx);
+        verify(cmd).run(ctx);
+    }
+
+    @Test
+    public void testGetCommands() {
+        Collection<Command> cmds = registry.getRegisteredCommands();
+        assertTrue(cmds.contains(cmd1));
+        assertTrue(cmds.contains(cmd2));
+        assertEquals(2, cmds.size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/cli/HelpCommandTest.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,146 @@
+/*
+ * 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.cli;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class HelpCommandTest {
+
+    private TestCommandContextFactory  ctxFactory;
+
+    @Before
+    public void setUp() {
+
+        CLITestEnvironment.setUp();
+        ctxFactory = new TestCommandContextFactory();
+        CommandContextFactory.setInstance(ctxFactory);
+
+
+    }
+
+    @After
+    public void tearDown() {
+        CLITestEnvironment.tearDown();
+    }
+
+    @Test
+    public void testName() {
+        HelpCommand cmd = new HelpCommand();
+        assertEquals("help", cmd.getName());
+    }
+
+    @Test
+    public void verifyHelpNoArgPrintsListOfCommandsNoCommands() {
+
+        HelpCommand cmd = new HelpCommand();
+        cmd.run(ctxFactory.createContext(new String[0]));
+        String expected = "list of commands:\n\n";
+        String actual = ctxFactory.getOutput();
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void verifyHelpNoArgPrintsListOfCommands2Commands() {
+
+        TestCommand cmd1 = new TestCommand("test1");
+        cmd1.setDescription("test command 1");
+        TestCommand cmd2 = new TestCommand("test2");
+        cmd2.setDescription("test command 2");
+        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1, cmd2));
+
+        HelpCommand cmd = new HelpCommand();
+        cmd.run(ctxFactory.createContext(new String[0]));
+        String expected = "list of commands:\n\n"
+                          + " test1\t\ttest command 1\n"
+                          + " test2\t\ttest command 2\n";
+        String actual = ctxFactory.getOutput();
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void verifyHelpKnownCmdPrintsCommandUsage() {
+        TestCommand cmd1 = new TestCommand("test1");
+        String usage = "test usage command 1";
+        cmd1.setUsage(usage);
+        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1));
+
+        HelpCommand cmd = new HelpCommand();
+        cmd.run(ctxFactory.createContext(new String[] { "test1" }));
+
+        String actual = ctxFactory.getOutput();
+        assertEquals(usage, actual);
+    }
+
+    @Test
+    public void verifyHelpUnknownCmdPrintsSummaries() {
+        TestCommand cmd1 = new TestCommand("test1");
+        cmd1.setUsage("test usage command 1");
+        cmd1.setDescription("test command 1");
+        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1));
+
+        HelpCommand cmd = new HelpCommand();
+        cmd.run(ctxFactory.createContext(new String[] { "test12" }));
+
+        String expected = "list of commands:\n\n"
+                + " test1\t\ttest command 1\n";
+        String actual = ctxFactory.getOutput();
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testDescription() {
+        HelpCommand cmd = new HelpCommand();
+        assertEquals("show help for a given command or help overview", cmd.getDescription());
+    }
+
+    @Test
+    public void testUsage() {
+        HelpCommand cmd = new HelpCommand();
+        String expected = "help [COMMAND]\n\n"
+                          + "show help for a given command or help overview\n\n"
+                          + "    With no arguments, print a list of commands with short help messages.\n\n"
+                          + "    Given a command, print help for that command.";
+
+        assertEquals(expected, cmd.getUsage());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/cli/MainTest.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,109 @@
+/*
+ * 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.cli;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MainTest {
+
+    private static class TestCmd1 implements TestCommand.Handle {
+
+        @Override
+        public void run(CommandContext ctx) {
+            ctx.getConsole().getOutput().print(ctx.getArguments()[0] + ", " + ctx.getArguments()[1]);
+        }
+
+    }
+
+    private static class TestCmd2 implements TestCommand.Handle {
+        @Override
+        public void run(CommandContext ctx) {
+            ctx.getConsole().getOutput().print(ctx.getArguments()[1] + ": " + ctx.getArguments()[0]);
+        }
+    }
+
+    private TestCommandContextFactory  ctxFactory;
+
+    @Before
+    public void setUp() {
+
+        CLITestEnvironment.setUp();
+        ctxFactory = new TestCommandContextFactory();
+        CommandContextFactory.setInstance(ctxFactory);
+
+        TestCommand cmd1 = new TestCommand("test1", new TestCmd1());
+        cmd1.setDescription("description 1");
+        TestCommand cmd2 = new TestCommand("test2", new TestCmd2());
+        cmd2.setDescription("description 2");
+        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1, cmd2, new HelpCommand()));
+
+    }
+
+    @After
+    public void tearDown() {
+        CLITestEnvironment.tearDown();
+    }
+
+    @Test
+    public void testMain() {
+        runAndVerifyCommand(new String[] {"test1", "Hello", "World"}, "Hello, World");
+
+        ctxFactory.reset();
+
+        runAndVerifyCommand(new String[] {"test2", "Hello", "World"}, "World: Hello");
+    }
+
+    @Test
+    public void testMainNoArgs() {
+        String expected = "list of commands:\n\n"
+                          + " help\t\tshow help for a given command or help overview\n"
+                          + " test1\t\tdescription 1\n"
+                          + " test2\t\tdescription 2\n";
+        runAndVerifyCommand(new String[0], expected);
+    }
+
+    private void runAndVerifyCommand(String[] args, String expected) {
+        Main.main(args);
+        assertEquals(expected, ctxFactory.getOutput());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/cli/TestCommand.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,87 @@
+/*
+ * 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.cli;
+
+
+class TestCommand implements Command {
+
+    private String name;
+    private Handle handle;
+    private String description;
+    private String usage;
+
+    static interface Handle {
+        public void run(CommandContext ctx);
+    }
+
+    TestCommand(String name) {
+        this(name, null);
+    }
+
+    TestCommand(String name, Handle r) {
+        this.name = name;
+        this.handle = r;
+    }
+
+    @Override
+    public void run(CommandContext ctx) {
+        handle.run(ctx);
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    void setDescription(String desc) {
+        description = desc;
+    }
+
+    @Override
+    public String getUsage() {
+        return usage;
+    }
+
+    void setUsage(String usage) {
+        this.usage = usage;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/cli/TestCommandContextFactory.java	Tue Apr 10 21:27:33 2012 +0200
@@ -0,0 +1,119 @@
+/*
+ * 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.cli;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+class TestCommandContextFactory extends CommandContextFactory {
+
+    private ByteArrayOutputStream out;
+    private ByteArrayOutputStream err;
+    private ByteArrayInputStream in;
+
+    TestCommandContextFactory() {
+        reset();
+    }
+
+    private CommandRegistry commandRegistry = new CommandRegistry();
+
+    private class TestConsole implements Console {
+
+        @Override
+        public PrintStream getOutput() {
+            return new PrintStream(out);
+        }
+
+        @Override
+        public PrintStream getError() {
+            return new PrintStream(err);
+        }
+
+        @Override
+        public InputStream getInput() {
+            return in;
+        }
+        
+    }
+
+    @Override
+    CommandContext createContext(final String[] args) {
+        return new CommandContext() {
+
+            @Override
+            public Console getConsole() {
+                return new TestConsole();
+            }
+
+            @Override
+            public String[] getArguments() {
+                return args;
+            }
+
+            @Override
+            public CommandRegistry getCommandRegistry() {
+                return commandRegistry;
+            }
+            
+        };
+    }
+
+    @Override
+    CommandRegistry getCommandRegistry() {
+        return commandRegistry;
+    }
+
+    String getOutput() {
+        return new String(out.toByteArray());
+    }
+
+    void setInput(String input) {
+        in = new ByteArrayInputStream(input.getBytes());
+    }
+
+    Object getError() {
+        return new String(err.toByteArray());
+    }
+
+    void reset() {
+        out = new ByteArrayOutputStream();
+        err = new ByteArrayOutputStream();
+        in = new ByteArrayInputStream(new byte[0]);
+    }
+}