changeset 160:cc759d53b7e9

RFC: Big Refactoring: new tools subproject Reviewed-by: rkennke, omajid, vanaltj Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-March/000510.html
author Mario Torre <neugens.limasoftware@gmail.com>
date Thu, 29 Mar 2012 17:34:20 +0200
parents c03293472933
children 44740832172e
files common/pom.xml distribution/config/agent.properties distribution/config/db.properties distribution/pom.xml distribution/scripts/thermostat-agent distribution/scripts/thermostat-db distribution/scripts/thermostat-init-layout tools/pom.xml tools/src/main/java/com/redhat/thermostat/tools/db/DBConfig.java tools/src/main/java/com/redhat/thermostat/tools/db/DBOptionParser.java tools/src/main/java/com/redhat/thermostat/tools/db/DBService.java tools/src/main/java/com/redhat/thermostat/tools/db/DBStartupConfiguration.java
diffstat 12 files changed, 857 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/common/pom.xml	Thu Mar 29 17:19:01 2012 +0200
+++ b/common/pom.xml	Thu Mar 29 17:34:20 2012 +0200
@@ -101,6 +101,11 @@
     	<artifactId>easymock</artifactId>
     	<version>3.1</version>
     </dependency>
+    <dependency>
+    	<groupId>net.sf.jopt-simple</groupId>
+    	<artifactId>jopt-simple</artifactId>
+    	<version>4.3</version>
+    </dependency>
   </dependencies>
 
   <properties>
--- a/distribution/config/agent.properties	Thu Mar 29 17:19:01 2012 +0200
+++ b/distribution/config/agent.properties	Thu Mar 29 17:34:20 2012 +0200
@@ -1,43 +1,5 @@
-## Mongo storage configuration
-# To be used when agent is running with --local argument
-mongod_port=27518
-mongo_launch_script=@project.build.directory@/scripts/localmongo.sh
-# To be used when connecting on localhost without --local argument (cluster)
-mongos_port=27517
-### Next few settings are used only by the mongo launch script
-config_port=27519
-config_url=mongodb://127.0.0.1
-### End section specific to launch script
-### Properties needed by client
-agent_launch_script=@project.build.directory@/scripts/thermostat-agent
-### End properties needed by client
-#
 ## Backend Configuration
-# This must be a comma separated list naming the fully qualified class name for
-# each backend that should run
-backends=
-# Backends may also use their name as prefix for backend-specific configuration.
-# For example, if backend foo requires a property called bar, then a line
-# containing 'foo.bar=baz' should be included.  'foo' in this case should be
-# the human-friendly alias for the backend, ie the string returned by the
-# getName() method of the class listed in the backends string.
-#
-# For each backend, there may be a .active property specified.
-# ie: for backend 'foo' there should be a 'foo.active = bar' line.  'bar'
-# must be a comma separated list including one or more of:
-#   'new' - The backend should attempt to attach to any new java process that
-#           starts.  Existing processes should not be instrumented.
-#   'all' - The backend should attempt to attach to all existing java
-#           java processes currently running on the machine.
-#   '[lvmid]' - One or more Local Virtual Machine IDs may be specified.  These
-#           are equivalent to the Linux process id.  This allows for the case
-#           of specific existing java processes to be instrumented.
-#
-# Alternatively, you may specify 'none' and the backend will not begin collecting
-# from any VM, but will be available to clients who wish to activate it.
-#
-# If there is no .active property specified, then 'none' is implied.
-#
-## Sample backend configuration
-#sample-backend.active=none
-#sample-backend.myconfiguration=property
\ No newline at end of file
+# This must be a comma separated list naming the backend
+# specific backend configurations will be searched under the
+# $THERMOSTAT_HOME/backends/[backend_name.properties]
+BACKENDS=system
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/config/db.properties	Thu Mar 29 17:34:20 2012 +0200
@@ -0,0 +1,4 @@
+LOCAL=27518
+CLUSTER=27517
+BIND=127.0.0.1
+URL=mongodb://127.0.0.1
--- a/distribution/pom.xml	Thu Mar 29 17:19:01 2012 +0200
+++ b/distribution/pom.xml	Thu Mar 29 17:34:20 2012 +0200
@@ -139,5 +139,10 @@
       <artifactId>thermostat-common</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+    	<groupId>com.redhat.thermostat</groupId>
