changeset 1184:d448210350bf

Make thermostat work with a read-only $THERMOSTAT_HOME Revewied-by: jerboaa, neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-July/007592.html PR1333
author Omair Majid <omajid@redhat.com>
date Fri, 26 Jul 2013 12:29:07 -0400
parents 9ec44cd38946
children 169f039b133e
files agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfiguration.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfigurationTest.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommandTest.java agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentConfigsUtils.java agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentConfigsUtilsTest.java agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentOptionParserTest.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java client/core/src/main/java/com/redhat/thermostat/client/ui/ClientConfigurationController.java common/core/src/main/java/com/redhat/thermostat/common/config/ClientPreferences.java common/core/src/main/java/com/redhat/thermostat/common/ssl/SSLConfiguration.java common/core/src/main/java/com/redhat/thermostat/common/utils/LoggingUtils.java common/core/src/test/java/com/redhat/thermostat/common/config/ClientPreferencesTest.java common/test/src/main/java/com/redhat/thermostat/testutils/TestUtils.java config/src/main/java/com/redhat/thermostat/shared/config/Configuration.java config/src/main/java/com/redhat/thermostat/shared/config/NativeLibraryResolver.java config/src/test/java/com/redhat/thermostat/shared/config/ConfigurationTest.java config/src/test/java/com/redhat/thermostat/shared/config/NativeLibrayResolverTest.java distribution/pom.xml distribution/scripts/thermostat eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/preferences/MainPreferencePage.java integration-tests/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java integration-tests/src/test/java/com/redhat/thermostat/itest/StorageTest.java integration-tests/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/BundleManagerImpl.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/BundleManagerImplTest.java main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java main/src/test/java/com/redhat/thermostat/main/ThermostatTest.java web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java
diffstat 35 files changed, 634 insertions(+), 276 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfiguration.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfiguration.java	Fri Jul 26 12:29:07 2013 -0400
@@ -63,12 +63,12 @@
     
     private String ip;
         
