Mercurial > hg > release > thermostat-0.9
changeset 66:1fdd16a78761
client starts own agent
author | Jon VanAlten <jon.vanalten@redhat.com> |
---|---|
date | Thu, 02 Feb 2012 10:53:45 -0500 |
parents | ad21cb32aad1 |
children | 3b1baa5f0bf2 |
files | build.xml config/agent.properties scripts/thermostat-agent scripts/thermostat-client-gui src/com/redhat/thermostat/client/ClientArgs.java src/com/redhat/thermostat/client/Main.java src/com/redhat/thermostat/client/MongoConnection.java src/com/redhat/thermostat/common/Constants.java |
diffstat | 8 files changed, 185 insertions(+), 77 deletions(-) [+] |
line wrap: on
line diff
--- a/build.xml Wed Feb 01 17:00:45 2012 -0500 +++ b/build.xml Thu Feb 02 10:53:45 2012 -0500 @@ -100,7 +100,7 @@ <target name="build-client-gui-classes" depends="build-common-classes"> <mkdir dir="${classes.dir}"/> <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="true"> - <include name="${client.path.prefix}**" /> + <include name="${client-gui.path.prefix}**" /> <classpath> <path location="${classes.dir}" /> <path refid="client-gui.classpath" /> @@ -112,8 +112,8 @@ <mkdir dir="${dist.dir}" /> <jar destfile="${client-gui.jar}" duplicate="fail"> <fileset dir="${classes.dir}"> - <include name="${client.path.prefix}**/*.class" /> - <include name="${client.path.prefix}**/*.properties" /> + <include name="${client-gui.path.prefix}**/*.class" /> + <include name="${client-gui.path.prefix}**/*.properties" /> </fileset> </jar> </target>
--- a/config/agent.properties Wed Feb 01 17:00:45 2012 -0500 +++ b/config/agent.properties Thu Feb 02 10:53:45 2012 -0500 @@ -4,9 +4,13 @@ mongo_launch_script=@THERM_INSTALL_DIR@/scripts/localmongo.sh # To be used when connecting on localhost without --local argument (cluster) mongos_port=27517 -### Below settings are used only by the mongo launch script +### 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=@THERM_INSTALL_DIR@/scripts/thermostat-agent +### End properties needed by client # ## Backend Configuration # This must be a comma separated list naming the fully qualified class name for
--- a/scripts/thermostat-agent Wed Feb 01 17:00:45 2012 -0500 +++ b/scripts/thermostat-agent Thu Feb 02 10:53:45 2012 -0500 @@ -38,7 +38,7 @@ # # Some necessary variables. JAVA_DIR="@JAVA_DIR@" -JAVA_EXE="@JAVA_HOME@/bin/java" +JAVA="@JAVA_HOME@/bin/java" JCOMMON_JAR="${JAVA_DIR}/jcommon.jar" MONGO_JAR="${JAVA_DIR}/mongo.jar" BSON_JAR="${JAVA_DIR}/bson.jar" @@ -62,7 +62,7 @@ } function run_agent { - ${JAVA_EXE} -cp ${AGENT_CLASSPATH} ${AGENT_MAIN} ${AGENT_ARGS} + ${JAVA} -cp ${AGENT_CLASSPATH} ${AGENT_MAIN} ${AGENT_ARGS} } function run_local {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/thermostat-client-gui Thu Feb 02 10:53:45 2012 -0500 @@ -0,0 +1,66 @@ +#!/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" +JCOMMON_JAR="${JAVA_DIR}/jcommon.jar" +JFREECHART_JAR="${JAVA_DIR}/jfreechart/jfreechart.jar" +MONGO_JAR="${JAVA_DIR}/mongo.jar" +BSON_JAR="${JAVA_DIR}/bson.jar" +TOOLS_JAR="@JAVA_HOME@/../lib/tools.jar" +CLIENT_CLASSPATH="${JCOMMON_JAR}:${JFREECHART_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. +CLIENT_CLASSPATH="${CLIENT_CLASSPATH}:${THERM_DIR}/lib/thermostat-client-gui.jar:${THERM_DIR}/lib/thermostat-common.jar" +CLIENT_MAIN="com.redhat.thermostat.client.Main" + +CLIENT_ARGS="--properties ${THERM_DIR}/config/agent.properties" + +function usage { + echo "Usage:" + echo " thermostat-client-gui [args]" +} + +${JAVA} -cp ${CLIENT_CLASSPATH} ${CLIENT_MAIN} ${CLIENT_ARGS} & +
--- a/src/com/redhat/thermostat/client/ClientArgs.java Wed Feb 01 17:00:45 2012 -0500 +++ b/src/com/redhat/thermostat/client/ClientArgs.java Thu Feb 02 10:53:45 2012 -0500 @@ -37,28 +37,43 @@ package com.redhat.thermostat.client; import java.awt.Window; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; import com.redhat.thermostat.client.ui.LayoutDebugHelper; public class ClientArgs { - private static boolean isDebugLayout = - Boolean.getBoolean("thermostat.debug-layout"); - - // private static boolean isDebugLayout = true; - - private boolean dummyDataSource = false; + private boolean isDebugLayout = Boolean.getBoolean("thermostat.debug-layout"); + private Properties props = new Properties(); - public ClientArgs(String[] initialArgs) { - // remove 'unused' warnings - for (String arg : initialArgs) { - if (arg.equals("--debug-layout")) { + public ClientArgs(String[] args) { + boolean hasValidPropertiesArg = false; + for (int i=0; i < args.length; i++) { + if (args[i].equals("--debug-layout")) { isDebugLayout = true; - } else if (arg.equals("--dummy-data-source")) { - dummyDataSource = true; + } else if (args[i].equals("--properties")) { + i++; + if (i >= args.length) { + throw new IllegalArgumentException("--properties argument requires filename."); + } + try { + props.load(new FileReader(args[i])); + } catch (FileNotFoundException e) { + // ignore + } catch (IOException e) { + // ignore + } + // Ok props file must be good. + hasValidPropertiesArg = true; } } - // TODO what arguments do we care about? + if (!hasValidPropertiesArg) { + throw new IllegalArgumentException("Properties argument with valid properties file is required."); + } + // TODO what other arguments do we care about? // perhaps skipping the mode selection? if (isDebugLayout()) { @@ -85,11 +100,11 @@ } } - public static boolean isDebugLayout() { + public boolean isDebugLayout() { return isDebugLayout; } - public boolean useDummyDataSource() { - return dummyDataSource; + public Properties getProperties() { + return props; } }
--- a/src/com/redhat/thermostat/client/Main.java Wed Feb 01 17:00:45 2012 -0500 +++ b/src/com/redhat/thermostat/client/Main.java Thu Feb 02 10:53:45 2012 -0500 @@ -61,24 +61,14 @@ private UiFacadeFactory uiFacadeFactory; private Main(String[] args) { - this.arguments = new ClientArgs(args); + try { + this.arguments = new ClientArgs(args); + } catch (IllegalArgumentException ex) { + logger.log(Level.SEVERE, "Bad arguments to Thermostat client.", ex); + System.exit(-1); + } - if (arguments.useDummyDataSource()) { - logger.log(Level.CONFIG, "using dummy data"); - connection = new Connection() { - @Override - public void disconnect() { - /* no op */ - } - - @Override - public void connect() { - /* no op */ - } - }; - } else { - connection = new MongoConnection(); - } + connection = new MongoConnection(arguments.getProperties()); } private void showGui() {
--- a/src/com/redhat/thermostat/client/MongoConnection.java Wed Feb 01 17:00:45 2012 -0500 +++ b/src/com/redhat/thermostat/client/MongoConnection.java Thu Feb 02 10:53:45 2012 -0500 @@ -36,7 +36,10 @@ package com.redhat.thermostat.client; +import java.io.IOException; +import java.io.OutputStream; import java.net.UnknownHostException; +import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; @@ -45,6 +48,8 @@ import com.mongodb.MongoException; import com.mongodb.MongoURI; import com.redhat.thermostat.agent.storage.StorageConstants; +import com.redhat.thermostat.common.Constants; +import com.redhat.thermostat.common.NotImplementedException; import com.redhat.thermostat.common.utils.LoggingUtils; public class MongoConnection extends Connection { @@ -52,34 +57,33 @@ private Mongo m = null; private DB db = null; - private boolean isLocal = false; + private boolean hasLocalAgent = false; + private Process localAgentProcess = null; + private Properties props; + + public MongoConnection(Properties props) { + this.props = props; + } @Override public void connect() { - switch (getType()) { - case LOCAL: - try { - m = new Mongo(getMongoURI()); - db = m.getDB(StorageConstants.THERMOSTAT_DB_NAME); - /* the mongo java driver does not ensure this connection is actually working */ - testConnection(db); - } catch (MongoException e) { - fireChanged(ConnectionStatus.FAILED_TO_CONNECT); - return; - } catch (UnknownHostException e) { - fireChanged(ConnectionStatus.FAILED_TO_CONNECT); - return; - } - isLocal = true; - break; - case REMOTE: - // TODO connect to a remote machine - fireChanged(ConnectionStatus.FAILED_TO_CONNECT); - return; - case CLUSTER: - // TODO connect to a cluster - fireChanged(ConnectionStatus.FAILED_TO_CONNECT); - return; + try { + m = new Mongo(getMongoURI()); + db = m.getDB(StorageConstants.THERMOSTAT_DB_NAME); + /* the mongo java driver does not ensure this connection is actually working */ + testConnection(db); + } catch (MongoException e) { + fireChanged(ConnectionStatus.FAILED_TO_CONNECT); + return; + } catch (UnknownHostException e) { + fireChanged(ConnectionStatus.FAILED_TO_CONNECT); + return; + } catch (LocalAgentException e) { + fireChanged(ConnectionStatus.FAILED_TO_CONNECT); + return; + } catch (NotImplementedException e) { + fireChanged(ConnectionStatus.FAILED_TO_CONNECT); + return; } fireChanged(ConnectionStatus.CONNECTED); connected = true; @@ -90,24 +94,39 @@ } private MongoURI getMongoURI() { - MongoURI uri = new MongoURI("mongodb://127.0.0.1:27017"); + MongoURI uri = null; switch (getType()) { case LOCAL: startLocalAgent(); - // FIXME hardcorded address, use config/agent.properties instead. - uri = new MongoURI("mongodb://127.0.0.1:27518"); + uri = new MongoURI("mongodb://127.0.0.1:" + + props.getProperty(Constants.AGENT_PROPERTY_MONGOD_PORT)); case REMOTE: - // TODO + throw new NotImplementedException("No mongo URI implemented for REMOTE."); case CLUSTER: - // TODO + throw new NotImplementedException("No mongo URI implemented for CLUSTER."); } return uri; } - private void startLocalAgent() { - // TODO implement this - logger.log(Level.WARNING, "startLocalAgent not implemented"); - logger.log(Level.WARNING, "please start mongodb and agent yourself"); + private void startLocalAgent() throws LocalAgentException { + int status = 0; + try { + String agentCommand = props.getProperty(Constants.CLIENT_PROPERTY_AGENT_LAUNCH_SCRIPT) + " --local"; + localAgentProcess = Runtime.getRuntime().exec(agentCommand); + // Allow some time for things to get started. + try { + // TODO provide some UI feedback here instead of just seeming dead. + Thread.sleep(2000); + } catch (InterruptedException e) { + // ignore + } + } catch (IOException e) { + throw new LocalAgentException(); + } + if (status != 0) { + throw new LocalAgentException(); + } + hasLocalAgent = true; } public DB getDB() { @@ -119,16 +138,28 @@ if (m != null) { m.close(); } - if (isLocal) { + if (hasLocalAgent) { stopLocalAgent(); } connected = false; } private void stopLocalAgent() { - // TODO implement this - logger.log(Level.WARNING, "stopLocalAgent not implemented"); - logger.log(Level.WARNING, "please stop mongodb and agent yourself"); + // TODO this is currently using Agent's 'run until some data avail on stdin' hack. + // That hack will go away, at which point we will need another way to shut down. + OutputStream agentIn = localAgentProcess.getOutputStream(); + byte[] anything = { 0x04 }; + try { + agentIn.write(anything); + agentIn.flush(); + localAgentProcess.waitFor(); + } catch (IOException e) { + logger.warning("Error shutting down local agent."); + } catch (InterruptedException e) { + logger.warning("Interrupted waiting for local agent to shut down."); + } } + private class LocalAgentException extends RuntimeException { + } }
--- a/src/com/redhat/thermostat/common/Constants.java Wed Feb 01 17:00:45 2012 -0500 +++ b/src/com/redhat/thermostat/common/Constants.java Thu Feb 02 10:53:45 2012 -0500 @@ -62,6 +62,8 @@ public static final String AGENT_PROPERTY_BACKENDS = "backends"; public static final String AGENT_PROPERTY_BACKEND_ACTIVE = "active"; + public static final String CLIENT_PROPERTY_AGENT_LAUNCH_SCRIPT = "agent_launch_script"; + public static final String AGENT_LOCAL_HOSTNAME = "localhost"; public static final long KILOBYTES_TO_BYTES = 1000;