+    	<artifactId>thermostat-tools</artifactId>
+    	<version>${project.version}</version>
+    </dependency>
   </dependencies>
 </project>
--- a/distribution/scripts/thermostat-agent	Thu Mar 29 17:19:01 2012 +0200
+++ b/distribution/scripts/thermostat-agent	Thu Mar 29 17:34:20 2012 +0200
@@ -39,60 +39,20 @@
 # Some necessary variables.
 JAVA_DIR="@java.dir@"
 JAVA="@java.home@/bin/java"
-JCOMMON_JAR="${JAVA_DIR}/jcommon.jar"
-MONGO_JAR="${JAVA_DIR}/mongo.jar"
-BSON_JAR="${JAVA_DIR}/bson.jar"
+
+THERMOSTAT_LIBS="${THERMOSTAT_HOME}/libs"
+
+JCOMMON_JAR="${THERMOSTAT_LIBS}/jcommon.jar"
+MONGO_JAR="${THERMOSTAT_LIBS}/mongo.jar"
+BSON_JAR="${THERMOSTAT_LIBS}/bson.jar"
+JOPT_JAR="${THERMOSTAT_LIBS}/jopt-simple-4.3.jar"
 TOOLS_JAR="@java.home@/../lib/tools.jar"
-AGENT_CLASSPATH="${JCOMMON_JAR}:${MONGO_JAR}:${BSON_JAR}:${TOOLS_JAR}"
-# Find the directory where thermostat is installed.
-# Note this will not work if there are symlinks to resolve that
-# are not full paths.
-SOURCE="${BASH_SOURCE[0]}"
-while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
-THERM_DIR=`dirname "$( cd -P "$( dirname "$SOURCE" )" && pwd )"`
-# Some other necessary variables.
-AGENT_CLASSPATH="${AGENT_CLASSPATH}:${THERM_DIR}/lib/thermostat-agent-@project.version@.jar:${THERM_DIR}/lib/thermostat-common-@project.version@.jar"
-AGENT_MAIN="com.redhat.thermostat.agent.Main"
-
-AGENT_ARGS="--properties ${THERM_DIR}/config/agent.properties"
-
-function usage {
-  echo "Usage:"
-  echo "  thermostat-agent <--local|--remote|--cluster>"
-}
-
-function run_agent {
-  ${JAVA} -cp ${AGENT_CLASSPATH} ${AGENT_MAIN} ${AGENT_ARGS}
-}
 
-function run_local {
-  AGENT_ARGS="${AGENT_ARGS} --local"
-  run_agent
-  exit $?
-}
+SERVICE_CLASSPATH="${JCOMMON_JAR}:${MONGO_JAR}:${BSON_JAR}:${TOOLS_JAR}:${JOPT_JAR}"
 
-function run_remote {
-  echo "Remote agent not yet supported."
-  exit -1
-}
-
-function run_cluster {
-  echo "Cluster agent not yet supported."
-  exit -1
-}
+THERM_DIR=${THERMOSTAT_LIBS}
 
-if [ $# != 1 ]; then
-  usage
-  exit -1
-fi
+SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERM_DIR}/thermostat-agent-@project.version@.jar:${THERM_DIR}/thermostat-common-@project.version@.jar:${THERM_DIR}/thermostat-tools-@project.version@.jar"
+SERVICE_MAIN="com.redhat.thermostat.agent.AgentService"
 