-    public DBStartupConfiguration(File properties, File dbPath, File logFile,
-            File pidFile) throws InvalidConfigurationException {
+    public DBStartupConfiguration(File systemProperties, File userProperties,
+            File dbPath, File logFile, File pidFile) throws InvalidConfigurationException {
         this.dbPath = dbPath;
         this.logFile = logFile;
         this.pidFile = pidFile;
-        readAndSetProperties(properties);
+        readAndSetProperties(systemProperties, userProperties);
     }
     
     public File getDBPath() {
@@ -142,26 +142,36 @@
         this.sslKeyPassphrase = sslKeyPassphrase;
     }
     
-    private void readAndSetProperties(File propertyFile) throws InvalidConfigurationException {
+    private void readAndSetProperties(File systemPropertiesFile, File userPropertiesFile) throws InvalidConfigurationException {
         
-        Properties properties = new Properties();
+        Properties systemProperties = new Properties();
         try {
-            properties.load(new FileInputStream(propertyFile));
-            
+            systemProperties.load(new FileInputStream(systemPropertiesFile));
         } catch (IOException e) {
-            throw new InvalidConfigurationException(e);
+            throw new InvalidConfigurationException(/* "Could not find system configuration", */e);
         }
         
-        if (properties.containsKey(DBConfig.PORT.name())) {
-            String port = (String) properties.get(DBConfig.PORT.name());
+        Properties properties = new Properties(systemProperties);
+        try {
+            properties.load(new FileInputStream(userPropertiesFile));
+        } catch (IOException e) {
+            // that's fine. we will just rely on system properties
+        }
+
+        readAndSetProperties(properties);
+    }
+
+    private void readAndSetProperties(Properties properties) {
+        String port = properties.getProperty(DBConfig.PORT.name());
+        if (port != null) {
             int localPort = Integer.parseInt(port);
             setPort(localPort);
         } else {
             throw new InvalidConfigurationException(t.localize(LocaleResources.MISSING_PROPERTY, DBConfig.PORT.toString()));
         }
         
-        if (properties.containsKey(DBConfig.BIND.name())) {
-            String ip = (String) properties.get(DBConfig.BIND.name());
+        String ip = properties.getProperty(DBConfig.BIND.name());
+        if (ip != null) {
             setBindIP(ip);
         } else {
             throw new InvalidConfigurationException(t.localize(LocaleResources.MISSING_PROPERTY, DBConfig.BIND.toString()));
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java	Fri Jul 26 12:29:07 2013 -0400
@@ -68,15 +68,16 @@
     private void parseArguments(Arguments args) throws InvalidConfigurationException {
     
         Configuration thermostatConfiguration = new Configuration();
-        File dbPath = thermostatConfiguration.getStorageDirectory();
-        File logFile = thermostatConfiguration.getStorageLogFile();
-        File pidFile = thermostatConfiguration.getStoragePidFile();
-        File propertyFile = thermostatConfiguration.getStorageConfigurationFile();
-        if (!propertyFile.exists()) {
-            throw new InvalidConfigurationException(t.localize(LocaleResources.MISSING_DB_CONFIG, propertyFile.toString()));
+        File dbPath = thermostatConfiguration.getUserStorageDirectory();
+        File logFile = thermostatConfiguration.getUserStorageLogFile();
+        File pidFile = thermostatConfiguration.getUserStoragePidFile();
+        File systemPropertyFile = thermostatConfiguration.getSystemStorageConfigurationFile();
+        if (!systemPropertyFile.exists()) {
+            throw new InvalidConfigurationException(t.localize(LocaleResources.MISSING_DB_CONFIG, systemPropertyFile.toString()));
         }
+        File userPropertyFile = thermostatConfiguration.getUserStorageConfigurationFile();
         // read everything that is in the configs
-        this.configuration = new DBStartupConfiguration(propertyFile, dbPath, logFile, pidFile);
+        this.configuration = new DBStartupConfiguration(systemPropertyFile, userPropertyFile, dbPath, logFile, pidFile);
         parser = new DBOptionParser(configuration, args);
         parser.parse();
     }
@@ -119,6 +120,7 @@
     
     private void startService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException {
         try {
+            createNeededDirectories();
             runner.startService();
         } catch (ApplicationException | InvalidConfigurationException | IOException e) {
             // something went wrong set status appropriately. This makes sure
@@ -130,6 +132,29 @@
         getNotifier().fireAction(ApplicationState.START);
     }
     
+    private void createNeededDirectories() throws InvalidConfigurationException {
+        File[] requiredDirectories = new File[] {
+                configuration.getDBPath(),
+        };
+
+        for (File directory : requiredDirectories) {
+            if (!directory.isDirectory() && !directory.mkdirs()) {
+                throw new InvalidConfigurationException(t.localize(LocaleResources.MISSING_DB_DIR));
+            }
+        }
+
+        File[] requiredFiles = new File[] {
+                configuration.getLogFile(),
+                configuration.getPidFile(),
+        };
+
+        for (File file : requiredFiles) {
+            File directory = file.getParentFile();
+            if (!directory.isDirectory() && !directory.mkdirs()) {
+                throw new InvalidConfigurationException(t.localize(LocaleResources.MISSING_DB_DIR));
+            }
+        }
+    }
     
     private void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException {
         try {
@@ -144,6 +169,15 @@
         getNotifier().fireAction(ApplicationState.STOP);
     }
     
+    private void check() throws InvalidConfigurationException {
+        if (!configuration.getDBPath().exists() ||
+            !configuration.getLogFile().getParentFile().exists() ||
+            !configuration.getPidFile().getParentFile().exists())
+        {
+            throw new InvalidConfigurationException(t.localize(LocaleResources.MISSING_DB_DIR));
+        }
+    }
+
     private void printServiceStatus(CommandContext ctx) {
         if (runner.isStorageRunning()) {
             ctx.getConsole().getOutput().println(t.localize(LocaleResources.STORAGE_RUNNING).getContents());
@@ -156,15 +190,6 @@
         return new MongoProcessRunner(configuration, parser.isQuiet());
     }
 
-    private void check() throws InvalidConfigurationException {
-        if (!configuration.getDBPath().exists() ||
-            !configuration.getLogFile().getParentFile().exists() || 
-            !configuration.getPidFile().getParentFile().exists())
-        {
-            throw new InvalidConfigurationException(t.localize(LocaleResources.MISSING_DB_DIR));
-        }
-    }
-
     public DBStartupConfiguration getConfiguration() {
         return configuration;
     }
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfigurationTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfigurationTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -71,7 +71,8 @@
     @Test
     public void canGetConfigFromPropertiesFile() throws Exception {
         File dbProps = new File(this.getClass().getResource("/testDbConfig.properties").getFile());
-        DBStartupConfiguration dbConfig = new DBStartupConfiguration(dbProps, dbPath, dbLogFile, dbPidFile);
+        File canNotBeFoundFile = new File("");
+        DBStartupConfiguration dbConfig = new DBStartupConfiguration(dbProps, canNotBeFoundFile, dbPath, dbLogFile, dbPidFile);
         
         assertEquals(dbLogFile.getAbsolutePath(), dbConfig.getLogFile().getAbsolutePath());
         assertEquals(dbPidFile.getAbsolutePath(), dbConfig.getPidFile().getAbsolutePath());
@@ -86,7 +87,8 @@
     @Test
     public void canGetConfigFromPropertiesFile2() throws Exception {
         File dbProps = new File(this.getClass().getResource("/testDbConfig2.properties").getFile());
-        DBStartupConfiguration dbConfig = new DBStartupConfiguration(dbProps, dbPath, dbLogFile, dbPidFile);
+        File canNotBeFoundFile = new File("");
+        DBStartupConfiguration dbConfig = new DBStartupConfiguration(dbProps, canNotBeFoundFile, dbPath, dbLogFile, dbPidFile);
         
         assertEquals(dbLogFile.getAbsolutePath(), dbConfig.getLogFile().getAbsolutePath());
         assertEquals(dbPidFile.getAbsolutePath(), dbConfig.getPidFile().getAbsolutePath());
@@ -101,8 +103,9 @@
     @Test
     public void missingBindThrowsConfigException() throws Exception {
         File dbProps = new File(this.getClass().getResource("/brokenDbConfig.properties").getFile());
+        File canNotBeFoundFile = new File("");
         try {
-            new DBStartupConfiguration(dbProps, dbPath, dbLogFile, dbPidFile);
+            new DBStartupConfiguration(dbProps, canNotBeFoundFile, dbPath, dbLogFile, dbPidFile);
             fail("BIND was not specified in properties file");
         } catch (InvalidConfigurationException e) {
             assertEquals("BIND property missing", e.getMessage());
@@ -112,8 +115,9 @@
     @Test
     public void missingPortThrowsConfigException() throws Exception {
         File dbProps = new File(this.getClass().getResource("/brokenDbConfig2.properties").getFile());
+        File canNotBeFoundFile = new File("");
         try {
-            new DBStartupConfiguration(dbProps, dbPath, dbLogFile, dbPidFile);
+            new DBStartupConfiguration(dbProps, canNotBeFoundFile, dbPath, dbLogFile, dbPidFile);
             fail("PORT was not specified in properties file");
         } catch (InvalidConfigurationException e) {
             assertEquals("PORT property missing", e.getMessage());
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommandTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommandTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -64,12 +64,13 @@
 import com.redhat.thermostat.common.tools.ApplicationException;
 import com.redhat.thermostat.common.tools.ApplicationState;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
+import com.redhat.thermostat.testutils.TestUtils;
 
 public class StorageCommandTest {
     
     private static final String PORT = "27518";
     private static final String BIND = "127.0.0.1";
-    private static final String DB = "storage/db";
+    private static final String DB = "data/db";
 
     private String tmpDir;
     private ExitStatus exitStatus;
@@ -79,28 +80,12 @@
         exitStatus = mock(ExitStatus.class);
         // need to create a dummy config file for the test
         try {
-            Random random = new Random();
-            
-            tmpDir = System.getProperty("java.io.tmpdir") + File.separatorChar +
-                     Math.abs(random.nextInt()) + File.separatorChar;
-            
-            System.setProperty("THERMOSTAT_HOME", tmpDir);
-            File base = new File(tmpDir + "storage");
-            base.mkdirs();
-                        
-            File tmpConfigs = new File(base, "db.properties");
-            
-            new File(base, "run").mkdirs();
-            new File(base, "logs").mkdirs();
-            new File(base, "db").mkdirs();
-            
             Properties props = new Properties();
             
             props.setProperty(DBConfig.BIND.name(), BIND);
             props.setProperty(DBConfig.PORT.name(), PORT);
 
-            props.store(new FileOutputStream(tmpConfigs), "thermostat test properties");
-            
+            tmpDir = TestUtils.setupStorageConfigs(props);
         } catch (IOException e) {
             Assert.fail("cannot setup tests: " + e);
         }
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentConfigsUtils.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentConfigsUtils.java	Fri Jul 26 12:29:07 2013 -0400
@@ -62,26 +62,33 @@
         AgentStartupConfiguration config = new AgentStartupConfiguration();
 
         Configuration mainConfig = new Configuration();
-        File propertyFile = mainConfig.getAgentConfigurationFile();
-        readAndSetProperties(propertyFile, config);
-        File agentAuthFile = mainConfig.getAgentAuthConfigFile();
+        File systemConfiguration = mainConfig.getSystemAgentConfigurationFile();
+        File userConfiguration = mainConfig.getUserAgentConfigurationFile();
+        readAndSetProperties(systemConfiguration, userConfiguration, config);
+        File agentAuthFile = mainConfig.getUserAgentAuthConfigFile();
         setAuthConfigFromFile(agentAuthFile, config);
         return config;
     }
     
-    private static void readAndSetProperties(File propertyFile, AgentStartupConfiguration configuration)
+    private static void readAndSetProperties(File systemConfigFile, File userConfigFile, AgentStartupConfiguration configuration)
             throws InvalidConfigurationException
     {
-        Properties properties = new Properties();
+        Properties systemConfig = new Properties();
         try {
-            properties.load(new FileInputStream(propertyFile));
-            
+            systemConfig.load(new FileInputStream(systemConfigFile));
         } catch (IOException e) {
             throw new InvalidConfigurationException(e);
         }
-        
-        if (properties.containsKey(AgentProperties.DB_URL.name())) {
-            String db = properties.getProperty(AgentProperties.DB_URL.name());
+
+        Properties properties = new Properties(systemConfig);
+        try {
+            properties.load(new FileInputStream(userConfigFile));
+        } catch (IOException e) {
+            // that's okay. just use system config
+        }
+
+        String db = properties.getProperty(AgentProperties.DB_URL.name());
+        if (db != null) {
             configuration.setDatabaseURL(db);
         }
         
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentConfigsUtilsTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentConfigsUtilsTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -39,6 +39,7 @@
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.util.Properties;
 import java.util.Random;
 
 import org.junit.Assert;
@@ -53,13 +54,22 @@
     private static Random random;
 
     @BeforeClass
-    public static void setUpRandom() {
+    public static void setUpOnce() {
         random = new Random();
+
+        Properties agentProperties = new Properties();
+        agentProperties.setProperty("SAVE_ON_EXIT", "true");
+        agentProperties.setProperty("CONFIG_LISTEN_ADDRESS", "42.42.42.42:42");
+
+        try {
+            TestUtils.setupAgentConfigs(agentProperties);
+        } catch (IOException e) {
+            throw new AssertionError("Unable to create agent configuration", e);
+        }
     }
     
     @Test
     public void testCreateAgentConfigs() throws InvalidConfigurationException, IOException {
-        TestUtils.setupAgentConfigs();
         AgentStartupConfiguration config = AgentConfigsUtils.createAgentConfigs();        
 
         Assert.assertFalse(config.purge());
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentOptionParserTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentOptionParserTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -38,6 +38,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Properties;
 
 import junit.framework.Assert;
 
@@ -55,7 +56,12 @@
     
     @BeforeClass
     public static void setup() throws IOException {
-        tmpFile = new File(TestUtils.setupAgentConfigs());
+
+        Properties agentProperties = new Properties();
+        agentProperties.setProperty("SAVE_ON_EXIT", "true");
+        agentProperties.setProperty("CONFIG_LISTEN_ADDRESS", "42.42.42.42:42");
+
+        tmpFile = new File(TestUtils.setupAgentConfigs(agentProperties));
     }
     
     @AfterClass
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java	Fri Jul 26 12:29:07 2013 -0400
@@ -81,7 +81,7 @@
         public PersistentHistory get() {
             PersistentHistory history = null;
             try {
-                history = new FileHistory(new Configuration().getHistoryFile());
+                history = new FileHistory(new Configuration().getUserHistoryFile());
             } catch (InvalidConfigurationException | IOException e) {
                 /* no history available */
             }
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/ClientConfigurationController.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/ClientConfigurationController.java	Fri Jul 26 12:29:07 2013 -0400
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.client.ui;
 
+import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.prefs.BackingStoreException;
@@ -87,7 +88,7 @@
         
         try {
             model.flush();
-        } catch (BackingStoreException e) {
+        } catch (IOException e) {
             logger.log(Level.WARNING, "error saving client preferences", e);
         }
     }
--- a/common/core/src/main/java/com/redhat/thermostat/common/config/ClientPreferences.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/config/ClientPreferences.java	Fri Jul 26 12:29:07 2013 -0400
@@ -36,9 +36,19 @@
 
 package com.redhat.thermostat.common.config;
 
-import java.util.prefs.BackingStoreException;
-import java.util.prefs.Preferences;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.utils.keyring.Credentials;
 import com.redhat.thermostat.utils.keyring.Keyring;
 
@@ -49,26 +59,47 @@
     static final String CONNECTION_URL = "connection-url";
     static final String SAVE_ENTITLEMENTS = "save-entitlements";
     static final String DEFAULT_CONNECTION_URL = "mongodb://127.0.0.1:27518";
+
+    private static final Logger logger = LoggingUtils.getLogger(ClientPreferences.class);
     
-    private final Preferences prefs;
+    private Properties prefs;
     
     private Keyring keyring;
     
     private Credentials userCredentials;
     
     public ClientPreferences(Keyring keyring) {
-        this(Preferences.userRoot().node("thermostat"), keyring);
+        Properties props = new Properties();
+        try {
+            File userConfig = new Configuration().getUserClientConfigurationFile();
+            if (userConfig.isFile()) {
+                try {
+                    try (InputStream fis = new FileInputStream(userConfig)) {
+                        props.load(fis);
+                    }
+                } catch (IOException e) {
+                    logger.log(Level.CONFIG, "unable to load client configuration", e);
+                }
+            }
+        } catch (InvalidConfigurationException e) {
+            logger.log(Level.CONFIG, "unable to load configuration", e);
+        }
+        init(props, keyring);
     }
 
-    // Testing hook with injectable j.u.p.Preferences
-    ClientPreferences(Preferences prefs, Keyring keyring) {
-        this.prefs = prefs;
+    // Testing hook with injectable j.u.Properties
+    ClientPreferences(Properties properties, Keyring keyring) {
+        init(properties, keyring);
+    }
+
+    private void init(Properties properties, Keyring keyring) {
+        this.prefs = properties;
         this.keyring = keyring;
         this.userCredentials = new Credentials();
         userCredentials.setDescription("thermostat keychain");
 
         // load the initial defaults
-        userCredentials.setUserName(prefs.get(USERNAME, ""));
+        userCredentials.setUserName(prefs.getProperty(USERNAME, ""));
         this.userCredentials.setPassword("");
         if (getSaveEntitlements()) {
             keyring.loadPassword(userCredentials);
@@ -76,15 +107,15 @@
     }
 
     public boolean getSaveEntitlements() {
-        return prefs.getBoolean(SAVE_ENTITLEMENTS, false);
+        return Boolean.valueOf(prefs.getProperty(SAVE_ENTITLEMENTS, "false"));
     }
     
     public void setSaveEntitlements(boolean save) {
-        prefs.putBoolean(SAVE_ENTITLEMENTS, save);
+        prefs.setProperty(SAVE_ENTITLEMENTS, Boolean.toString(save));
     }
     
     public String getConnectionUrl() {
-        return prefs.get(CONNECTION_URL, DEFAULT_CONNECTION_URL);
+        return prefs.getProperty(CONNECTION_URL, DEFAULT_CONNECTION_URL);
     }
 
     public String getPassword() {
@@ -95,7 +126,7 @@
     }
 
     public String getUserName() {        
-        return prefs.get(USERNAME, "");
+        return prefs.getProperty(USERNAME, "");
     }
 
     public void setConnectionUrl(String url) {
@@ -113,8 +144,8 @@
         }
     }
     
-    public void flush() throws BackingStoreException {
-        prefs.flush();
+    public void flush() throws IOException {
+        prefs.store(new FileWriter(new Configuration().getUserClientConfigurationFile()), "");
         userCredentials.setUserName(getUserName());
         if (getSaveEntitlements()) {
             keyring.loadPassword(userCredentials);
--- a/common/core/src/main/java/com/redhat/thermostat/common/ssl/SSLConfiguration.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/ssl/SSLConfiguration.java	Fri Jul 26 12:29:07 2013 -0400
@@ -157,7 +157,7 @@
     private static void loadClientProperties()
             throws InvalidConfigurationException {
         if (clientProps == null) {
-            File clientPropertiesFile = new File(new Configuration().getConfigurationDir(),
+            File clientPropertiesFile = new File(new Configuration().getUserConfigurationDirectory(),
                     "ssl.properties");
             initClientProperties(clientPropertiesFile);
         }
--- a/common/core/src/main/java/com/redhat/thermostat/common/utils/LoggingUtils.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/utils/LoggingUtils.java	Fri Jul 26 12:29:07 2013 -0400
@@ -125,15 +125,15 @@
     }
 
     public static void loadGlobalLoggingConfig() throws InvalidConfigurationException {
-        File thermostatConfigurationDir = new File(new Configuration().getConfigurationDir());
-        File loggingPropertiesFile = new File(thermostatConfigurationDir, "logging.properties");
+        File systemConfigurationDir = new Configuration().getSystemConfigurationDirectory();
+        File loggingPropertiesFile = new File(systemConfigurationDir, "logging.properties");
         loadConfig(loggingPropertiesFile);
     }
     
 
     public static void loadUserLoggingConfig() throws InvalidConfigurationException {
-        File thermostatUserDir = new File(new Configuration().getThermostatUserHome());
-        File loggingPropertiesFile = new File(thermostatUserDir, "logging.properties");
+        File userConfigurationDir = new Configuration().getUserConfigurationDirectory();
+        File loggingPropertiesFile = new File(userConfigurationDir, "logging.properties");
         loadConfig(loggingPropertiesFile);
     }
 
--- a/common/core/src/test/java/com/redhat/thermostat/common/config/ClientPreferencesTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/config/ClientPreferencesTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -38,7 +38,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
@@ -46,7 +45,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.util.prefs.Preferences;
+import java.util.Properties;
 
 import org.junit.Test;
 
@@ -59,21 +58,21 @@
     public void testGetConnectionUrl() {
 
         Keyring keyring = mock(Keyring.class);
-        Preferences prefs = mock(Preferences.class);
-        when(prefs.get(eq(ClientPreferences.CONNECTION_URL), any(String.class))).thenReturn("mock-value");
+        Properties prefs = mock(Properties.class);
+        when(prefs.getProperty(eq(ClientPreferences.CONNECTION_URL), any(String.class))).thenReturn("mock-value");
 
         ClientPreferences clientPrefs = new ClientPreferences(prefs, keyring);
         String value = clientPrefs.getConnectionUrl();
 
         assertEquals("mock-value", value);
-        verify(prefs).get(eq(ClientPreferences.CONNECTION_URL), any(String.class));
+        verify(prefs).getProperty(eq(ClientPreferences.CONNECTION_URL), any(String.class));
     }
 
     @Test
     public void testSetConnectionUrl() {
 
         Keyring keyring = mock(Keyring.class);
-        Preferences prefs = mock(Preferences.class);
+        Properties prefs = mock(Properties.class);
 
         ClientPreferences clientPrefs = new ClientPreferences(prefs, keyring);
         clientPrefs.setConnectionUrl("test");
@@ -85,28 +84,28 @@
     public void testSetUsernamePassowrd() {
         
         Keyring keyring = mock(Keyring.class);
-        Preferences prefs = mock(Preferences.class);
-        when(prefs.getBoolean(eq(ClientPreferences.SAVE_ENTITLEMENTS), any(boolean.class))).thenReturn(true);
+        Properties prefs = mock(Properties.class);
+        when(prefs.getProperty(eq(ClientPreferences.SAVE_ENTITLEMENTS), any(String.class))).thenReturn("true");
         
         ClientPreferences clientPrefs = new ClientPreferences(prefs, keyring);
         clientPrefs.setCredentials("fluff", "fluffPassword");
 
         verify(prefs).put(eq(ClientPreferences.USERNAME), eq("fluff"));
-        verify(prefs, times(0)).put(eq(ClientPreferences.PASSWORD), anyString());
+        verify(prefs, times(0)).put(eq(ClientPreferences.PASSWORD), any(String.class));
     }
     
     @Test
     public void testGetUsername() {
         
         Keyring keyring = mock(Keyring.class);
-        Preferences prefs = mock(Preferences.class);
-        when(prefs.get(eq(ClientPreferences.USERNAME), any(String.class))).thenReturn("mock-value");
+        Properties prefs = mock(Properties.class);
+        when(prefs.getProperty(eq(ClientPreferences.USERNAME), any(String.class))).thenReturn("mock-value");
         
         ClientPreferences clientPrefs = new ClientPreferences(prefs, keyring);
         String username = clientPrefs.getUserName();
 
         assertEquals("mock-value", username);
-        verify(prefs, atLeastOnce()).get(eq(ClientPreferences.USERNAME), any(String.class));
+        verify(prefs, atLeastOnce()).getProperty(eq(ClientPreferences.USERNAME), any(String.class));
     }
     
     @Test
@@ -114,14 +113,14 @@
         
         Keyring keyring = mock(Keyring.class);
         
-        Preferences prefs = mock(Preferences.class);
-        when(prefs.get(eq(ClientPreferences.USERNAME), any(String.class))).thenReturn("mock-value");
-        when(prefs.getBoolean(eq(ClientPreferences.SAVE_ENTITLEMENTS), any(boolean.class))).
-            thenReturn(false).thenReturn(false).thenReturn(true);
+        Properties prefs = mock(Properties.class);
+        when(prefs.getProperty(eq(ClientPreferences.USERNAME), any(String.class))).thenReturn("mock-value");
+        when(prefs.getProperty(eq(ClientPreferences.SAVE_ENTITLEMENTS), any(String.class))).
+            thenReturn("false").thenReturn("false").thenReturn("true");
                 
         ClientPreferences clientPrefs = new ClientPreferences(prefs, keyring);
         String password = clientPrefs.getPassword();
-        verify(prefs, times(0)).get(eq(ClientPreferences.PASSWORD), any(String.class));
+        verify(prefs, times(0)).getProperty(eq(ClientPreferences.PASSWORD), any(String.class));
         verify(keyring, times(0)).loadPassword(any(Credentials.class));
         
         assertEquals("", password);
@@ -134,29 +133,29 @@
     public void testGetSaveEntitlements() {
         
         Keyring keyring = mock(Keyring.class);
-        Preferences prefs = mock(Preferences.class);
-        when(prefs.getBoolean(eq(ClientPreferences.SAVE_ENTITLEMENTS), any(boolean.class))).thenReturn(true);
+        Properties prefs = mock(Properties.class);
+        when(prefs.getProperty(eq(ClientPreferences.SAVE_ENTITLEMENTS), any(String.class))).thenReturn("true");
         
         ClientPreferences clientPrefs = new ClientPreferences(prefs, keyring);
         boolean saveEntitlements = clientPrefs.getSaveEntitlements();
 
         assertEquals(true, saveEntitlements);
-        verify(prefs, atLeastOnce()).getBoolean(eq(ClientPreferences.SAVE_ENTITLEMENTS), any(boolean.class));
+        verify(prefs, atLeastOnce()).getProperty(eq(ClientPreferences.SAVE_ENTITLEMENTS), any(String.class));
     }
     
     @Test
     public void testSetSaveEntitlements() {
         
         Keyring keyring = mock(Keyring.class);
-        Preferences prefs = mock(Preferences.class);
+        Properties prefs = mock(Properties.class);
 
         ClientPreferences clientPrefs = new ClientPreferences(prefs, keyring);
         clientPrefs.setSaveEntitlements(false);
 
-        verify(prefs).putBoolean(eq(ClientPreferences.SAVE_ENTITLEMENTS), eq(false));
+        verify(prefs).setProperty(eq(ClientPreferences.SAVE_ENTITLEMENTS), eq("false"));
         
         clientPrefs.setSaveEntitlements(true);
-        verify(prefs).putBoolean(eq(ClientPreferences.SAVE_ENTITLEMENTS), eq(true));
+        verify(prefs).setProperty(eq(ClientPreferences.SAVE_ENTITLEMENTS), eq("true"));
     }
     
     @Test
@@ -164,8 +163,8 @@
         // Default preferences for GUI is mongodb:// since this is accomodates
         // more use cases
         Keyring keyring = mock(Keyring.class);
-        Preferences prefs = mock(Preferences.class);
-        when(prefs.get(eq("connection-url"), any(String.class))).thenReturn(ClientPreferences.DEFAULT_CONNECTION_URL);
+        Properties prefs = mock(Properties.class);
+        when(prefs.getProperty(eq("connection-url"), any(String.class))).thenReturn(ClientPreferences.DEFAULT_CONNECTION_URL);
         ClientPreferences clientPrefs = new ClientPreferences(prefs, keyring);
         assertEquals("mongodb://127.0.0.1:27518", clientPrefs.getConnectionUrl());
     }
--- a/common/test/src/main/java/com/redhat/thermostat/testutils/TestUtils.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/common/test/src/main/java/com/redhat/thermostat/testutils/TestUtils.java	Fri Jul 26 12:29:07 2013 -0400
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.testutils;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
@@ -65,47 +66,86 @@
     }
 
     /**
+     * Creates and initializes a directory suitable for use as the storage's
+     * configuration directory
+     */
+    public static String setupStorageConfigs(Properties dbConfig) throws IOException {
+        Random random = new Random();
+
+        String tmpDir = System.getProperty("java.io.tmpdir") + File.separatorChar +
+                 Math.abs(random.nextInt()) + File.separatorChar;
+
+        setupSystemStorageConfig(tmpDir, dbConfig);
+        setupUserStorageConfig(tmpDir);
+
+        return tmpDir;
+    }
+
+    private static void setupSystemStorageConfig(String root, Properties dbConfig) throws FileNotFoundException, IOException {
+        System.setProperty("THERMOSTAT_HOME", root);
+
+        File config = new File(root, "etc");
+        config.mkdirs();
+        File tmpConfigs = new File(config, "db.properties");
+
+        dbConfig.store(new FileOutputStream(tmpConfigs), "thermostat test properties");
+    }
+
+    private static void setupUserStorageConfig(String root) {
+        System.setProperty("USER_THERMOSTAT_HOME", root);
+
+        new File(root, "run").mkdirs();
+        new File(root, "logs").mkdirs();
+
+        File data = new File(root + "data");
+        data.mkdirs();
+        new File(data, "db").mkdirs();
+    }
+
+    /**
      * Creates and initializes a directory suitable for use as the agent's
      * configuration directory
-     *
-     * @return a String containing the path to the temporary configuration directory
-     * @throws IOException
      */
-    public static String setupAgentConfigs() throws IOException {
+    public static String setupAgentConfigs(Properties agentProperties) throws IOException {
         // need to create dummy config files for the tests
         Random random = new Random();
 
         String tmpDir = System.getProperty("java.io.tmpdir") + File.separatorChar +
                 Math.abs(random.nextInt()) + File.separatorChar;
 
-        System.setProperty("THERMOSTAT_HOME", tmpDir);
-        File agent = new File(tmpDir, "agent");
+        setupSystemAgentConfig(tmpDir, agentProperties);
+        setupUserAgentConfig(tmpDir);
+
+        return tmpDir;
+    }
+
+    private static void setupSystemAgentConfig(String root, Properties agentProperties) throws FileNotFoundException, IOException {
+        System.setProperty("THERMOSTAT_HOME", root);
+
+        File etc = new File(root, "etc");
+        etc.mkdirs();
+        File tmpConfigs = new File(etc, "agent.properties");
+
+        try (OutputStream propsOutputStream = new FileOutputStream(tmpConfigs)) {
+            agentProperties.store(propsOutputStream, "thermostat agent test properties");
+        }
+
+        File tmpAuth = new File(etc, "agent.auth");
+        FileWriter authWriter = new FileWriter(tmpAuth);
+        authWriter.append("username=user\npassword=pass\n");
+        authWriter.flush();
+        authWriter.close();
+    }
+
+    private static void setupUserAgentConfig(String root) throws IOException {
+        System.setProperty("USER_THERMOSTAT_HOME", root);
+
+        File agent = new File(root, "agent");
         agent.mkdirs();
 
-        File tmpConfigs = new File(agent, "agent.properties");
-
         new File(agent, "run").mkdirs();
         new File(agent, "logs").mkdirs();
 
-        File backends = new File(tmpDir, "backends");
-        File system = new File(backends, "system");
-        system.mkdirs();
-
-        Properties props = new Properties();
-        
-        props.setProperty("SAVE_ON_EXIT", "true");
-        props.setProperty("CONFIG_LISTEN_ADDRESS", "42.42.42.42:42");
-        
-        try (OutputStream propsOutputStream = new FileOutputStream(tmpConfigs)) {
-            props.store(propsOutputStream, "thermostat agent test properties");
-        }
-
-        File tmpAuth = new File(agent, "agent.auth");
-        FileWriter authWriter = new FileWriter(tmpAuth);
-        authWriter.append("username=user\npassword=pass\n");
-        authWriter.flush();
-        authWriter.close();
-        return tmpDir;
     }
 }
 
--- a/config/src/main/java/com/redhat/thermostat/shared/config/Configuration.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/config/src/main/java/com/redhat/thermostat/shared/config/Configuration.java	Fri Jul 26 12:29:07 2013 -0400
@@ -41,107 +41,170 @@
 import com.redhat.thermostat.shared.locale.LocaleResources;
 import com.redhat.thermostat.shared.locale.Translate;
 
+/**
+ * Contains locations to various files and directories used by thermostat
+ * components.
+ * <p>
+ * Some configuration files or directories are system-wide while
+ * others are per-user. System-wide file or directories are indicated
+ * by the word System in the name. These should contain non-mutable
+ * data that is meant to be used by all instances of thermostat
+ * running on one machine. Per-user directories will normally contain
+ * configuration and data specific for a different instance of
+ * thermostat. Per-user files and directories indicated by the word
+ * "User" in the method name.
+ * <p>
+ * The directories are split according to functionality, along the lines of
+ * Filesystem Hierarchy Standard (FHS).
+ */
 public class Configuration {
 
+    // Note: these paths are used by the integration tests too. Please update
+    // them whenever you change this class.
+
+    private static final String THERMOSTAT_HOME = "THERMOSTAT_HOME";
+    private static final String USER_THERMOSTAT_HOME = "USER_THERMOSTAT_HOME";
     private static final String THERMOSTAT_USER_DIR = ".thermostat";
     private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
 
-    private String home;
+    private final String home;
+    private final File userHome;
+
     private boolean printOsgiInfo = false;
 
     public Configuration() throws InvalidConfigurationException {
         // allow this to be specified also as a property, especially for
         // tests, this overrides the env setting
-        String home = System.getProperty("THERMOSTAT_HOME");
+        String home = System.getProperty(THERMOSTAT_HOME);
         if (home == null) {
-            home = System.getenv("THERMOSTAT_HOME");
+            home = System.getenv(THERMOSTAT_HOME);
         }
         
         if (home == null) {
-            throw new InvalidConfigurationException(t.localize(LocaleResources.ENV_NO_HOME));
+            throw new InvalidConfigurationException(THERMOSTAT_HOME + " not defined...");
         }
         this.home = home;
-    }
 
-    public String getThermostatHome() throws InvalidConfigurationException {
-        return home;
+        // allow this to be specified also as a special property, meant for tests
+        String userHome = System.getProperty(USER_THERMOSTAT_HOME);
+        if (userHome == null) {
+            userHome = System.getenv(USER_THERMOSTAT_HOME);
+        }
+        if (userHome == null) {
+            userHome = System.getProperty("user.home") + File.separatorChar + THERMOSTAT_USER_DIR;
+        }
+        this.userHome = new File(userHome);
     }
 
-    public String getThermostatUserHome() {
-        String home = System.getProperty("user.home");
-        return home + File.separator + THERMOSTAT_USER_DIR;
+    /*
+     * Overall hierarchy
+     *
+     * TODO: these might have to be different for 'root' or 'thermostat' users
+     */
+
+    public File getSystemThermostatHome() throws InvalidConfigurationException {
+        return new File(home);
     }
 
-    public String getPluginRoot() throws InvalidConfigurationException {
-        return home + File.separator + "plugins";
+    public File getUserThermostatHome() throws InvalidConfigurationException {
+        return userHome;
     }
 
-    public File getBackendsBaseDirectory() throws InvalidConfigurationException {
-        String loc = getThermostatHome() + File.separatorChar + "backends";
-        File file = new File(loc);
-        return file;
+    public File getSystemPluginRoot() throws InvalidConfigurationException {
+        return new File(home, "plugins");
+    }
+
+    public File getSystemLibRoot() throws InvalidConfigurationException {
+        return new File(home, "libs");
+    }
+    
+    public File getSystemNativeLibsRoot() throws InvalidConfigurationException {
+        return new File(getSystemLibRoot(), "native");
     }
 
-    public String getLibRoot() throws InvalidConfigurationException {
-        return home + File.separator + "libs";
+    public File getSystemConfigurationDirectory() throws InvalidConfigurationException {
+        return new File(getSystemThermostatHome(), "etc");
     }
-    
-    public String getNativeLibsRoot() throws InvalidConfigurationException {
-        return getLibRoot() + File.separator + "native";
+
+    public File getUserConfigurationDirectory() throws InvalidConfigurationException {
+        return new File(getUserThermostatHome(), "etc");
     }
 
-    public String getConfigurationDir() throws InvalidConfigurationException {
-        return home + File.separator + "etc";
+    /** A location that contains data that is persisted */
+    public File getUserPersistentDataDirectory() throws InvalidConfigurationException {
+        File dataDir = new File(getUserThermostatHome(), "data");
+        return dataDir;
+    }
+
+    /** Contains data that is only useful for the duration that thermostat is running */
+    public File getUserRuntimeDataDirectory() throws InvalidConfigurationException {
+        File runDir = new File(getUserThermostatHome(), "run");
+        return runDir;
     }
 
-    public File getStorageBaseDirectory() throws InvalidConfigurationException {
-        String loc = getThermostatHome() + File.separatorChar + "storage";
-        File file = new File(loc);
-        return file;
+    public File getUserLogDirectory() throws InvalidConfigurationException {
+        File logDir = new File(getUserThermostatHome(), "logs");
+        return logDir;
     }
-    
-    public File getStorageDirectory() throws InvalidConfigurationException {
-        return new File(getStorageBaseDirectory(), "db");
-    }
-    
-    public File getStorageConfigurationFile() throws InvalidConfigurationException {
-        return new File(getStorageBaseDirectory(), "db.properties");
+
+    public File getUserCacheDirectory() throws InvalidConfigurationException {
+        File cacheDir = new File(getUserThermostatHome(), "cache");
+        return cacheDir;
     }
 
-    public File getStorageLogFile() throws InvalidConfigurationException {
-        File logDir = new File(getStorageBaseDirectory(), "logs");
-        File logFile = new File(logDir, "db.log");
-        
+    /* Specific files and directories */
+
+    public File getUserStorageDirectory() throws InvalidConfigurationException {
+        return new File(getUserPersistentDataDirectory(), "db");
+    }
+
+    public File getSystemStorageConfigurationFile() throws InvalidConfigurationException {
+        return new File(getSystemConfigurationDirectory(), "db.properties");
+    }
+
+    public File getUserStorageConfigurationFile() throws InvalidConfigurationException {
+        return new File(getUserConfigurationDirectory(), "db.properties");
+    }
+
+    public File getUserStorageLogFile() throws InvalidConfigurationException {
+        File logFile = new File(getUserLogDirectory(), "db.log");
         return logFile;
     }
 
-    public File getStoragePidFile() throws InvalidConfigurationException {
-        File logDir = new File(getStorageBaseDirectory(), "run");
-        File logFile = new File(logDir, "db.pid");
-        
+    public File getUserStoragePidFile() throws InvalidConfigurationException {
+        File logFile = new File(getUserRuntimeDataDirectory(), "db.pid");
         return logFile;
     }
 
-    public File getAgentConfigurationFile() throws InvalidConfigurationException {
-        File agent = new File(getThermostatHome(), "agent");
-        return new File(agent, "agent.properties");
+    public File getSystemAgentConfigurationFile() throws InvalidConfigurationException {
+        return new File(getSystemConfigurationDirectory(), "agent.properties");
+    }
+
+    public File getUserAgentConfigurationFile() throws InvalidConfigurationException {
+        return new File(getUserConfigurationDirectory(), "agent.properties");
     }
 
-    public File getAgentAuthConfigFile() throws InvalidConfigurationException {
-        File agent = new File(getThermostatHome(), "agent");
-        return new File(agent, "agent.auth");
+    public File getSystemAgentAuthConfigFile() throws InvalidConfigurationException {
+        return new File(getSystemConfigurationDirectory(), "agent.auth");
     }
 
-    public File getClientConfigurationDirectory() throws InvalidConfigurationException {
-        File client = new File(getThermostatHome(), "client");
+    public File getUserAgentAuthConfigFile() throws InvalidConfigurationException {
+        return new File(getUserConfigurationDirectory(), "agent.auth");
+    }
+
+    public File getUserClientConfigurationFile() throws InvalidConfigurationException {
+        File client = new File(getUserConfigurationDirectory(), "client.properties");
         return client;
     }
 
-    public File getHistoryFile() throws InvalidConfigurationException {
-        File history = new File(getClientConfigurationDirectory(), "cli-history");
+    public File getUserHistoryFile() throws InvalidConfigurationException {
+        File history = new File(getUserPersistentDataDirectory(), "cli-history");
         return history;
     }
 
+    // TODO add logging files here (see LoggingUtils)
+    // TODO add ssl.properties file here (see SSLConfiguration)
+    
     public boolean getPrintOSGiInfo() {
         return printOsgiInfo;
     }
--- a/config/src/main/java/com/redhat/thermostat/shared/config/NativeLibraryResolver.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/config/src/main/java/com/redhat/thermostat/shared/config/NativeLibraryResolver.java	Fri Jul 26 12:29:07 2013 -0400
@@ -65,7 +65,7 @@
         }
         try {
             Configuration config = new Configuration();
-            nativeLibsRoot = config.getNativeLibsRoot();
+            nativeLibsRoot = config.getSystemNativeLibsRoot().getPath();
         } catch (InvalidConfigurationException e) {
             throw new AssertionError(e);
         }
@@ -73,6 +73,6 @@
     }
     
     private static String doResolve(String root, String libraryName) {
-        return root + File.separator + System.mapLibraryName(libraryName);
+        return new File(root, System.mapLibraryName(libraryName)).getAbsolutePath();
     }
 }
--- a/config/src/test/java/com/redhat/thermostat/shared/config/ConfigurationTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/config/src/test/java/com/redhat/thermostat/shared/config/ConfigurationTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -57,7 +57,7 @@
         // remove THERMOSTAT_HOME system property for a clean slate
         Properties props = System.getProperties();
         Properties newProps = new Properties();
-        for (Object key: props.keySet()) {
+        for (Object key : props.keySet()) {
             if (!key.equals("THERMOSTAT_HOME")) {
                 newProps.put(key, props.get(key));
             }
@@ -66,35 +66,46 @@
     }
 
     @Test
-    public void testLocations() throws InvalidConfigurationException, IOException {
+    public void testSystemLocations() throws InvalidConfigurationException, IOException {
         String thermostatHome = "/tmp";
         System.setProperty("THERMOSTAT_HOME", thermostatHome);
-        
+
         char s = File.separatorChar;
 
         Configuration config = new Configuration();
 
-        Assert.assertEquals(thermostatHome, config.getThermostatHome());
+        Assert.assertEquals(thermostatHome, config.getSystemThermostatHome().getCanonicalPath());
+
+        Assert.assertEquals(thermostatHome + s + "libs" + s + "native",
+                config.getSystemNativeLibsRoot().getCanonicalPath());
+        Assert.assertEquals(thermostatHome + s + "etc", config.getSystemConfigurationDirectory().getCanonicalPath());
+        Assert.assertEquals(thermostatHome + s + "libs", config.getSystemLibRoot().getCanonicalPath());
+        Assert.assertEquals(thermostatHome + s + "plugins", config.getSystemPluginRoot().getCanonicalPath());
+    }
 
-        Assert.assertEquals(thermostatHome + s + "agent" + s + "agent.properties",
-                            config.getAgentConfigurationFile().getCanonicalPath());
-        Assert.assertEquals(thermostatHome + s + "agent" + s + "agent.auth",
-                                    config.getAgentAuthConfigFile().getCanonicalPath());
-        Assert.assertEquals(thermostatHome + s + "storage", config.getStorageBaseDirectory().getCanonicalPath());
-        Assert.assertEquals(thermostatHome + s + "storage" + s + "db.properties",
-                            config.getStorageConfigurationFile().getCanonicalPath());
-        Assert.assertEquals(thermostatHome + s + "storage" + s + "db",
-                config.getStorageDirectory().getCanonicalPath());
-        Assert.assertEquals(thermostatHome + s + "storage" + s + "logs" + s + "db.log",
-                config.getStorageLogFile().getCanonicalPath());
-        Assert.assertEquals(thermostatHome + s + "storage" + s + "run" + s + "db.pid",
-                config.getStoragePidFile().getCanonicalPath());
-        Assert.assertEquals(thermostatHome + s + "libs" + s + "native",
-                config.getNativeLibsRoot());
-        Assert.assertEquals(thermostatHome + s + "libs", config.getLibRoot());
-        Assert.assertEquals(thermostatHome + s + "plugins", config.getPluginRoot());
+    @Test
+    public void testUserLocations() throws InvalidConfigurationException, IOException {
+        String thermostatHome = "/tmp";
+        System.setProperty("THERMOSTAT_HOME", thermostatHome);
+        char s = File.separatorChar;
+        String userHome = System.getProperty("user.home") + s + ".thermostat";
+        Configuration config = new Configuration();
+
+        Assert.assertEquals(userHome + s + "etc" + s + "agent.properties",
+                config.getUserAgentConfigurationFile().getCanonicalPath());
+        Assert.assertEquals(userHome + s + "etc" + s + "agent.auth",
+                config.getUserAgentAuthConfigFile().getCanonicalPath());
+        Assert.assertEquals(userHome + s + "etc" + s + "db.properties",
+                config.getUserStorageConfigurationFile().getCanonicalPath());
+
+        Assert.assertEquals(userHome + s + "data" + s + "db",
+                config.getUserStorageDirectory().getCanonicalPath());
+        Assert.assertEquals(userHome + s + "run" + s + "db.pid",
+                config.getUserStoragePidFile().getCanonicalPath());
+        Assert.assertEquals(userHome + s + "logs" + s + "db.log",
+                config.getUserStorageLogFile().getCanonicalPath());
     }
-    
+
     @Test
     public void instantiationThrowsException() {
         try {
@@ -106,4 +117,3 @@
         }
     }
 }
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/src/test/java/com/redhat/thermostat/shared/config/NativeLibrayResolverTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012, 2013 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.shared.config;
+
+import static org.junit.Assert.assertFalse;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NativeLibrayResolverTest {
+
+    private static final String THERMOSTAT_HOME = "THERMOSTAT_HOME";
+
+    private String saved;
+
+    @Before
+    public void setUp() {
+        saved = System.setProperty(THERMOSTAT_HOME, "../foo/");
+    }
+
+    @After
+    public void tearDown() {
+        if (saved == null) {
+            System.clearProperty(THERMOSTAT_HOME);
+        } else {
+            System.setProperty(THERMOSTAT_HOME, null);
+        }
+    }
+
+    @Test
+    public void testGetAbsoluteLibraryPath() {
+        String absPath = NativeLibraryResolver.getAbsoluteLibraryPath("foo");
+        assertFalse(absPath.startsWith(".."));
+    }
+}
--- a/distribution/pom.xml	Mon Jul 22 20:01:46 2013 +0200
+++ b/distribution/pom.xml	Fri Jul 26 12:29:07 2013 -0400
@@ -144,7 +144,7 @@
                 </resource>
                 <resource>
                   <directory>config</directory>
-                  <targetPath>agent</targetPath>
+                  <targetPath>etc</targetPath>
                   <filtering>true</filtering>
                   <includes>
                     <include>agent.properties</include>
@@ -164,7 +164,7 @@
                 </resource>
                 <resource>
                   <directory>config</directory>
-                  <targetPath>storage</targetPath>
+                  <targetPath>etc</targetPath>
                   <filtering>true</filtering>
                   <includes>
                     <include>db.properties</include>
--- a/distribution/scripts/thermostat	Mon Jul 22 20:01:46 2013 +0200
+++ b/distribution/scripts/thermostat	Fri Jul 26 12:29:07 2013 -0400
@@ -45,8 +45,10 @@
 fi
 # Not always are installation directory and thermostat home one and
 # the same location.
-THERMOSTAT_HOME=${THERMOSTAT_INSTALL_DIR}
-export THERMOSTAT_HOME
+if [ x"$THERMOSTAT_HOME" = x ] ; then
+  THERMOSTAT_HOME=${THERMOSTAT_INSTALL_DIR}
+  export THERMOSTAT_HOME
+fi
 THERMOSTAT_LIBS="${THERMOSTAT_HOME}/libs"
 
 # need tools from the JVM
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/preferences/MainPreferencePage.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/preferences/MainPreferencePage.java	Fri Jul 26 12:29:07 2013 -0400
@@ -36,7 +36,7 @@
 
 package com.redhat.thermostat.eclipse.internal.preferences;
 
-import java.util.prefs.BackingStoreException;
+import java.io.IOException;
 
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.preferences.DefaultScope;
@@ -113,7 +113,7 @@
             clientPrefs.setCredentials(usernameEditor.getStringValue(), passwordEditor.getStringValue());
             try {
                 clientPrefs.flush();
-            } catch (BackingStoreException e) {
+            } catch (IOException e) {
                 LoggerFacility.getInstance().log(IStatus.ERROR, "Failed to save preferences", e);
             }
         }
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -44,6 +44,7 @@
 import java.lang.reflect.Field;
 import java.nio.file.Files;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import com.redhat.thermostat.common.utils.StreamUtils;
@@ -55,14 +56,36 @@
 
 /**
  * Helper methods to support writing an integration test.
+ * <p>
+ * This class should be used by all integration tests to start
+ * thermostat and to obtain paths to various locations. Starting
+ * thermostat manually will cause issues with wrong paths being
+ * used.
  */
 public class IntegrationTest {
 
+    public static class SpawnResult {
+        final Process process;
+        final Spawn spawn;
+
+        public SpawnResult(Process process, Spawn spawn) {
+            this.process = process;
+            this.spawn = spawn;
+        }
+    }
+
+    // FIXME Make sure all methods are using a sane environment that's set up correctly
+
     public static final long TIMEOUT_IN_SECONDS = 30;
 
     public static final String SHELL_PROMPT = "Thermostat >";
 
-    public static String getThermostatExecutable() {
+    private static final String THERMOSTAT_HOME = "THERMOSTAT_HOME";
+    private static final String USER_THERMOSTAT_HOME = "USER_THERMOSTAT_HOME";
+
+    /* This is a mirror of paths from c.r.t.shared.Configuration */
+
+    private static String getThermostatExecutable() {
         return "../distribution/target/bin/thermostat";
     }
     
@@ -70,8 +93,20 @@
         return "../distribution/target";
     }
 
+    public static String getPluginHome() {
+        return getThermostatHome() + "/plugins";
+    }
+
+    public static String getConfigurationDir() {
+        return getThermostatHome() + "/etc";
+    }
+
+    public static String getUserThermostatHome() {
+        return "../distribution/target/user-home";
+    }
+
     public static String getStorageDataDirectory() {
-        return "../distribution/target/storage/db";
+        return getUserThermostatHome() + "/data/db";
     }
 
     public static void clearStorageDataDirectory() throws IOException {
@@ -79,6 +114,15 @@
         deleteFilesRecursivelyUnder(storageDir);
     }
 
+    public static Process runThermostat(String... args) throws IOException {
+        List<String> completeArgs = new ArrayList<String>(args.length+1);
+        completeArgs.add(getThermostatExecutable());
+        completeArgs.addAll(Arrays.asList(args));
+        ProcessBuilder builder = buildThermostatProcess(completeArgs);
+
+        return builder.start();
+    }
+
     public static Spawn spawnThermostat(String... args) throws IOException {
         return spawnThermostat(false, args);
     }
@@ -92,14 +136,52 @@
             }
         }
         String toExecute = result.toString();
+        Executor exec = null;
         if (localeDependent) {
-            Executor exec = new LocaleExecutor(toExecute);
-            return expect.spawn(exec);
+            exec = new LocaleExecutor(toExecute);
         } else {
-            return expect.spawn(toExecute);
+            exec = new SimpleExecutor(toExecute);
         }
+        return expect.spawn(exec);
     }
 
+    public static SpawnResult spawnThermostatAndGetProcess(String... args) throws IOException {
+        final List<String> completeArgs = new ArrayList<String>(args.length+1);
+        completeArgs.add(getThermostatExecutable());
+        completeArgs.addAll(Arrays.asList(args));
+
+        final Process[] process = new Process[1];
+
+        ExpectJ expect = new ExpectJ(TIMEOUT_IN_SECONDS);
+
+        Spawn spawn = expect.spawn(new Executor() {
+            @Override
+            public Process execute() throws IOException {
+                ProcessBuilder builder = buildThermostatProcess(completeArgs);
+                Process service = builder.start();
+                process[0] = service;
+                return service;
+            }
+        });
+
+        return new SpawnResult(process[0], spawn);
+    }
+
+    private static ProcessBuilder buildThermostatProcess(List<String> args) {
+        ProcessBuilder builder = new ProcessBuilder(args);
+        builder.environment().put(THERMOSTAT_HOME, getThermostatHome());
+        builder.environment().put(USER_THERMOSTAT_HOME, getUserThermostatHome());
+
+        return builder;
+    }
+
+    /**
+     * Generic method to run a program.
+     * <p>
+     * DO NOT USE THIS TO RUN THERMOSTAT ITSELF. It does not set up the
+     * environment correctly, using incorrect data and possibly overwriting
+     * important data.
+     */
     public static Spawn spawn(List<String> args) throws IOException {
         ExpectJ expect = new ExpectJ(TIMEOUT_IN_SECONDS);
         StringBuilder result = new StringBuilder();
@@ -109,11 +191,6 @@
         return expect.spawn(result.substring(0, result.length() - 1));
     }
 
-    public static Spawn spawn(Executor executor) throws IOException {
-        ExpectJ expect = new ExpectJ(TIMEOUT_IN_SECONDS);
-        return expect.spawn(executor);
-    }
-
     /**
      * Kill the process and all its children, recursively. Sends SIGTERM.
      */
@@ -202,18 +279,45 @@
         spawn.send(password + "\r");
     }
 
-    private static class LocaleExecutor implements Executor {
+    private static class LocaleExecutor extends EnvironmentExecutor {
 
-        public static final String[] LANG_C = { "LANG=C " };
-        private String process;
+        public static final String[] ENV_WITH_LANG_C = {
+                THERMOSTAT_HOME + "=" + getThermostatHome(),
+                USER_THERMOSTAT_HOME + "=" + getUserThermostatHome(),
+                "LANG=C"
+        };
 
         public LocaleExecutor(String process) {
+            super(process, ENV_WITH_LANG_C);
+        }
+
+    }
+
+    private static class SimpleExecutor extends EnvironmentExecutor {
+
+        public static final String[] ENV_WITH = {
+                THERMOSTAT_HOME + "=" + getThermostatHome(),
+                USER_THERMOSTAT_HOME + "=" + getUserThermostatHome(),
+        };
+
+        public SimpleExecutor(String process) {
+            super(process, ENV_WITH);
+        }
+    }
+
+    private static class EnvironmentExecutor implements Executor {
+
+        private final String[] env;
+        private final String process;
+
+        public EnvironmentExecutor(String process, String[] env) {
             this.process = process;
+            this.env = env;
         }
 
         @Override
         public Process execute() throws IOException {
-            return Runtime.getRuntime().exec(process, LANG_C);
+            return Runtime.getRuntime().exec(process, env);
         }
 
         @Override
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -51,7 +51,7 @@
 
 public class PluginTest extends IntegrationTest {
 
-    private static final String PLUGIN_HOME = getThermostatHome() + File.separator + "plugins";
+    private static final String PLUGIN_HOME = getPluginHome();
 
     private static NewCommandPlugin newPlugin = new NewCommandPlugin(PLUGIN_HOME + File.separator + "new");
     private static UnknownExtendsPlugin unknownExtension = new UnknownExtendsPlugin(PLUGIN_HOME + File.separator + "unknown");
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/StorageTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/StorageTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -36,11 +36,8 @@
 
 package com.redhat.thermostat.itest;
 
-import java.io.IOException;
-
 import org.junit.Test;
 
-import expectj.Executor;
 import expectj.Spawn;
 
 public class StorageTest extends IntegrationTest {
@@ -76,25 +73,17 @@
 
     @Test
     public void testServiceStartAndKilling() throws Exception {
-        Spawn storage;
-        final Process[] process = new Process[1];
 
-        storage = spawn(new Executor() {
-            @Override
-            public Process execute() throws IOException {
-                ProcessBuilder builder = new ProcessBuilder(getThermostatExecutable(), "service");
-                Process service = builder.start();
-                process[0] = service;
-                return service;
-            }
-        });
+        SpawnResult spawnResult = spawnThermostatAndGetProcess("service");
+        Spawn storage = spawnResult.spawn;
 
         try {
             storage.expectErr("agent started");
         }
         finally {
-            killRecursively(process[0]);
+            killRecursively(spawnResult.process);
         }
+
     }
 
 }
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -55,7 +55,7 @@
     public static void setUpOnce() throws IOException, InterruptedException {
         clearStorageDataDirectory();
 
-        Process startStorage = new ProcessBuilder(getThermostatExecutable(), "storage", "--start").start();
+        Process startStorage = runThermostat("storage", "--start");
         startStorage.waitFor();
 
         // TODO insert actual data into the database and test that
@@ -63,7 +63,7 @@
 
     @AfterClass
     public static void tearDownOnce() throws InterruptedException, IOException {
-        Process stopStorage = new ProcessBuilder(getThermostatExecutable(), "storage", "--stop").start();
+        Process stopStorage = runThermostat("storage", "--stop");
         stopStorage.waitFor();
     }
 
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -95,7 +95,7 @@
 
 import expectj.Spawn;
 
-/*
+/**
  * This test class starts up a mongod instance and a web storage instance
  * (in jetty container) in front of that.  Tests should make their own
  * connection to the web storage, probably by making use of one of the
@@ -217,10 +217,8 @@
     private static final String PREP_USER = "prepuser";
     private static final String PREP_PASSWORD = "preppassword";
     private static final double EQUALS_DELTA = 0.00000000000001;
-    private static final String THERMOSTAT_USERS_FILE = getThermostatHome() +
-            "/etc/thermostat-users.properties";
-    private static final String THERMOSTAT_ROLES_FILE = getThermostatHome() +
-            "/etc/thermostat-roles.properties";
+    private static final String THERMOSTAT_USERS_FILE = getConfigurationDir() + "/thermostat-users.properties";
+    private static final String THERMOSTAT_ROLES_FILE = getConfigurationDir() + "/thermostat-roles.properties";
     private static final String VM_ID1 = "vmId1";
     private static final String VM_ID2 = "vmId2";
     private static final String VM_ID3 = "vmId3";
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java	Fri Jul 26 12:29:07 2013 -0400
@@ -80,11 +80,11 @@
             Keyring keyring = (Keyring)context.getService(reference);
             Configuration config = bundleService.getConfiguration();
 
-            String commandsDir = config.getConfigurationDir() + File.separator + "commands";
+            String commandsDir = new File(config.getSystemConfigurationDirectory(), "commands").toString();
             CommandInfoSource builtInCommandSource =
-                    new BuiltInCommandInfoSource(commandsDir, config.getLibRoot());
+                    new BuiltInCommandInfoSource(commandsDir, config.getSystemLibRoot().toString());
             CommandInfoSource pluginCommandSource = new PluginCommandInfoSource(
-                            config.getLibRoot(), config.getPluginRoot());
+                            config.getSystemLibRoot().toString(), config.getSystemPluginRoot().toString());
             CommandInfoSource commands = new CompoundCommandInfoSource(builtInCommandSource, pluginCommandSource);
 
             cmdInfoReg = context.registerService(CommandInfoSource.class, commands, null);
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BundleManagerImpl.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BundleManagerImpl.java	Fri Jul 26 12:29:07 2013 -0400
@@ -36,12 +36,12 @@
 
 package com.redhat.thermostat.launcher.internal;
 
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
@@ -90,8 +90,8 @@
         long t1 = System.nanoTime();
 
         try {
-            for (String root : new String[] { configuration.getLibRoot(), configuration.getPluginRoot() }) {
-                Files.walkFileTree(Paths.get(root), new SimpleFileVisitor<Path>() {
+            for (File root : new File[] { configuration.getSystemLibRoot(), configuration.getSystemPluginRoot() }) {
+                Files.walkFileTree(root.toPath(), new SimpleFileVisitor<Path>() {
                     @Override
                     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                         if (file.toFile().getName().endsWith(".jar")) {
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -108,7 +108,7 @@
         context.registerService(Command.class, helpCommand, props);
 
         Configuration config = mock(Configuration.class);
-        when(config.getThermostatHome()).thenReturn("");
+        when(config.getSystemThermostatHome()).thenReturn(new File(""));
         when(registryService.getConfiguration()).thenReturn(config);
 
         BuiltInCommandInfoSource source1 = mock(BuiltInCommandInfoSource.class);
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BundleManagerImplTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BundleManagerImplTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -38,14 +38,12 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.powermock.api.mockito.PowerMockito.mockStatic;
 import static org.powermock.api.mockito.PowerMockito.whenNew;
 
-import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.nio.file.FileVisitResult;
@@ -67,15 +65,12 @@
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
-import com.redhat.thermostat.plugin.validator.PluginConfigurationValidatorException;
 import com.redhat.thermostat.shared.config.Configuration;
 
 @RunWith(PowerMockRunner.class)
 @PrepareForTest({BundleManagerImpl.class, FrameworkUtil.class})
 public class BundleManagerImplTest {
 
-    private static final String cmdName = "one";
-
     private static final String jar1Name = "/one.jar";
     private static final String jar2Name = "/two.jar";
     private static final String jar3Name = "/three.jar";
@@ -100,8 +95,8 @@
         Files.createDirectories(jarRootDir);
 
         conf = mock(Configuration.class);
-        when(conf.getLibRoot()).thenReturn(jarRootDir.toFile().getPath());
-        when(conf.getPluginRoot()).thenReturn(pluginRootDir.toFile().getPath());
+        when(conf.getSystemLibRoot()).thenReturn(jarRootDir.toFile());
+        when(conf.getSystemPluginRoot()).thenReturn(pluginRootDir.toFile());
 
         theContext = mock(BundleContext.class);
         theFramework = mock(Framework.class);
--- a/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java	Fri Jul 26 12:29:07 2013 -0400
@@ -95,7 +95,7 @@
     }
 
     private String getOSGiPublicPackages() throws FileNotFoundException, IOException {
-        File osgiBundleDefinitions = new File(configuration.getConfigurationDir(), "osgi-export.properties");
+        File osgiBundleDefinitions = new File(configuration.getSystemConfigurationDirectory(), "osgi-export.properties");
 
         Properties bundles = new Properties();
         bundles.load(new FileInputStream(osgiBundleDefinitions));
@@ -161,7 +161,10 @@
     }
 
     private Framework makeFramework() throws FileNotFoundException, IOException {
-        File osgiCacheDir = new File(configuration.getThermostatHome(), "osgi-cache");
+        File osgiCacheDir = new File(configuration.getUserCacheDirectory(), "osgi-cache");
+        if (!osgiCacheDir.isDirectory() && !osgiCacheDir.mkdirs()) {
+            throw new RuntimeException("Unable to create " + osgiCacheDir);
+        }
 
         // Create temporary directory which will be used as cache for OSGi bundles. See
         // http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/Constants.html#FRAMEWORK_STORAGE
@@ -281,7 +284,7 @@
     }
 
     private String actualLocation(String resourceName) {
-        return new File(configuration.getLibRoot(), resourceName).toURI().toString();
+        return new File(configuration.getSystemLibRoot(), resourceName).toURI().toString();
     }
 }
 
--- a/main/src/test/java/com/redhat/thermostat/main/ThermostatTest.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/main/src/test/java/com/redhat/thermostat/main/ThermostatTest.java	Fri Jul 26 12:29:07 2013 -0400
@@ -80,6 +80,7 @@
         tempDir = Files.createTempDirectory("test");
         tempDir.toFile().deleteOnExit();
         System.setProperty("THERMOSTAT_HOME", tempDir.toString());
+        System.setProperty("USER_THERMOSTAT_HOME", tempDir.toString());
         
         File tempEtc = new File(tempDir.toFile(), "etc");
         tempEtc.mkdirs();
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Fri Jul 26 12:29:07 2013 -0400
@@ -270,7 +270,7 @@
     private File getThermostatHome() {
         try {
             Configuration config = new Configuration();
-            return new File(config.getThermostatHome());
+            return config.getSystemThermostatHome();
         } catch (InvalidConfigurationException e) {
             // we should have just checked if this throws any exception
             logger.log(Level.SEVERE, "Illegal configuration!", e);
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java	Fri Jul 26 12:29:07 2013 -0400
@@ -61,7 +61,9 @@
     private Properties users;
     
     PropertiesUserValidator() {
-        this((new Configuration().getConfigurationDir() + File.separator + DEFAULT_USERS_FILE));
+        // this is the default configuration. it should be overriden through different means
+        // see javadoc of PropertiesUsernameRolesLoginModule
+        this((new Configuration().getSystemConfigurationDirectory() + File.separator + DEFAULT_USERS_FILE));
     }
     
     PropertiesUserValidator(String usersFile) {
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java	Mon Jul 22 20:01:46 2013 +0200
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java	Fri Jul 26 12:29:07 2013 -0400
@@ -71,7 +71,10 @@
     private final Set<Object> users; 
 
     RolesAmender(Set<Object> users) {
-        this((new Configuration().getConfigurationDir() + File.separator + DEFAULT_ROLES_FILE), users);
+        // this is the default configuration supplied with thermostat
+        // it should not be overriden by editing this configuraton file
+        // see javadocs of PropertiesUsernameRolesLoginModule
+        this((new Configuration().getSystemConfigurationDirectory() + File.separator + DEFAULT_ROLES_FILE), users);
     }
     
     RolesAmender(String rolesFile, Set<Object> users) {