changeset 591:918b58ad8bbb

Split off agent and backend DAOs from storage This has been a TODO for a while. Storage should not have to know about the agent as much as possible. This patch extracts some bits into AgentInfoDAO and BackendInfoDAO and reduces the interface exposted by Storage. Two separate DAOs are being used instead of one to keep the schema as flat as possible. Reviewed-by: vanaltj Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-September/003068.html
author Omair Majid <omajid@redhat.com>
date Fri, 07 Sep 2012 16:14:49 -0400
parents 549a5e6562c6
children 136dfbad25fb
files agent/cli/src/main/java/com/redhat/thermostat/agent/cli/AgentApplication.java agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java client/command/src/main/java/com/redhat/thermostat/client/command/cli/PingCommand.java client/core/src/main/java/com/redhat/thermostat/client/internal/Main.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/KillVMAction.java client/killvm/src/test/java/com/redhat/thermostat/client/killvm/internal/KillVMActionTest.java common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoConverter.java common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoConverter.java common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java common/core/src/main/java/com/redhat/thermostat/common/model/AgentInformation.java common/core/src/main/java/com/redhat/thermostat/common/model/BackendInformation.java common/core/src/main/java/com/redhat/thermostat/common/storage/AgentInformation.java common/core/src/main/java/com/redhat/thermostat/common/storage/BackendInformation.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java common/core/src/main/java/com/redhat/thermostat/common/storage/StorageConstants.java common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoConverterTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoConverterTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java common/core/src/test/java/com/redhat/thermostat/common/model/BackendInformationTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/BackendInformationTest.java thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollector.java thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollectorFactory.java thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorFactoryImpl.java thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadMXBeanCollector.java thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/osgi/Activator.java thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollectorFactoryTest.java thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorTest.java
diffstat 40 files changed, 1752 insertions(+), 501 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/AgentApplication.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/AgentApplication.java	Fri Sep 07 16:14:49 2012 -0400
@@ -58,6 +58,8 @@
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandException;
 import com.redhat.thermostat.common.config.InvalidConfigurationException;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.common.dao.BackendInfoDAO;
 import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.HostInfoDAO;
 import com.redhat.thermostat.common.dao.MongoDAOFactory;
@@ -197,6 +199,8 @@
          * the dao instances will be shared across multiple unrelated classes
          * and any state maintained will quickly lead to bugs
          */
+        registerer.registerService(AgentInfoDAO.class, daoFactory.getAgentInfoDAO());
+        registerer.registerService(BackendInfoDAO.class, daoFactory.getBackendInfoDAO());
         registerer.registerService(HostInfoDAO.class, daoFactory.getHostInfoDAO());
         registerer.registerService(NetworkInterfaceInfoDAO.class, daoFactory.getNetworkInterfaceInfoDAO());
         registerer.registerService(VmInfoDAO.class, daoFactory.getVmInfoDAO());
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Fri Sep 07 16:14:49 2012 -0400
@@ -36,6 +36,8 @@
 
 package com.redhat.thermostat.agent;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.UUID;
 import java.util.logging.Logger;
 
@@ -43,9 +45,11 @@
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendRegistry;
 import com.redhat.thermostat.common.LaunchException;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.common.dao.BackendInfoDAO;
 import com.redhat.thermostat.common.dao.DAOFactory;
-import com.redhat.thermostat.common.storage.AgentInformation;
-import com.redhat.thermostat.common.storage.BackendInformation;
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.model.BackendInformation;
 import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
@@ -62,7 +66,11 @@
 
     private AgentInformation agentInfo;
     
+    private List<BackendInformation> backendInfos;
+
     private Storage storage;
