changeset 1342:17897c533dff

Configuration now is CommonPaths and a service reviewed-by: omajid, jerboaa, ebaron review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-November/008729.html
author Jon VanAlten <jon.vanalten@redhat.com>
date Mon, 18 Nov 2013 08:22:15 -0700
parents 70ab2071e074
children c97362b7a23d
files agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.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/ActivatorTest.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/main/java/com/redhat/thermostat/agent/internal/Activator.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnector.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 agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/Activator.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ActivatorTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainTest.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistry.java common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistryImpl.java common/core/src/main/java/com/redhat/thermostat/common/config/ClientPreferences.java common/core/src/main/java/com/redhat/thermostat/common/utils/LoggingUtils.java common/core/src/main/java/com/redhat/thermostat/test/TestCommandContextFactory.java common/core/src/main/java/com/redhat/thermostat/test/TestCommandRegistry.java common/test/src/main/java/com/redhat/thermostat/testutils/Asserts.java common/test/src/main/java/com/redhat/thermostat/testutils/StubServiceReference.java common/test/src/main/java/com/redhat/thermostat/testutils/TestUtils.java config/pom.xml config/src/main/java/com/redhat/thermostat/shared/config/CommonPaths.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/main/java/com/redhat/thermostat/shared/config/internal/Activator.java config/src/main/java/com/redhat/thermostat/shared/config/internal/CommonPathsImpl.java config/src/main/java/com/redhat/thermostat/shared/config/internal/SSLConfigurationImpl.java config/src/main/java/com/redhat/thermostat/shared/locale/LocaleResources.java config/src/main/java/com/redhat/thermostat/shared/locale/internal/LocaleResources.java config/src/main/resources/com/redhat/thermostat/shared/locale/internal/strings.properties config/src/main/resources/com/redhat/thermostat/shared/locale/strings.properties config/src/test/java/com/redhat/thermostat/shared/config/ConfigurationTest.java config/src/test/java/com/redhat/thermostat/shared/config/NativeLibrayResolverTest.java config/src/test/java/com/redhat/thermostat/shared/config/internal/ActivatorTest.java config/src/test/java/com/redhat/thermostat/shared/config/internal/CommonPathsImplTest.java config/src/test/java/com/redhat/thermostat/shared/config/internal/SSLConfigurationImplTest.java config/src/test/java/com/redhat/thermostat/shared/locale/LocaleResourcesTest.java eclipse/com.redhat.thermostat.client.feature/build.properties eclipse/com.redhat.thermostat.eclipse/META-INF/MANIFEST.MF eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/Activator.java eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/preferences/MainPreferencePage.java eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/views/HostsVmsTreeViewPart.java integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java launcher/src/main/java/com/redhat/thermostat/launcher/BundleManager.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/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/BundleManagerImplTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java main/src/main/java/com/redhat/thermostat/main/Thermostat.java main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactory.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 web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java
diffstat 72 files changed, 1562 insertions(+), 957 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java	Mon Nov 18 08:22:15 2013 -0700
@@ -47,6 +47,7 @@
 import com.redhat.thermostat.common.MultipleServiceTracker.Action;
 import com.redhat.thermostat.common.cli.CommandRegistry;
 import com.redhat.thermostat.common.cli.CommandRegistryImpl;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.storage.core.WriterID;
 
 public class Activator implements BundleActivator {
@@ -61,6 +62,7 @@
         
         Class<?>[] deps = new Class<?>[] {
                 ExitStatus.class,
+                CommonPaths.class,
                 WriterID.class // agent app uses it
         };
         tracker = new MultipleServiceTracker(context, deps, new Action() {
@@ -68,10 +70,11 @@
             @Override
             public void dependenciesAvailable(Map<String, Object> services) {
                 ExitStatus exitStatus = (ExitStatus) services.get(ExitStatus.class.getName());
+                CommonPaths paths = (CommonPaths) services.get(CommonPaths.class.getName());
                 WriterID writerID = (WriterID) services.get(WriterID.class.getName());
                 agentApplication = new AgentApplication(context, exitStatus, writerID);
                 reg.registerCommand("service", new ServiceCommand(context));
-                reg.registerCommand("storage", new StorageCommand(exitStatus));
+                reg.registerCommand("storage", new StorageCommand(exitStatus, paths));
                 reg.registerCommand("agent", agentApplication);
             }
 
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java	Mon Nov 18 08:22:15 2013 -0700
@@ -50,7 +50,7 @@
 import com.redhat.thermostat.common.tools.ApplicationException;
 import com.redhat.thermostat.common.tools.ApplicationState;
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.locale.Translate;
 
@@ -62,24 +62,24 @@
     private DBStartupConfiguration configuration;
     private DBOptionParser parser;
     private final ExitStatus exitStatus;
+    private final CommonPaths paths;
     
     private MongoProcessRunner runner;
     
-    public StorageCommand(ExitStatus exitStatus) {
+    public StorageCommand(ExitStatus exitStatus, CommonPaths paths) {
         this.exitStatus = exitStatus;
+        this.paths = paths;
     }
     
     private void parseArguments(Arguments args) throws InvalidConfigurationException {
-    
-        Configuration thermostatConfiguration = new Configuration();
-        File dbPath = thermostatConfiguration.getUserStorageDirectory();
-        File logFile = thermostatConfiguration.getUserStorageLogFile();
-        File pidFile = thermostatConfiguration.getUserStoragePidFile();
-        File systemPropertyFile = thermostatConfiguration.getSystemStorageConfigurationFile();
+        File dbPath = paths.getUserStorageDirectory();
+        File logFile = paths.getUserStorageLogFile();
+        File pidFile = paths.getUserStoragePidFile();
+        File systemPropertyFile = paths.getSystemStorageConfigurationFile();
         if (!systemPropertyFile.exists()) {
             throw new InvalidConfigurationException(t.localize(LocaleResources.MISSING_DB_CONFIG, systemPropertyFile.toString()));
         }
-        File userPropertyFile = thermostatConfiguration.getUserStorageConfigurationFile();
+        File userPropertyFile = paths.getUserStorageConfigurationFile();
         // read everything that is in the configs
         this.configuration = new DBStartupConfiguration(systemPropertyFile, userPropertyFile, dbPath, logFile, pidFile);
         parser = new DBOptionParser(configuration, args);
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -44,6 +44,7 @@
 
 import com.redhat.thermostat.agent.cli.impl.db.StorageCommand;
 import com.redhat.thermostat.common.ExitStatus;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.testutils.StubBundleContext;
 
@@ -55,8 +56,10 @@
 
         ExitStatus exitStatus = mock(ExitStatus.class);
         WriterID writerID = mock(WriterID.class);
+        CommonPaths paths = mock(CommonPaths.class);
         bundleContext.registerService(WriterID.class, writerID, null);
         bundleContext.registerService(ExitStatus.class, exitStatus, null);
+        bundleContext.registerService(CommonPaths.class, paths, null);
         
         Activator activator = new Activator();
 
@@ -64,7 +67,7 @@
         
         activator.start(bundleContext);
         
-        assertEquals(2, bundleContext.getServiceListeners().size());
+        assertEquals(3, bundleContext.getServiceListeners().size());
         
         assertCommandIsRegistered(bundleContext, "agent", AgentApplication.class);
         assertCommandIsRegistered(bundleContext, "service", ServiceCommand.class);
@@ -73,7 +76,7 @@
         activator.stop(bundleContext);
 
         assertEquals(0, bundleContext.getServiceListeners().size());
-        assertEquals(2, bundleContext.getAllServices().size());
+        assertEquals(3, bundleContext.getAllServices().size());
     }
 }
 
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommandTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommandTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -43,10 +43,8 @@
 import static org.mockito.Mockito.when;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Properties;
-import java.util.Random;
 import java.util.concurrent.CountDownLatch;
 
 import junit.framework.Assert;
@@ -63,7 +61,9 @@
 import com.redhat.thermostat.common.cli.SimpleArguments;
 import com.redhat.thermostat.common.tools.ApplicationException;
 import com.redhat.thermostat.common.tools.ApplicationState;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
+import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
 import com.redhat.thermostat.testutils.TestUtils;
 
 public class StorageCommandTest {
@@ -74,6 +74,7 @@
 
     private String tmpDir;
     private ExitStatus exitStatus;
+    private CommonPaths paths;
     
     @Before
     public void setup() {
@@ -89,6 +90,27 @@
         } catch (IOException e) {
             Assert.fail("cannot setup tests: " + e);
         }
+
+        paths = mock(CommonPathsImpl.class);
+        File baseDir = new File(tmpDir);
+        File userRuntimeDir = new File(baseDir, "run");
+        File userDataDir = new File(baseDir, "data");
+        File logsDir = new File(baseDir, "logs");
+        File confDir = new File(baseDir, "etc");
+
+        when(paths.getUserThermostatHome()).thenReturn(baseDir);
+        when(paths.getUserRuntimeDataDirectory()).thenReturn(userRuntimeDir);
+        when(paths.getUserPersistentDataDirectory()).thenReturn(userDataDir);
+        when(paths.getUserConfigurationDirectory()).thenReturn(confDir);
+        when(paths.getUserStorageDirectory()).thenCallRealMethod();
+        when(paths.getUserStorageConfigurationFile()).thenCallRealMethod();
+        when(paths.getUserLogDirectory()).thenReturn(logsDir);
+        when(paths.getUserStorageLogFile()).thenCallRealMethod();
+        when(paths.getUserStoragePidFile()).thenCallRealMethod();
+
+        when(paths.getSystemThermostatHome()).thenReturn(baseDir);
+        when(paths.getSystemConfigurationDirectory()).thenCallRealMethod();
+        when(paths.getSystemStorageConfigurationFile()).thenCallRealMethod();
     }
     
     @After
@@ -105,7 +127,7 @@
         CommandContext ctx = mock(CommandContext.class);
         when(ctx.getArguments()).thenReturn(args);
 
-        StorageCommand service = new StorageCommand(exitStatus) {
+        StorageCommand service = new StorageCommand(exitStatus, paths) {
             @Override
             MongoProcessRunner createRunner() {
                 throw new AssertionError("dry run should never create an actual runner");
@@ -132,7 +154,7 @@
         // TODO: stop not tested yet, but be sure it's not called from the code
         doThrow(new ApplicationException("mock exception")).when(runner).stopService();
         
-        StorageCommand service = new StorageCommand(exitStatus) {
+        StorageCommand service = new StorageCommand(exitStatus, paths) {
             @Override
             MongoProcessRunner createRunner() {
                 return runner;
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentConfigsUtils.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentConfigsUtils.java	Mon Nov 18 08:22:15 2013 -0700
@@ -46,28 +46,29 @@
 import java.util.Properties;
 
 import com.redhat.thermostat.agent.locale.LocaleResources;
-import com.redhat.thermostat.shared.config.Configuration;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.locale.Translate;
 
 public class AgentConfigsUtils {
 
     private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
+    private static File systemConfiguration, userConfiguration, agentAuthFile;
 
     private static char[] pw = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
     private static char[] user = {'u', 's', 'e', 'r', 'n', 'a', 'm', 'e'};
     private static String newLine = System.lineSeparator();
     private static char comment = '#';
 
+    public static void setConfigFiles(File systemConfigFile, File userConfigFile, File agentAuthFile) {
+        AgentConfigsUtils.systemConfiguration = systemConfigFile;
+        AgentConfigsUtils.userConfiguration = userConfigFile;
+        AgentConfigsUtils.agentAuthFile = agentAuthFile;
+    }
+
     public static AgentStartupConfiguration createAgentConfigs() throws InvalidConfigurationException {
         
         AgentStartupConfiguration config = new AgentStartupConfiguration();
-
-        Configuration mainConfig = new Configuration();
-        File systemConfiguration = mainConfig.getSystemAgentConfigurationFile();
-        File userConfiguration = mainConfig.getUserAgentConfigurationFile();
         readAndSetProperties(systemConfiguration, userConfiguration, config);
-        File agentAuthFile = mainConfig.getUserAgentAuthConfigFile();
         setAuthConfigFromFile(agentAuthFile, config);
         return config;
     }
@@ -76,17 +77,21 @@
             throws InvalidConfigurationException
     {
         Properties systemConfig = new Properties();
-        try {
-            systemConfig.load(new FileInputStream(systemConfigFile));
-        } catch (IOException e) {
-            throw new InvalidConfigurationException(e);
+        if (systemConfigFile != null) {
+            try {
+                systemConfig.load(new FileInputStream(systemConfigFile));
+            } catch (IOException e) {
+                throw new InvalidConfigurationException(e);
+            }
         }
 
         Properties properties = new Properties(systemConfig);
-        try {
-            properties.load(new FileInputStream(userConfigFile));
-        } catch (IOException e) {
-            // that's okay. just use system config
+        if (userConfigFile != null) {
+            try {
+                properties.load(new FileInputStream(userConfigFile));
+            } catch (IOException e) {
+                // that's okay. just use system config
+            }
         }
 
         String db = properties.getProperty(AgentProperties.DB_URL.name());
@@ -114,7 +119,7 @@
         // Default values will be enough if storage configured with not auth necessary.
         config.setUsername("");
         config.setPassword("");
-        if (authFile.canRead() && authFile.isFile()) {
+        if (authFile != null && authFile.canRead() && authFile.isFile()) {
             long length = authFile.length();
             char[] authData = null;
             try (Reader reader = new InputStreamReader(new FileInputStream(authFile), StandardCharsets.US_ASCII)) {
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Mon Nov 18 08:22:15 2013 -0700
@@ -38,8 +38,12 @@
 
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
 
 import com.redhat.thermostat.agent.VmBlacklist;
+
+import com.redhat.thermostat.agent.config.AgentConfigsUtils;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.utils.management.MXBeanConnectionPool;
 import com.redhat.thermostat.utils.management.internal.AgentProxyFilter;
 import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl;
@@ -48,19 +52,18 @@
 
 public class Activator implements BundleActivator {
     
-    private final MXBeanConnectionPoolImpl pool;
-    
-    public Activator() {
-        this(new MXBeanConnectionPoolImpl());
-    }
-    
-    Activator(MXBeanConnectionPoolImpl pool) {
-        this.pool = pool;
-    }
+    private MXBeanConnectionPoolImpl pool;
 
     @Override
     public void start(BundleContext context) throws Exception {
+        ServiceReference<CommonPaths> pathsRef = context.getServiceReference(CommonPaths.class);
+        CommonPaths paths = context.getService(pathsRef);
+        pool = new MXBeanConnectionPoolImpl(paths.getSystemBinRoot());
         context.registerService(MXBeanConnectionPool.class, pool, null);
+        AgentConfigsUtils.setConfigFiles(paths.getSystemAgentConfigurationFile(), paths.getUserAgentConfigurationFile(),
+        		                   paths.getUserAgentAuthConfigFile());
+        paths = null;
+        context.ungetService(pathsRef);
         context.registerService(UserNameUtil.class, new UserNameUtilImpl(), null);
         VmBlacklistImpl blacklist = new VmBlacklistImpl();
         blacklist.addVmFilter(new AgentProxyFilter());
@@ -70,7 +73,15 @@
     @Override
     public void stop(BundleContext context) throws Exception {
         // Services automatically unregistered by framework
-        pool.shutdown();
+        if (pool != null) {
+            pool.shutdown();
+            pool = null;
+        }
+    }
+
+    // Testing hook.
+    void setPool(MXBeanConnectionPoolImpl pool) {
+        this.pool = pool;
     }
 
 }
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java	Mon Nov 18 08:22:15 2013 -0700
@@ -51,7 +51,6 @@
 import com.redhat.thermostat.common.tools.ApplicationException;
 import com.redhat.thermostat.common.utils.LoggedExternalProcess;
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.Configuration;
 
 class AgentProxyClient implements AgentProxyListener {
     
@@ -62,22 +61,22 @@
     private final RMIRegistry registry;
     private final int pid;
     private final ProcessCreator procCreator;
-    private final Configuration config;
+    private final File binPath;
     private final CountDownLatch started;
     
     private AgentProxyControl proxy;
     private Exception serverError;
     
-    AgentProxyClient(RMIRegistry registry, int pid) {
-        this(registry, pid, new Configuration(), new CountDownLatch(1), 
+    AgentProxyClient(RMIRegistry registry, int pid, File binPath) {
+        this(registry, pid, binPath, new CountDownLatch(1), 
                 new ProcessCreator());
     }
 
-    AgentProxyClient(RMIRegistry registry, int pid, Configuration config,
+    AgentProxyClient(RMIRegistry registry, int pid, File binPath,
             CountDownLatch started, ProcessCreator procCreator) {
         this.registry = registry;
         this.pid = pid;
-        this.config = config;
+        this.binPath = binPath;
         this.started = started;
         this.procCreator = procCreator;
     }
@@ -120,7 +119,7 @@
     }
 
     private void startProcess() throws IOException, ApplicationException {
-        String serverPath = config.getSystemBinRoot() + File.separator + SERVER_NAME;
+        String serverPath = binPath + File.separator + SERVER_NAME;
         procCreator.createAndRunProcess(new String[] { serverPath, String.valueOf(pid) });
         try {
             boolean result = started.await(SERVER_TIMEOUT_MS, TimeUnit.MILLISECONDS);
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java	Mon Nov 18 08:22:15 2013 -0700
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.utils.management.internal;
 
+import java.io.File;
 import java.io.IOException;
 import java.rmi.RemoteException;
 import java.util.HashMap;
@@ -58,19 +59,21 @@
 
     private final ConnectorCreator creator;
     private final RMIRegistry registry;
+    private final File binPath;
 
-    public MXBeanConnectionPoolImpl() {
-        this(new ConnectorCreator(), new RMIRegistry());
+    public MXBeanConnectionPoolImpl(File binPath) {
+        this(new ConnectorCreator(), new RMIRegistry(), binPath);
     }
     
     // For testing purposes only
-    public MXBeanConnectionPoolImpl(RMIRegistry registry) {
-        this(new ConnectorCreator(), registry);
+    public MXBeanConnectionPoolImpl(RMIRegistry registry, File binPath) {
+        this(new ConnectorCreator(), registry, binPath);
     }
 
-    MXBeanConnectionPoolImpl(ConnectorCreator connectorCreator, RMIRegistry registry) {
+    MXBeanConnectionPoolImpl(ConnectorCreator connectorCreator, RMIRegistry registry, File binPath) {
         this.creator = connectorCreator;
         this.registry = registry;
+        this.binPath = binPath;
         
         // Start RMI registry
         try {
@@ -86,7 +89,7 @@
         if (data == null) {
             MXBeanConnector connector = null;
             try {
-                connector = creator.create(registry, pid);
+                connector = creator.create(registry, pid, binPath);
                 connector.attach();
                 MXBeanConnectionImpl connection = connector.connect();
                 data = new Pair<Integer, MXBeanConnectionImpl>(1, connection);
@@ -126,8 +129,8 @@
     }
 
     static class ConnectorCreator {
-        public MXBeanConnector create(RMIRegistry registry, int pid) throws IOException, ApplicationException {
-            MXBeanConnector connector = new MXBeanConnector(registry, pid);
+        public MXBeanConnector create(RMIRegistry registry, int pid, File binPath) throws IOException, ApplicationException {
+            MXBeanConnector connector = new MXBeanConnector(registry, pid, binPath);
             return connector;
         }
     }
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnector.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnector.java	Mon Nov 18 08:22:15 2013 -0700
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.utils.management.internal;
 
 import java.io.Closeable;
+import java.io.File;
 import java.io.IOException;
 import java.rmi.RemoteException;
 
@@ -52,8 +53,8 @@
     private final AgentProxyClient client;
     private final JMXConnectionCreator jmxCreator;
     
-    public MXBeanConnector(RMIRegistry registry, int pid) throws IOException, ApplicationException {
-        this(new AgentProxyClient(registry, pid), new JMXConnectionCreator());
+    public MXBeanConnector(RMIRegistry registry, int pid, File binPath) throws IOException, ApplicationException {
+        this(new AgentProxyClient(registry, pid, binPath), new JMXConnectionCreator());
     }
     
     MXBeanConnector(AgentProxyClient client, JMXConnectionCreator jmxCreator) throws IOException, ApplicationException {
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentConfigsUtilsTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentConfigsUtilsTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -63,6 +63,10 @@
 
         try {
             TestUtils.setupAgentConfigs(agentProperties);
+            File agentConf = TestUtils.getAgentConfFile();
+            File agentAuth = TestUtils.getAgentAuthFile();
+            // By default system config == user config
+            AgentConfigsUtils.setConfigFiles(agentConf, agentConf, agentAuth);
         } catch (IOException e) {
             throw new AssertionError("Unable to create agent configuration", e);
         }
@@ -96,6 +100,8 @@
         Assert.assertEquals("", config.getPassword());
     }
 
+    // TODO add test to ensure user agent config overrides system agent config.
+
     @Test
     public void testAuthConfigWithConfigCommentedOut() throws IOException {
         File tmpAuth = createTempAuthFile("#username=user\n#password=pass\n");
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentOptionParserTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentOptionParserTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -75,12 +75,14 @@
         SimpleArguments args = new SimpleArguments();
         args.addArgument("dbUrl", "testURL");
         
-        AgentStartupConfiguration configs = AgentConfigsUtils.createAgentConfigs();
+        AgentStartupConfiguration configs = new AgentStartupConfiguration();
+        configs.setDatabaseURL("Not the right URL");
+        configs.setPurge(true);
         AgentOptionParser parser = new AgentOptionParser(configs, args);
         parser.parse();
         
         Assert.assertEquals("testURL", configs.getDBConnectionString());
-        Assert.assertFalse(configs.purge());
+        Assert.assertTrue(configs.purge());
     }
     
     @Test
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -39,14 +39,18 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
 
 import org.junit.Test;
 
 import com.redhat.thermostat.agent.VmBlacklist;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.shared.config.NativeLibraryResolver;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import com.redhat.thermostat.utils.management.MXBeanConnectionPool;
 import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl;
-import com.redhat.thermostat.utils.management.internal.RMIRegistry;
 import com.redhat.thermostat.utils.username.UserNameUtil;
 import com.redhat.thermostat.utils.username.internal.UserNameUtilImpl;
 
@@ -54,11 +58,16 @@
     @Test
     public void verifyServiceIsRegistered() throws Exception {
 
-        StubBundleContext context = new StubBundleContext();
+    	CommonPaths paths = mock(CommonPaths.class);
+    	when(paths.getSystemNativeLibsRoot()).thenReturn(new File("target"));
+    	NativeLibraryResolver.setCommonPaths(paths);
 
-        RMIRegistry registry = mock(RMIRegistry.class);
-        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(registry);
-        Activator activator = new Activator(pool);
+        StubBundleContext context = new StubBundleContext();
+        context.registerService(CommonPaths.class.getName(), paths, null);
+
+        //RMIRegistry registry = mock(RMIRegistry.class);
+        //MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(registry);
+        Activator activator = new Activator();
 
         activator.start(context);
 
@@ -73,7 +82,8 @@
         StubBundleContext context = new StubBundleContext();
 
         MXBeanConnectionPoolImpl pool = mock(MXBeanConnectionPoolImpl.class);
-        Activator activator = new Activator(pool);
+        Activator activator = new Activator();
+        activator.setPool(pool);
 
         activator.stop(context);
 
--- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -61,7 +61,6 @@
 import com.redhat.thermostat.agent.proxy.common.AgentProxyListener;
 import com.redhat.thermostat.agent.proxy.common.AgentProxyLogin;
 import com.redhat.thermostat.common.tools.ApplicationException;
-import com.redhat.thermostat.shared.config.Configuration;
 import com.redhat.thermostat.utils.management.internal.AgentProxyClient.ProcessCreator;
 
 public class AgentProxyClientTest {
@@ -70,11 +69,11 @@
     private RMIRegistry rmi;
     private Registry registry;
     private ProcessCreator procCreator;
-    private Configuration config;
     private CountDownLatch latch;
     private AgentProxyListener listenerStub;
     private AgentProxyLogin proxyLogin;
     private AgentProxyControl proxyControl;
+    private File binPath;
     
     @Before
     public void setup() throws Exception {
@@ -89,9 +88,7 @@
         when(proxyLogin.login()).thenReturn(proxyControl);
         
         procCreator = mock(ProcessCreator.class);
-        config = mock(Configuration.class);
-        String binPath = "/path/to/thermostat/bin";
-        when(config.getSystemBinRoot()).thenReturn(new File(binPath));
+        binPath = new File("/path/to/thermostat/bin");
         latch = mock(CountDownLatch.class);
     }
     
@@ -122,7 +119,7 @@
 
     private void createClient() throws InterruptedException, IOException,
             ApplicationException {
-        client = new AgentProxyClient(rmi, 0, config, latch, procCreator);
+        client = new AgentProxyClient(rmi, 0, binPath, latch, procCreator);
         
         doAnswer(new Answer<Boolean>() {
             @Override
@@ -138,7 +135,7 @@
     
     @Test
     public void testCreateProxyFailed() throws Exception {
-        client = new AgentProxyClient(rmi, 0, config, latch, procCreator);
+        client = new AgentProxyClient(rmi, 0, binPath, latch, procCreator);
         
         final Exception error = mock(Exception.class);
         doAnswer(new Answer<Boolean>() {
@@ -174,7 +171,7 @@
     @Test
     public void testCreateProxyTimeout() throws Exception {
         when(latch.await(any(Long.class), any(TimeUnit.class))).thenReturn(false);
-        client = new AgentProxyClient(rmi, 0, config, latch, procCreator);
+        client = new AgentProxyClient(rmi, 0, binPath, latch, procCreator);
         
         try {
             client.createProxy();
--- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -46,6 +46,8 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import java.io.File;
+
 import org.junit.Test;
 
 import com.redhat.thermostat.utils.management.MXBeanConnection;
@@ -53,17 +55,19 @@
 
 public class MXBeanConnectionPoolImplTest {
 
+    private File binDir = mock(File.class);
+
     @Test
     public void testAcquire() throws Exception {
         MXBeanConnectionImpl toReturn = mock(MXBeanConnectionImpl.class);
         MXBeanConnector connector = mock(MXBeanConnector.class);
         ConnectorCreator creator = mock(ConnectorCreator.class);
 
-        when(creator.create(any(RMIRegistry.class), anyInt())).thenReturn(connector);
+        when(creator.create(any(RMIRegistry.class), anyInt(), any(File.class))).thenReturn(connector);
         when(connector.connect()).thenReturn(toReturn);
 
         RMIRegistry registry = mock(RMIRegistry.class);
-        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry);
+        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir);
 
         MXBeanConnection connection = pool.acquire(0);
 
@@ -81,11 +85,11 @@
         MXBeanConnector connector = mock(MXBeanConnector.class);
         ConnectorCreator creator = mock(ConnectorCreator.class);
 
-        when(creator.create(any(RMIRegistry.class), anyInt())).thenReturn(connector);
+        when(creator.create(any(RMIRegistry.class), anyInt(), any(File.class))).thenReturn(connector);
         when(connector.connect()).thenReturn(toReturn);
 
         RMIRegistry registry = mock(RMIRegistry.class);
-        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry);
+        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir);
 
         MXBeanConnection connection1 = pool.acquire(0);
 
@@ -107,11 +111,11 @@
         MXBeanConnector connector = mock(MXBeanConnector.class);
         ConnectorCreator creator = mock(ConnectorCreator.class);
 
-        when(creator.create(any(RMIRegistry.class), anyInt())).thenReturn(connector);
+        when(creator.create(any(RMIRegistry.class), anyInt(), any(File.class))).thenReturn(connector);
         when(connector.connect()).thenReturn(actualConnection);
 
         RMIRegistry registry = mock(RMIRegistry.class);
-        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry);
+        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir);
 
         MXBeanConnection connection = pool.acquire(0);
 
@@ -128,11 +132,11 @@
         MXBeanConnector connector = mock(MXBeanConnector.class);
         ConnectorCreator creator = mock(ConnectorCreator.class);
 
-        when(creator.create(any(RMIRegistry.class), anyInt())).thenReturn(connector);
+        when(creator.create(any(RMIRegistry.class), anyInt(), any(File.class))).thenReturn(connector);
         when(connector.connect()).thenReturn(actualConnection);
 
         RMIRegistry registry = mock(RMIRegistry.class);
-        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry);
+        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir);
 
         // connection1 == connection1 == actualConnection
         MXBeanConnection connection1 = pool.acquire(0);
@@ -152,7 +156,7 @@
     public void testShutdown() throws Exception {
         RMIRegistry registry = mock(RMIRegistry.class);
         ConnectorCreator creator = mock(ConnectorCreator.class);
-        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry);
+        MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir);
         verify(registry).start();
         
         pool.shutdown();
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/Activator.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/Activator.java	Mon Nov 18 08:22:15 2013 -0700
@@ -36,31 +36,61 @@
 
 package com.redhat.thermostat.client.cli.internal;
 
+import java.util.Map;
+
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.MultipleServiceTracker.Action;
 import com.redhat.thermostat.common.cli.CommandRegistry;
 import com.redhat.thermostat.common.cli.CommandRegistryImpl;
+import com.redhat.thermostat.common.config.ClientPreferences;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class Activator implements BundleActivator {
 
-    private CommandRegistry reg;
+    private CommandRegistry reg = null;
+    private MultipleServiceTracker tracker;
 
     @Override
-    public void start(BundleContext context) throws Exception {
+    public void start(final BundleContext context) throws Exception {
         reg = new CommandRegistryImpl(context);
 
         reg.registerCommand("list-vms", new ListVMsCommand());
-        reg.registerCommand("shell", new ShellCommand());
         reg.registerCommand("vm-info", new VMInfoCommand());
         reg.registerCommand("vm-stat", new VMStatCommand());
         reg.registerCommand("disconnect", new DisconnectCommand());
-        reg.registerCommand("connect", new ConnectCommand());
         reg.registerCommand("clean-data", new CleanDataCommand(context));
+
+        Class<?>[] classes = new Class[] {
+            Keyring.class,
+            CommonPaths.class,
+        };
+        tracker = new MultipleServiceTracker(context, classes, new Action() {
+
+            @Override
+            public void dependenciesAvailable(Map<String, Object> services) {
+                Keyring keyring = (Keyring) services.get(Keyring.class.getName());
+                CommonPaths paths = (CommonPaths) services.get(CommonPaths.class.getName());
+                ClientPreferences prefs = new ClientPreferences(keyring, paths);
+                reg.registerCommand("connect", new ConnectCommand(prefs));
+                reg.registerCommand("shell", new ShellCommand(context, paths));
+            }
+
+            @Override
+            public void dependenciesUnavailable() {
+                reg.unregisterCommand("connect");
+            }
+            
+        });
+        tracker.open();
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
+        tracker.close();
         reg.unregisterCommands();
     }
 
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ConnectCommand.java	Mon Nov 18 08:22:15 2013 -0700
@@ -48,6 +48,7 @@
 import com.redhat.thermostat.common.cli.CommandException;
 import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.common.tools.StorageAuthInfoGetter;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.locale.Translate;
 import com.redhat.thermostat.storage.core.ConnectionException;
 import com.redhat.thermostat.storage.core.DbService;
@@ -73,13 +74,14 @@
     private BundleContext context;
     private DbServiceFactory dbServiceFactory;
 
-    public ConnectCommand() {
-        this(FrameworkUtil.getBundle(ConnectCommand.class).getBundleContext(), new DbServiceFactory());
+    public ConnectCommand(ClientPreferences prefs) {
+        this(FrameworkUtil.getBundle(ConnectCommand.class).getBundleContext(), new DbServiceFactory(), prefs);
     }
     
-    ConnectCommand(BundleContext context, DbServiceFactory dbServiceFactory) {
+    ConnectCommand(BundleContext context, DbServiceFactory dbServiceFactory, ClientPreferences prefs) {
         this.context = context;
         this.dbServiceFactory = dbServiceFactory;
+        this.prefs = prefs;
     }
 
     @Override
@@ -92,15 +94,6 @@
             // Already connected, bail out
             throw new CommandException(translator.localize(LocaleResources.COMMAND_CONNECT_ALREADY_CONNECTED, connectionUrl));
         }
-        if (prefs == null) {
-            ServiceReference keyringRef = context.getServiceReference(Keyring.class);
-            if (keyringRef == null) {
-                throw new CommandException(translator.localize(LocaleResources.COMMAND_CONNECT_NO_KEYRING));
-            }
-            Keyring keyring = (Keyring) context.getService(keyringRef);
-            prefs = new ClientPreferences(keyring);
-            context.ungetService(keyringRef);
-        }
         String dbUrl = ctx.getArguments().getArgument(DB_URL_ARG);
         // This argument is considered "required" so option parsing should mean this is impossible.
         Objects.requireNonNull(dbUrl);
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/ShellCommand.java	Mon Nov 18 08:22:15 2013 -0700
@@ -59,7 +59,7 @@
 import com.redhat.thermostat.common.cli.Console;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.launcher.Launcher;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.locale.Translate;
 
@@ -78,10 +78,17 @@
     private BundleContext bundleContext;
     
     static class HistoryProvider {
+
+        private CommonPaths paths;
+
+        HistoryProvider(CommonPaths paths) {
+            this.paths = paths;
+        }
+
         public PersistentHistory get() {
             PersistentHistory history = null;
             try {
-                history = new FileHistory(new Configuration().getUserHistoryFile());
+                history = new FileHistory(paths.getUserHistoryFile());
             } catch (InvalidConfigurationException | IOException e) {
                 /* no history available */
             }
@@ -89,8 +96,8 @@
         }
     }
 
-    public ShellCommand() {
-        this(FrameworkUtil.getBundle(ShellCommand.class).getBundleContext(), new Version(), new HistoryProvider());
+    public ShellCommand(BundleContext context, CommonPaths paths) {
+        this(context, new Version(), new HistoryProvider(paths));
     }
 
     ShellCommand(BundleContext context, Version version, HistoryProvider provider) {
@@ -171,6 +178,7 @@
         if (launcherRef != null) {
             Launcher launcher = (Launcher) bundleContext.getService(launcherRef);
             launcher.run(parsed, true);
+            bundleContext.ungetService(launcherRef);
         } else {
             throw new CommandException(t.localize(LocaleResources.MISSING_LAUNCHER));
         }
--- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ActivatorTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ActivatorTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -37,21 +37,27 @@
 package com.redhat.thermostat.client.cli.internal;
 
 import static com.redhat.thermostat.testutils.Asserts.assertCommandIsRegistered;
+import static com.redhat.thermostat.testutils.Asserts.assertCommandIsNotRegistered;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.io.File;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceRegistration;
 import org.powermock.api.mockito.PowerMockito;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.testutils.StubBundleContext;
+import com.redhat.thermostat.utils.keyring.Keyring;
 
 @RunWith(PowerMockRunner.class)
 @PrepareForTest(FrameworkUtil.class)
@@ -68,6 +74,14 @@
 
         StubBundleContext ctx = new StubBundleContext();
         when(mockBundle.getBundleContext()).thenReturn(ctx);
+
+        Keyring keyring = mock(Keyring.class);
+        ctx.registerService(Keyring.class, keyring, null);
+        CommonPaths paths = mock(CommonPaths.class);
+        File userConfig = mock(File.class);
+        when(userConfig.isFile()).thenReturn(false);
+        when(paths.getUserClientConfigurationFile()).thenReturn(userConfig);
+        ctx.registerService(CommonPaths.class, paths, null);
         
         Activator activator = new Activator();
         
@@ -79,10 +93,45 @@
         assertCommandIsRegistered(ctx, "shell", ShellCommand.class);
         assertCommandIsRegistered(ctx, "vm-info", VMInfoCommand.class);
         assertCommandIsRegistered(ctx, "vm-stat", VMStatCommand.class);
-        
+
         activator.stop(ctx);
+
+        assertEquals(2, ctx.getAllServices().size());
+    }
+
+    @Test
+    public void testConnectCommandUnregisteredWhenDepsDisappear() throws Exception {
+        // Need to mock FrameworkUtil to avoid NPE in commands' no-arg constructors
+        PowerMockito.mockStatic(FrameworkUtil.class);
+        Bundle mockBundle = mock(Bundle.class);
+        when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(mockBundle);
+        // When we call createFilter, we need a real return value
+        when(FrameworkUtil.createFilter(anyString())).thenCallRealMethod();
+
+        StubBundleContext ctx = new StubBundleContext();
+        when(mockBundle.getBundleContext()).thenReturn(ctx);
         
-        assertEquals(0, ctx.getAllServices().size());
+        Activator activator = new Activator();
+        
+        activator.start(ctx);
+        
+        assertCommandIsNotRegistered(ctx, "connect", ConnectCommand.class);
+
+        Keyring keyring = mock(Keyring.class);
+        ServiceRegistration keyringReg = ctx.registerService(Keyring.class, keyring, null);
+        CommonPaths paths = mock(CommonPaths.class);
+        File userConfig = mock(File.class);
+        when(userConfig.isFile()).thenReturn(false);
+        when(paths.getUserClientConfigurationFile()).thenReturn(userConfig);
+        ctx.registerService(CommonPaths.class, paths, null);
+
+        assertCommandIsRegistered(ctx, "connect", ConnectCommand.class);
+
+        keyringReg.unregister();
+
+        assertCommandIsNotRegistered(ctx, "connect", ConnectCommand.class);
+
+        activator.stop(ctx);
     }
 
 }
--- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ConnectCommandTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -38,11 +38,8 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -55,12 +52,12 @@
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
 import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.shared.locale.Translate;
 import com.redhat.thermostat.storage.core.DbService;
 import com.redhat.thermostat.storage.core.DbServiceFactory;
 import com.redhat.thermostat.test.TestCommandContextFactory;
 import com.redhat.thermostat.testutils.StubBundleContext;
-import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class ConnectCommandTest {
 
@@ -78,7 +75,9 @@
 
         context = new StubBundleContext();
         dbServiceFactory = mock(DbServiceFactory.class);
-        cmd = new ConnectCommand(context, dbServiceFactory);
+        ClientPreferences prefs = mock(ClientPreferences.class);
+        when(prefs.getConnectionUrl()).thenReturn("http://localhost");
+        cmd = new ConnectCommand(context, dbServiceFactory, prefs);
     }
 
     private void setupCommandContextFactory() {
@@ -86,7 +85,6 @@
         bundleContext = mock(BundleContext.class);
         when(bundleContext.getBundle(0)).thenReturn(sysBundle);
         cmdCtxFactory = new TestCommandContextFactory(bundleContext);
-        
     }
 
     @After
@@ -97,8 +95,6 @@
 
     @Test
     public void verifyConnectedThrowsExceptionWithDiagnosticMessage() {
-        Keyring keyring = mock(Keyring.class);
-        context.registerService(Keyring.class, keyring, null);
         String dbUrl = "fluff";
         DbService dbService = mock(DbService.class);
         when(dbService.getConnectionUrl()).thenReturn(dbUrl);
@@ -115,8 +111,6 @@
     
     @Test
     public void verifyNotConnectedConnects() throws CommandException {
-        Keyring keyring = mock(Keyring.class);
-        context.registerService(Keyring.class, keyring, null);
         DbService dbService = mock(DbService.class);
 
         String username = "testuser";
@@ -132,25 +126,6 @@
     }
     
     @Test
-    public void verifyNoKeyring() throws CommandException {
-        DbService dbService = mock(DbService.class);
-
-        String dbUrl = "mongodb://10.23.122.1:12578";
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("dbUrl", dbUrl);
-        CommandContext ctx = cmdCtxFactory.createContext(args);
-        
-        try {
-            cmd.run(ctx);
-            fail();
-        } catch (CommandException e) {
-            assertEquals(translator.localize(LocaleResources.COMMAND_CONNECT_NO_KEYRING).getContents(), e.getMessage());
-        }
-        
-        verify(dbService, never()).connect();
-    }
-    
-    @Test
     public void testIsStorageRequired() {
         assertFalse(cmd.isStorageRequired());
     }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java	Mon Nov 18 08:22:15 2013 -0700
@@ -59,6 +59,7 @@
 import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.internal.utils.laf.ThemeManager;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.locale.Translate;
 import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
 import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
@@ -77,35 +78,37 @@
     private ApplicationService appSvc;
     private DbServiceFactory dbServiceFactory;
     private Keyring keyring;
+    private CommonPaths paths;
     private CountDownLatch shutdown;
     private MainWindowControllerImpl mainController;
     private MainWindowRunnable mainWindowRunnable;
     
-    public Main(BundleContext context, Keyring keyring,
+    public Main(BundleContext context, Keyring keyring, CommonPaths paths,
             ApplicationService appSvc, String[] args) {
 
         DbServiceFactory dbServiceFactory = new DbServiceFactory();
         CountDownLatch shutdown = new CountDownLatch(1);
         MainWindowRunnable mainWindowRunnable = new MainWindowRunnable();
 
-        init(context, appSvc, dbServiceFactory, keyring, shutdown,
+        init(context, appSvc, dbServiceFactory, keyring, paths, shutdown,
                 mainWindowRunnable);
     }
 
     Main(BundleContext context, ApplicationService appSvc,
-            DbServiceFactory dbServiceFactory, Keyring keyring,
+            DbServiceFactory dbServiceFactory, Keyring keyring, CommonPaths paths,
             CountDownLatch shutdown, MainWindowRunnable mainWindowRunnable) {
-        init(context, appSvc, dbServiceFactory, keyring, shutdown,
+        init(context, appSvc, dbServiceFactory, keyring, paths, shutdown,
                 mainWindowRunnable);
     }
 
     private void init(BundleContext context, ApplicationService appSvc,
-            DbServiceFactory dbServiceFactory, Keyring keyring,
+            DbServiceFactory dbServiceFactory, Keyring keyring, CommonPaths paths,
             CountDownLatch shutdown, MainWindowRunnable mainWindowRunnable) {
         this.context = context;
         this.appSvc = appSvc;
         this.dbServiceFactory = dbServiceFactory;
         this.keyring = keyring;
+        this.paths = paths;
         this.shutdown = shutdown;
         this.mainWindowRunnable = mainWindowRunnable;
     }
@@ -151,7 +154,7 @@
 
     private void tryConnecting() {
         final ExecutorService service = appSvc.getApplicationExecutor();
-        ClientPreferences prefs = new ClientPreferences(keyring);
+        ClientPreferences prefs = new ClientPreferences(keyring, paths);
         connect(prefs, service);
     }
     
@@ -237,7 +240,7 @@
     }
     
     private void createPreferencesDialog(final ExecutorService service) {
-        ClientPreferences prefs = new ClientPreferences(keyring);
+        ClientPreferences prefs = new ClientPreferences(keyring, paths);
         ClientConfigurationView configDialog = new ClientConfigurationSwing();
         ClientConfigurationController controller =
                 new ClientConfigurationController(prefs, configDialog, new MainClientConfigReconnector(service));
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java	Mon Nov 18 08:22:15 2013 -0700
@@ -83,6 +83,7 @@
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
 import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.locale.Translate;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Ref;
@@ -107,6 +108,7 @@
 
     private MainView view;
     private Keyring keyring;
+    private CommonPaths paths;
     
     private HostInfoDAO hostInfoDAO;
     private VmInfoDAO vmInfoDAO;
@@ -210,6 +212,7 @@
 
         Class<?>[] deps = new Class<?>[] {
                 Keyring.class,
+                CommonPaths.class,
                 HostInfoDAO.class,
                 VmInfoDAO.class,
                 AgentInfoDAO.class,
@@ -228,6 +231,8 @@
             public void dependenciesAvailable(Map<String, Object> services) {
                 keyring = (Keyring) services.get(Keyring.class.getName());
                 Objects.requireNonNull(keyring);
+                paths = (CommonPaths) services.get(CommonPaths.class.getName());
+                Objects.requireNonNull(paths);
                 hostInfoDAO = (HostInfoDAO) services.get(HostInfoDAO.class.getName());
                 Objects.requireNonNull(hostInfoDAO);
                 vmInfoDAO = (VmInfoDAO) services.get(VmInfoDAO.class.getName());
@@ -438,7 +443,7 @@
     }
 
     private void showConfigureClientPreferences() {
-        ClientPreferences prefs = new ClientPreferences(keyring);
+        ClientPreferences prefs = new ClientPreferences(keyring, paths);
         ClientConfigurationView view = clientConfigViewProvider.createView();
         ClientConfigurationController controller = new ClientConfigurationController(prefs, view);
         controller.showDialog();
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java	Mon Nov 18 08:22:15 2013 -0700
@@ -61,7 +61,7 @@
 
 import com.redhat.thermostat.common.cli.CommandRegistry;
 import com.redhat.thermostat.common.cli.CommandRegistryImpl;
-
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class ThermostatActivator implements BundleActivator {
@@ -92,6 +92,7 @@
         
         Class<?>[] deps = new Class<?>[] {
                 Keyring.class,
+                CommonPaths.class,
                 ApplicationService.class,
         };
         dependencyTracker = new MultipleServiceTracker(context, deps, new Action() {
@@ -101,9 +102,10 @@
             @Override
             public void dependenciesAvailable(Map<String, Object> services) {
                 Keyring keyring = (Keyring) services.get(Keyring.class.getName());
+                CommonPaths paths = (CommonPaths) services.get(CommonPaths.class.getName());
                 ApplicationService appSvc = (ApplicationService) services.get(ApplicationService.class.getName());
                 cmdReg = new CommandRegistryImpl(context);
-                main = new Main(context, keyring, appSvc, new String[0]);
+                main = new Main(context, keyring, paths, appSvc, new String[0]);
                 
                 GUIClientCommand cmd = new GUIClientCommand(main);
                 cmdReg.registerCommand("gui", cmd);
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -44,6 +44,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.io.File;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 
@@ -59,6 +60,7 @@
 import com.redhat.thermostat.client.swing.internal.Main.MainWindowRunnable;
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
 import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
 import com.redhat.thermostat.storage.core.DbService;
@@ -83,6 +85,7 @@
     private StubBundleContext context;
     private ApplicationService appService;
     private Keyring keyring;
+    private CommonPaths paths;
     private CountDownLatch shutdown;
 
     @Before
@@ -116,6 +119,11 @@
         when(appService.getTimerFactory()).thenReturn(timerFactory);
 
         keyring = mock(Keyring.class);
+        paths = mock(CommonPaths.class);
+        File userConfig = mock(File.class);
+        when(userConfig.isFile()).thenReturn(false);
+        when(paths.getUserClientConfigurationFile()).thenReturn(userConfig);
+        
         shutdown = mock(CountDownLatch.class);
     }
 
@@ -134,7 +142,7 @@
 
     @Test
     public void verifyRunWaitsForShutdown() throws Exception {
-        Main main = new Main(context, appService, dbServiceFactory, keyring, shutdown, mainWindowRunnable);
+        Main main = new Main(context, appService, dbServiceFactory, keyring, paths, shutdown, mainWindowRunnable);
 
         main.run();
 
@@ -145,7 +153,7 @@
 
     @Test
     public void verifyConnectionIsMade() throws Exception {
-        Main main = new Main(context, appService, dbServiceFactory, keyring, shutdown, mainWindowRunnable);
+        Main main = new Main(context, appService, dbServiceFactory, keyring, paths, shutdown, mainWindowRunnable);
 
         main.run();
 
@@ -161,7 +169,7 @@
         context.registerService(HostInfoDAO.class, hostInfoDAO, null);
         VmInfoDAO vmInfoDAO = mock(VmInfoDAO.class);
         context.registerService(VmInfoDAO.class, vmInfoDAO, null);
-        Main main = new Main(context, appService, dbServiceFactory, keyring, shutdown, mainWindowRunnable);
+        Main main = new Main(context, appService, dbServiceFactory, keyring, paths, shutdown, mainWindowRunnable);
 
         main.run();
 
@@ -179,7 +187,7 @@
     @Test
     public void verifyFailedConnectionTriggersShutdown() throws Exception {
 
-        Main main = new Main(context, appService, dbServiceFactory, keyring, shutdown, mainWindowRunnable);
+        Main main = new Main(context, appService, dbServiceFactory, keyring, paths, shutdown, mainWindowRunnable);
 
         main.run();
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -75,6 +75,7 @@
 import com.redhat.thermostat.common.ThermostatExtensionRegistry.Action;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
@@ -135,6 +136,8 @@
 
         Keyring keyring = mock(Keyring.class);
         context.registerService(Keyring.class, keyring, null);
+        CommonPaths paths = mock(CommonPaths.class);
+        context.registerService(CommonPaths.class, paths, null);
         
         mockHostsDAO = mock(HostInfoDAO.class);
         context.registerService(HostInfoDAO.class, mockHostsDAO, null);
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistry.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistry.java	Mon Nov 18 08:22:15 2013 -0700
@@ -40,6 +40,8 @@
 
     public void registerCommand(String name, Command cmd);
 
+    public void unregisterCommand(String name);
+
     public void unregisterCommands();
 
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistryImpl.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistryImpl.java	Mon Nov 18 08:22:15 2013 -0700
@@ -36,9 +36,9 @@
 
 package com.redhat.thermostat.common.cli;
 
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Map;
 import java.util.Objects;
 
 import org.osgi.framework.BundleContext;
@@ -50,31 +50,39 @@
 public class CommandRegistryImpl implements CommandRegistry {
 
     private BundleContext context;
-    private Collection<ServiceRegistration<?>> myRegisteredCommands;
+    private Map<String, ServiceRegistration<?>> regMapping;
 
     public CommandRegistryImpl(BundleContext ctx) {
         context = ctx;
-        myRegisteredCommands = new ArrayList<>();
+        regMapping = new HashMap<>();
     }
 
     @Override
-    public void registerCommand(String name, Command cmd) {
+    public synchronized void registerCommand(String name, Command cmd) {
         Objects.requireNonNull(name);
         Objects.requireNonNull(cmd);
 
         Hashtable<String,String> props = new Hashtable<>();
         props.put(Command.NAME, name);
         ServiceRegistration<?> registration = context.registerService(Command.class.getName(), cmd, props);
-        myRegisteredCommands.add(registration);
+        regMapping.put(name, registration);
     }
 
     @Override
-    public void unregisterCommands() {
-        for (ServiceRegistration<?> reg : myRegisteredCommands) {
+    public synchronized void unregisterCommand(String name) {
+        Objects.requireNonNull(name);
+        ServiceRegistration reg = regMapping.remove(name);
+        if (reg != null) {
+             reg.unregister();
+         }
+     }
+
+    @Override
+    public synchronized void unregisterCommands() {
+        for (ServiceRegistration<?> reg : regMapping.values()) {
             reg.unregister();
         }
-        // we've just unregistered commands
-        myRegisteredCommands.clear();
+        regMapping.clear();
     }
 
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/config/ClientPreferences.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/common/core/src/main/java/com/redhat/thermostat/common/config/ClientPreferences.java	Mon Nov 18 08:22:15 2013 -0700
@@ -38,7 +38,6 @@
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
@@ -47,7 +46,7 @@
 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.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.utils.keyring.Credentials;
 import com.redhat.thermostat.utils.keyring.Keyring;
@@ -63,15 +62,20 @@
     private static final Logger logger = LoggingUtils.getLogger(ClientPreferences.class);
     
     private Properties prefs;
-    
     private Keyring keyring;
+    private File userConfig;
     
     private Credentials userCredentials;
     
-    public ClientPreferences(Keyring keyring) {
+    public ClientPreferences(Keyring keyring, CommonPaths files) {
+        userConfig = files.getUserClientConfigurationFile();
         Properties props = new Properties();
+        loadPrefs(props);
+        init(props, keyring);
+    }
+
+    private void loadPrefs(Properties props) {
         try {
-            File userConfig = new Configuration().getUserClientConfigurationFile();
             if (userConfig.isFile()) {
                 try {
                     try (InputStream fis = new FileInputStream(userConfig)) {
@@ -84,7 +88,6 @@
         } catch (InvalidConfigurationException e) {
             logger.log(Level.CONFIG, "unable to load configuration", e);
         }
-        init(props, keyring);
     }
 
     // Testing hook with injectable j.u.Properties
@@ -145,7 +148,7 @@
     }
     
     public void flush() throws IOException {
-        prefs.store(new FileWriter(new Configuration().getUserClientConfigurationFile()), "");
+        prefs.store(new FileWriter(userConfig), "");
         userCredentials.setUserName(getUserName());
         if (getSaveEntitlements()) {
             keyring.loadPassword(userCredentials);
--- a/common/core/src/main/java/com/redhat/thermostat/common/utils/LoggingUtils.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/common/core/src/main/java/com/redhat/thermostat/common/utils/LoggingUtils.java	Mon Nov 18 08:22:15 2013 -0700
@@ -48,7 +48,7 @@
 
 import com.redhat.thermostat.common.LogFormatter;
 import com.redhat.thermostat.common.locale.LocaleResources;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.locale.Translate;
 
@@ -124,15 +124,15 @@
         root.removeHandler(handler);
     }
 
-    public static void loadGlobalLoggingConfig() throws InvalidConfigurationException {
-        File systemConfigurationDir = new Configuration().getSystemConfigurationDirectory();
+    public static void loadGlobalLoggingConfig(CommonPaths paths) throws InvalidConfigurationException {
+        File systemConfigurationDir = paths.getSystemConfigurationDirectory();
         File loggingPropertiesFile = new File(systemConfigurationDir, "logging.properties");
         loadConfig(loggingPropertiesFile);
     }
     
 
-    public static void loadUserLoggingConfig() throws InvalidConfigurationException {
-        File userConfigurationDir = new Configuration().getUserConfigurationDirectory();
+    public static void loadUserLoggingConfig(CommonPaths paths) throws InvalidConfigurationException {
+        File userConfigurationDir = paths.getUserConfigurationDirectory();
         File loggingPropertiesFile = new File(userConfigurationDir, "logging.properties");
         loadConfig(loggingPropertiesFile);
     }
--- a/common/core/src/main/java/com/redhat/thermostat/test/TestCommandContextFactory.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/common/core/src/main/java/com/redhat/thermostat/test/TestCommandContextFactory.java	Mon Nov 18 08:22:15 2013 -0700
@@ -115,6 +115,11 @@
     }
 
     public String getOutput() {
+        try {
+            out.flush();
+        } catch (IOException e) {
+            // ignore
+        }
         return new String(out.toByteArray());
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/test/TestCommandRegistry.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/common/core/src/main/java/com/redhat/thermostat/test/TestCommandRegistry.java	Mon Nov 18 08:22:15 2013 -0700
@@ -64,5 +64,10 @@
         commands.clear();
     }
 
+    @Override
+    public void unregisterCommand(String name) {
+        commands.remove(name);
+    }
+
 }
 
--- a/common/test/src/main/java/com/redhat/thermostat/testutils/Asserts.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/common/test/src/main/java/com/redhat/thermostat/testutils/Asserts.java	Mon Nov 18 08:22:15 2013 -0700
@@ -41,12 +41,24 @@
 public class Asserts {
 
     public static void assertCommandIsRegistered(StubBundleContext context, String name, Class<?> klass) {
+        assertCommandRegistration(context, name, klass, true);
+    }
+
+    public static void assertCommandIsNotRegistered(StubBundleContext context, String name, Class<?> klass) {
+        assertCommandRegistration(context, name, klass, false);
+    }
+
+    private static void assertCommandRegistration(StubBundleContext context, String name, Class<?> klass, boolean wantRegistered) {
         // The Command class is not visible to this module, so we have to live
         // with hardcoding some details here
         Hashtable<String,String> props = new Hashtable<>();
         props.put("COMMAND_NAME", name);
-        if (!context.isServiceRegistered("com.redhat.thermostat.common.cli.Command", klass, props)) {
-            throw new AssertionError("Command " + name + " is not registered");
+        boolean isRegistered = context.isServiceRegistered("com.redhat.thermostat.common.cli.Command", klass, props);
+        if (!isRegistered && wantRegistered) {
+            throw new AssertionError("Command " + name + " is not registered but should be");
+        }
+        if (isRegistered && !wantRegistered) {
+            throw new AssertionError("Command " + name + " is registered but should not be");
         }
     }
 }
--- a/common/test/src/main/java/com/redhat/thermostat/testutils/StubServiceReference.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/common/test/src/main/java/com/redhat/thermostat/testutils/StubServiceReference.java	Mon Nov 18 08:22:15 2013 -0700
@@ -40,6 +40,7 @@
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.List;
+import java.util.Objects;
 
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
@@ -125,5 +126,25 @@
         return information;
     }
 
+    @Override
+    public int hashCode() {
+        Integer ranking = (Integer) getProperty(Constants.SERVICE_RANKING);
+        Integer serviceId = (Integer) getProperty(Constants.SERVICE_ID);
+        return Objects.hash(ranking, serviceId);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if ((other == null) || !(other instanceof ServiceReference)) {
+            return false;
+        }
+        ServiceReference ref = (ServiceReference) other;
+
+        int myRanking = ((Integer) getProperty(Constants.SERVICE_RANKING)).intValue();
+        int otherRanking = ((Integer) ref.getProperty(Constants.SERVICE_RANKING)).intValue();
+        int myServiceId = ((Integer) getProperty(Constants.SERVICE_ID)).intValue();
+        int otherServiceId = ((Integer) ref.getProperty(Constants.SERVICE_ID)).intValue();
+        return myRanking == otherRanking && myServiceId == otherServiceId;
+    }
 }
 
--- a/common/test/src/main/java/com/redhat/thermostat/testutils/TestUtils.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/common/test/src/main/java/com/redhat/thermostat/testutils/TestUtils.java	Mon Nov 18 08:22:15 2013 -0700
@@ -49,6 +49,8 @@
 // FIXME the methods in this class can probably be split more sanely
 public class TestUtils {
 
+	private static File agentConf, agentAuth;
+
     /**
      * @return the process id of the current process
      */
@@ -113,31 +115,62 @@
         String tmpDir = System.getProperty("java.io.tmpdir") + File.separatorChar +
                 Math.abs(random.nextInt()) + File.separatorChar;
 
-        setupSystemAgentConfig(tmpDir, agentProperties);
+        System.setProperty("THERMOSTAT_HOME", tmpDir);
+        File etc = makeEtc(tmpDir);
+        setupSystemAgentConfig(etc, agentProperties);
         setupUserAgentConfig(tmpDir);
+        setupAgentAuth(etc);
 
         return tmpDir;
     }
 
-    private static void setupSystemAgentConfig(String root, Properties agentProperties) throws FileNotFoundException, IOException {
-        System.setProperty("THERMOSTAT_HOME", root);
+    public static File getAgentConfFile() {
+    	return agentConf;
+    }
+
+    public static File getAgentAuthFile() {
+    	return agentAuth;
+    }
 
+    public static void deleteRecursively(File root) throws IOException {
+        if (root.isFile()) {
+            root.delete();
+            return;
+        } else if (root.isDirectory()) {
+            File[] children = root.listFiles();
+            for (File child : children) {
+                deleteRecursively(child);
+            }
+            root.delete();
+            return;
+        } else {
+            throw new IOException("Asked to delete but not file or directory" + root.getPath());
+        }
+    }
+
+    private static File makeEtc(String root) {
         File etc = new File(root, "etc");
         etc.mkdirs();
-        File tmpConfigs = new File(etc, "agent.properties");
+        return etc;
+    }
 
-        try (OutputStream propsOutputStream = new FileOutputStream(tmpConfigs)) {
+    private static void setupSystemAgentConfig(File etc, Properties agentProperties) throws FileNotFoundException, IOException {
+        agentConf = new File(etc, "agent.properties");
+
+        try (OutputStream propsOutputStream = new FileOutputStream(agentConf)) {
             agentProperties.store(propsOutputStream, "thermostat agent test properties");
         }
+    }
 
-        File tmpAuth = new File(etc, "agent.auth");
-        FileWriter authWriter = new FileWriter(tmpAuth);
+    private static void setupAgentAuth(File etc) throws IOException {
+        agentAuth = new File(etc, "agent.auth");
+        FileWriter authWriter = new FileWriter(agentAuth);
         authWriter.append("username=user\npassword=pass\n");
         authWriter.flush();
         authWriter.close();
     }
 
-    private static void setupUserAgentConfig(String root) throws IOException {
+    private static File setupUserAgentConfig(String root) throws IOException {
         System.setProperty("USER_THERMOSTAT_HOME", root);
 
         File agent = new File(root, "agent");
@@ -145,6 +178,7 @@
 
         new File(agent, "run").mkdirs();
         new File(agent, "logs").mkdirs();
+        return agent;
 
     }
 }
--- a/config/pom.xml	Fri Nov 15 17:28:05 2013 -0700
+++ b/config/pom.xml	Mon Nov 18 08:22:15 2013 -0700
@@ -28,6 +28,7 @@
             </Export-Package>
             <Private-Package>
               com.redhat.thermostat.shared.config.internal,
+              com.redhat.thermostat.shared.locale.internal,
             </Private-Package>
             <!-- Do not autogenerate uses clauses in Manifests -->
             <_nouses>true</_nouses>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/src/main/java/com/redhat/thermostat/shared/config/CommonPaths.java	Mon Nov 18 08:22:15 2013 -0700
@@ -0,0 +1,109 @@
+/*
+ * 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 java.io.File;
+
+/**
+ * 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 interface CommonPaths {
+
+    public File getSystemThermostatHome() throws InvalidConfigurationException;
+
+    public File getUserThermostatHome() throws InvalidConfigurationException;
+
+    public File getSystemPluginRoot() throws InvalidConfigurationException;
+
+    public File getSystemLibRoot() throws InvalidConfigurationException;
+
+    public File getSystemBinRoot() throws InvalidConfigurationException;
+
+    public File getSystemNativeLibsRoot() throws InvalidConfigurationException;
+
+    public File getSystemConfigurationDirectory() throws InvalidConfigurationException;
+
+    public File getUserConfigurationDirectory() throws InvalidConfigurationException;
+
+    /** A location that contains data that is persisted */
+    public File getUserPersistentDataDirectory() throws InvalidConfigurationException;
+
+    /** Contains data that is only useful for the duration that thermostat is running */
+    public File getUserRuntimeDataDirectory() throws InvalidConfigurationException;
+
+    public File getUserLogDirectory() throws InvalidConfigurationException;
+
+    public File getUserCacheDirectory() throws InvalidConfigurationException;
+
+    public File getUserPluginRoot() throws InvalidConfigurationException;
+
+    public File getUserStorageDirectory() throws InvalidConfigurationException;
+
+    public File getSystemStorageConfigurationFile() throws InvalidConfigurationException;
+
+    public File getUserStorageConfigurationFile() throws InvalidConfigurationException;
+
+    public File getUserStorageLogFile() throws InvalidConfigurationException;
+
+    public File getUserStoragePidFile() throws InvalidConfigurationException;
+
+    public File getSystemAgentConfigurationFile() throws InvalidConfigurationException;
+
+    public File getUserAgentConfigurationFile() throws InvalidConfigurationException;
+
+    public File getSystemAgentAuthConfigFile() throws InvalidConfigurationException;
+
+    public File getUserAgentAuthConfigFile() throws InvalidConfigurationException;
+
+    public File getUserClientConfigurationFile() throws InvalidConfigurationException;
+
+    public File getUserHistoryFile() throws InvalidConfigurationException;
+
+}
\ No newline at end of file
--- a/config/src/main/java/com/redhat/thermostat/shared/config/Configuration.java	Fri Nov 15 17:28:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,374 +0,0 @@
-/*
- * 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 java.io.File;
-
-/**
- * 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).
- * <p>
- * The behaviour of this class is affected by the following environment
- * variables:
- * <dl>
- *   <di>{@code THERMOSTAT_HOME}</di>
- *   <dd>Specifies the location thermostat uses for it's read-only data,
- *     such as jars.</dd>
- *   <di>{@code THERMOSTAT_SYSTEM_USER}</di>
- *   <dd>If set, indicates that thermostat is running as a system user.
- *     In this mode, it reads configuration from system paths and places
- *     data in system writeable locations.</dd>
- *   <di>{@code USER_THERMOSTAT_HOME}</di>
- *   <dd>The meaning of this varies depending on whether thermostat is
- *     running as a system user or not. In normal mode, this controls
- *     where thermostat places it's data and where configuration files
- *     are searched for. In system mode, this is treated as a prefix
- *     writing system data.</dd>
- * </dl>
- */
-public class Configuration {
-
-    // Note: these paths are used by the integration tests too. Please update
-    // them whenever you change this class.
-
-    // environment variables (also system properties for convenience):
-    private static final String THERMOSTAT_HOME = "THERMOSTAT_HOME";
-    private static final String USER_THERMOSTAT_HOME = "USER_THERMOSTAT_HOME";
-    private static final String THERMOSTAT_SYSTEM_USER = "THERMOSTAT_SYSTEM_USER";
-
-
-    private static final String THERMOSTAT_USER_DIR = ".thermostat";
-
-    private final File systemHome;
-    private final UserDirectories userDirectories;
-
-    private static File defaultSystemUserPrefix;
-
-    public Configuration() throws InvalidConfigurationException {
-        this(makeDir(null, "/"));
-    }
-
-    Configuration(String altTestingPrefix) {
-        this(makeDir(null, altTestingPrefix));
-    }
-
-    private Configuration(File defaultPrefix) {
-        Configuration.defaultSystemUserPrefix = defaultPrefix;
-        // allow this to be specified also as a property, especially for
-        // tests, this overrides the env setting
-        String home = System.getProperty(THERMOSTAT_HOME);
-        if (home == null) {
-            home = System.getenv(THERMOSTAT_HOME);
-        }
-
-        if (home == null) {
-            throw new InvalidConfigurationException(THERMOSTAT_HOME + " not defined...");
-        }
-        this.systemHome = new File(home);
-        if (!systemHome.exists()) {
-            systemHome.mkdirs();
-        }
-        if (!systemHome.isDirectory()) {
-            throw new InvalidConfigurationException(THERMOSTAT_HOME + " is not a directory: " + home);
-        }
-
-        String systemUser = System.getProperty(THERMOSTAT_SYSTEM_USER);
-        if (systemUser == null) {
-            systemUser = System.getenv(THERMOSTAT_SYSTEM_USER);
-        }
-
-        if (systemUser != null) {
-            userDirectories = new SystemUserDirectories();
-        } else {
-            userDirectories = new UnprivilegedUserDirectories();
-        }
-    }
-
-    /*
-     * Overall hierarchy
-     */
-
-    public File getSystemThermostatHome() throws InvalidConfigurationException {
-        return systemHome;
-    }
-
-    public File getUserThermostatHome() throws InvalidConfigurationException {
-        return userDirectories.getSystemRoot();
-    }
-
-    public File getSystemPluginRoot() throws InvalidConfigurationException {
-        return makeDir(systemHome, "plugins");
-    }
-
-    public File getSystemLibRoot() throws InvalidConfigurationException {
-        return makeDir(systemHome, "libs");
-    }
-    
-    public File getSystemBinRoot() throws InvalidConfigurationException {
-        return makeDir(systemHome, "bin");
-    }
-
-    public File getSystemNativeLibsRoot() throws InvalidConfigurationException {
-        return makeDir(getSystemLibRoot(), "native");
-    }
-
-    public File getSystemConfigurationDirectory() throws InvalidConfigurationException {
-        return makeDir(getSystemThermostatHome(), "etc");
-    }
-
-    public File getUserConfigurationDirectory() throws InvalidConfigurationException {
-        return userDirectories.getUserConfigurationDirectory();
-    }
-
-    /** A location that contains data that is persisted */
-    public File getUserPersistentDataDirectory() throws InvalidConfigurationException {
-        return userDirectories.getUserPersistentDataDirectory();
-    }
-
-    /**
-     * Contains data that is only useful for the duration that thermostat is
-     * running
-     */
-    public File getUserRuntimeDataDirectory() throws InvalidConfigurationException {
-        return userDirectories.getUserRuntimeDataDirectory();
-    }
-
-    public File getUserLogDirectory() throws InvalidConfigurationException {
-        return userDirectories.getUserLogDirectory();
-
-    }
-
-    public File getUserCacheDirectory() throws InvalidConfigurationException {
-        return userDirectories.getUserCacheDirectory();
-    }
-
-    /* Specific files and directories. All these methods should use the directories defined above */
-
-    public File getUserPluginRoot() throws InvalidConfigurationException {
-        return new File(getUserPersistentDataDirectory(), "plugins");
-    }
-
-    public File getUserStorageDirectory() throws InvalidConfigurationException {
-        return makeDir(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 getUserStoragePidFile() throws InvalidConfigurationException {
-        File logFile = new File(getUserRuntimeDataDirectory(), "db.pid");
-        return logFile;
-    }
-
-    public File getSystemAgentConfigurationFile() throws InvalidConfigurationException {
-        return new File(getSystemConfigurationDirectory(), "agent.properties");
-    }
-
-    public File getUserAgentConfigurationFile() throws InvalidConfigurationException {
-        return new File(getUserConfigurationDirectory(), "agent.properties");
-    }
-
-    public File getSystemAgentAuthConfigFile() throws InvalidConfigurationException {
-        return new File(getSystemConfigurationDirectory(), "agent.auth");
-    }
-
-    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 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)
-
-    private interface UserDirectories {
-
-        public File getSystemRoot();
-
-        public File getUserConfigurationDirectory();
-
-        public File getUserPersistentDataDirectory();
-
-        public File getUserRuntimeDataDirectory();
-
-        public File getUserLogDirectory();
-
-        public File getUserCacheDirectory();
-
-    }
-
-    private static File makeDir(File parent, String name) {
-        File dir = new File(parent, name);
-        boolean exists = dir.exists();
-        if (!exists) {
-            exists = dir.mkdirs();
-        }
-        if (!exists) {
-            throw new InvalidConfigurationException("Directory could not be created: " + dir.getAbsolutePath());
-        }
-        if (!dir.isDirectory()) {
-            throw new InvalidConfigurationException("File already exists but is not a directory: " + dir.getAbsolutePath());
-        }
-        return dir;
-    }
-
-    /*
-     * We need two different implementations because the paths are different. We
-     * can't get clean paths by simply changing the prefix.
-     *
-     * user path:   $USER/.thermostat/{etc,log,...}
-     * system path: /{etc,var/log,var/lib}/thermostat
-     *
-     * Notice how 'thermostat' comes first in one set of paths and later in the second set.
-     */
-
-    private static class UnprivilegedUserDirectories implements UserDirectories {
-
-        private File userHome;
-
-        public UnprivilegedUserDirectories() {
-            // 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 = makeDir(null, userHome);
-        }
-
-        public File getSystemRoot() throws InvalidConfigurationException {
-            return userHome;
-        }
-
-
-        public File getUserConfigurationDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "etc");
-        }
-
-        public File getUserPersistentDataDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "data");
-        }
-
-        public File getUserRuntimeDataDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "run");
-        }
-
-        public File getUserLogDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "logs");
-        }
-
-        public File getUserCacheDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "cache");
-        }
-    }
-
-    private static class SystemUserDirectories implements UserDirectories {
-
-        private File prefix;
-
-        public SystemUserDirectories() {
-            // 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) {
-                this.prefix = defaultSystemUserPrefix;
-            } else {
-                this.prefix = makeDir(null, userHome);
-            }
-        }
-
-        public File getSystemRoot() throws InvalidConfigurationException {
-            return prefix;
-        }
-
-
-        public File getUserConfigurationDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "etc/thermostat");
-        }
-
-        public File getUserPersistentDataDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "var/lib/thermostat");
-        }
-
-        public File getUserRuntimeDataDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "var/run/thermostat");
-        }
-
-        public File getUserLogDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "var/log/thermostat");
-        }
-
-        public File getUserCacheDirectory() throws InvalidConfigurationException {
-            return makeDir(getSystemRoot(), "var/cache/thermostat");
-        }
-    }
-
-}
--- a/config/src/main/java/com/redhat/thermostat/shared/config/NativeLibraryResolver.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/config/src/main/java/com/redhat/thermostat/shared/config/NativeLibraryResolver.java	Mon Nov 18 08:22:15 2013 -0700
@@ -38,17 +38,26 @@
 
 import java.io.File;
 
+import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
+
 
 /**
  * Class which enables resolving of native libraries placed in
- * {@link Configuration#getNativeLibsRoot()}.
+ * {@link CommonPaths#getNativeLibsRoot()}.
  *
  */
 public class NativeLibraryResolver {
 
+    private static CommonPaths paths;
+
+    // Set in Activator.start() to prevent IllegalStateException below.
+    public static void setCommonPaths(CommonPaths paths) {
+        NativeLibraryResolver.paths = paths;
+    }
+
     /**
      * Gets the absolute path of a native library. The native library must be
-     * placed in directory as returned by {@link Configuration#getNativeLibsRoot()}.
+     * placed in directory as returned by {@link CommonPathsImpl#getNativeLibsRoot()}.
      * 
      * @param libraryName
      *            The name of the library. Specified in the same fashion as for
@@ -63,9 +72,11 @@
         if (nativeLibsRoot != null) {
             return doResolve(nativeLibsRoot, libraryName);
         }
+        if (paths == null) {
+            throw new IllegalStateException("NativeLibraryResolver does not yet know about CommonPaths.");
+        }
         try {
-            Configuration config = new Configuration();
-            nativeLibsRoot = config.getSystemNativeLibsRoot().getPath();
+            nativeLibsRoot = paths.getSystemNativeLibsRoot().getPath();
         } catch (InvalidConfigurationException e) {
             throw new AssertionError(e);
         }
--- a/config/src/main/java/com/redhat/thermostat/shared/config/internal/Activator.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/config/src/main/java/com/redhat/thermostat/shared/config/internal/Activator.java	Mon Nov 18 08:22:15 2013 -0700
@@ -39,19 +39,25 @@
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
+import com.redhat.thermostat.shared.config.NativeLibraryResolver;
 
 public class Activator implements BundleActivator {
 
     @Override
     public void start(BundleContext context) throws Exception {
-        SSLConfiguration sslConf = new SSLConfigurationImpl();
+        CommonPaths paths = new CommonPathsImpl();
+        // Prevents IllegalStateException when external dependencies attempt to resolve native libraries.
+        NativeLibraryResolver.setCommonPaths(paths);
+        context.registerService(CommonPaths.class.getName(), paths, null);
+        SSLConfiguration sslConf = new SSLConfigurationImpl(paths);
         context.registerService(SSLConfiguration.class.getName(), sslConf, null);
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        // Nothing to do
+        NativeLibraryResolver.setCommonPaths(null);
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/src/main/java/com/redhat/thermostat/shared/config/internal/CommonPathsImpl.java	Mon Nov 18 08:22:15 2013 -0700
@@ -0,0 +1,405 @@
+/*
+ * 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.internal;
+
+import java.io.File;
+
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.shared.config.InvalidConfigurationException;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.shared.locale.internal.LocaleResources;
+
+/**
+ * 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).
+ * <p>
+ * The behaviour of this class is affected by the following environment
+ * variables:
+ * <dl>
+ *   <di>{@code THERMOSTAT_HOME}</di>
+ *   <dd>Specifies the location thermostat uses for it's read-only data,
+ *     such as jars.</dd>
+ *   <di>{@code THERMOSTAT_SYSTEM_USER}</di>
+ *   <dd>If set, indicates that thermostat is running as a system user.
+ *     In this mode, it reads configuration from system paths and places
+ *     data in system writeable locations.</dd>
+ *   <di>{@code USER_THERMOSTAT_HOME}</di>
+ *   <dd>The meaning of this varies depending on whether thermostat is
+ *     running as a system user or not. In normal mode, this controls
+ *     where thermostat places it's data and where configuration files
+ *     are searched for. In system mode, this is treated as a prefix
+ *     writing system data.</dd>
+ * </dl>
+ */
+public class CommonPathsImpl implements CommonPaths {
+
+    // Note: these paths are used by the integration tests too. Please update
+    // them whenever you change this class.
+
+    // environment variables (also system properties for convenience):
+    private static final String THERMOSTAT_HOME = "THERMOSTAT_HOME";
+    private static final String USER_THERMOSTAT_HOME = "USER_THERMOSTAT_HOME";
+    private static final String THERMOSTAT_SYSTEM_USER = "THERMOSTAT_SYSTEM_USER";
+
+
+    private static final String THERMOSTAT_USER_DIR = ".thermostat";
+
+    private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
+
+    private final File systemHome;
+    private final UserDirectories userDirectories;
+
+    private static File defaultSystemUserPrefix;
+
+    public CommonPathsImpl() throws InvalidConfigurationException {
+        this(makeDir(null, "/"));
+    }
+
+    CommonPathsImpl(String altTestingPrefix) {
+        this(makeDir(null, altTestingPrefix));
+    }
+
+    private CommonPathsImpl(File defaultPrefix) {
+        CommonPathsImpl.defaultSystemUserPrefix = defaultPrefix;
+        // allow this to be specified also as a property, especially for
+        // tests, this overrides the env setting
+        String home = System.getProperty(THERMOSTAT_HOME);
+        if (home == null) {
+            home = System.getenv(THERMOSTAT_HOME);
+        }
+
+        if (home == null) {
+            throw new InvalidConfigurationException(t.localize(LocaleResources.SYSHOME_NO_HOME));
+        }
+        this.systemHome = new File(home);
+        if (!systemHome.exists()) {
+            systemHome.mkdirs();
+        }
+        if (!systemHome.isDirectory()) {
+            throw new InvalidConfigurationException(t.localize(LocaleResources.SYSHOME_NOT_A_DIR, home));
+        }
+
+        String systemUser = System.getProperty(THERMOSTAT_SYSTEM_USER);
+        if (systemUser == null) {
+            systemUser = System.getenv(THERMOSTAT_SYSTEM_USER);
+        }
+
+        if (systemUser != null) {
+            userDirectories = new SystemUserDirectories();
+        } else {
+            userDirectories = new UnprivilegedUserDirectories();
+        }
+    }
+
+    /*
+     * Overall hierarchy
+     */
+
+    @Override
+    public File getSystemThermostatHome() throws InvalidConfigurationException {
+        return systemHome;
+    }
+
+    @Override
+    public File getUserThermostatHome() throws InvalidConfigurationException {
+        return userDirectories.getSystemRoot();
+    }
+
+    @Override
+    public File getSystemPluginRoot() throws InvalidConfigurationException {
+        return makeDir(systemHome, "plugins");
+    }
+
+    @Override
+    public File getSystemLibRoot() throws InvalidConfigurationException {
+        return makeDir(systemHome, "libs");
+    }
+
+    @Override
+    public File getSystemBinRoot() throws InvalidConfigurationException {
+        return makeDir(systemHome, "bin");
+    }
+
+    @Override
+    public File getSystemNativeLibsRoot() throws InvalidConfigurationException {
+        return makeDir(getSystemLibRoot(), "native");
+    }
+
+    @Override
+    public File getSystemConfigurationDirectory() throws InvalidConfigurationException {
+        return makeDir(getSystemThermostatHome(), "etc");
+    }
+
+    @Override
+    public File getUserConfigurationDirectory() throws InvalidConfigurationException {
+        return userDirectories.getUserConfigurationDirectory();
+    }
+
+    /** A location that contains data that is persisted */
+    @Override
+    public File getUserPersistentDataDirectory() throws InvalidConfigurationException {
+        return userDirectories.getUserPersistentDataDirectory();
+    }
+
+    /**
+     * Contains data that is only useful for the duration that thermostat is
+     * running
+     */
+    @Override
+    public File getUserRuntimeDataDirectory() throws InvalidConfigurationException {
+        return userDirectories.getUserRuntimeDataDirectory();
+    }
+
+    @Override
+    public File getUserLogDirectory() throws InvalidConfigurationException {
+        return userDirectories.getUserLogDirectory();
+
+    }
+
+    @Override
+    public File getUserCacheDirectory() throws InvalidConfigurationException {
+        return userDirectories.getUserCacheDirectory();
+    }
+
+    /* Specific files and directories. All these methods should use the directories defined above */
+
+    @Override
+    public File getUserPluginRoot() throws InvalidConfigurationException {
+        return new File(getUserPersistentDataDirectory(), "plugins");
+    }
+
+    @Override
+    public File getUserStorageDirectory() throws InvalidConfigurationException {
+        return makeDir(getUserPersistentDataDirectory(), "db");
+    }
+
+    @Override
+    public File getSystemStorageConfigurationFile() throws InvalidConfigurationException {
+        return new File(getSystemConfigurationDirectory(), "db.properties");
+    }
+
+    @Override
+    public File getUserStorageConfigurationFile() throws InvalidConfigurationException {
+        return new File(getUserConfigurationDirectory(), "db.properties");
+    }
+
+    @Override
+    public File getUserStorageLogFile() throws InvalidConfigurationException {
+        File logFile = new File(getUserLogDirectory(), "db.log");
+        return logFile;
+    }
+
+    @Override
+    public File getUserStoragePidFile() throws InvalidConfigurationException {
+        File logFile = new File(getUserRuntimeDataDirectory(), "db.pid");
+        return logFile;
+    }
+
+    @Override
+    public File getSystemAgentConfigurationFile() throws InvalidConfigurationException {
+        return new File(getSystemConfigurationDirectory(), "agent.properties");
+    }
+
+    @Override
+    public File getUserAgentConfigurationFile() throws InvalidConfigurationException {
+        return new File(getUserConfigurationDirectory(), "agent.properties");
+    }
+
+    @Override
+    public File getSystemAgentAuthConfigFile() throws InvalidConfigurationException {
+        return new File(getSystemConfigurationDirectory(), "agent.auth");
+    }
+
+    @Override
+    public File getUserAgentAuthConfigFile() throws InvalidConfigurationException {
+        return new File(getUserConfigurationDirectory(), "agent.auth");
+    }
+
+    @Override
+    public File getUserClientConfigurationFile() throws InvalidConfigurationException {
+        File client = new File(getUserConfigurationDirectory(), "client.properties");
+        return client;
+    }
+
+    @Override
+    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)
+
+    private interface UserDirectories {
+
+        public File getSystemRoot();
+
+        public File getUserConfigurationDirectory();
+
+        public File getUserPersistentDataDirectory();
+
+        public File getUserRuntimeDataDirectory();
+
+        public File getUserLogDirectory();
+
+        public File getUserCacheDirectory();
+
+    }
+
+    private static File makeDir(File parent, String name) {
+        File dir = new File(parent, name);
+        boolean exists = dir.exists();
+        if (!exists) {
+            exists = dir.mkdirs();
+        }
+        if (!exists) {
+            throw new InvalidConfigurationException("Directory could not be created: " + dir.getAbsolutePath());
+        }
+        if (!dir.isDirectory()) {
+            throw new InvalidConfigurationException(t.localize(LocaleResources.GENERAL_NOT_A_DIR, dir.getAbsolutePath()));
+        }
+        return dir;
+    }
+
+    /*
+     * We need two different implementations because the paths are different. We
+     * can't get clean paths by simply changing the prefix.
+     *
+     * user path:   $USER/.thermostat/{etc,log,...}
+     * system path: /{etc,var/log,var/lib}/thermostat
+     *
+     * Notice how 'thermostat' comes first in one set of paths and later in the second set.
+     */
+
+    private static class UnprivilegedUserDirectories implements UserDirectories {
+
+        private File userHome;
+
+        public UnprivilegedUserDirectories() {
+            // 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 = makeDir(null, userHome);
+        }
+
+        public File getSystemRoot() throws InvalidConfigurationException {
+            return userHome;
+        }
+
+
+        public File getUserConfigurationDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "etc");
+        }
+
+        public File getUserPersistentDataDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "data");
+        }
+
+        public File getUserRuntimeDataDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "run");
+        }
+
+        public File getUserLogDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "logs");
+        }
+
+        public File getUserCacheDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "cache");
+        }
+    }
+
+    private static class SystemUserDirectories implements UserDirectories {
+
+        private File prefix;
+
+        public SystemUserDirectories() {
+            // 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) {
+                this.prefix = defaultSystemUserPrefix;
+            } else {
+                this.prefix = makeDir(null, userHome);
+            }
+        }
+
+        public File getSystemRoot() throws InvalidConfigurationException {
+            return prefix;
+        }
+
+
+        public File getUserConfigurationDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "etc/thermostat");
+        }
+
+        public File getUserPersistentDataDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "var/lib/thermostat");
+        }
+
+        public File getUserRuntimeDataDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "var/run/thermostat");
+        }
+
+        public File getUserLogDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "var/log/thermostat");
+        }
+
+        public File getUserCacheDirectory() throws InvalidConfigurationException {
+            return makeDir(getSystemRoot(), "var/cache/thermostat");
+        }
+    }
+
+}
--- a/config/src/main/java/com/redhat/thermostat/shared/config/internal/SSLConfigurationImpl.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/config/src/main/java/com/redhat/thermostat/shared/config/internal/SSLConfigurationImpl.java	Mon Nov 18 08:22:15 2013 -0700
@@ -43,12 +43,13 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
 
 public class SSLConfigurationImpl implements SSLConfiguration {
 
+    private CommonPaths paths;
     private Properties clientProps = null;
     private static final String KEYSTORE_FILE_KEY = "KEYSTORE_FILE";
     private static final String KEYSTORE_FILE_PWD_KEY = "KEYSTORE_PASSWORD";
@@ -57,6 +58,10 @@
     private static final String DISABLE_HOSTNAME_VERIFICATION = "DISABLE_HOSTNAME_VERIFICATION";
     private static final Logger logger = Logger.getLogger(SSLConfigurationImpl.class.getName());
 
+    public SSLConfigurationImpl(CommonPaths paths) {
+        this.paths = paths;
+    }
+
     @Override
     public File getKeystoreFile() {
         try {
@@ -132,7 +137,7 @@
     private void loadClientProperties()
             throws InvalidConfigurationException {
         if (clientProps == null) {
-            File clientPropertiesFile = new File(new Configuration().getUserConfigurationDirectory(),
+            File clientPropertiesFile = new File(paths.getUserConfigurationDirectory(),
                     "ssl.properties");
             initClientProperties(clientPropertiesFile);
         }
--- a/config/src/main/java/com/redhat/thermostat/shared/locale/LocaleResources.java	Fri Nov 15 17:28:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * 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.locale;
-
-import com.redhat.thermostat.shared.locale.Translate;
-
-public enum LocaleResources {
-
-    ENV_NO_HOME,
-    ;
-
-    public static final String RESOURCE_BUNDLE =
-            "com.redhat.thermostat.shared.locale.strings";
-    
-    public static Translate<LocaleResources> createLocalizer() {
-        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/src/main/java/com/redhat/thermostat/shared/locale/internal/LocaleResources.java	Mon Nov 18 08:22:15 2013 -0700
@@ -0,0 +1,56 @@
+/*
+ * 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.locale.internal;
+
+import com.redhat.thermostat.shared.locale.Translate;
+
+public enum LocaleResources {
+
+    SYSHOME_NO_HOME,
+    SYSHOME_NOT_A_DIR,
+    USERHOME_NOT_A_DIR,
+    GENERAL_NOT_A_DIR,
+    ;
+
+    public static final String RESOURCE_BUNDLE =
+            "com.redhat.thermostat.shared.locale.internal.strings";
+    
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/src/main/resources/com/redhat/thermostat/shared/locale/internal/strings.properties	Mon Nov 18 08:22:15 2013 -0700
@@ -0,0 +1,4 @@
+SYSHOME_NO_HOME = THERMOSTAT_HOME not defined...
+SYSHOME_NOT_A_DIR = THERMOSTAT_HOME is defined but not a directory: {0}
+USERHOME_NOT_A_DIR = USER_THERMOSTAT_HOME is defined but not a directory: {0}
+GENERAL_NOT_A_DIR = Expecting directory, got other: {0}
--- a/config/src/main/resources/com/redhat/thermostat/shared/locale/strings.properties	Fri Nov 15 17:28:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-ENV_NO_HOME = THERMOSTAT_HOME not defined...
--- a/config/src/test/java/com/redhat/thermostat/shared/config/ConfigurationTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-/*
- * 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.fail;
-
-import java.io.File;
-import java.io.IOException;
-
-import junit.framework.Assert;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class ConfigurationTest {
-
-    @Before
-    public void setUp() {
-        System.clearProperty("THERMOSTAT_HOME");
-        System.clearProperty("USER_THERMOSTAT_HOME");
-        System.clearProperty("THERMOSTAT_SYSTEM_USER");
-    }
-    
-    @After
-    public void tearDown() {
-        System.clearProperty("THERMOSTAT_HOME");
-        System.clearProperty("USER_THERMOSTAT_HOME");
-        System.clearProperty("THERMOSTAT_SYSTEM_USER");
-    }
-
-    @Test
-    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.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());
-    }
-
-    @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());
-
-        Assert.assertEquals(userHome + s + "data" + s + "plugins",
-                config.getUserPluginRoot().getCanonicalPath());
-    }
-
-    @Test
-    public void testPrivilegedUserLocations() throws InvalidConfigurationException, IOException {
-        String thermostatHome = "/tmp/thermostat_test";
-        System.setProperty("THERMOSTAT_HOME", thermostatHome);
-        System.setProperty("THERMOSTAT_SYSTEM_USER", "");
-        Configuration config = new Configuration(thermostatHome);
-
-        // the paths are unix specific, but so are the paths in Configuration
-
-        Assert.assertEquals("/tmp/thermostat_test/etc/thermostat/agent.properties", config.getUserAgentConfigurationFile().getCanonicalPath());
-        Assert.assertEquals("/tmp/thermostat_test/etc/thermostat/agent.auth", config.getUserAgentAuthConfigFile().getCanonicalPath());
-        Assert.assertEquals("/tmp/thermostat_test/etc/thermostat/db.properties", config.getUserStorageConfigurationFile().getCanonicalPath());
-
-        Assert.assertEquals("/tmp/thermostat_test/var/lib/thermostat/db", config.getUserStorageDirectory().getCanonicalPath());
-        Assert.assertEquals("/tmp/thermostat_test/var/run/thermostat/db.pid", config.getUserStoragePidFile().getAbsolutePath());
-        Assert.assertEquals("/tmp/thermostat_test/var/log/thermostat/db.log", config.getUserStorageLogFile().getCanonicalPath());
-
-        Assert.assertEquals("/tmp/thermostat_test/var/lib/thermostat/plugins", config.getUserPluginRoot().getCanonicalPath());
-    }
-
-    @Test
-    public void testPrivilegedUserLocationsWithPrefix() throws InvalidConfigurationException, IOException {
-        String thermostatHome = "/tmp";
-        String prefix = "/tmp/opt/custom/prefix";
-        System.setProperty("THERMOSTAT_HOME", thermostatHome);
-        System.setProperty("USER_THERMOSTAT_HOME", prefix);
-        System.setProperty("THERMOSTAT_SYSTEM_USER", "");
-        Configuration config = new Configuration();
-
-        // the paths are unix specific, but so are the paths in Configuration
-
-        Assert.assertEquals(prefix + "/etc/thermostat/agent.properties", config.getUserAgentConfigurationFile().getCanonicalPath());
-        Assert.assertEquals(prefix + "/etc/thermostat/agent.auth", config.getUserAgentAuthConfigFile().getCanonicalPath());
-        Assert.assertEquals(prefix + "/etc/thermostat/db.properties", config.getUserStorageConfigurationFile().getCanonicalPath());
-
-        Assert.assertEquals(prefix + "/var/lib/thermostat/db", config.getUserStorageDirectory().getCanonicalPath());
-        Assert.assertEquals(prefix + "/var/run/thermostat/db.pid", config.getUserStoragePidFile().getAbsolutePath());
-        Assert.assertEquals(prefix + "/var/log/thermostat/db.log", config.getUserStorageLogFile().getCanonicalPath());
-
-        Assert.assertEquals(prefix + "/var/lib/thermostat/plugins", config.getUserPluginRoot().getCanonicalPath());
-    }
-
-    @Test
-    public void instantiationThrowsException() {
-        try {
-            new Configuration();
-            // The web archive uses this. See WebStorageEndPoint#init();
-            fail("Should have thrown InvalidConfigurationException");
-        } catch (InvalidConfigurationException e) {
-            // pass
-        }
-    }
-}
--- a/config/src/test/java/com/redhat/thermostat/shared/config/NativeLibrayResolverTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/config/src/test/java/com/redhat/thermostat/shared/config/NativeLibrayResolverTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -42,6 +42,8 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
+
 public class NativeLibrayResolverTest {
 
     private static final String THERMOSTAT_HOME = "THERMOSTAT_HOME";
@@ -51,6 +53,7 @@
     @Before
     public void setUp() {
         saved = System.setProperty(THERMOSTAT_HOME, "../foo/");
+        NativeLibraryResolver.setCommonPaths(new CommonPathsImpl());
     }
 
     @After
--- a/config/src/test/java/com/redhat/thermostat/shared/config/internal/ActivatorTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/config/src/test/java/com/redhat/thermostat/shared/config/internal/ActivatorTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -39,22 +39,61 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
 import com.redhat.thermostat.testutils.StubBundleContext;
+import com.redhat.thermostat.testutils.TestUtils;
 
 public class ActivatorTest {
 
+    private String originalThermostatHomeProperty;
+    private File testHome;
+
+    @Before
+    public void setUp() {
+        Path testHomePath = null;
+        try {
+            testHomePath = Files.createTempDirectory("ActivatorTest_THERMOSTAT_HOME");
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        File testHome = testHomePath.toFile();
+        originalThermostatHomeProperty = System.getProperty("THERMOSTAT_HOME");
+        System.setProperty("THERMOSTAT_HOME", testHome.getAbsolutePath());
+    }
+
+    @After
+    public void tearDown() throws IOException {
+        if (testHome != null) {
+            TestUtils.deleteRecursively(testHome);
+        }
+        if (originalThermostatHomeProperty != null) {
+            System.setProperty("THERMOSTAT_HOME", originalThermostatHomeProperty);
+        } else {
+            System.clearProperty("THERMOSTAT_HOME");
+        }
+    }
+
     @Test
-    public void verifyServiceRegistered() throws Exception {
+    public void verifyServicesRegistered() throws Exception {
         StubBundleContext ctx = new StubBundleContext();
         Activator activator = new Activator();
         activator.start(ctx);
 
         assertTrue(ctx.isServiceRegistered(SSLConfiguration.class.getName(),
                 SSLConfigurationImpl.class));
-        assertEquals(1, ctx.getAllServices().size());
+        assertTrue(ctx.isServiceRegistered(CommonPaths.class.getName(),
+                CommonPathsImpl.class));
+        assertEquals(2, ctx.getAllServices().size());
 
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/src/test/java/com/redhat/thermostat/shared/config/internal/CommonPathsImplTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -0,0 +1,165 @@
+/*
+ * 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.internal;
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.shared.config.InvalidConfigurationException;
+
+public class CommonPathsImplTest {
+
+    @Before
+    public void setUp() {
+        System.clearProperty("THERMOSTAT_HOME");
+        System.clearProperty("USER_THERMOSTAT_HOME");
+        System.clearProperty("THERMOSTAT_SYSTEM_USER");
+    }
+    
+    @After
+    public void tearDown() {
+        System.clearProperty("THERMOSTAT_HOME");
+        System.clearProperty("USER_THERMOSTAT_HOME");
+        System.clearProperty("THERMOSTAT_SYSTEM_USER");
+    }
+
+    @Test
+    public void testSystemLocations() throws InvalidConfigurationException, IOException {
+        String thermostatHome = "/tmp";
+        System.setProperty("THERMOSTAT_HOME", thermostatHome);
+
+        char s = File.separatorChar;
+
+        CommonPaths config = new CommonPathsImpl();
+
+        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());
+    }
+
+    @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";
+        CommonPaths config = new CommonPathsImpl();
+
+        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());
+
+        Assert.assertEquals(userHome + s + "data" + s + "plugins",
+                config.getUserPluginRoot().getCanonicalPath());
+    }
+
+    @Test
+    public void testPrivilegedUserLocations() throws InvalidConfigurationException, IOException {
+        String thermostatHome = "/tmp/thermostat_test";
+        System.setProperty("THERMOSTAT_HOME", thermostatHome);
+        System.setProperty("THERMOSTAT_SYSTEM_USER", "");
+        CommonPaths config = new CommonPathsImpl(thermostatHome);
+
+        // the paths are unix specific, but so are the paths in Configuration
+
+        Assert.assertEquals("/tmp/thermostat_test/etc/thermostat/agent.properties", config.getUserAgentConfigurationFile().getCanonicalPath());
+        Assert.assertEquals("/tmp/thermostat_test/etc/thermostat/agent.auth", config.getUserAgentAuthConfigFile().getCanonicalPath());
+        Assert.assertEquals("/tmp/thermostat_test/etc/thermostat/db.properties", config.getUserStorageConfigurationFile().getCanonicalPath());
+
+        Assert.assertEquals("/tmp/thermostat_test/var/lib/thermostat/db", config.getUserStorageDirectory().getCanonicalPath());
+        Assert.assertEquals("/tmp/thermostat_test/var/run/thermostat/db.pid", config.getUserStoragePidFile().getAbsolutePath());
+        Assert.assertEquals("/tmp/thermostat_test/var/log/thermostat/db.log", config.getUserStorageLogFile().getCanonicalPath());
+
+        Assert.assertEquals("/tmp/thermostat_test/var/lib/thermostat/plugins", config.getUserPluginRoot().getCanonicalPath());
+    }
+
+    @Test
+    public void testPrivilegedUserLocationsWithPrefix() throws InvalidConfigurationException, IOException {
+        String thermostatHome = "/tmp";
+        String prefix = "/tmp/opt/custom/prefix";
+        System.setProperty("THERMOSTAT_HOME", thermostatHome);
+        System.setProperty("USER_THERMOSTAT_HOME", prefix);
+        System.setProperty("THERMOSTAT_SYSTEM_USER", "");
+        CommonPaths config = new CommonPathsImpl();
+
+        // the paths are unix specific, but so are the paths in Configuration
+
+        Assert.assertEquals(prefix + "/etc/thermostat/agent.properties", config.getUserAgentConfigurationFile().getCanonicalPath());
+        Assert.assertEquals(prefix + "/etc/thermostat/agent.auth", config.getUserAgentAuthConfigFile().getCanonicalPath());
+        Assert.assertEquals(prefix + "/etc/thermostat/db.properties", config.getUserStorageConfigurationFile().getCanonicalPath());
+
+        Assert.assertEquals(prefix + "/var/lib/thermostat/db", config.getUserStorageDirectory().getCanonicalPath());
+        Assert.assertEquals(prefix + "/var/run/thermostat/db.pid", config.getUserStoragePidFile().getAbsolutePath());
+        Assert.assertEquals(prefix + "/var/log/thermostat/db.log", config.getUserStorageLogFile().getCanonicalPath());
+
+        Assert.assertEquals(prefix + "/var/lib/thermostat/plugins", config.getUserPluginRoot().getCanonicalPath());
+    }
+
+    @Test
+    public void instantiationThrowsException() {
+        try {
+            new CommonPathsImpl();
+            // The web archive uses this. See WebStorageEndPoint#init();
+            fail("Should have thrown InvalidConfigurationException");
+        } catch (InvalidConfigurationException e) {
+            // pass
+        }
+    }
+}
--- a/config/src/test/java/com/redhat/thermostat/shared/config/internal/SSLConfigurationImplTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/config/src/test/java/com/redhat/thermostat/shared/config/internal/SSLConfigurationImplTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -53,7 +53,7 @@
 
     @Before
     public void setUp() {
-        sslConf = new SSLConfigurationImpl();
+        sslConf = new SSLConfigurationImpl(null);
         File clientProps = new File(this.getClass().getResource("/client.properties").getFile());
         sslConf.initClientProperties(clientProps);
     }
@@ -68,7 +68,7 @@
     
     @Test
     public void notExistingPropertiesFileReturnsNull() throws Exception {
-        SSLConfigurationImpl badSSLConf = new SSLConfigurationImpl();
+        SSLConfigurationImpl badSSLConf = new SSLConfigurationImpl(null);
         File clientProps = new File("i/am/not/there/file.txt");
         badSSLConf.initClientProperties(clientProps);
         assertTrue(badSSLConf.getKeystoreFile() == null);
@@ -81,7 +81,7 @@
         assertTrue(sslConf.enableForBackingStorage());
         assertTrue(sslConf.disableHostnameVerification());
         File disabledSSLProps = new File(this.getClass().getResource("/ssl.properties").getFile());
-        SSLConfigurationImpl disabledSSLConf = new SSLConfigurationImpl();
+        SSLConfigurationImpl disabledSSLConf = new SSLConfigurationImpl(null);
         disabledSSLConf.initClientProperties(disabledSSLProps);
         assertFalse(disabledSSLConf.enableForCmdChannel());
         assertFalse(disabledSSLConf.enableForBackingStorage());
--- a/config/src/test/java/com/redhat/thermostat/shared/locale/LocaleResourcesTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/config/src/test/java/com/redhat/thermostat/shared/locale/LocaleResourcesTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -46,6 +46,8 @@
 
 import org.junit.Test;
 
+import com.redhat.thermostat.shared.locale.internal.LocaleResources;
+
 public class LocaleResourcesTest {
     @Test
     public void testLocalizedStringsArePresent() throws IOException {
--- a/eclipse/com.redhat.thermostat.client.feature/build.properties	Fri Nov 15 17:28:05 2013 -0700
+++ b/eclipse/com.redhat.thermostat.client.feature/build.properties	Mon Nov 18 08:22:15 2013 -0700
@@ -1,4 +1,5 @@
 bin.includes = feature.xml
-forceContextQualifier = SNAPSHOT
+
 root.linux.gtk.x86=linux_x86
 root.linux.gtk.x86_64=linux_x86_64
+forceContextQualifier = SNAPSHOT
--- a/eclipse/com.redhat.thermostat.eclipse/META-INF/MANIFEST.MF	Fri Nov 15 17:28:05 2013 -0700
+++ b/eclipse/com.redhat.thermostat.eclipse/META-INF/MANIFEST.MF	Mon Nov 18 08:22:15 2013 -0700
@@ -16,6 +16,7 @@
  com.redhat.thermostat.client.locale,
  com.redhat.thermostat.client.ui,
  com.redhat.thermostat.common,
+ com.redhat.thermostat.shared.config,
  com.redhat.thermostat.shared.locale,
  com.redhat.thermostat.common.utils,
  com.redhat.thermostat.host.overview.client.core,
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/Activator.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/Activator.java	Mon Nov 18 08:22:15 2013 -0700
@@ -49,6 +49,7 @@
 import com.redhat.thermostat.eclipse.LoggerFacility;
 import com.redhat.thermostat.eclipse.internal.views.SWTHostOverviewViewProvider;
 import com.redhat.thermostat.host.overview.client.core.HostOverviewViewProvider;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.storage.core.ConnectionException;
 import com.redhat.thermostat.storage.core.DbService;
 import com.redhat.thermostat.utils.keyring.Keyring;
@@ -68,6 +69,10 @@
     @SuppressWarnings({ "rawtypes" })
     private ServiceTracker keyringTracker;
 
+    private CommonPaths paths;
+    @SuppressWarnings({ "rawtypes" })
+    private ServiceTracker pathsTracker;
+
     /**
      * The constructor
      */
@@ -89,7 +94,7 @@
         // Register ViewProvider
         context.registerService(HostOverviewViewProvider.class,
                 new SWTHostOverviewViewProvider(), null);
-        
+
         keyringTracker = new ServiceTracker(context, Keyring.class, null) {
             @Override
             public Object addingService(ServiceReference reference) {
@@ -105,8 +110,24 @@
             }
             
         };
-        // Track for Keyring service.
+        pathsTracker = new ServiceTracker(context, CommonPaths.class, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                CommonPaths paths = (CommonPaths) context.getService(reference);
+                Activator.this.paths = paths;
+                return keyring;
+            }
+
+            @Override
+            public void removedService(ServiceReference reference, Object service) {
+                Activator.this.paths = null;
+                context.ungetService(reference);
+            }
+            
+        };
+        // Track Keyring and CommonPaths services.
         keyringTracker.open();
+        pathsTracker.open();
     }
 
     /*
@@ -197,5 +218,8 @@
         return keyring;
     }
 
+    public CommonPaths getCommonPaths() {
+        return paths;
+    }
 }
 
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/preferences/MainPreferencePage.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/preferences/MainPreferencePage.java	Mon Nov 18 08:22:15 2013 -0700
@@ -174,7 +174,7 @@
         addField(passwordEditor);
         addField(saveEntitlementsEditor);
         updateMargins(generalGroup);
-        this.clientPrefs = new ClientPreferences(Activator.getDefault().getKeyring());
+        this.clientPrefs = new ClientPreferences(Activator.getDefault().getKeyring(), Activator.getDefault().getCommonPaths());
         synchronizeValues();
     }
     
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/views/HostsVmsTreeViewPart.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/internal/views/HostsVmsTreeViewPart.java	Mon Nov 18 08:22:15 2013 -0700
@@ -97,7 +97,8 @@
     private Timer timer;
 
     public HostsVmsTreeViewPart() {
-        ClientPreferences clientPrefs = new ClientPreferences(Activator.getDefault().getKeyring());
+        ClientPreferences clientPrefs = new ClientPreferences(Activator.getDefault().getKeyring(),
+                                                              Activator.getDefault().getCommonPaths());
         ConnectionConfiguration configuration = new ConnectionConfiguration(
                 clientPrefs.getUserName(), clientPrefs.getPassword(),
                 clientPrefs.getConnectionUrl());
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -42,6 +42,7 @@
 import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
+import java.io.File;
 import java.io.InputStream;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -55,6 +56,8 @@
 
 import com.redhat.thermostat.host.cpu.common.CpuStatDAO;
 import com.redhat.thermostat.host.cpu.common.model.CpuStat;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
 import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl;
 import com.redhat.thermostat.storage.config.StartupConfiguration;
@@ -144,7 +147,129 @@
             }
             
         };
-        SSLConfiguration sslConf = new SSLConfigurationImpl();
+        SSLConfiguration sslConf = new SSLConfigurationImpl(new CommonPaths() {
+
+            @Override
+            public File getSystemThermostatHome() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserThermostatHome() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getSystemPluginRoot() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getSystemLibRoot() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getSystemNativeLibsRoot() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getSystemBinRoot() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getSystemConfigurationDirectory() throws InvalidConfigurationException { 
+                return null;
+            }
+
+            @Override
+            public File getUserConfigurationDirectory() throws InvalidConfigurationException {
+                return new File("/tmp");
+            }
+
+            @Override
+            public File getUserPersistentDataDirectory() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserRuntimeDataDirectory() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserLogDirectory() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserCacheDirectory() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserPluginRoot() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserStorageDirectory() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getSystemStorageConfigurationFile() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserStorageConfigurationFile() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserStorageLogFile() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserStoragePidFile() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getSystemAgentConfigurationFile() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserAgentConfigurationFile() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getSystemAgentAuthConfigFile() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserAgentAuthConfigFile() throws InvalidConfigurationException {
+                return null;
+            }
+
+            @Override
+            public File getUserClientConfigurationFile() throws InvalidConfigurationException { 
+                return null;
+            }
+
+            @Override
+            public File getUserHistoryFile() throws InvalidConfigurationException {
+                return null;
+            }
+            
+        });
         BackingStorage storage = new MongoStorage(config, sslConf);
         if (listener != null) {
             storage.getConnection().addListener(listener);
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -76,6 +76,7 @@
 import com.redhat.thermostat.host.cpu.common.CpuStatDAO;
 import com.redhat.thermostat.host.cpu.common.model.CpuStat;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
+import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
 import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl;
 import com.redhat.thermostat.storage.config.ConnectionConfiguration;
 import com.redhat.thermostat.storage.config.StartupConfiguration;
@@ -357,7 +358,7 @@
         setupJAASForUser(roleNames, username, password);
         String url = "http://localhost:" + port + "/thermostat/storage";
         StartupConfiguration config = new ConnectionConfiguration(url, username, password);
-        SSLConfiguration sslConf = new SSLConfigurationImpl();
+        SSLConfiguration sslConf = new SSLConfigurationImpl(new CommonPathsImpl());
         Storage storage = new WebStorage(config, sslConf);
         if (listener != null) {
             storage.getConnection().addListener(listener);
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/BundleManager.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/BundleManager.java	Mon Nov 18 08:22:15 2013 -0700
@@ -44,7 +44,7 @@
 
 import com.redhat.thermostat.annotations.Service;
 import com.redhat.thermostat.launcher.internal.BundleLoader;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 
 /**
  * A Service that provides features to load bundles for given command names.
@@ -67,7 +67,7 @@
         loader.installAndStartBundles(framework, bundleLocations);
     }
 
-    public abstract Configuration getConfiguration();
+    public abstract CommonPaths getCommonPaths();
 
 }
 
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java	Mon Nov 18 08:22:15 2013 -0700
@@ -37,90 +37,93 @@
 package com.redhat.thermostat.launcher.internal;
 
 import java.io.File;
+import java.io.IOException;
+import java.util.Map;
 
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
 import com.redhat.thermostat.common.ExitStatus;
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.MultipleServiceTracker.Action;
 import com.redhat.thermostat.common.cli.CommandContextFactory;
 import com.redhat.thermostat.common.cli.CommandRegistry;
 import com.redhat.thermostat.common.cli.CommandRegistryImpl;
+import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.launcher.Launcher;
 import com.redhat.thermostat.launcher.internal.CurrentEnvironment.CurrentEnvironmentChangeListener;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class Activator implements BundleActivator {
     
-    @SuppressWarnings({"rawtypes", "unchecked"})
-    class RegisterLauncherCustomizer implements ServiceTrackerCustomizer {
+    @SuppressWarnings({ "rawtypes" })
+    class RegisterLauncherAction implements Action {
 
         private ServiceRegistration launcherReg;
         private ServiceRegistration bundleManReg;
         private ServiceRegistration cmdInfoReg;
         private ServiceRegistration exitStatusReg;
         private BundleContext context;
-        private BundleManager bundleService;
-        private CurrentEnvironment currentEnvironment;
+        private CurrentEnvironment env;
 
-        RegisterLauncherCustomizer(BundleContext context, BundleManager bundleService, CurrentEnvironment env) {
+        RegisterLauncherAction(BundleContext context, CurrentEnvironment env) {
             this.context = context;
-            this.bundleService = bundleService;
-            this.currentEnvironment = env;
+            this.env = env;
         }
 
         @Override
-        public Object addingService(ServiceReference reference) {
-            // keyring is now ready
-            Keyring keyring = (Keyring)context.getService(reference);
-            Configuration config = bundleService.getConfiguration();
+        public void dependenciesAvailable(Map<String, Object> services) {
+            CommonPaths paths = (CommonPaths) services.get(CommonPaths.class.getName());
+            Keyring keyring = (Keyring) services.get(Keyring.class.getName());
+            ClientPreferences prefs = new ClientPreferences(keyring, paths);
 
-            String commandsDir = new File(config.getSystemConfigurationDirectory(), "commands").toString();
+            String commandsDir = new File(paths.getSystemConfigurationDirectory(), "commands").toString();
             CommandInfoSource builtInCommandSource =
-                    new BuiltInCommandInfoSource(commandsDir, config.getSystemLibRoot().toString());
+                    new BuiltInCommandInfoSource(commandsDir, paths.getSystemLibRoot().toString());
             CommandInfoSource pluginCommandSource = new PluginCommandInfoSource(
-                            config.getSystemLibRoot().toString(), config.getSystemPluginRoot().toString(),
-                            config.getUserPluginRoot().toString());
+                            paths.getSystemLibRoot().toString(), paths.getSystemPluginRoot().toString(),
+                            paths.getUserPluginRoot().toString());
             CommandInfoSource commands = new CompoundCommandInfoSource(builtInCommandSource, pluginCommandSource);
 
             cmdInfoReg = context.registerService(CommandInfoSource.class, commands, null);
 
+            BundleManager bundleService = null;
+            try {
+                bundleService = new BundleManagerImpl(paths);
+            } catch (IOException e) {
+                throw new RuntimeException("Could not initialize launcher.", e);
+            }
+
             // Register Launcher service since FrameworkProvider is waiting for it blockingly.
-            LauncherImpl launcher = new LauncherImpl(context,
-                    new CommandContextFactory(context), bundleService, commands, currentEnvironment);
+            LauncherImpl launcher = new LauncherImpl(context, new CommandContextFactory(context),
+                    bundleService, commands, env, prefs, paths);
             launcherReg = context.registerService(Launcher.class.getName(), launcher, null);
             bundleManReg = context.registerService(BundleManager.class, bundleService, null);
             ExitStatus exitStatus = new ExitStatusImpl(ExitStatus.EXIT_SUCCESS);
             exitStatusReg = context.registerService(ExitStatus.class, exitStatus, null);
-            return keyring;
         }
 
         @Override
-        public void modifiedService(ServiceReference reference, Object service) {
-            // nothing
-        }
-
-        @Override
-        public void removedService(ServiceReference reference, Object service) {
-            // Keyring is gone, remove launcher, et. al. as well
+        public void dependenciesUnavailable() {
+            // Keyring or CommonPaths are gone, remove launcher, et. al. as well
             launcherReg.unregister();
             bundleManReg.unregister();
             cmdInfoReg.unregister();
             exitStatusReg.unregister();
         }
-
+        
     }
 
-    @SuppressWarnings("rawtypes")
-    private ServiceTracker serviceTracker;
+    private MultipleServiceTracker launcherDepsTracker;
 
     private CommandRegistry registry;
 
+    @SuppressWarnings("rawtypes")
     private ServiceTracker commandInfoSourceTracker;
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
@@ -128,11 +131,13 @@
     public void start(final BundleContext context) throws Exception {
         CurrentEnvironment environment = new CurrentEnvironment(Environment.CLI);
 
-        BundleManager bundleService = new BundleManagerImpl(new Configuration());
-        ServiceTrackerCustomizer customizer = new RegisterLauncherCustomizer(context, bundleService, environment);
-        serviceTracker = new ServiceTracker(context, Keyring.class, customizer);
-        // Track for Keyring service.
-        serviceTracker.open();
+        Class[] launcherDeps = new Class[]{
+            Keyring.class,
+            CommonPaths.class,
+        };
+        launcherDepsTracker = new MultipleServiceTracker(context, launcherDeps,
+                new RegisterLauncherAction(context, environment));
+        launcherDepsTracker.open();
 
         final HelpCommand helpCommand = new HelpCommand();
         environment.addListener(new CurrentEnvironmentChangeListener() {
@@ -165,10 +170,12 @@
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        if (serviceTracker != null) {
-            serviceTracker.close();
+        if (launcherDepsTracker != null) {
+            launcherDepsTracker.close();
         }
-        commandInfoSourceTracker.close();
+        if (commandInfoSourceTracker != null) {
+            commandInfoSourceTracker.close();
+        }
         registry.unregisterCommands();
     }
 }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BundleManagerImpl.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BundleManagerImpl.java	Mon Nov 18 08:22:15 2013 -0700
@@ -54,8 +54,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import javax.naming.ConfigurationException;
-
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
@@ -67,7 +65,7 @@
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.launcher.BundleInformation;
 import com.redhat.thermostat.launcher.BundleManager;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 
 public class BundleManagerImpl extends BundleManager {
 
@@ -80,15 +78,15 @@
     // name/version. See
     // http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1514
     private final Map<BundleInformation, Path> known;
-    private Configuration configuration;
+    private CommonPaths paths;
     private boolean printOSGiInfo = false;
     private boolean ignoreBundleVersions = false;
     private BundleLoader loader;
 
-    BundleManagerImpl(Configuration configuration) throws ConfigurationException, FileNotFoundException, IOException {
+    BundleManagerImpl(CommonPaths paths) throws FileNotFoundException, IOException {
         known = new HashMap<>();
 
-        this.configuration = configuration;
+        this.paths = paths;
         loader = new BundleLoader();
 
         scanForBundles();
@@ -98,7 +96,7 @@
         long t1 = System.nanoTime();
 
         try {
-            for (File root : new File[] { configuration.getSystemLibRoot(), configuration.getSystemPluginRoot() }) {
+            for (File root : new File[] { paths.getSystemLibRoot(), paths.getSystemPluginRoot() }) {
                 Files.walkFileTree(root.toPath(), new SimpleFileVisitor<Path>() {
                     @Override
                     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
@@ -245,8 +243,8 @@
     }
 
     @Override
-    public Configuration getConfiguration() {
-        return configuration;
+    public CommonPaths getCommonPaths() {
+        return paths;
     }
 }
 
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Mon Nov 18 08:22:15 2013 -0700
@@ -68,6 +68,7 @@
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.launcher.Launcher;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 import com.redhat.thermostat.shared.locale.Translate;
@@ -76,7 +77,6 @@
 import com.redhat.thermostat.storage.core.DbServiceFactory;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.StorageException;
-import com.redhat.thermostat.utils.keyring.Keyring;
 
 /**
  * This class is thread-safe.
@@ -98,20 +98,20 @@
     private final CommandInfoSource commandInfoSource;
     private final CurrentEnvironment currentEnvironment;
 
-    /** MUST be mutated in a 'synchronized (this)' block */
-    private ClientPreferences prefs;
+    private final ClientPreferences prefs;
 
 
 
-    public LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory, BundleManager registry, CommandInfoSource infoSource, CurrentEnvironment env) {
-        this(context, cmdCtxFactory, registry, infoSource,
-                new CommandSource(context), env, new LoggingInitializer(), new DbServiceFactory(), new Version());
+    public LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory, BundleManager registry,
+            CommandInfoSource infoSource, CurrentEnvironment env, ClientPreferences prefs, CommonPaths paths) {
+        this(context, cmdCtxFactory, registry, infoSource, new CommandSource(context), env,
+                new DbServiceFactory(), new Version(), prefs, paths, new LoggingInitializer(paths));
     }
 
     LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory, BundleManager registry,
             CommandInfoSource commandInfoSource, CommandSource commandSource,
-            CurrentEnvironment currentEnvironment,
-            LoggingInitializer loggingInitializer, DbServiceFactory dbServiceFactory, Version version) {
+            CurrentEnvironment currentEnvironment, DbServiceFactory dbServiceFactory, Version version,
+            ClientPreferences prefs, CommonPaths paths, LoggingInitializer loggingInitializer) {
         this.context = context;
         this.cmdCtxFactory = cmdCtxFactory;
         this.registry = registry;
@@ -120,6 +120,7 @@
         this.commandSource = commandSource;
         this.commandInfoSource = commandInfoSource;
         this.currentEnvironment = currentEnvironment;
+        this.prefs = prefs;
 
         loggingInitializer.initialize();
         logger = LoggingUtils.getLogger(LauncherImpl.class);
@@ -204,10 +205,6 @@
         }
     }
 
-    synchronized void setPreferences(ClientPreferences prefs) {
-        this.prefs = prefs;
-    }
-
     private boolean hasNoArguments(String[] args) {
         return args == null || args.length == 0;
     }
@@ -333,16 +330,8 @@
 
         CommandContext ctx = cmdCtxFactory.createContext(args);
         
-        synchronized (this) {
-            if (prefs == null) {
-                ServiceReference keyringReference = context.getServiceReference(Keyring.class);
-                @SuppressWarnings("unchecked")
-                Keyring keyring = (Keyring) context.getService(keyringReference);
-                prefs = new ClientPreferences(keyring);
-            }
-        }
-        
         if (cmd.isStorageRequired()) {
+
             ServiceReference dbServiceReference = context.getServiceReference(DbService.class);
             if (dbServiceReference == null) {
                 String dbUrl = ctx.getArguments().getArgument(CommonOptions.DB_URL_ARG);
@@ -389,14 +378,21 @@
     }
 
     static class LoggingInitializer {
+
+        private CommonPaths paths;
+
+        LoggingInitializer(CommonPaths paths) {
+            this.paths = paths;
+        }
+
         public void initialize() {
             try {
-                LoggingUtils.loadGlobalLoggingConfig();
+                LoggingUtils.loadGlobalLoggingConfig(paths);
             } catch (InvalidConfigurationException e) {
                 System.err.println("WARNING: Could not read global Thermostat logging configuration.");
             }
             try {
-                LoggingUtils.loadUserLoggingConfig();
+                LoggingUtils.loadUserLoggingConfig(paths);
             } catch (InvalidConfigurationException e) {
                 // We intentionally ignore this.
             }
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -53,7 +53,9 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Map;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -63,10 +65,8 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.launch.Framework;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.powermock.api.mockito.PowerMockito;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
@@ -77,13 +77,12 @@
 import com.redhat.thermostat.common.cli.Command;
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.launcher.Launcher;
-import com.redhat.thermostat.launcher.internal.Activator.RegisterLauncherCustomizer;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import com.redhat.thermostat.utils.keyring.Keyring;
 
 @RunWith(PowerMockRunner.class)
-@PrepareForTest({Activator.class, Activator.RegisterLauncherCustomizer.class, FrameworkUtil.class})
+@PrepareForTest({Activator.class, Activator.RegisterLauncherAction.class, FrameworkUtil.class})
 public class ActivatorTest {
 
     private StubBundleContext context;
@@ -107,9 +106,9 @@
         props.put(Command.NAME, "help");
         context.registerService(Command.class, helpCommand, props);
 
-        Configuration config = mock(Configuration.class);
+        CommonPaths config = mock(CommonPaths.class);
         when(config.getSystemThermostatHome()).thenReturn(new File(""));
-        when(registryService.getConfiguration()).thenReturn(config);
+        when(registryService.getCommonPaths()).thenReturn(config);
 
         BuiltInCommandInfoSource source1 = mock(BuiltInCommandInfoSource.class);
         when(source1.getCommandInfos()).thenReturn(new ArrayList<CommandInfo>());
@@ -139,10 +138,12 @@
 
     @Test
     public void testActivatorLifecycle() throws Exception {
-        ArgumentCaptor<RegisterLauncherCustomizer> customizerCaptor = ArgumentCaptor.forClass(RegisterLauncherCustomizer.class);
-        ServiceTracker mockTracker = mock(ServiceTracker.class);
-        whenNew(ServiceTracker.class).withParameterTypes(BundleContext.class, Class.class, ServiceTrackerCustomizer.class).withArguments(eq(context),
-                any(Keyring.class), customizerCaptor.capture()).thenReturn(mockTracker);
+        ArgumentCaptor<Action> actionCaptor = ArgumentCaptor.forClass(Action.class);
+        MultipleServiceTracker mockTracker = mock(MultipleServiceTracker.class);
+        whenNew(MultipleServiceTracker.class)
+                .withParameterTypes(BundleContext.class, Class[].class, Action.class)
+                .withArguments(eq(context), any(Class[].class), actionCaptor.capture())
+                .thenReturn(mockTracker);
         
         Activator activator = new Activator();
         activator.start(context);
@@ -151,8 +152,8 @@
 
         verify(mockTracker).open();
         
-        RegisterLauncherCustomizer customizer = customizerCaptor.getValue();
-        assertNotNull(customizer);
+        Action action = actionCaptor.getValue();
+        assertNotNull(action);
         activator.stop(context);
         verify(mockTracker).close();
     }
@@ -160,10 +161,10 @@
     @Test
     public void testServiceTrackerCustomizer() throws Exception {
         StubBundleContext context = new StubBundleContext();
-        ArgumentCaptor<RegisterLauncherCustomizer> customizerCaptor = ArgumentCaptor.forClass(RegisterLauncherCustomizer.class);
-        ServiceTracker mockTracker = mock(ServiceTracker.class);
-        whenNew(ServiceTracker.class).withParameterTypes(BundleContext.class, Class.class, ServiceTrackerCustomizer.class).withArguments(eq(context),
-                any(Keyring.class), customizerCaptor.capture()).thenReturn(mockTracker);
+        ArgumentCaptor<Action> actionCaptor = ArgumentCaptor.forClass(Action.class);
+        MultipleServiceTracker mockTracker = mock(MultipleServiceTracker.class);
+        whenNew(MultipleServiceTracker.class).withParameterTypes(BundleContext.class, Class[].class, Action.class).withArguments(eq(context),
+                any(Class[].class), actionCaptor.capture()).thenReturn(mockTracker);
         
         Activator activator = new Activator();
         context.registerService(Keyring.class, mock(Keyring.class), null);
@@ -171,19 +172,31 @@
         
         assertTrue(context.isServiceRegistered(Command.class.getName(), HelpCommand.class));
         
-        RegisterLauncherCustomizer customizer = customizerCaptor.getValue();
-        assertNotNull(customizer);
+        Action action = actionCaptor.getValue();
+        assertNotNull(action);
         Keyring keyringService = mock(Keyring.class);
-        context.registerService(Keyring.class, keyringService, null);
-        ServiceReference ref = context.getServiceReference(Keyring.class);
-        customizer.addingService(ref);
+        CommonPaths paths = mock(CommonPaths.class);
+        when(paths.getSystemLibRoot()).thenReturn(new File(""));
+        when(paths.getSystemPluginRoot()).thenReturn(new File(""));
+        when(paths.getUserPluginRoot()).thenReturn(new File(""));
+        when(paths.getUserClientConfigurationFile()).thenReturn(new File(""));
+        @SuppressWarnings("rawtypes")
+        ServiceRegistration keyringReg = context.registerService(Keyring.class, keyringService, null);
+        @SuppressWarnings("rawtypes")
+        ServiceRegistration pathsReg = context.registerService(CommonPaths.class, paths, null);
+        Map<String, Object> services = new HashMap<>();
+        services.put(Keyring.class.getName(), keyringService);
+        services.put(CommonPaths.class.getName(), paths);
+        action.dependenciesAvailable(services);
         
         assertTrue(context.isServiceRegistered(CommandInfoSource.class.getName(), mock(CompoundCommandInfoSource.class).getClass()));
         assertTrue(context.isServiceRegistered(BundleManager.class.getName(), BundleManagerImpl.class));
         assertTrue(context.isServiceRegistered(Launcher.class.getName(), LauncherImpl.class));
         assertTrue(context.isServiceRegistered(ExitStatus.class.getName(), ExitStatusImpl.class));
 
-        customizer.removedService(null, null);
+        action.dependenciesUnavailable();
+        keyringReg.unregister();
+        pathsReg.unregister();
         
         assertFalse(context.isServiceRegistered(CommandInfoSource.class.getName(), CompoundCommandInfoSource.class));
         assertFalse(context.isServiceRegistered(BundleManager.class.getName(), BundleManagerImpl.class));
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BundleManagerImplTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BundleManagerImplTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -71,7 +71,7 @@
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import com.redhat.thermostat.launcher.BundleInformation;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 
 @RunWith(PowerMockRunner.class)
 @PrepareForTest({BundleManagerImpl.class, FrameworkUtil.class})
@@ -88,7 +88,7 @@
     private BundleContext theContext;
 
     private BundleLoader loader;
-    private Configuration conf;
+    private CommonPaths paths;
 
     private Path testRoot;
     
@@ -100,9 +100,9 @@
         Path jarRootDir = testRoot.resolve("libs");
         Files.createDirectories(jarRootDir);
 
-        conf = mock(Configuration.class);
-        when(conf.getSystemLibRoot()).thenReturn(jarRootDir.toFile());
-        when(conf.getSystemPluginRoot()).thenReturn(pluginRootDir.toFile());
+        paths = mock(CommonPaths.class);
+        when(paths.getSystemLibRoot()).thenReturn(jarRootDir.toFile());
+        when(paths.getSystemPluginRoot()).thenReturn(pluginRootDir.toFile());
 
         theContext = mock(BundleContext.class);
         theFramework = mock(Framework.class);
@@ -159,7 +159,7 @@
 
         when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle);
 
-        BundleManagerImpl registry = new BundleManagerImpl(conf);
+        BundleManagerImpl registry = new BundleManagerImpl(paths);
         registry.loadBundlesByPath(bundleLocs);
         verify(loader).installAndStartBundles(any(Framework.class), eq(bundleLocs));
     }
@@ -174,7 +174,7 @@
 
         when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle);
 
-        BundleManagerImpl registry = new BundleManagerImpl(conf);
+        BundleManagerImpl registry = new BundleManagerImpl(paths);
         Map<BundleInformation, Path> bundleToPath = new HashMap<>();
 
         registry.setKnownBundles(bundleToPath);
@@ -195,7 +195,7 @@
 
         when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle);
 
-        BundleManagerImpl registry = new BundleManagerImpl(conf);
+        BundleManagerImpl registry = new BundleManagerImpl(paths);
         Map<BundleInformation, Path> bundleToPath = new HashMap<>();
         bundleToPath.put(new BundleInformation("foo", "1.0"), Paths.get(jar1Name));
         registry.setKnownBundles(bundleToPath);
@@ -216,7 +216,7 @@
 
         when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle);
 
-        BundleManagerImpl registry = new BundleManagerImpl(conf);
+        BundleManagerImpl registry = new BundleManagerImpl(paths);
         registry.setIgnoreBundleVersions(true);
         Map<BundleInformation, Path> bundleToPath = new HashMap<>();
         bundleToPath.put(new BundleInformation("foo", "1.0"), Paths.get(jar1Name));
@@ -240,7 +240,7 @@
 
         when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle);
 
-        BundleManagerImpl registry = new BundleManagerImpl(conf);
+        BundleManagerImpl registry = new BundleManagerImpl(paths);
         Map<BundleInformation, Path> bundleToPath = new HashMap<>();
         bundleToPath.put(new BundleInformation("foo", "1.0"), Paths.get(jar1Name));
         bundleToPath.put(new BundleInformation("foo", "2.0"), Paths.get(jar2Name));
@@ -264,7 +264,7 @@
         mockStatic(FrameworkUtil.class);
         when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle);
 
-        BundleManagerImpl registry = new BundleManagerImpl(conf);
+        BundleManagerImpl registry = new BundleManagerImpl(paths);
         registry.loadBundlesByPath(bundleLocs);
         verify(loader).installAndStartBundles(theFramework, Arrays.asList(jar3Name));
     }
@@ -283,7 +283,7 @@
         mockStatic(FrameworkUtil.class);
         when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle);
 
-        Object registry = new BundleManagerImpl(conf);
+        Object registry = new BundleManagerImpl(paths);
         Class<?> clazz = registry.getClass();
         Method m = clazz.getMethod("setPrintOSGiInfo", Boolean.TYPE);
         m.invoke(registry, true); // If this fails, then API has changed in ways that break FrameworkProvider.
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -45,6 +45,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -80,6 +81,7 @@
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.launcher.internal.DisallowSystemExitSecurityManager.ExitException;
 import com.redhat.thermostat.launcher.internal.LauncherImpl.LoggingInitializer;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 import com.redhat.thermostat.storage.core.DbService;
 import com.redhat.thermostat.storage.core.DbServiceFactory;
@@ -147,6 +149,9 @@
 
     private LauncherImpl launcher;
 
+    private CurrentEnvironment environment;
+    private CommonPaths paths;
+
     @Before
     public void setUp() throws CommandInfoNotFoundException, BundleException, IOException {
         setupCommandContextFactory();
@@ -259,15 +264,20 @@
         when(appSvc.getApplicationExecutor()).thenReturn(exec);
         bundleContext.registerService(ApplicationService.class, appSvc, null);
 
-        CurrentEnvironment environment = mock(CurrentEnvironment.class);
+        environment = mock(CurrentEnvironment.class);
         loggingInitializer = mock(LoggingInitializer.class);
         dbServiceFactory = mock(DbServiceFactory.class);
         version = mock(Version.class);
 
-        launcher = new LauncherImpl(bundleContext, ctxFactory, registry, infos, new CommandSource(bundleContext), environment, loggingInitializer, dbServiceFactory, version);
+        Keyring keyring = mock(Keyring.class);
+        paths = mock(CommonPaths.class);
+        File userConfigFile = mock(File.class);
+        when(userConfigFile.isFile()).thenReturn(false);
+        when(paths.getUserClientConfigurationFile()).thenReturn(userConfigFile);
+        ClientPreferences prefs = new ClientPreferences(keyring, paths);
 
-        Keyring keyring = mock(Keyring.class);
-        launcher.setPreferences(new ClientPreferences(keyring));
+        launcher = new LauncherImpl(bundleContext, ctxFactory, registry, infos, new CommandSource(bundleContext),
+                environment, dbServiceFactory, version, prefs, paths, loggingInitializer);
     }
 
     private void setupCommandContextFactory() {
@@ -473,10 +483,12 @@
         when(prefs.getUserName()).thenReturn("user");
         when(prefs.getPassword()).thenReturn("password");
 
+        LauncherImpl launcher = new LauncherImpl(bundleContext, ctxFactory, registry, infos, new CommandSource(bundleContext),
+                environment, dbServiceFactory, version, prefs, paths, loggingInitializer);
+
         DbService dbService = mock(DbService.class);
         ArgumentCaptor<String> dbUrlCaptor = ArgumentCaptor.forClass(String.class);
         when(dbServiceFactory.createDbService(eq("user"), eq("password"), dbUrlCaptor.capture())).thenReturn(dbService);
-        launcher.setPreferences(prefs);
         wrappedRun(launcher, new String[] { "test3" }, false);
         verify(dbService).connect();
         verify(prefs).getConnectionUrl();
@@ -488,11 +500,12 @@
         ClientPreferences prefs = mock(ClientPreferences.class);
         String dbUrl = "mongo://fluff:12345";
         when(prefs.getConnectionUrl()).thenReturn(dbUrl);
+        LauncherImpl launcher = new LauncherImpl(bundleContext, ctxFactory, registry, infos, new CommandSource(bundleContext),
+                environment, dbServiceFactory, version, prefs, paths, loggingInitializer);
 
         DbService dbService = mock(DbService.class);
         ArgumentCaptor<String> dbUrlCaptor = ArgumentCaptor.forClass(String.class);
         when(dbServiceFactory.createDbService(eq("user"), eq("pass"), dbUrlCaptor.capture())).thenReturn(dbService);
-        launcher.setPreferences(prefs);
         ctxFactory.setInput("user\rpass\r");
         wrappedRun(launcher, new String[] { "test3" }, false);
         verify(dbService).connect();
--- a/main/src/main/java/com/redhat/thermostat/main/Thermostat.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/main/src/main/java/com/redhat/thermostat/main/Thermostat.java	Mon Nov 18 08:22:15 2013 -0700
@@ -42,7 +42,8 @@
 import java.util.List;
 
 import com.redhat.thermostat.main.impl.FrameworkProvider;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
 
 public class Thermostat {
 
@@ -68,8 +69,8 @@
             }
         }
 
-        Configuration config = new Configuration();
-        FrameworkProvider frameworkProvider = new FrameworkProvider(config, printOSGiInfo, ignoreBundleVersions);
+        CommonPaths paths = new CommonPathsImpl();
+        FrameworkProvider frameworkProvider = new FrameworkProvider(paths, printOSGiInfo, ignoreBundleVersions);
         frameworkProvider.start(toProcess.toArray(new String[0]));
     }
 
--- a/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java	Mon Nov 18 08:22:15 2013 -0700
@@ -61,8 +61,7 @@
 
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.launcher.Launcher;
-import com.redhat.thermostat.shared.config.Configuration;
-import com.redhat.thermostat.shared.config.InvalidConfigurationException;
+import com.redhat.thermostat.shared.config.CommonPaths;
 
 public class FrameworkProvider {
 
@@ -70,15 +69,15 @@
     private static final String PROPS_FILE = "/com/redhat/thermostat/main/impl/bootstrapbundles.properties";
     private static final String BUNDLELIST = "bundles";
 
-    private Configuration configuration;
+    private CommonPaths paths;
     private boolean printOSGiInfo;
     private boolean ignoreBundleVersions;
 
     // The framework cache location; Must not be shared between apps!
     private Path osgiCacheStorage;
 
-    public FrameworkProvider(Configuration config, boolean printOSGiInfo, boolean ignoreBundleVersions) {
-        this.configuration = config;
+    public FrameworkProvider(CommonPaths paths, boolean printOSGiInfo, boolean ignoreBundleVersions) {
+        this.paths = paths;
 
         this.printOSGiInfo = printOSGiInfo;
         this.ignoreBundleVersions = ignoreBundleVersions;
@@ -101,7 +100,7 @@
     }
 
     private String getOSGiPublicPackages() throws FileNotFoundException, IOException {
-        File osgiBundleDefinitions = new File(configuration.getSystemConfigurationDirectory(), "osgi-export.properties");
+        File osgiBundleDefinitions = new File(paths.getSystemConfigurationDirectory(), "osgi-export.properties");
 
         Properties bundles = new Properties();
         bundles.load(new FileInputStream(osgiBundleDefinitions));
@@ -167,7 +166,7 @@
     }
 
     private Framework makeFramework() throws FileNotFoundException, IOException {
-        File osgiCacheDir = new File(configuration.getUserCacheDirectory(), "osgi-cache");
+        File osgiCacheDir = new File(paths.getUserCacheDirectory(), "osgi-cache");
         if (!osgiCacheDir.isDirectory() && !osgiCacheDir.mkdirs()) {
             throw new RuntimeException("Unable to create " + osgiCacheDir);
         }
@@ -299,7 +298,7 @@
     // files across bootstrap and later code provide the same bundle symbolic
     // name version
     private String actualLocation(String resourceName) {
-        File file = new File(configuration.getSystemLibRoot(), resourceName);
+        File file = new File(paths.getSystemLibRoot(), resourceName);
         try {
             return file.getCanonicalFile().toURI().toString();
         } catch (IOException e) {
--- a/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties	Fri Nov 15 17:28:05 2013 -0700
+++ b/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties	Mon Nov 18 08:22:15 2013 -0700
@@ -4,7 +4,6 @@
         thermostat-common-core-${project.version}.jar, \
         thermostat-plugin-validator-${project.version}.jar, \
         thermostat-launcher-${project.version}.jar, \
-        thermostat-main-${project.version}.jar, \
         jline-${jline.version}.jar, \
         commons-cli-${commons-cli.version}.jar, \
         org.apache.servicemix.bundles.lucene-${lucene.version}.jar
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactory.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactory.java	Mon Nov 18 08:22:15 2013 -0700
@@ -37,6 +37,7 @@
 
 package com.redhat.thermostat.web.server;
 
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
 import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl;
 import com.redhat.thermostat.storage.config.ConnectionConfiguration;
@@ -50,12 +51,13 @@
     private static Storage storage;
 
     // Web server is not OSGi, this factory method is workaround.
-    static Storage getStorage(String storageClass, final String storageEndpoint, final String username, final String password) {
+    static Storage getStorage(String storageClass, final String storageEndpoint, final String username,
+    		    final String password, final CommonPaths paths) {
         if (storage != null) {
             return storage;
         }
         StartupConfiguration conf = new ConnectionConfiguration(storageEndpoint, username, password);
-        SSLConfiguration sslConf = new SSLConfigurationImpl();
+        SSLConfiguration sslConf = new SSLConfigurationImpl(paths);
         try {
             StorageProvider provider = (StorageProvider) Class.forName(storageClass).newInstance();
             provider.setConfig(conf, sslConf);
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Mon Nov 18 08:22:15 2013 -0700
@@ -70,8 +70,9 @@
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.Configuration;
+import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
+import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
 import com.redhat.thermostat.storage.core.Categories;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.CategoryAdapter;
@@ -128,6 +129,7 @@
 
     private Storage storage;
     private Gson gson;
+    private CommonPaths paths;
 
     public static final String STORAGE_ENDPOINT = "storage.endpoint";
     public static final String STORAGE_USERNAME = "storage.username";
@@ -158,6 +160,7 @@
         logger.log(Level.INFO, "Initializing web service");
         
         // check if thermostat home is set and readable
+        // Side effect: sets this.paths
         checkThermostatHome();
         
         gson = new GsonBuilder()
@@ -213,7 +216,7 @@
             String storageEndpoint = getServletConfig().getInitParameter(STORAGE_ENDPOINT);
             String username = getServletConfig().getInitParameter(STORAGE_USERNAME);
             String password = getServletConfig().getInitParameter(STORAGE_PASSWORD);
-            storage = StorageFactory.getStorage(storageClass, storageEndpoint, username, password);
+            storage = StorageFactory.getStorage(storageClass, storageEndpoint, username, password, paths);
         }
         String uri = req.getRequestURI();
         int lastPartIdx = uri.lastIndexOf("/");
@@ -240,18 +243,20 @@
             verifyToken(req, resp);
         }
     }
-    
+
+    // Side effect: sets this.paths
     private boolean isThermostatHomeSet() {
         try {
             // this throws config exception if neither the property
             // nor the env var is set
-            new Configuration();
+            paths = new CommonPathsImpl();
             return true;
         } catch (InvalidConfigurationException e) {
             return false;
         }
     }
-    
+
+    // Side effect: sets this.paths
     private void checkThermostatHome() {
         if (!isThermostatHomeSet()) {
             String msg = "THERMOSTAT_HOME context parameter not set!";
@@ -274,8 +279,7 @@
 
     private File getThermostatHome() {
         try {
-            Configuration config = new Configuration();
-            return config.getSystemThermostatHome();
+            return paths.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	Fri Nov 15 17:28:05 2013 -0700
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java	Mon Nov 18 08:22:15 2013 -0700
@@ -46,8 +46,8 @@
 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.shared.config.internal.CommonPathsImpl;
 
 /**
  * 
@@ -63,7 +63,7 @@
     PropertiesUserValidator() {
         // 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));
+        this((new CommonPathsImpl().getSystemConfigurationDirectory() + File.separator + DEFAULT_USERS_FILE));
     }
     
     PropertiesUserValidator(String usersFile) {
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java	Mon Nov 18 08:22:15 2013 -0700
@@ -50,8 +50,8 @@
 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.shared.config.internal.CommonPathsImpl;
 import com.redhat.thermostat.web.server.auth.BasicRole;
 import com.redhat.thermostat.web.server.auth.RolePrincipal;
 
@@ -74,7 +74,7 @@
         // 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);
+        this((new CommonPathsImpl().getSystemConfigurationDirectory() + File.separator + DEFAULT_ROLES_FILE), users);
     }
     
     RolesAmender(String rolesFile, Set<Object> users) {
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Fri Nov 15 17:28:05 2013 -0700
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Mon Nov 18 08:22:15 2013 -0700
@@ -48,7 +48,6 @@
 import static org.mockito.Mockito.when;
 
 import java.io.ByteArrayInputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -63,8 +62,6 @@
 import java.net.URL;
 import java.net.URLEncoder;
 import java.security.Principal;
-import java.nio.file.Files;
-import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -184,22 +181,6 @@
     private static Key<Integer> key2;
     private static Category<TestClass> category;
     private static String categoryName = "test";
-    private static String originalThermostatHome;
-
-    @BeforeClass
-    public static void setupThermostatHome() {
-        Path tempHomePath = null;
-        try {
-            tempHomePath = Files.createTempDirectory("WebStorageEndpointTest_THERMOSTAT_HOME");
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        File fakeHome = tempHomePath.toFile();
-        fakeHome.deleteOnExit();
-        assertTrue(fakeHome.canRead());
-        originalThermostatHome = System.getProperty("THERMOSTAT_HOME");
-        System.setProperty("THERMOSTAT_HOME", fakeHome.getAbsolutePath());
-    }
 
     @BeforeClass
     public static void setupCategory() {
@@ -209,15 +190,6 @@
     }
 
     @AfterClass
-    public static void cleanupThermostatHome() {
-        if (originalThermostatHome != null) {
-            System.setProperty("THERMOSTAT_HOME", originalThermostatHome);
-        } else {
-            System.clearProperty("THERMOSTAT_HOME");
-        }
-    }
-
-    @AfterClass
     public static void cleanupCategory() {
         Categories.remove(category);
         category = null;