-if [ $1 = "--local" ]; then
-  run_local
-elif [ $1 = "--remote" ]; then
-  run_remote
-elif [ $1 = "--cluster" ]; then
-  run_cluster
-else
-  usage
-  exit -1
-fi
+${JAVA} -cp ${SERVICE_CLASSPATH} ${SERVICE_MAIN} $@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/scripts/thermostat-db	Thu Mar 29 17:34:20 2012 +0200
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# 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.
+#
+#####################################################################
+#
+# Some necessary variables.
+JAVA_DIR="@java.dir@"
+JAVA="@java.home@/bin/java"
+
+THERMOSTAT_LIBS="${THERMOSTAT_HOME}/libs"
+
+JCOMMON_JAR="${THERMOSTAT_LIBS}/jcommon.jar"
+MONGO_JAR="${THERMOSTAT_LIBS}/mongo.jar"
+BSON_JAR="${THERMOSTAT_LIBS}/bson.jar"
+JOPT_JAR="${THERMOSTAT_LIBS}/jopt-simple-4.3.jar"
+TOOLS_JAR="@java.home@/../lib/tools.jar"
+
+SERVICE_CLASSPATH="${JCOMMON_JAR}:${MONGO_JAR}:${BSON_JAR}:${TOOLS_JAR}:${JOPT_JAR}"
+
+THERM_DIR=${THERMOSTAT_LIBS}
+
+SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERM_DIR}/thermostat-agent-@project.version@.jar:${THERM_DIR}/thermostat-common-@project.version@.jar:${THERM_DIR}/thermostat-tools-@project.version@.jar"
+SERVICE_MAIN="com.redhat.thermostat.tools.db.DBService"
+
+${JAVA} -cp ${SERVICE_CLASSPATH} ${SERVICE_MAIN} $@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/scripts/thermostat-init-layout	Thu Mar 29 17:34:20 2012 +0200
@@ -0,0 +1,76 @@
+#!/bin/bash
+#
+# 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.
+#
+#####################################################################
+#
+# Some necessary variables.
+if [ "$THERMOSTAT_HOME" = "" ]; then
+    echo "THERMOSTAT_HOME not set!"
+
+else
+    THERMOSTAT_STORAGE="${THERMOSTAT_HOME}/storage/db"
+    THERMOSTAT_LOG="${THERMOSTAT_HOME}/storage/log"
+    THERMOSTAT_PID="${THERMOSTAT_HOME}/storage/run"
+    THERMOSTAT_BACKEND="${THERMOSTAT_HOME}/backends/system"
+    THERMOSTAT_BIN="${THERMOSTAT_HOME}/bin"
+    THERMOSTAT_AGENT_LOG="${THERMOSTAT_HOME}/agent/log"
+    THERMOSTAT_AGENT_RUN="${THERMOSTAT_HOME}/agent/run"
+    THERMOSTAT_LIBS="${THERMOSTAT_HOME}/libs"
+
+    echo "creating $THERMOSTAT_STORAGE"
+    mkdir -p $THERMOSTAT_STORAGE
+    
+    echo "creating $THERMOSTAT_LOG"
+    mkdir -p $THERMOSTAT_LOG
+    
+    echo "creating $THERMOSTAT_PID"
+    mkdir -p $THERMOSTAT_PID
+    
+    echo "creating $THERMOSTAT_BACKEND"
+    mkdir -p $THERMOSTAT_BACKEND
+    
+    echo "creating $THERMOSTAT_BIN"
+    mkdir -p $THERMOSTAT_BIN
+    
+    echo "creating $THERMOSTAT_AGENT_LOG"
+    mkdir -p $THERMOSTAT_AGENT_LOG
+    
+    echo "creating $THERMOSTAT_AGENT_RUN"
+    mkdir -p $THERMOSTAT_AGENT_RUN
+    
+    echo "creating $THERMOSTAT_LIBS"
+    mkdir -p $THERMOSTAT_LIBS
+fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pom.xml	Thu Mar 29 17:34:20 2012 +0200
@@ -0,0 +1,80 @@
+<?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-tools</artifactId>
+  <packaging>jar</packaging>
+
+  <name>Thermostat Tools</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.10</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.9.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-agent</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBConfig.java	Thu Mar 29 17:34:20 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.tools.db;
+
+/**
+ * Set of configuration option that the {@link DBService} understands.
+ */
+enum DBConfig {
+
+    BIND,
+    LOCAL,
+    CLUSTER,
+    URL,
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBOptionParser.java	Thu Mar 29 17:34:20 2012 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.tools.db;
+
+import java.io.IOException;
+import java.util.List;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+import com.redhat.thermostat.common.config.ThermostatOptionParser;
+import com.redhat.thermostat.tools.ApplicationState;
+
+class DBOptionParser implements ThermostatOptionParser {
+    
+    private boolean quiet;
+    
+    private DBStartupConfiguration configuration;
+    
+    private List<String> args;
+    private OptionParser parser;
+
+    private DBArgs serviceAction;
+    
+    private boolean dryRun;
+    
+    DBOptionParser(DBStartupConfiguration configuration, List<String> args) {
+        this.args = args;
+        this.configuration = configuration;
+        parser = new OptionParser();
+    }
+    
+    @Override
+    public void parse() throws InvalidConfigurationException {
+        
+        parser.accepts(DBArgs.START.option, DBArgs.START.description);
+        parser.accepts(DBArgs.STOP.option, DBArgs.STOP.description);
+        
+        parser.accepts(DBArgs.DRY.option, DBArgs.DRY.description);
+        
+        parser.accepts(DBArgs.HELP.option, DBArgs.HELP.description);
+        parser.accepts(DBArgs.QUIET.option, DBArgs.QUIET.description);
+             
+        OptionSet options = parser.parse(args.toArray(new String[0]));
+        if (!options.hasOptions() || options.has(DBArgs.HELP.option)) {
+            displayHelp();
+            return;
+        }
+
+        if (options.has(DBArgs.START.option)) {
+            serviceAction = DBArgs.START;
+        } else if (options.has(DBArgs.STOP.option)) {
+            serviceAction = DBArgs.STOP;
+            
+        } else {
+            throw new InvalidConfigurationException("either --start or --stop must be given");
+        }
+
+        if (options.has(DBArgs.DRY.option)) {
+            dryRun = true;
+        }
+        
+        if (options.has(DBArgs.QUIET.option)) {
+            quiet = true;
+        }
+        
+        // leave at the end, since it depends on the previous settings
+        String url = configuration.getUrl();
+        long port = configuration.getLocalPort();
+        configuration.setLocal(true);
+        if (options.has(DBArgs.CLUSTER.option)) {
+            port = configuration.getClusterPort();
+            configuration.setLocal(false);
+        }
+        configuration.setDBConnectionString(url + ":" + port);
+    }
+
+    boolean isDryRun() {
+        return dryRun;
+    }
+    
+    @Override
+    public void displayHelp() {
+        
+        if (quiet) return;
+        
+        try {
+            System.out.println("Module [DBService]");
+            parser.printHelpOn(System.out);
+        } catch (IOException ignore) {}
+    }
+    
+    ApplicationState getAction() {
+        return serviceAction.state;
+    }
+    
+    static enum DBArgs {
+                        
+        CLUSTER("cluster", "launch the db in cluster mode, if not specified, " +
+                "local mode is the default", ApplicationState.NONE),
+                
+        DRY("dry-run", "run the service in dry run mode", ApplicationState.NONE),
+        
+        HELP("help", "print this usage help", ApplicationState.HELP),
+        
+        START("start", "start the database", ApplicationState.START),
+        STOP("stop", "stop the database", ApplicationState.STOP),
+        
+        QUIET("quiet", "don't produce any output", ApplicationState.NONE);
+        
+        private String option;
+        private String description;
+        private ApplicationState state;
+        
+        DBArgs(String option, String description, ApplicationState state) {
+            this.option = option;
+            this.description = description;
+            this.state = state;
+        }
+    }
+
+    boolean isQuiet() {
+        return quiet;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBService.java	Thu Mar 29 17:34:20 2012 +0200
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.tools.db;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import com.redhat.thermostat.common.config.ConfigUtils;
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+import com.redhat.thermostat.common.utils.LoggedExternalProcess;
+import com.redhat.thermostat.tools.BasicApplication;
+
+public class DBService extends BasicApplication {
+
+    private DBStartupConfiguration configuration;
+    private DBOptionParser parser;
+    
+    private static final String [] MONGO_BASIC_ARGS = {
+        "mongod", "--quiet", "--fork", "--nojournal", "--noauth", "--bind_ip"
+    };
+    
+    private static final String [] MONGO_SHUTDOWN_ARGS = {
+        "mongod", "--shutdown", "--dbpath"
+    };
+    
+    @Override
+    public void parseArguments(List<String> args) throws InvalidConfigurationException {
+    
+        this.configuration = new DBStartupConfiguration();
+        // configs, read everything that is in the configs
+        File propertyFile = ConfigUtils.getStorageConfigurationFile();
+        if (!propertyFile.exists()) {
+            throw new InvalidConfigurationException("can't access database configuration file " +
+                                                    propertyFile);
+        }
+        readAndSetProperties(propertyFile);
+        
+        parser = new DBOptionParser(configuration, args);
+        parser.parse();
+        
+    }
+    
+    private void readAndSetProperties(File propertyFile) throws InvalidConfigurationException {
+    
+        Properties properties = new Properties();
+        try {
+            properties.load(new FileInputStream(propertyFile));
+            
+        } catch (IOException e) {
+            throw new InvalidConfigurationException(e);
+        }
+        
+        if (properties.containsKey(DBConfig.LOCAL.name())) {
+            String port = (String) properties.get(DBConfig.LOCAL.name());
+            int localPort = Integer.parseInt(port);
+            configuration.setLocalPort(localPort);
+        } else {
+            throw new InvalidConfigurationException(DBConfig.LOCAL + " property missing");
+        }
+        
+        if (properties.containsKey(DBConfig.CLUSTER.name())) {
+            String port = (String) properties.get(DBConfig.CLUSTER.name());
+            int localPort = Integer.parseInt(port);
+            configuration.setClusterPort(localPort);
+        } else {
+            throw new InvalidConfigurationException(DBConfig.CLUSTER + " property missing");
+        }
+        
+        if (properties.containsKey(DBConfig.URL.name())) {
+            String url = (String) properties.get(DBConfig.URL.name());
+            configuration.setUrl(url);
+        } else {
+            throw new InvalidConfigurationException(DBConfig.URL + " property missing");
+        }
+        
+        if (properties.containsKey(DBConfig.BIND.name())) {
+            String ip = (String) properties.get(DBConfig.BIND.name());
+            configuration.setBindIP(ip);
+        } else {
+            throw new InvalidConfigurationException(DBConfig.BIND + " property missing");
+        }
+    }
+    
+    private void startService() throws IOException, InterruptedException {
+        
+        String pid = checkPid();
+        if (pid != null) {
+            String message = "cannot start server " + configuration.getDBPath() +
+                    ", found pid file rom previous run, please, cleanup";
+            display(message);
+            notifyFail();
+            return;
+        }
+        
+        List<String> commands = new ArrayList<>(Arrays.asList(MONGO_BASIC_ARGS));
+       
+        // check that the db directory exist
+        display("starting storage server...");
+
+        commands.add(configuration.getBindIP());
+
+        commands.add("--dbpath");
+        commands.add(configuration.getDBPath().getCanonicalPath());
+
+        commands.add("--logpath");
+        commands.add(configuration.getLogFile().getCanonicalPath());
+
+        commands.add("--pidfilepath");
+        commands.add(configuration.getPidFile().getCanonicalPath());
+
+        commands.add("--port");
+        if (configuration.isLocal()) {
+            commands.add(Long.toString(configuration.getLocalPort()));
+        } else {
+            commands.add(Long.toString(configuration.getClusterPort()));
+        }
+        
+        LoggedExternalProcess process = new LoggedExternalProcess(commands);
+        int status = process.runAndReturnResult();
+        if (status == 0) {
+            pid = checkPid();
+            if (pid == null) status = -1;
+        }
+        
+        if (status == 0) {
+            display("server listening on ip: " + configuration.getDBConnectionString());
+            display("log file is here: " + configuration.getLogFile());
+            display("pid: " + pid);
+            notifySuccess();
+            
+        } else {
+            
+            String message = "cannot start server " + configuration.getDBPath() +
+                             ", exit status: " + status +
+                             ". Please check that your configuration is valid";
+            display(message);
+            notifyFail();
+        }
+    }
+    
+    private String checkPid() {
+        String pid = null;
+        // check the pid to be sure
+        File pidfile = configuration.getPidFile();
+        Charset charset = Charset.defaultCharset();
+        if (pidfile.exists()) {
+            try (BufferedReader reader = Files.newBufferedReader(pidfile.toPath(), charset)) {
+                pid = reader.readLine();
+                if (pid == null || pid.isEmpty()) {
+                    pid = null;
+                }
+            } catch (IOException ignore) {
+                ignore.printStackTrace();
+                pid = null;
+            }
+        }
+        
+        return pid;
+    }
+    
+    private void stopService() throws IOException, InterruptedException, InvalidConfigurationException {
+        check();
+        
+        List<String> commands = new ArrayList<>(Arrays.asList(MONGO_SHUTDOWN_ARGS));
+        commands.add(configuration.getDBPath().getCanonicalPath());
+
+        LoggedExternalProcess process = new LoggedExternalProcess(commands);
+        int status = process.runAndReturnResult();
+        if (status == 0) {
+            display("server shutdown complete: " + configuration.getDBPath());
+            display("log file is here: " + configuration.getLogFile());
+            notifySuccess();
+            
+        } else {
+            // TODO: check the pid and see if it's running or not
+            // perhaps was already down
+            String message = "cannot shutdown server " + configuration.getDBPath() +
+                    ", exit status: " + status +
+                    ". Please check that your configuration is valid";
+            display(message);
+            notifyFail();
+        }
+    }
+    
+    @Override
+    public void run() {
+        
+        if (parser.isDryRun()) return;
+        
+        try {
+            switch (parser.getAction()) {
+            case START:
+                startService();
+                break;
+            case STOP:
+                stopService();
+                break;
+            }
+        } catch (Exception e) {
+            // TODO: exception should be at least logged
+            notifyFail();
+        }
+    }
+    
+    private void check() throws InvalidConfigurationException {
+        if (!configuration.getDBPath().exists() ||
+                !configuration.getLogFile().getParentFile().exists() || 
+                !configuration.getPidFile().getParentFile().exists())
+        {
+            throw new InvalidConfigurationException("database directories do not exist...");
+        }
+    }
+    
+    @Override
+    public void printHelp() {
+        parser.displayHelp();
+    }
+    
+    @Override
+    public DBStartupConfiguration getConfiguration() {
+        return configuration;
+    }
+    
+    private void display(String message) {
+        if (!parser.isQuiet()) {
+            System.out.println(message);
+        }
+    }
+    
+    public static void main(String[] args) throws InvalidConfigurationException {
+        DBService service = new DBService();
+        service.parseArguments(Arrays.asList(args));
+        service.run();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBStartupConfiguration.java	Thu Mar 29 17:34:20 2012 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.tools.db;
+
+import java.io.File;
+
+import com.redhat.thermostat.common.config.ConfigUtils;
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+import com.redhat.thermostat.common.config.StartupConfiguration;
+
+class DBStartupConfiguration implements StartupConfiguration {
+    
+    private File dbPath;
+    private File logFile;
+    private File pidFile;
+        
+    private long localPort;
+    private long clusterPort;
+    
+    private String url;
+    
+    private String dbConnectionString;
+    
+    private String ip;
+    
+    private boolean local;
+    
+    public DBStartupConfiguration() throws InvalidConfigurationException {
+        dbPath = ConfigUtils.getStorageDirectory();
+        logFile = ConfigUtils.getStorageLogFile();
+        pidFile = ConfigUtils.getStoragePidFile();
+    }
+    
+    public File getDBPath() {
+        return dbPath;
+    }
+    
+    public File getLogFile() {
+        return logFile;
+    }
+    
+    public File getPidFile() {
+        return pidFile;
+    }
+   
+    void setLocalPort(long localPort) {
+        this.localPort = localPort;
+    }
+    
+    public long getLocalPort() {
+        return localPort;
+    }
+    
+    public long getClusterPort() {
+        return clusterPort;
+    }
+    
+    void setClusterPort(long clusterPort) {
+        this.clusterPort = clusterPort;
+    }
+    
+    void setUrl(String url) {
+        this.url = url;
+    }
+    
+    public String getUrl() {
+        return url;
+    }
+    
+    void setDBConnectionString(String dbConnectionString) {
+        this.dbConnectionString = dbConnectionString;
+    }
+    
+    @Override
+    public String getDBConnectionString() {
+        return dbConnectionString;
+    }
+
+    void setBindIP(String ip) {
+        this.ip = ip;
+    }
+    
+    public String getBindIP() {
+        return ip;
+    }
+    
+    void setLocal(boolean local) {
+        this.local = local;
+    }
+    
+    public boolean isLocal() {
+        return local;
+    }
+}
\ No newline at end of file