+    private AgentInfoDAO agentDao;
+    private BackendInfoDAO backendDao;
     private boolean started = false;
 
     public Agent(BackendRegistry backendRegistry, AgentStartupConfiguration config, DAOFactory daos) {
@@ -75,6 +83,8 @@
         this.config = config;
         this.storage = daos.getStorage();
         this.storage.setAgentId(agentId);
+        this.agentDao = daos.getAgentInfoDAO();
+        this.backendDao = daos.getBackendInfoDAO();
     }
 
     private void startBackends() throws LaunchException {
@@ -103,7 +113,12 @@
         if (!started) {
             startBackends();
             agentInfo = createAgentInformation();
-            storage.addAgentInformation(agentInfo);
+            agentDao.addAgentInformation(agentInfo);
+
+            backendInfos = createBackendInformation();
+            for (BackendInformation backendInfo : backendInfos) {
+                backendDao.addBackendInformation(backendInfo);
+            }
             started = true;
         } else {
             logger.warning("Attempt to start agent when already started.");
@@ -113,38 +128,64 @@
     private AgentInformation createAgentInformation() {
         AgentInformation agentInfo = new AgentInformation();
         agentInfo.setStartTime(config.getStartTime());
+        agentInfo.setAlive(true);
+        agentInfo.setConfigListenAddress(config.getConfigListenAddress());
+        return agentInfo;
+    }
+
+    private List<BackendInformation> createBackendInformation() {
+        List<BackendInformation> results = new ArrayList<>();
+
         for (Backend backend : backendRegistry.getAll()) {
             BackendInformation backendInfo = new BackendInformation();
             backendInfo.setName(backend.getName());
             backendInfo.setDescription(backend.getDescription());
             backendInfo.setObserveNewJvm(backend.getObserveNewJvm());
-            agentInfo.addBackend(backendInfo);
+            backendInfo.setActive(true);
+            backendInfo.setPids(new ArrayList<Integer>());
+
+            results.add(backendInfo);
+
         }
-        agentInfo.setAlive(true);
-        agentInfo.setConfigListenAddress(config.getConfigListenAddress());
-        return agentInfo;
+        return results;
     }
 
     public synchronized void stop() {
         if (started) {
 
             stopBackends();
+            removeBackendInformation();
             if (config.purge()) {
-                System.out.println("purging database");
-                logger.info("purging database");
-                storage.removeAgentInformation();
-                storage.purge();
+                removeAllAgentRelatedInformation();
             } else {
-                agentInfo.setStopTime(System.currentTimeMillis());
-                agentInfo.setAlive(false);
-                storage.updateAgentInformation(agentInfo);
+                updateAgentStatusToStopped();
             }
+
             started = false;
         } else {
             logger.warning("Attempt to stop agent which is not active");
         }
     }
 
+    private void removeBackendInformation() {
+        for (BackendInformation info : backendInfos) {
+            backendDao.removeBackendInformation(info);
+        }
+    }
+
+    private void removeAllAgentRelatedInformation() {
+        System.out.println("purging database");
+        logger.info("purging database");
+        agentDao.removeAgentInformation(agentInfo);
+        storage.purge();
+    }
+
+    private void updateAgentStatusToStopped() {
+        agentInfo.setStopTime(System.currentTimeMillis());
+        agentInfo.setAlive(false);
+        agentDao.updateAgentInformation(agentInfo);
+    }
+
     public UUID getId() {
         return id;
     }
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -37,10 +37,12 @@
 package com.redhat.thermostat.agent;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.isA;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
@@ -54,18 +56,23 @@
 import com.redhat.thermostat.agent.config.AgentStartupConfiguration;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendRegistry;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.common.dao.BackendInfoDAO;
 import com.redhat.thermostat.common.dao.DAOFactory;
-import com.redhat.thermostat.common.storage.AgentInformation;
-import com.redhat.thermostat.common.storage.BackendInformation;
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.model.BackendInformation;
 import com.redhat.thermostat.common.storage.Storage;
 
 public class AgentTest {
 
     private AgentStartupConfiguration config;
-    private Storage storage;
     private BackendRegistry backendRegistry;
     private Backend backend;
+
+    private Storage storage;
     private DAOFactory daos;
+    private AgentInfoDAO agentInfoDao;
+    private BackendInfoDAO backendInfoDao;
     
     @Before
     public void setUp() {
@@ -74,8 +81,12 @@
         when(config.purge()).thenReturn(true);
         
         storage = mock(Storage.class);
+        agentInfoDao = mock(AgentInfoDAO.class);
+        backendInfoDao = mock(BackendInfoDAO.class);
         daos = mock(DAOFactory.class);
         when(daos.getStorage()).thenReturn(storage);
+        when(daos.getAgentInfoDAO()).thenReturn(agentInfoDao);
+        when(daos.getBackendInfoDAO()).thenReturn(backendInfoDao);
         
         backend = mock(Backend.class);
         when(backend.getName()).thenReturn("testname");
@@ -99,14 +110,20 @@
         // Verify that backend has been activated and storage received the agent information.
         verify(backend).activate();
         ArgumentCaptor<AgentInformation> argument = ArgumentCaptor.forClass(AgentInformation.class);
-        verify(storage).addAgentInformation(argument.capture());
+
+        verify(agentInfoDao).addAgentInformation(argument.capture());
         assertEquals(123, argument.getValue().getStartTime());
-        List<BackendInformation> backendInfos = argument.getValue().getBackends();
+
+        ArgumentCaptor<BackendInformation> backendsArg = ArgumentCaptor.forClass(BackendInformation.class);
+        verify(backendInfoDao).addBackendInformation(backendsArg.capture());
+
+        List<BackendInformation> backendInfos = backendsArg.getAllValues();
         assertEquals(1, backendInfos.size());
         BackendInformation backend0 = backendInfos.get(0);
         assertEquals("testname", backend0.getName());
         assertEquals("testdesc", backend0.getDescription());
         assertEquals(true, backend0.isObserveNewJvm());
+        assertEquals(true, backend0.isActive());
         // TODO: We should probably also test getPIDs() and getConfiguration(), but it's not clear to me at this point
         // what those should really do (and it looks like they're not implemented yet).
     }
@@ -122,12 +139,12 @@
         verify(backend).deactivate();
 
         ArgumentCaptor<AgentInformation> argument = ArgumentCaptor.forClass(AgentInformation.class);        
-        verify(storage, never()).updateAgentInformation(argument.capture());
+        verify(agentInfoDao, never()).updateAgentInformation(argument.capture());
         verify(storage, times(1)).purge();
     }
     
     @Test
-    public void testStopAgent() throws Exception {
+    public void testStopAgentWithoutPurging() throws Exception {
         
         AgentStartupConfiguration config = mock(AgentStartupConfiguration.class);
         when(config.getStartTime()).thenReturn(123L);
@@ -141,8 +158,8 @@
         
         verify(backend).deactivate();
 
-        ArgumentCaptor<AgentInformation> argument = ArgumentCaptor.forClass(AgentInformation.class);        
-        verify(storage).updateAgentInformation(argument.capture());
+        verify(agentInfoDao).updateAgentInformation(isA(AgentInformation.class));
+        verify(backendInfoDao, atLeast(1)).removeBackendInformation(isA(BackendInformation.class));
         verify(storage, times(0)).purge();
     }
 }
--- a/client/command/src/main/java/com/redhat/thermostat/client/command/cli/PingCommand.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/client/command/src/main/java/com/redhat/thermostat/client/command/cli/PingCommand.java	Fri Sep 07 16:14:49 2012 -0400
@@ -116,7 +116,7 @@
             printCustomMessageWithUsage(out, "Invalid host ID or agent no longer running.  See \'help list-vms to obtain a valid host ID.");
             return;
         }
-        String address = df.getStorage().getConfigListenAddress(targetHostRef);
+        String address = df.getAgentInfoDAO().getAgentInformation(targetHostRef).getConfigListenAddress();
         
         String [] host = address.split(":");
         InetSocketAddress target = new InetSocketAddress(host[0], Integer.parseInt(host[1]));
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/Main.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/client/core/src/main/java/com/redhat/thermostat/client/internal/Main.java	Fri Sep 07 16:14:49 2012 -0400
@@ -71,6 +71,8 @@
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.common.config.StartupConfiguration;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.common.dao.BackendInfoDAO;
 import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.HostInfoDAO;
 import com.redhat.thermostat.common.dao.MongoDAOFactory;
@@ -318,6 +320,8 @@
          * the dao instances will be shared across multiple unrelated classes
          * and any state maintained will quickly lead to bugs
          */
+        OSGIUtils.getInstance().registerService(AgentInfoDAO.class, daoFactory.getAgentInfoDAO());
+        OSGIUtils.getInstance().registerService(BackendInfoDAO.class, daoFactory.getBackendInfoDAO());
         OSGIUtils.getInstance().registerService(HostInfoDAO.class, daoFactory.getHostInfoDAO());
         OSGIUtils.getInstance().registerService(NetworkInterfaceInfoDAO.class, daoFactory.getNetworkInterfaceInfoDAO());
         OSGIUtils.getInstance().registerService(VmInfoDAO.class, daoFactory.getVmInfoDAO());
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java	Fri Sep 07 16:14:49 2012 -0400
@@ -73,7 +73,7 @@
 
         DAOFactory df = ApplicationContext.getInstance().getDAOFactory();
         HostRef targetHostRef = reference.getAgent();
-        String address = df.getStorage().getConfigListenAddress(targetHostRef);
+        String address = df.getAgentInfoDAO().getAgentInformation(targetHostRef).getConfigListenAddress();
         
         String [] host = address.split(":");
         InetSocketAddress target = new InetSocketAddress(host[0], Integer.parseInt(host[1]));
--- a/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -59,9 +59,11 @@
 import com.redhat.thermostat.common.command.RequestResponseListener;
 import com.redhat.thermostat.common.command.Response;
 import com.redhat.thermostat.common.command.Response.ResponseType;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.AgentInformation;
 import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.utils.OSGIUtils;
 
@@ -82,10 +84,15 @@
         OSGIUtils.setInstance(osgiUtils);
 
         HostRef host = mock(HostRef.class);
-        Storage storage = mock(Storage.class);
-        when(storage.getConfigListenAddress(host)).thenReturn("test:123");
+
+        AgentInformation agentInfo = mock(AgentInformation.class);
+        when(agentInfo.getConfigListenAddress()).thenReturn("test:123");
+
+        AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
+        when(agentInfoDao.getAgentInformation(host)).thenReturn(agentInfo);
+
         DAOFactory daoFactory = mock(DAOFactory.class);
-        when(daoFactory.getStorage()).thenReturn(storage);
+        when(daoFactory.getAgentInfoDAO()).thenReturn(agentInfoDao);
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
 
         cmd = new HeapDumperCommand();
--- a/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/KillVMAction.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/KillVMAction.java	Fri Sep 07 16:14:49 2012 -0400
@@ -78,7 +78,7 @@
 
     @Override
     public void execute(VmRef reference) {
-        String address = dao.getStorage().getConfigListenAddress(reference.getAgent());
+        String address = dao.getAgentInfoDAO().getAgentInformation(reference.getAgent()).getConfigListenAddress();
         
         String [] host = address.split(":");
         InetSocketAddress target = new InetSocketAddress(host[0], Integer.parseInt(host[1]));
--- a/client/killvm/src/test/java/com/redhat/thermostat/client/killvm/internal/KillVMActionTest.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/client/killvm/src/test/java/com/redhat/thermostat/client/killvm/internal/KillVMActionTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -61,10 +61,12 @@
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
 import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmInfoDAO;
 import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.AgentInformation;
 import com.redhat.thermostat.common.model.VmInfo;
 import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.utils.OSGIUtils;
@@ -112,7 +114,15 @@
         HostRef hostref = mock(HostRef.class);
         when(ref.getAgent()).thenReturn(hostref);
         String agentAddress = "127.0.0.1:8888";
-        when(storage.getConfigListenAddress(hostref)).thenReturn(agentAddress);
+
+        AgentInformation agentInfo = mock(AgentInformation.class);
+        when(agentInfo.getConfigListenAddress()).thenReturn(agentAddress);
+
+        AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
+        when(agentDao.getAgentInformation(hostref)).thenReturn(agentInfo);
+
+        when(factory.getAgentInfoDAO()).thenReturn(agentDao);
+
         final Request req = mock(Request.class);
         KillVMAction action = new KillVMAction() {
             @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoConverter.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Key;
+
+public class AgentInfoConverter {
+
+    public Chunk toChunk(AgentInformation agentInfo) {
+        Chunk agentChunk = new Chunk(AgentInfoDAO.CATEGORY, true);
+
+        agentChunk.put(Key.AGENT_ID, agentInfo.getAgentId());
+        agentChunk.put(AgentInfoDAO.START_TIME_KEY, agentInfo.getStartTime());
+        agentChunk.put(AgentInfoDAO.STOP_TIME_KEY, agentInfo.getStopTime());
+        agentChunk.put(AgentInfoDAO.ALIVE_KEY, agentInfo.isAlive());
+        agentChunk.put(AgentInfoDAO.CONFIG_LISTEN_ADDRESS, agentInfo.getConfigListenAddress());
+
+        return agentChunk;
+    }
+
+    public AgentInformation fromChunk(Chunk agentChunk) {
+        AgentInformation agentInfo = new AgentInformation();
+
+        agentInfo.setAgentId(agentChunk.get(Key.AGENT_ID));
+        agentInfo.setStartTime(agentChunk.get(AgentInfoDAO.START_TIME_KEY));
+        agentInfo.setStopTime(agentChunk.get(AgentInfoDAO.STOP_TIME_KEY));
+        agentInfo.setAlive(agentChunk.get(AgentInfoDAO.ALIVE_KEY));
+        agentInfo.setConfigListenAddress(agentChunk.get(AgentInfoDAO.CONFIG_LISTEN_ADDRESS));
+
+        return agentInfo;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAO.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import java.util.List;
+
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Key;
+
+public interface AgentInfoDAO extends Countable {
+
+    static final Key<Long> START_TIME_KEY = new Key<>("start-time", false);
+    static final Key<Long> STOP_TIME_KEY = new Key<>("stop-time", false);
+    static final Key<Boolean> ALIVE_KEY = new Key<>("alive", false);
+    static final Key<String> CONFIG_LISTEN_ADDRESS = new Key<>("config-listen-address", false);
+
+    static final Category CATEGORY = new Category("agent-config",
+            Key.AGENT_ID,
+            START_TIME_KEY,
+            STOP_TIME_KEY,
+            ALIVE_KEY,
+            CONFIG_LISTEN_ADDRESS);
+
+    List<AgentInformation> getAllAgentInformation();
+
+    List<AgentInformation> getAliveAgents();
+
+    AgentInformation getAgentInformation(HostRef agentRef);
+
+    void addAgentInformation(AgentInformation agentInfo);
+
+    void updateAgentInformation(AgentInformation agentInfo);
+
+    void removeAgentInformation(AgentInformation agentInfo);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Cursor;
+import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Query;
+import com.redhat.thermostat.common.storage.Storage;
+import com.redhat.thermostat.common.storage.Query.Criteria;
+
+public class AgentInfoDAOImpl implements AgentInfoDAO {
+
+    private final Storage storage;
+    private final AgentInfoConverter converter = new AgentInfoConverter();
+
+    public AgentInfoDAOImpl(Storage storage) {
+        this.storage = storage;
+        storage.createConnectionKey(CATEGORY);
+    }
+
+    @Override
+    public long getCount() {
+        return storage.getCount(CATEGORY);
+    }
+
+    @Override
+    public List<AgentInformation> getAllAgentInformation() {
+        Cursor agentCursor = storage.findAllFromCategory(CATEGORY);
+
+        List<AgentInformation> results = new ArrayList<>();
+
+        while (agentCursor.hasNext()) {
+            Chunk agentChunk = agentCursor.next();
+            results.add(converter.fromChunk(agentChunk));
+        }
+        return results;
+    }
+
+    @Override
+    public List<AgentInformation> getAliveAgents() {
+        Query query = storage.createQuery()
+                .from(CATEGORY)
+                .where(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true);
+
+        Cursor agentCursor = storage.findAll(query);
+
+        List<AgentInformation> results = new ArrayList<>();
+
+        while (agentCursor.hasNext()) {
+            Chunk agentChunk = agentCursor.next();
+            results.add(converter.fromChunk(agentChunk));
+        }
+        return results;
+    }
+
+    @Override
+    public AgentInformation getAgentInformation(HostRef agentRef) {
+        Query query = storage.createQuery()
+                .from(CATEGORY)
+                .where(Key.AGENT_ID, Criteria.EQUALS, agentRef.getAgentId());
+
+        Chunk agentInfo = storage.find(query);
+        return agentInfo == null ? null : converter.fromChunk(agentInfo);
+    }
+
+    @Override
+    public void addAgentInformation(AgentInformation agentInfo) {
+        storage.putChunk(converter.toChunk(agentInfo));
+    }
+
+    @Override
+    public void removeAgentInformation(AgentInformation agentInfo) {
+        Chunk chunk = new Chunk(CATEGORY, true);
+        chunk.put(Key.AGENT_ID, agentInfo.getAgentId());
+
+        storage.removeChunk(chunk);
+    }
+
+    @Override
+    public void updateAgentInformation(AgentInformation agentInfo) {
+        storage.updateChunk(converter.toChunk(agentInfo));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoConverter.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.redhat.thermostat.common.model.BackendInformation;
+import com.redhat.thermostat.common.storage.Chunk;
+
+public class BackendInfoConverter {
+
+    public Chunk toChunk(BackendInformation backendInfo) {
+        Chunk chunk = new Chunk(BackendInfoDAO.CATEGORY, false);
+
+        chunk.put(BackendInfoDAO.BACKEND_NAME, backendInfo.getName());
+        chunk.put(BackendInfoDAO.BACKEND_DESCRIPTION, backendInfo.getDescription());
+        chunk.put(BackendInfoDAO.IS_ACTIVE, backendInfo.isActive());
+        List<Integer> pids = backendInfo.getPids();
+        chunk.put(BackendInfoDAO.PIDS_TO_MONITOR, pids);
+        chunk.put(BackendInfoDAO.SHOULD_MONITOR_NEW_PROCESSES, backendInfo.isObserveNewJvm());
+
+        return chunk;
+    }
+
+    public BackendInformation fromChunk(Chunk parseFrom) {
+        if (!parseFrom.getCategory().equals(BackendInfoDAO.CATEGORY)) {
+            throw new IllegalArgumentException("chunk not a " + BackendInfoDAO.CATEGORY);
+        }
+
+        BackendInformation info = new BackendInformation();
+
+        info.setName(parseFrom.get(BackendInfoDAO.BACKEND_NAME));
+        info.setDescription(parseFrom.get(BackendInfoDAO.BACKEND_DESCRIPTION));
+        info.setActive(parseFrom.get(BackendInfoDAO.IS_ACTIVE));
+        info.setPids(parseFrom.get(BackendInfoDAO.PIDS_TO_MONITOR));
+        info.setObserveNewJvm(parseFrom.get(BackendInfoDAO.SHOULD_MONITOR_NEW_PROCESSES));
+
+        return info;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import java.util.List;
+
+import com.redhat.thermostat.common.model.BackendInformation;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Key;
+
+public interface BackendInfoDAO {
+
+    static final Key<String> BACKEND_NAME = new Key<>("name", true);
+    static final Key<String> BACKEND_DESCRIPTION = new Key<>("description", false);
+    static final Key<Boolean> IS_ACTIVE = new Key<>("active", false);
+    static final Key<Boolean> SHOULD_MONITOR_NEW_PROCESSES = new Key<>("new", false);
+    static final Key<List<Integer>> PIDS_TO_MONITOR = new Key<>("pids", false);
+
+    static final Category CATEGORY = new Category("backend-info",
+            Key.AGENT_ID,
+            BACKEND_NAME,
+            BACKEND_DESCRIPTION,
+            IS_ACTIVE,
+            SHOULD_MONITOR_NEW_PROCESSES,
+            PIDS_TO_MONITOR);
+
+    List<BackendInformation> getBackendInformation(HostRef host);
+
+    void addBackendInformation(BackendInformation info);
+
+    void removeBackendInformation(BackendInformation info);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.redhat.thermostat.common.model.BackendInformation;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Cursor;
+import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Query;
+import com.redhat.thermostat.common.storage.Storage;
+import com.redhat.thermostat.common.storage.Query.Criteria;
+
+public class BackendInfoDAOImpl implements BackendInfoDAO {
+
+    private final BackendInfoConverter converter = new BackendInfoConverter();
+    private final Storage storage;
+
+    public BackendInfoDAOImpl(Storage storage) {
+        this.storage = storage;
+        storage.createConnectionKey(CATEGORY);
+    }
+
+    @Override
+    public List<BackendInformation> getBackendInformation(HostRef host) {
+        Query query = storage.createQuery()
+                .from(CATEGORY)
+                .where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId());
+
+        List<BackendInformation> results = new ArrayList<>();
+        Cursor cursor = storage.findAll(query);
+        while (cursor.hasNext()) {
+            Chunk backendInfoPart = cursor.next();
+            results.add(converter.fromChunk(backendInfoPart));
+        }
+        return results;
+    }
+
+    @Override
+    public void addBackendInformation(BackendInformation info) {
+        Chunk chunk = converter.toChunk(info);
+        storage.putChunk(chunk);
+    }
+
+    @Override
+    public void removeBackendInformation(BackendInformation info) {
+        Chunk toRemove = converter.toChunk(info);
+        storage.removeChunk(toRemove);
+    }
+
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Fri Sep 07 16:14:49 2012 -0400
@@ -46,6 +46,10 @@
 
     public Connection getConnection();
 
+    public AgentInfoDAO getAgentInfoDAO();
+
+    public BackendInfoDAO getBackendInfoDAO();
+
     public HostInfoDAO getHostInfoDAO();
 
     public CpuStatDAO getCpuStatDAO();
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Fri Sep 07 16:14:49 2012 -0400
@@ -38,9 +38,10 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
+import com.redhat.thermostat.common.model.AgentInformation;
 import com.redhat.thermostat.common.model.HostInfo;
-import com.redhat.thermostat.common.storage.AgentInformation;
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Cursor;
 import com.redhat.thermostat.common.storage.Key;
@@ -50,11 +51,13 @@
 
 class HostInfoDAOImpl implements HostInfoDAO {
     private Storage storage;
+    private AgentInfoDAO agentInfoDao;
 
     private HostInfoConverter converter;
 
-    public HostInfoDAOImpl(Storage storage) {
+    public HostInfoDAOImpl(Storage storage, AgentInfoDAO agentInfo) {
         this.storage = storage;
+        this.agentInfoDao = agentInfo;
         converter = new HostInfoConverter();
     }
 
@@ -77,7 +80,23 @@
         Query allHosts = storage.createQuery().from(hostInfoCategory);
         return getHosts(allHosts);
     }
-    
+
+    @Override
+    public Collection<HostRef> getAliveHosts() {
+        List<HostRef> hosts = new ArrayList<>();
+        List<AgentInformation> agentInfos = agentInfoDao.getAliveAgents();
+        for (AgentInformation agentInfo : agentInfos) {
+            Query filter = storage.createQuery()
+                    .from(hostInfoCategory)
+                    .where(Key.AGENT_ID, Criteria.EQUALS, agentInfo.getAgentId());
+
+            hosts.addAll(getHosts(filter));
+        }
+
+        return hosts;
+    }
+
+
     private Collection<HostRef> getHosts(Query filter) {
         Collection<HostRef> hosts = new ArrayList<HostRef>();
         
@@ -90,29 +109,7 @@
         }
         return hosts;
     }
-    
-    @Override
-    public Collection<HostRef> getAliveHosts() {
-        
-        Collection<HostRef> hosts = new ArrayList<HostRef>();
-        
-        Query aliveAgents = storage.createQuery()
-                .from(AgentInformation.AGENT_INFO_CATEGORY)
-                .where(AgentInformation.AGENT_ALIVE_KEY, Criteria.EQUALS, true);
 
-        Cursor agentCursor = storage.findAll(aliveAgents);
-        while(agentCursor.hasNext()) {
-            Chunk chunk = agentCursor.next();
-            
-            Query filter = storage.createQuery()
-                    .from(hostInfoCategory)
-                    .where(Key.AGENT_ID, Criteria.EQUALS, chunk.get(Key.AGENT_ID));
-            
-            hosts.addAll(getHosts(filter));
-        }
-        
-        return hosts;
-    }
     @Override
     public long getCount() {
         return storage.getCount(hostInfoCategory);
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java	Fri Sep 07 16:14:49 2012 -0400
@@ -54,9 +54,19 @@
     }
 
     @Override
+    public AgentInfoDAO getAgentInfoDAO() {
+        return new AgentInfoDAOImpl(storage);
+    }
+
+    @Override
+    public BackendInfoDAO getBackendInfoDAO() {
+        return new BackendInfoDAOImpl(storage);
+    }
+
+    @Override
     public HostInfoDAO getHostInfoDAO() {
         ensureStorageConnected();
-        return new HostInfoDAOImpl(storage);
+        return new HostInfoDAOImpl(storage, new AgentInfoDAOImpl(storage));
     }
 
     @Override
@@ -89,6 +99,7 @@
         return new VmCpuStatDAOImpl(storage);
     }
 
+    @Override
     public VmMemoryStatDAO getVmMemoryStatDAO() {
         ensureStorageConnected();
         return new VmMemoryStatDAOImpl(storage);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/AgentInformation.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+public class AgentInformation {
+
+    private String agentId;
+    private long startTime;
+    private long stopTime;
+
+    private boolean alive;
+    private String address;
+
+    private List<BackendInformation> backends = new ArrayList<BackendInformation>();
+
+    public String getAgentId() {
+        return agentId;
+    }
+
+    public void setAgentId(String agentId) {
+        this.agentId = agentId;
+    }
+
+    public long getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(long startTime) {
+        this.startTime = startTime;
+    }
+
+    public void setStopTime(long stopTime) {
+        this.stopTime = stopTime;
+    }
+    
+    public long getStopTime() {
+        return stopTime;
+    }
+
+    public boolean isAlive() {
+        return alive;
+    }
+    
+    public void setAlive(boolean alive) {
+        this.alive = alive;
+    }
+
+    public String getConfigListenAddress() {
+        return address;
+    }
+
+    public void setConfigListenAddress(String address) {
+        this.address = address;
+    }
+
+    @Override
+    public String toString() {
+        return "agent " + agentId;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof AgentInformation)) {
+            return false;
+        }
+        AgentInformation other = (AgentInformation) obj;
+        return Objects.equals(this.agentId, other.agentId) &&
+                Objects.equals(this.alive, other.alive) &&
+                Objects.equals(this.address, other.address) &&
+                Objects.equals(this.startTime, other.startTime) &&
+                Objects.equals(this.stopTime, other.stopTime);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(agentId, alive, address, startTime, stopTime);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/BackendInformation.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.model;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+public class BackendInformation {
+
+    private String name;
+    private String description;
+    private boolean isActive;
+    private boolean observeNewJvm;
+    private List<Integer> pids;
+    private Map<String, String> configuration = new HashMap<String,String>();
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public boolean isObserveNewJvm() {
+        return observeNewJvm;
+    }
+
+    public void setObserveNewJvm(boolean observeNewJvm) {
+        this.observeNewJvm = observeNewJvm;
+    }
+
+    public List<Integer> getPids() {
+        return pids;
+    }
+
+    public void setPids(List<Integer> pids) {
+        this.pids = pids;
+    }
+
+    public Map<String, String> getConfiguration() {
+        return configuration;
+    }
+
+    public boolean isActive() {
+        return isActive;
+    }
+
+    public void setActive(boolean active) {
+        this.isActive = active;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof BackendInformation)) {
+            return false;
+        }
+        BackendInformation other = (BackendInformation) obj;
+        return Objects.equals(this.name, other.name) &&
+                Objects.equals(this.description, other.description) &&
+                Objects.equals(this.configuration, other.configuration) &&
+                Objects.equals(this.isActive, other.isActive) &&
+                Objects.equals(this.observeNewJvm, other.observeNewJvm) &&
+                Objects.equals(this.pids, other.pids);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, description, configuration, isActive, observeNewJvm, pids);
+    }
+
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/AgentInformation.java	Fri Sep 07 13:05:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.storage;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class AgentInformation {
-
-    public static final Category AGENT_INFO_CATEGORY =
-            new Category(StorageConstants.CATEGORY_AGENT_CONFIG, Key.AGENT_ID);
-
-    public static final Key<Boolean> AGENT_ALIVE_KEY = new Key<>("alive", false);
-    
-    private long startTime;
-    private long stopTime;
-
-    private boolean alive;
-    private String address;
-
-    private List<BackendInformation> backends = new ArrayList<BackendInformation>();
-    
-    public long getStartTime() {
-        return startTime;
-    }
-
-    public void setStartTime(long startTime) {
-        this.startTime = startTime;
-    }
-
-    public void setStopTime(long stopTime) {
-        this.stopTime = stopTime;
-    }
-    
-    public long getStopTime() {
-        return stopTime;
-    }
-    
-    public List<BackendInformation> getBackends() {
-        return Collections.unmodifiableList(backends);
-    }
-
-    public boolean isAlive() {
-        return alive;
-    }
-    
-    public void setAlive(boolean alive) {
-        this.alive = alive;
-    }
-    
-    public void addBackend(BackendInformation backend) {
-        backends.add(backend);
-    }
-
-    public String getConfigListenAddress() {
-        return address;
-    }
-
-    public void setConfigListenAddress(String address) {
-        this.address = address;
-    }
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/BackendInformation.java	Fri Sep 07 13:05:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.storage;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class BackendInformation {
-
-    private String name;
-    private String description;
-    private boolean observeNewJvm;
-    private List<Integer> pids;
-    private Map<String, String> configuration = new HashMap<String,String>();
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    public boolean isObserveNewJvm() {
-        return observeNewJvm;
-    }
-
-    public void setObserveNewJvm(boolean observeNewJvm) {
-        this.observeNewJvm = observeNewJvm;
-    }
-
-    public List<Integer> getPids() {
-        return pids;
-    }
-
-    public Map<String, String> getConfiguration() {
-        return configuration;
-    }
-
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Fri Sep 07 16:14:49 2012 -0400
@@ -42,20 +42,15 @@
 import java.util.Map.Entry;
 import java.util.UUID;
 
-import org.bson.BSONObject;
-
-import com.mongodb.BasicDBList;
 import com.mongodb.BasicDBObject;
 import com.mongodb.DB;
 import com.mongodb.DBCollection;
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
-import com.mongodb.WriteConcern;
 import com.mongodb.gridfs.GridFS;
 import com.mongodb.gridfs.GridFSDBFile;
 import com.mongodb.gridfs.GridFSInputFile;
 import com.redhat.thermostat.common.config.StartupConfiguration;
-import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.storage.Connection.ConnectionListener;
 import com.redhat.thermostat.common.storage.Connection.ConnectionStatus;
 
@@ -244,6 +239,21 @@
         throw new IllegalArgumentException("Attempt to insert chunk with incomplete partial key.  Missing: '" + keyName + "' in " + chunk);
     }
 
+    @Override
+    public void removeChunk(Chunk query) {
+        Category category = query.getCategory();
+        DBCollection coll = getCachedCollection(category.getName());
+
+        BasicDBObject toRemove = getAgentQueryKeyFromChunkOrGlobalAgent(query);
+        for (Key<?> key : category.getKeys()) {
+            if (key.isPartialCategoryKey()) {
+                toRemove.put(key.getName(), query.get(key));
+            }
+        }
+
+        coll.remove(toRemove);
+    }
+
     private DBCollection getCachedCollection(String collName) {
         DBCollection coll = collectionCache.get(collName);
         if (coll == null && db.collectionExists(collName)) {
@@ -263,42 +273,6 @@
     }
 
 
-    private DBObject createConfigDBObject(AgentInformation agentInfo) {
-        BasicDBObject result = getAgentQueryKeyFromGlobalAgent();
-        result.put(StorageConstants.KEY_AGENT_CONFIG_AGENT_START_TIME, agentInfo.getStartTime());
-        result.put(StorageConstants.KEY_AGENT_CONFIG_AGENT_STOP_TIME, agentInfo.getStopTime());
-        result.put(StorageConstants.KEY_AGENT_CONFIG_AGENT_ALIVE, agentInfo.isAlive());
-        result.put(StorageConstants.KEY_AGENT_CONFIG_LISTEN_ADDRESS, agentInfo.getConfigListenAddress());
-        
-        BasicDBObject backends = new BasicDBObject();
-        for (BackendInformation backend : agentInfo.getBackends()) {
-            backends.put(backend.getName(), createBackendConfigDBObject(backend));
-        }
-        result.put(StorageConstants.KEY_AGENT_CONFIG_BACKENDS, backends);
-        
-        return result;
-    }
-
-    private DBObject createBackendConfigDBObject(BackendInformation backend) {
-        BasicDBObject result = new BasicDBObject();
-        Map<String, String> configMap = backend.getConfiguration();
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_NAME, backend.getName());
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_DESC, backend.getDescription());
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_ACTIVE, createBackendActiveDBObject(backend));
-        for (Entry<String, String> entry: configMap.entrySet()) {
-            result.append(entry.getKey(), entry.getValue());
-        }
-        return result;
-    }
-
-    private DBObject createBackendActiveDBObject(BackendInformation backend) {
-        BasicDBObject result = new BasicDBObject();
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_NEW, backend.isObserveNewJvm());
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_PIDS, new BasicDBList());
-        // TODO check which processes are already being listened to.
-        return result;
-    }
-
     @Override
     public void purge() {
         BasicDBObject deleteKey = getAgentQueryKeyFromGlobalAgent();
@@ -366,64 +340,6 @@
         return 0L;
     }
 
-    // TODO these methods below belong in some DAO.
-    @Override
-    public void addAgentInformation(AgentInformation agentInfo) {
-        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
-        DBObject toInsert = createConfigDBObject(agentInfo);
-        /* cast required to disambiguate between putAll(BSONObject) and putAll(Map) */
-        toInsert.putAll((BSONObject) getAgentQueryKeyFromGlobalAgent());
-        configCollection.insert(toInsert, WriteConcern.SAFE);
-    }
-    
-    @Override
-    public void updateAgentInformation(AgentInformation agentInfo) {
-        BasicDBObject queryObject = getAgentQueryKeyFromGlobalAgent();
-
-        DBObject updated = createConfigDBObject(agentInfo);
-        updated.putAll((BSONObject) queryObject);
-
-        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
-        configCollection.update(queryObject, updated);
-    }
-
-    @Override
-    public void removeAgentInformation() {
-        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
-        BasicDBObject toRemove = getAgentQueryKeyFromGlobalAgent();
-        configCollection.remove(toRemove, WriteConcern.NORMAL);
-    }
-
-    @Override
-    public String getBackendConfig(String backendName, String configurationKey) {
-        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
-        BasicDBObject query = getAgentQueryKeyFromGlobalAgent();
-        query.put(StorageConstants.KEY_AGENT_CONFIG_BACKENDS + "." + backendName, new BasicDBObject("$exists", true));
-        DBObject config = configCollection.findOne(query);
-        Object value = config.get(configurationKey);
-        if (value instanceof String) {
-            return (String) value;
-        }
-        return null;
-    }
-
-    @Override
-    public String getConfigListenAddress(HostRef ref) {
-        return getConfigListenAddress(ref.getAgentId());
-    }
-
-    private String getConfigListenAddress(String id) {
-        String address = null;
-        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
-        BasicDBObject query = new BasicDBObject(KEY_AGENT_ID, id);
-        DBObject config = configCollection.findOne(query);
-        Object value = config.get(StorageConstants.KEY_AGENT_CONFIG_LISTEN_ADDRESS);
-        if (value instanceof String) {
-            address = (String) value;
-        }
-        return address;
-    }
-
     @Override
     public void saveFile(String filename, InputStream data) {
         GridFS gridFS = new GridFS(db);
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Fri Sep 07 16:14:49 2012 -0400
@@ -39,9 +39,6 @@
 import java.io.InputStream;
 import java.util.UUID;
 
-import com.redhat.thermostat.common.dao.HostRef;
-
-
 public abstract class Storage {
 
     public abstract void setAgentId(UUID id);
@@ -62,6 +59,8 @@
 
     public abstract void updateChunk(Chunk chunk);
 
+    public abstract void removeChunk(Chunk chunk);
+
     /**
      * Drop all data related to the currently running agent.
      */
@@ -75,20 +74,6 @@
     
     public abstract long getCount(Category category);
 
-    // TODO these will move to appropriate DAO
-    public abstract void addAgentInformation(AgentInformation agentInfo);
-
-    public abstract void removeAgentInformation();
-
-    public abstract void updateAgentInformation(AgentInformation agentInfo);
-
-    /**
-     * @return {@code null} if the value is invalid or missing
-     */
-    public abstract String getBackendConfig(String backendName, String configurationKey);
-
-    public abstract String getConfigListenAddress(HostRef ref);
-
     public abstract void saveFile(String filename, InputStream data);
 
     public abstract InputStream loadFile(String filename);
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/StorageConstants.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/StorageConstants.java	Fri Sep 07 16:14:49 2012 -0400
@@ -38,19 +38,4 @@
 
 public class StorageConstants {
     public static final String THERMOSTAT_DB_NAME = "thermostat";
-
-    public static final String CATEGORY_AGENT_CONFIG = "agent-config";
-
-    public static final String KEY_AGENT_CONFIG_BACKENDS = "backends";
-    public static final String KEY_AGENT_CONFIG_AGENT_START_TIME = "start-time";
-    public static final String KEY_AGENT_CONFIG_BACKEND_NAME = "name";
-    public static final String KEY_AGENT_CONFIG_BACKEND_DESC = "description";
-    public static final String KEY_AGENT_CONFIG_BACKEND_ACTIVE = "active";
-    public static final String KEY_AGENT_CONFIG_BACKEND_NEW = "new";
-    public static final String KEY_AGENT_CONFIG_BACKEND_PIDS = "pids";
-
-    public static final String KEY_AGENT_CONFIG_AGENT_ALIVE = "alive";
-    public static final String KEY_AGENT_CONFIG_AGENT_STOP_TIME = "stop-time";
-
-    public static final String KEY_AGENT_CONFIG_LISTEN_ADDRESS = "config-listen-address";
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoConverterTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Key;
+
+public class AgentInfoConverterTest {
+
+    @Test
+    public void testFromChunk() {
+        final String AGENT_ID = "12345";
+        final boolean ALIVE = true;
+        final long START_TIME = 1234;
+        final long STOP_TIME = 5678;
+        final String CONFIG_ADDRESS = "foobar:666";
+
+        Chunk agentInfoChunk = new Chunk(AgentInfoDAO.CATEGORY, true);
+        agentInfoChunk.put(Key.AGENT_ID, AGENT_ID);
+        agentInfoChunk.put(AgentInfoDAO.ALIVE_KEY, ALIVE);
+        agentInfoChunk.put(AgentInfoDAO.START_TIME_KEY, START_TIME);
+        agentInfoChunk.put(AgentInfoDAO.STOP_TIME_KEY, STOP_TIME);
+        agentInfoChunk.put(AgentInfoDAO.CONFIG_LISTEN_ADDRESS, CONFIG_ADDRESS);
+
+        AgentInfoConverter converter = new AgentInfoConverter();
+        AgentInformation info = converter.fromChunk(agentInfoChunk);
+
+        assertEquals(AGENT_ID, info.getAgentId());
+        assertEquals(ALIVE, info.isAlive());
+        assertEquals(START_TIME, info.getStartTime());
+        assertEquals(STOP_TIME, info.getStopTime());
+    }
+
+    @Test
+    public void testToChunk() {
+        final String AGENT_ID = "12345";
+        final boolean ALIVE = true;
+        final long START_TIME = 1234;
+        final long STOP_TIME = 5678;
+        final String CONFIG_ADDRESS = "localhost:666";
+
+        AgentInformation agentInfo = new AgentInformation();
+        agentInfo.setAgentId(AGENT_ID);
+        agentInfo.setAlive(ALIVE);
+        agentInfo.setConfigListenAddress(CONFIG_ADDRESS);
+        agentInfo.setStartTime(START_TIME);
+        agentInfo.setStopTime(STOP_TIME);
+
+        AgentInfoConverter converter = new AgentInfoConverter();
+        Chunk chunk = converter.toChunk(agentInfo);
+
+        assertEquals(AgentInfoDAO.CATEGORY, chunk.getCategory());
+        assertEquals(AGENT_ID, chunk.get(Key.AGENT_ID));
+        assertEquals(ALIVE, chunk.get(AgentInfoDAO.ALIVE_KEY));
+        assertEquals((Long) START_TIME, chunk.get(AgentInfoDAO.START_TIME_KEY));
+        assertEquals((Long) STOP_TIME, chunk.get(AgentInfoDAO.STOP_TIME_KEY));
+        assertEquals((String) CONFIG_ADDRESS, chunk.get(AgentInfoDAO.CONFIG_LISTEN_ADDRESS));
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Cursor;
+import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Storage;
+import com.redhat.thermostat.common.storage.Query.Criteria;
+import com.redhat.thermostat.test.MockQuery;
+
+public class AgentInfoDAOTest {
+
+    private AgentInformation agentInfo1;
+    private Chunk agentChunk1;
+
+    @Before
+    public void setUp() {
+        agentInfo1 = new AgentInformation();
+        agentInfo1.setAgentId("1234");
+        agentInfo1.setAlive(true);
+        agentInfo1.setConfigListenAddress("foobar:666");
+        agentInfo1.setStartTime(100);
+        agentInfo1.setStopTime(10);
+
+        agentChunk1 = new AgentInfoConverter().toChunk(agentInfo1);
+    }
+
+    @Test
+    public void verifyCategoryName() {
+        Category category = AgentInfoDAO.CATEGORY;
+        assertEquals("agent-config", category.getName());
+    }
+
+    @Test
+    public void verifyKeyNames() {
+        assertEquals("agent-id", Key.AGENT_ID.getName());
+        assertEquals("alive", AgentInfoDAO.ALIVE_KEY.getName());
+        assertEquals("start-time", AgentInfoDAO.START_TIME_KEY.getName());
+        assertEquals("stop-time", AgentInfoDAO.STOP_TIME_KEY.getName());
+        assertEquals("config-listen-address", AgentInfoDAO.CONFIG_LISTEN_ADDRESS.getName());
+    }
+
+    @Test
+    public void verifyCategoryHasAllKeys() {
+        Collection<Key<?>> keys = AgentInfoDAO.CATEGORY.getKeys();
+
+        assertTrue(keys.contains(Key.AGENT_ID));
+        assertTrue(keys.contains(AgentInfoDAO.ALIVE_KEY));
+        assertTrue(keys.contains(AgentInfoDAO.START_TIME_KEY));
+        assertTrue(keys.contains(AgentInfoDAO.STOP_TIME_KEY));
+        assertTrue(keys.contains(AgentInfoDAO.CONFIG_LISTEN_ADDRESS));
+    }
+
+    @Test
+    public void verifyGetAllAgentInformationWithOneAgentInStorage() {
+        Cursor agentCursor = mock(Cursor.class);
+        when(agentCursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(agentCursor.next()).thenReturn(agentChunk1).thenReturn(null);
+
+        Storage storage = mock(Storage.class);
+        when(storage.findAllFromCategory(AgentInfoDAO.CATEGORY)).thenReturn(agentCursor);
+
+        AgentInfoDAOImpl dao = new AgentInfoDAOImpl(storage);
+
+        List<AgentInformation> allAgentInfo = dao.getAllAgentInformation();
+
+        assertEquals(1, allAgentInfo.size());
+
+        AgentInformation result = allAgentInfo.get(0);
+        AgentInformation expected = agentInfo1;
+        assertEquals(expected, result);
+    }
+
+    @Test
+    public void verifyGetAliveAgent() {
+        Cursor agentCursor = mock(Cursor.class);
+        when(agentCursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(agentCursor.next()).thenReturn(agentChunk1).thenReturn(null);
+
+        MockQuery query = new MockQuery();
+        Storage storage = mock(Storage.class);
+        when(storage.createQuery()).thenReturn(query);
+        when(storage.findAll(query)).thenReturn(agentCursor);
+
+        AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
+        List<AgentInformation> aliveAgents = dao.getAliveAgents();
+
+        assertEquals(AgentInfoDAO.CATEGORY, query.getCategory());
+        assertTrue(query.hasWhereClause(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true));
+
+        assertEquals(1, aliveAgents.size());
+
+        AgentInformation result = aliveAgents.get(0);
+        AgentInformation expected = agentInfo1;
+        assertEquals(expected, result);
+    }
+
+    @Test
+    public void verifyGetAgentInformationWhenStorageCantFindIt() {
+        HostRef agentRef = mock(HostRef.class);
+
+        MockQuery query = new MockQuery();
+        Storage storage = mock(Storage.class);
+        when(storage.createQuery()).thenReturn(query);
+
+        AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
+
+        AgentInformation computed = dao.getAgentInformation(agentRef);
+
+        assertEquals(null, computed);
+    }
+
+    @Test
+    public void verifyGetAgentInformation() {
+        HostRef agentRef = mock(HostRef.class);
+        when(agentRef.getAgentId()).thenReturn(agentInfo1.getAgentId());
+
+        Storage storage = mock(Storage.class);
+        MockQuery query = new MockQuery();
+        when(storage.createQuery()).thenReturn(query);
+        when(storage.find(query)).thenReturn(agentChunk1);
+        AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
+
+        AgentInformation computed = dao.getAgentInformation(agentRef);
+
+        assertEquals(AgentInfoDAO.CATEGORY, query.getCategory());
+        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, agentInfo1.getAgentId()));
+
+        AgentInformation expected = agentInfo1;
+        assertEquals(expected, computed);
+    }
+
+    @Test
+    public void verifyAddAgentInformation() {
+        Storage storage = mock(Storage.class);
+        AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
+
+        dao.addAgentInformation(agentInfo1);
+
+        ArgumentCaptor<Chunk> chunkCaptor = ArgumentCaptor.forClass(Chunk.class);
+        verify(storage).putChunk(chunkCaptor.capture());
+
+        Chunk insertedChunk = chunkCaptor.getValue();
+        Chunk expectedChunk = agentChunk1;
+
+        assertEquals(expectedChunk, insertedChunk);
+    }
+
+    @Test
+    public void verifyUpdateAgentInformation() {
+        Storage storage = mock(Storage.class);
+        AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
+
+        dao.updateAgentInformation(agentInfo1);
+
+        ArgumentCaptor<Chunk> chunkCaptor = ArgumentCaptor.forClass(Chunk.class);
+        verify(storage).updateChunk(chunkCaptor.capture());
+
+        Chunk updatedChunk = chunkCaptor.getValue();
+        Chunk expectedChunk = agentChunk1;
+
+        assertEquals(expectedChunk, updatedChunk);
+    }
+
+    @Test
+    public void verifyRemoveAgentInformation() {
+        Storage storage = mock(Storage.class);
+        AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
+
+        dao.removeAgentInformation(agentInfo1);
+
+        ArgumentCaptor<Chunk> queryCaptor = ArgumentCaptor.forClass(Chunk.class);
+        verify(storage).removeChunk(queryCaptor.capture());
+
+        Chunk removeQuery = queryCaptor.getValue();
+        Chunk expectedQuery = new Chunk(AgentInfoDAO.CATEGORY, true);
+        expectedQuery.put(Key.AGENT_ID, agentInfo1.getAgentId());
+
+        assertEquals(expectedQuery, removeQuery);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoConverterTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.common.model.BackendInformation;
+import com.redhat.thermostat.common.storage.Chunk;
+
+public class BackendInfoConverterTest {
+
+    @Test
+    public void testFromChunk() {
+        final String BACKEND_NAME = "test-backend";
+        final String BACKEND_DESC = "test-backend-description-that-may-be-long";
+        final Boolean ACTIVE = true;
+        final List<Integer> TO_MONITOR = Arrays.asList(new Integer[] { -1, 0, 1 });
+        final Boolean MONITOR_NEW = false;
+
+        Chunk input = new Chunk(BackendInfoDAO.CATEGORY, true);
+        input.put(BackendInfoDAO.BACKEND_NAME, BACKEND_NAME);
+        input.put(BackendInfoDAO.BACKEND_DESCRIPTION, BACKEND_DESC);
+        input.put(BackendInfoDAO.IS_ACTIVE, ACTIVE);
+        input.put(BackendInfoDAO.PIDS_TO_MONITOR, TO_MONITOR);
+        input.put(BackendInfoDAO.SHOULD_MONITOR_NEW_PROCESSES, MONITOR_NEW);
+
+        BackendInfoConverter converter = new BackendInfoConverter();
+
+        BackendInformation result = converter.fromChunk(input);
+
+        assertEquals(BACKEND_NAME, result.getName());
+        assertEquals(BACKEND_DESC, result.getDescription());
+        assertEquals(ACTIVE, result.isActive());
+        assertEquals(MONITOR_NEW, result.isObserveNewJvm());
+        assertEquals(TO_MONITOR, result.getPids());
+    }
+
+    @Test
+    public void testToChunk() {
+        final String BACKEND_NAME = "test-backend";
+        final String BACKEND_DESC = "test-backend-description-that-may-be-long";
+        final Boolean ACTIVE = true;
+        final List<Integer> TO_MONITOR = Arrays.asList(new Integer[] { -1, 0, 1 });
+        final Boolean MONITOR_NEW = false;
+
+        BackendInformation backendInfo = new BackendInformation();
+        backendInfo.setName(BACKEND_NAME);
+        backendInfo.setDescription(BACKEND_DESC);
+        backendInfo.setActive(ACTIVE);
+        backendInfo.setObserveNewJvm(MONITOR_NEW);
+        backendInfo.setPids(TO_MONITOR);
+
+        BackendInfoConverter converter = new BackendInfoConverter();
+
+        Chunk result = converter.toChunk(backendInfo);
+
+        assertEquals(BackendInfoDAO.CATEGORY, result.getCategory());
+
+        assertEquals(BACKEND_NAME, result.get(BackendInfoDAO.BACKEND_NAME));
+        assertEquals(BACKEND_DESC, result.get(BackendInfoDAO.BACKEND_DESCRIPTION));
+        assertEquals(ACTIVE, result.get(BackendInfoDAO.IS_ACTIVE));
+        assertEquals(TO_MONITOR, result.get(BackendInfoDAO.PIDS_TO_MONITOR));
+        assertEquals(MONITOR_NEW, result.get(BackendInfoDAO.SHOULD_MONITOR_NEW_PROCESSES));
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.model.BackendInformation;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Cursor;
+import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Query.Criteria;
+import com.redhat.thermostat.common.storage.Storage;
+import com.redhat.thermostat.test.MockQuery;
+
+public class BackendInfoDAOTest {
+
+    private BackendInfoConverter converter;
+    private BackendInformation backendInfo1;
+    private Chunk backendChunk1;
+
+    @Before
+    public void setUp() {
+        converter = new BackendInfoConverter();
+
+        backendInfo1 = new BackendInformation();
+
+        backendInfo1.setName("backend-name");
+        backendInfo1.setDescription("description");
+        backendInfo1.setActive(true);
+        backendInfo1.setObserveNewJvm(true);
+        backendInfo1.setPids(Arrays.asList(new Integer[] { -1, 0, 1}));
+
+        backendChunk1 = converter.toChunk(backendInfo1);
+    }
+
+    @Test
+    public void verifyCategoryName() {
+        Category c = BackendInfoDAO.CATEGORY;
+        assertEquals("backend-info", c.getName());
+    }
+
+    @Test
+    public void verifyCategoryHasAllKeys() {
+        Category c = BackendInfoDAO.CATEGORY;
+        Collection<Key<?>> keys = c.getKeys();
+
+        assertTrue(keys.contains(Key.AGENT_ID));
+        assertTrue(keys.contains(BackendInfoDAO.BACKEND_NAME));
+        assertTrue(keys.contains(BackendInfoDAO.BACKEND_DESCRIPTION));
+        assertTrue(keys.contains(BackendInfoDAO.IS_ACTIVE));
+        assertTrue(keys.contains(BackendInfoDAO.PIDS_TO_MONITOR));
+        assertTrue(keys.contains(BackendInfoDAO.SHOULD_MONITOR_NEW_PROCESSES));
+    }
+
+    @Test
+    public void verifyAddBackendInformation() {
+        Storage storage = mock(Storage.class);
+        BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
+
+        dao.addBackendInformation(backendInfo1);
+
+        ArgumentCaptor<Chunk> chunkCaptor = ArgumentCaptor.forClass(Chunk.class);
+        verify(storage).putChunk(chunkCaptor.capture());
+
+        BackendInformation inserted = converter.fromChunk(chunkCaptor.getValue());
+        assertEquals(backendInfo1, inserted);
+    }
+
+    @Test
+    public void verifyGetBackendInformation() {
+        final String AGENT_ID = "agent-id";
+        HostRef agentref = mock(HostRef.class);
+        when(agentref.getAgentId()).thenReturn(AGENT_ID);
+
+        Cursor backendCursor = mock(Cursor.class);
+        when(backendCursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(backendCursor.next()).thenReturn(backendChunk1).thenReturn(null);
+
+        MockQuery query = new MockQuery();
+        Storage storage = mock(Storage.class);
+        when(storage.createQuery()).thenReturn(query);
+        when(storage.findAll(query)).thenReturn(backendCursor);
+
+        BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
+
+        List<BackendInformation> result = dao.getBackendInformation(agentref);
+
+        assertEquals(BackendInfoDAO.CATEGORY, query.getCategory());
+        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
+
+        assertEquals(Arrays.asList(backendInfo1), result);
+    }
+
+    @Test
+    public void verifyRemoveBackendInformation() {
+        Storage storage = mock(Storage.class);
+
+        BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
+
+        dao.removeBackendInformation(backendInfo1);
+
+        verify(storage).removeChunk(backendChunk1);
+    }
+
+}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -40,6 +40,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Arrays;
 import java.util.Collection;
 
 import org.junit.Test;
@@ -53,8 +54,8 @@
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.times;
 
+import com.redhat.thermostat.common.model.AgentInformation;
 import com.redhat.thermostat.common.model.HostInfo;
-import com.redhat.thermostat.common.storage.AgentInformation;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Cursor;
@@ -65,6 +66,16 @@
 
 public class HostInfoDAOTest {
 
+    static class Pair<T,U> {
+        final T first;
+        final U second;
+
+        public Pair(T first, U second) {
+            this.first = first;
+            this.second = second;
+        }
+    }
+
     private static final String HOST_NAME = "a host name";
     private static final String OS_NAME = "some os";
     private static final String OS_KERNEL = "some kernel";
@@ -101,7 +112,11 @@
         when(storage.createQuery()).thenReturn(new MockQuery());
         when(storage.find(any(Query.class))).thenReturn(chunk);
 
-        HostInfo info = new HostInfoDAOImpl(storage).getHostInfo(new HostRef("some uid", HOST_NAME));
+        AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
+
+        HostInfo info = new HostInfoDAOImpl(storage, agentInfoDao)
+            .getHostInfo(new HostRef("some uid", HOST_NAME));
+
         assertNotNull(info);
         assertEquals(HOST_NAME, info.getHostname());
         assertEquals(OS_NAME, info.getOsName());
@@ -115,8 +130,9 @@
     public void testGetHostsSingleHost() {
 
         Storage storage = setupStorageForSingleHost();
+        AgentInfoDAO agentInfo = mock(AgentInfoDAO.class);
 
-        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage);
+        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage, agentInfo);
         Collection<HostRef> hosts = hostsDAO.getHosts();
 
         assertEquals(1, hosts.size());
@@ -150,8 +166,9 @@
     public void testGetHosts3Hosts() {
 
         Storage storage = setupStorageFor3Hosts();
+        AgentInfoDAO agentInfo = mock(AgentInfoDAO.class);
 
-        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage);
+        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage, agentInfo);
         Collection<HostRef> hosts = hostsDAO.getHosts();
 
         assertEquals(3, hosts.size());
@@ -192,8 +209,10 @@
     @Test
     public void testPutHostInfo() {
         Storage storage = mock(Storage.class);
+        AgentInfoDAO agentInfo = mock(AgentInfoDAO.class);
+
         HostInfo info = new HostInfo(HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
-        HostInfoDAO dao = new HostInfoDAOImpl(storage);
+        HostInfoDAO dao = new HostInfoDAOImpl(storage, agentInfo);
         dao.putHostInfo(info);
 
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
@@ -213,35 +232,38 @@
     public void testGetCount() {
         Storage storage = mock(Storage.class);
         when(storage.getCount(any(Category.class))).thenReturn(5L);
-        HostInfoDAO dao = new HostInfoDAOImpl(storage);
+        AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
+
+        HostInfoDAO dao = new HostInfoDAOImpl(storage, agentInfoDao);
         Long count = dao.getCount();
         assertEquals((Long) 5L, count);
     }
     
     @Test
     public void getAliveHostSingle() {
-        Storage storage = setupStorageForSingleAliveHost();
+        Pair<Storage, AgentInfoDAO> setup = setupForSingleAliveHost();
+        Storage storage = setup.first;
+        AgentInfoDAO agentInfoDao = setup.second;
 
-        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage);
+        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage, agentInfoDao);
         Collection<HostRef> hosts = hostsDAO.getAliveHosts();
 
-        // cursor 3 from the above storage should not be used
         assertEquals(1, hosts.size());
         assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
-        verify(storage, times(2)).findAll(any(Query.class));
+        verify(storage, times(1)).findAll(any(Query.class));
     }
     
-    private Storage setupStorageForSingleAliveHost() {
+    private Pair<Storage, AgentInfoDAO> setupForSingleAliveHost() {
         
         // agents
         
-        Chunk agentConfig1 = new Chunk(AgentInformation.AGENT_INFO_CATEGORY, false);
+        Chunk agentConfig1 = new Chunk(AgentInfoDAO.CATEGORY, false);
         agentConfig1.put(Key.AGENT_ID, "123");
-        agentConfig1.put(AgentInformation.AGENT_ALIVE_KEY, true);
+        agentConfig1.put(AgentInfoDAO.ALIVE_KEY, true);
         
-        Cursor cursor1 = mock(Cursor.class);
-        when(cursor1.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor1.next()).thenReturn(agentConfig1);
+        AgentInformation agentInfo1 = new AgentInformation();
+        agentInfo1.setAgentId("123");
+        agentInfo1.setAlive(true);
         
         // hosts
         
@@ -253,14 +275,12 @@
         hostConfig2.put(HostInfoDAO.hostNameKey, "fluffhost2");
         hostConfig2.put(Key.AGENT_ID, "456");
         
-        Cursor cursor2 = mock(Cursor.class);
-        when(cursor2.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor2.next()).thenReturn(hostConfig1);
+        // cursor
 
-        Cursor cursor3 = mock(Cursor.class);
-        when(cursor3.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor3.next()).thenReturn(hostConfig2);
-        
+        Cursor cursor1 = mock(Cursor.class);
+        when(cursor1.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor1.next()).thenReturn(hostConfig1);
+
         // storage
         
         Storage storage = mock(Storage.class);
@@ -270,16 +290,21 @@
                 return new MockQuery();
             }
         });
-        when(storage.findAll(any(Query.class))).thenReturn(cursor1).thenReturn(cursor2).thenReturn(cursor3);
-        
-        return storage;
+        when(storage.findAll(any(Query.class))).thenReturn(cursor1);
+
+        AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
+        when(agentDao.getAliveAgents()).thenReturn(Arrays.asList(agentInfo1));
+
+        return new Pair<>(storage, agentDao);
     }
     
     @Test
     public void getAliveHost3() {
-        Storage storage = setupStorageForSingleAliveHost3();
+        Pair<Storage, AgentInfoDAO> setup = setupForAliveHost3();
+        Storage storage = setup.first;
+        AgentInfoDAO agentInfoDao = setup.second;
 
-        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage);
+        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage, agentInfoDao);
         Collection<HostRef> hosts = hostsDAO.getAliveHosts();
 
         // cursor 3 from the above storage should not be used
@@ -287,28 +312,36 @@
         assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
         assertTrue(hosts.contains(new HostRef("456", "fluffhost2")));
         assertTrue(hosts.contains(new HostRef("678", "fluffhost3")));
-        verify(storage, times(4)).findAll(any(Query.class));
+        verify(storage, times(3)).findAll(any(Query.class));
     }
     
-    private Storage setupStorageForSingleAliveHost3() {
+    private Pair<Storage, AgentInfoDAO> setupForAliveHost3() {
         
         // agents
         
-        Chunk agentConfig1 = new Chunk(AgentInformation.AGENT_INFO_CATEGORY, false);
+        Chunk agentConfig1 = new Chunk(AgentInfoDAO.CATEGORY, false);
         agentConfig1.put(Key.AGENT_ID, "123");
-        agentConfig1.put(AgentInformation.AGENT_ALIVE_KEY, true);
-        
-        Chunk agentConfig2 = new Chunk(AgentInformation.AGENT_INFO_CATEGORY, false);
+        agentConfig1.put(AgentInfoDAO.ALIVE_KEY, true);
+
+        AgentInformation agentInfo1 = new AgentInformation();
+        agentInfo1.setAgentId("123");
+        agentInfo1.setAlive(true);
+
+        Chunk agentConfig2 = new Chunk(AgentInfoDAO.CATEGORY, false);
         agentConfig2.put(Key.AGENT_ID, "456");
-        agentConfig2.put(AgentInformation.AGENT_ALIVE_KEY, true);
-        
-        Chunk agentConfig3 = new Chunk(AgentInformation.AGENT_INFO_CATEGORY, false);
+        agentConfig2.put(AgentInfoDAO.ALIVE_KEY, true);
+
+        AgentInformation agentInfo2 = new AgentInformation();
+        agentInfo2.setAgentId("456");
+        agentInfo2.setAlive(true);
+
+        Chunk agentConfig3 = new Chunk(AgentInfoDAO.CATEGORY, false);
         agentConfig3.put(Key.AGENT_ID, "678");
-        agentConfig3.put(AgentInformation.AGENT_ALIVE_KEY, true);
-        
-        Cursor cursor1 = mock(Cursor.class);
-        when(cursor1.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(cursor1.next()).thenReturn(agentConfig1).thenReturn(agentConfig2).thenReturn(agentConfig3);
+        agentConfig3.put(AgentInfoDAO.ALIVE_KEY, true);
+
+        AgentInformation agentInfo3 = new AgentInformation();
+        agentInfo3.setAgentId("678");
+        agentInfo3.setAlive(true);
         
         // hosts
         
@@ -324,17 +357,17 @@
         hostConfig3.put(HostInfoDAO.hostNameKey, "fluffhost3");
         hostConfig3.put(Key.AGENT_ID, "678");
         
+        Cursor cursor1 = mock(Cursor.class);
+        when(cursor1.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor1.next()).thenReturn(hostConfig1);
+
         Cursor cursor2 = mock(Cursor.class);
         when(cursor2.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor2.next()).thenReturn(hostConfig1);
+        when(cursor2.next()).thenReturn(hostConfig2);
 
         Cursor cursor3 = mock(Cursor.class);
         when(cursor3.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor3.next()).thenReturn(hostConfig2);
-        
-        Cursor cursor4 = mock(Cursor.class);
-        when(cursor4.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor4.next()).thenReturn(hostConfig3);
+        when(cursor3.next()).thenReturn(hostConfig3);
         
         // storage
         
@@ -347,9 +380,11 @@
         });
         when(storage.findAll(any(Query.class))).thenReturn(cursor1).
                                                 thenReturn(cursor2).
-                                                thenReturn(cursor3).
-                                                thenReturn(cursor4);
+                                                thenReturn(cursor3);
         
-        return storage;
+        AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
+        when(agentDao.getAliveAgents()).thenReturn(Arrays.asList(agentInfo1, agentInfo2, agentInfo3));
+
+        return new Pair<>(storage, agentDao);
     }
 }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -76,6 +76,18 @@
     }
 
     @Test
+    public void testGetAgentInfoDAO() {
+        AgentInfoDAO dao = daoFactory.getAgentInfoDAO();
+        assertNotNull(dao);
+    }
+
+    @Test
+    public void testGetBackendInfoDAO() {
+        BackendInfoDAO dao = daoFactory.getBackendInfoDAO();
+        assertNotNull(dao);
+    }
+
+    @Test
     public void testGetVmClassStatsDAO() {
         VmClassStatDAO dao = daoFactory.getVmClassStatsDAO();
         assertNotNull(dao);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/model/BackendInformationTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.model;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+public class BackendInformationTest {
+
+    @Test
+    public void testConfigurationNotNull() {
+        BackendInformation backendInfo = new BackendInformation();
+        Map<String,String> config = backendInfo.getConfiguration();
+        assertNotNull(config);
+    }
+
+}
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/BackendInformationTest.java	Fri Sep 07 13:05:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.storage;
-
-import static org.junit.Assert.assertNotNull;
-
-import java.util.Map;
-
-import org.junit.Test;
-
-public class BackendInformationTest {
-
-    @Test
-    public void testConfigurationNotNull() {
-        BackendInformation backendInfo = new BackendInformation();
-        Map<String,String> config = backendInfo.getConfiguration();
-        assertNotNull(config);
-    }
-
-}
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollector.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollector.java	Fri Sep 07 16:14:49 2012 -0400
@@ -38,12 +38,17 @@
 
 import java.util.List;
 
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadInfoData;
 import com.redhat.thermostat.thread.model.ThreadSummary;
 import com.redhat.thermostat.thread.model.VMThreadCapabilities;
 
 public interface ThreadCollector {
     
+    void setAgentInfoDao(AgentInfoDAO agentDao);
+    void setThreadDao(ThreadDao threadDao);
+
     VMThreadCapabilities getVMThreadCapabilities();
     
     boolean startHarvester();
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollectorFactory.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollectorFactory.java	Fri Sep 07 16:14:49 2012 -0400
@@ -36,9 +36,15 @@
 
 package com.redhat.thermostat.thread.client.common.collector;
 
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.thread.dao.ThreadDao;
 
 public interface ThreadCollectorFactory {
 
+    void setAgentDao(AgentInfoDAO agentDao);
+
+    void setThreadDao(ThreadDao threadDao);
+
     ThreadCollector getCollector(VmRef reference);
 }
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorFactoryImpl.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorFactoryImpl.java	Fri Sep 07 16:14:49 2012 -0400
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.thread.client.common.collector.impl;
 
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.thread.client.common.collector.ThreadCollector;
 import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory;
@@ -43,14 +44,23 @@
 
 public class ThreadCollectorFactoryImpl implements ThreadCollectorFactory {
 
+    private AgentInfoDAO agentDao;
     private ThreadDao threadDao;
     
-    public ThreadCollectorFactoryImpl(ThreadDao threadDao) {
+    public void setAgentDao(AgentInfoDAO agentDao) {
+        this.agentDao = agentDao;
+    }
+
+    public void setThreadDao(ThreadDao threadDao) {
         this.threadDao = threadDao;
     }
     
     @Override
     public synchronized ThreadCollector getCollector(VmRef reference) {
-        return new ThreadMXBeanCollector(threadDao, reference);
+        // TODO set the values when the agent/thread dao changes
+        ThreadMXBeanCollector result = new ThreadMXBeanCollector(reference);
+        result.setAgentInfoDao(agentDao);
+        result.setThreadDao(threadDao);
+        return result;
     }
 }
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadMXBeanCollector.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadMXBeanCollector.java	Fri Sep 07 16:14:49 2012 -0400
@@ -45,6 +45,7 @@
 import com.redhat.thermostat.common.command.RequestResponseListener;
 import com.redhat.thermostat.common.command.Response;
 import com.redhat.thermostat.common.command.Request.RequestType;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.utils.OSGIUtils;
@@ -57,19 +58,26 @@
 
 public class ThreadMXBeanCollector implements ThreadCollector {
 
+    private AgentInfoDAO agentDao;
     private ThreadDao threadDao;
     private VmRef ref;
 
-    public ThreadMXBeanCollector(ThreadDao threadDao, VmRef ref) {
+    public ThreadMXBeanCollector(VmRef ref) {
+        this.ref = ref;
+    }
+
+    public void setThreadDao(ThreadDao threadDao) {
         this.threadDao = threadDao;
-        this.ref = ref;
+    }
+
+    public void setAgentInfoDao(AgentInfoDAO agentDao) {
+        this.agentDao = agentDao;
     }
 
     Request createRequest() {
         HostRef targetHostRef = ref.getAgent();
         
-        // todo
-        String address = threadDao.getStorage().getConfigListenAddress(targetHostRef);
+        String address = agentDao.getAgentInformation(targetHostRef).getConfigListenAddress();
         String [] host = address.split(":");
         
         InetSocketAddress target = new InetSocketAddress(host[0], Integer.parseInt(host[1]));
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/osgi/Activator.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/osgi/Activator.java	Fri Sep 07 16:14:49 2012 -0400
@@ -41,37 +41,61 @@
 import org.osgi.framework.ServiceReference;
 import org.osgi.util.tracker.ServiceTracker;
 
-import com.redhat.thermostat.common.storage.Storage;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory;
 import com.redhat.thermostat.thread.client.common.collector.impl.ThreadCollectorFactoryImpl;
 import com.redhat.thermostat.thread.dao.ThreadDao;
-import com.redhat.thermostat.thread.dao.impl.ThreadDaoImpl;
 
 public class Activator implements BundleActivator {
     
     private ThreadCollectorFactoryImpl collectorFactory;
+    private ServiceTracker agentInfoDaoTracker;
+    private ServiceTracker threadDaoTracker;
     
     @Override
     public void start(final BundleContext context) throws Exception {
         
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        ServiceTracker tracker = new ServiceTracker(context, ThreadDao.class.getName(), null) {
+        collectorFactory = new ThreadCollectorFactoryImpl();
+        context.registerService(ThreadCollectorFactory.class.getName(), collectorFactory, null);
+
+        agentInfoDaoTracker = new ServiceTracker(context, AgentInfoDAO.class.getName(), null) {
             @Override
             public Object addingService(ServiceReference reference) {
-                
-                ThreadDao threadDao = (ThreadDao) context.getService(reference);
-                
-                collectorFactory = new ThreadCollectorFactoryImpl(threadDao);
-
-                context.registerService(ThreadCollectorFactory.class.getName(), collectorFactory, null);
-
+                AgentInfoDAO agentDao = (AgentInfoDAO) context.getService(reference);
+                collectorFactory.setAgentDao(agentDao);
                 return super.addingService(reference);
             }
+
+            @Override
+            public void removedService(ServiceReference reference, Object service) {
+                collectorFactory.setAgentDao(null);
+                context.ungetService(reference);
+                super.removedService(reference, service);
+            }
         };
-        tracker.open();
+        agentInfoDaoTracker.open();
+
+        threadDaoTracker = new ServiceTracker(context, ThreadDao.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                ThreadDao threadDao = (ThreadDao) context.getService(reference);
+                collectorFactory.setThreadDao(threadDao);
+                return super.addingService(reference);
+            }
+
+            @Override
+            public void removedService(ServiceReference reference, Object service) {
+                collectorFactory.setThreadDao(null);
+                context.ungetService(reference);
+                super.removedService(reference, service);
+            }
+        };
+        threadDaoTracker.open();
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
+        agentInfoDaoTracker.close();
+        threadDaoTracker.close();
     }
 }
--- a/thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollectorFactoryTest.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollectorFactoryTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -39,13 +39,10 @@
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.mock;
 
-import java.util.concurrent.ScheduledExecutorService;
-
 import org.junit.Test;
 
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.thread.client.common.collector.ThreadCollector;
-import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory;
 import com.redhat.thermostat.thread.client.common.collector.impl.ThreadCollectorFactoryImpl;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 
@@ -53,10 +50,22 @@
 
     @Test
     public void testThreadCollectorFactory() {
+        VmRef reference = mock(VmRef.class);
+
+        ThreadCollectorFactory factory = new ThreadCollectorFactoryImpl();
+        ThreadCollector collector = factory.getCollector(reference);
+        assertNotNull(collector);
+    }
+
+    @Test
+    public void testThreadCollectorFactoryWithAgentAndThreadDaos() {
+        AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
         ThreadDao threadDao = mock(ThreadDao.class);
         VmRef reference = mock(VmRef.class);
-                
-        ThreadCollectorFactory factory = new ThreadCollectorFactoryImpl(threadDao);
+
+        ThreadCollectorFactory factory = new ThreadCollectorFactoryImpl();
+        factory.setAgentDao(agentDao);
+        factory.setThreadDao(threadDao);
         ThreadCollector collector = factory.getCollector(reference);
         assertNotNull(collector);
     }
--- a/thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorTest.java	Fri Sep 07 13:05:50 2012 -0400
+++ b/thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorTest.java	Fri Sep 07 16:14:49 2012 -0400
@@ -56,6 +56,7 @@
 import com.redhat.thermostat.common.command.RequestResponseListener;
 import com.redhat.thermostat.common.command.Response;
 import com.redhat.thermostat.common.command.Response.ResponseType;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.thread.client.common.collector.ThreadCollector;
@@ -75,6 +76,7 @@
         VmRef reference = mock(VmRef.class);
         when(reference.getIdString()).thenReturn("00101010");
         when(reference.getAgent()).thenReturn(agent);
+        AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
         ThreadDao threadDao = mock(ThreadDao.class);
         
         VMThreadCapabilities resCaps = mock(VMThreadCapabilities.class);
@@ -102,7 +104,7 @@
                 
         /* ************* */
         
-        ThreadCollector collector = new ThreadMXBeanCollector(threadDao, reference) {
+        ThreadCollector collector = new ThreadMXBeanCollector(reference) {
             @Override
             Request createRequest() {
                 return request;
@@ -112,6 +114,8 @@
                 return requestQueue;
             }
         };
+        collector.setAgentInfoDao(agentDao);
+        collector.setThreadDao(threadDao);
         
         VMThreadCapabilities caps = collector.getVMThreadCapabilities();
 
@@ -129,12 +133,13 @@
     public void testVMCapabilitiesInDAO() throws Exception {
         
         VmRef reference = mock(VmRef.class);
+        AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
         ThreadDao threadDao = mock(ThreadDao.class);
         
         VMThreadCapabilities resCaps = mock(VMThreadCapabilities.class);
         when(threadDao.loadCapabilities(reference)).thenReturn(resCaps);
         
-        ThreadCollector collector = new ThreadMXBeanCollector(threadDao, reference) {
+        ThreadCollector collector = new ThreadMXBeanCollector(reference) {
             @Override
             Request createRequest() {
                 fail();
@@ -147,6 +152,9 @@
             }
         };
         
+        collector.setAgentInfoDao(agentDao);
+        collector.setThreadDao(threadDao);
+
         VMThreadCapabilities caps = collector.getVMThreadCapabilities();
  
         verify(threadDao, times(1)).loadCapabilities(reference);
@@ -161,6 +169,7 @@
         
         final Request request = mock(Request.class);
         final RequestQueue requestQueue = mock(RequestQueue.class);
+        AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
         ThreadDao threadDao = mock(ThreadDao.class);
         VmRef reference = mock(VmRef.class);
         when(reference.getIdString()).thenReturn("00101010");
@@ -186,7 +195,7 @@
 
         }).when(requestQueue).putRequest(request);
         
-        ThreadCollector collector = new ThreadMXBeanCollector(threadDao, reference) {
+        ThreadCollector collector = new ThreadMXBeanCollector(reference) {
             @Override
             Request createRequest() {
                 return request;
@@ -196,6 +205,8 @@
                 return requestQueue;
             }
         };
+        collector.setAgentInfoDao(agentDao);
+        collector.setThreadDao(threadDao);
         
         collector.startHarvester();
         
@@ -212,6 +223,7 @@
 
         final Request request = mock(Request.class);
         final RequestQueue requestQueue = mock(RequestQueue.class);
+        AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
         ThreadDao threadDao = mock(ThreadDao.class);
         VmRef reference = mock(VmRef.class);
         when(reference.getIdString()).thenReturn("00101010");
@@ -236,7 +248,7 @@
 
         }).when(requestQueue).putRequest(request);
         
-        ThreadCollector collector = new ThreadMXBeanCollector(threadDao, reference) {
+        ThreadCollector collector = new ThreadMXBeanCollector(reference) {
             @Override
             Request createRequest() {
                 return request;
@@ -246,6 +258,8 @@
                 return requestQueue;
             }
         };
+        collector.setAgentInfoDao(agentDao);
+        collector.setThreadDao(threadDao);
         collector.stopHarvester();
         
         verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.STOP.name());