changeset 200:18fdcb51a38e

Merge
author Roman Kennke <rkennke@redhat.com>
date Wed, 04 Apr 2012 21:49:29 +0200
parents f2ce7773b93c (current diff) d794eace82e8 (diff)
children e7bd33c29e67
files agent/src/main/java/com/redhat/thermostat/backend/BackendRegistryUtils.java agent/src/test/java/com/redhat/thermostat/backend/BackendRegistryUtilsTest.java common/src/main/java/com/redhat/thermostat/common/dao/HostRefDAO.java common/src/main/java/com/redhat/thermostat/common/dao/HostRefDAOImpl.java common/src/main/java/com/redhat/thermostat/common/dao/VmRefDAO.java common/src/main/java/com/redhat/thermostat/common/dao/VmRefDAOImpl.java common/src/test/java/com/redhat/thermostat/common/dao/HostRefDAOTest.java common/src/test/java/com/redhat/thermostat/common/dao/VmRefDAOTest.java
diffstat 122 files changed, 2309 insertions(+), 1294 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/main/java/com/redhat/thermostat/agent/AgentApplication.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/main/java/com/redhat/thermostat/agent/AgentApplication.java	Wed Apr 04 21:49:29 2012 +0200
@@ -142,4 +142,9 @@
         service.parseArguments(Arrays.asList(args));
         service.run();
     }
+
+    @Override
+    public void printHelp() {
+        // TODO: add help
+    }
 }
--- a/agent/src/main/java/com/redhat/thermostat/agent/config/AgentStartupConfiguration.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/main/java/com/redhat/thermostat/agent/config/AgentStartupConfiguration.java	Wed Apr 04 21:49:29 2012 +0200
@@ -88,6 +88,10 @@
             
             // a file must exist, at least with the class name
             File backendSettings = ConfigUtils.getBackendPropertyFile(backendName);
+            if (!backendSettings.exists())
+                throw new InvalidConfigurationException("backends configuration " +
+                                                        "directory doesn't exist: " +
+                                                        backendSettings);
             Properties backendProps = new Properties();
             try {
                 backendProps.load(new FileInputStream(backendSettings));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/main/java/com/redhat/thermostat/backend/BackendConfigurationLoader.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,82 @@
+/*
+ * 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.backend;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import com.redhat.thermostat.common.config.ConfigUtils;
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+
+class BackendConfigurationLoader {
+
+    public Map<String, String> retrieveBackendConfigs(String name) throws InvalidConfigurationException {
+        
+        // reads the backend
+        File backend = new File(ConfigUtils.getBackendsBaseDirectory(), name);
+        backend = new File(backend, BackendsProperties.PROPERTY_FILE);
+        if (!backend.isFile() || !backend.canRead()) {
+            throw new InvalidConfigurationException("invalid backend configuration file: " + backend);
+        }
+        
+        Properties props = new Properties();
+        try {
+            props.load(new FileInputStream(backend));
+        } catch (IOException e) {
+            throw new InvalidConfigurationException("invalid backend configuration file", e);
+        }
+        
+        return toMap(props);
+    }
+
+    private static Map<String, String> toMap(Properties props) {
+
+        Map<String, String> configMap = new HashMap<>();
+        for (Entry<Object, Object> e : props.entrySet()) {
+            String key = (String) e.getKey();
+            String value = (String) e.getValue();
+            
+            configMap.put(key, value);
+        }
+        return configMap;
+    }
+}
--- a/agent/src/main/java/com/redhat/thermostat/backend/BackendRegistry.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/main/java/com/redhat/thermostat/backend/BackendRegistry.java	Wed Apr 04 21:49:29 2012 +0200
@@ -59,7 +59,10 @@
     private final Map<String, Backend> registeredBackends;
 
     public BackendRegistry(AgentStartupConfiguration config, Storage storage) throws BackendLoadException {
-        
+        this(config, new BackendConfigurationLoader(), storage);
+    }
+
+    public BackendRegistry(AgentStartupConfiguration config, BackendConfigurationLoader backendConfigLoader, Storage storage) throws BackendLoadException {
         registeredBackends = new HashMap<String, Backend>();
         
         List<BackendID> backends = config.getBackends();
@@ -78,7 +81,7 @@
                 
                 backend.setID(backendID);
                 
-                backend.setInitialConfiguration(BackendRegistryUtils.retrieveBackendConfigs(backend.getName()));
+                backend.setInitialConfiguration(backendConfigLoader.retrieveBackendConfigs(backend.getName()));
                 backend.setStorage(storage);
             } catch (Exception e) {
                 throw new BackendLoadException("Could not instantiate configured backend class: " + backendID.getClassName(), e);
--- a/agent/src/main/java/com/redhat/thermostat/backend/BackendRegistryUtils.java	Wed Apr 04 21:47:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +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.backend;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-
-import com.redhat.thermostat.common.config.ConfigUtils;
-import com.redhat.thermostat.common.config.InvalidConfigurationException;
-
-class BackendRegistryUtils {
-
-    public static Map<String, String> retrieveBackendConfigs(String name) throws InvalidConfigurationException {
-        
-        // reads the backend
-        File backend = new File(ConfigUtils.getBackendsBaseDirectory(), name);
-        backend = new File(backend, BackendsProperties.PROPERTY_FILE);
-        if (!backend.isFile() || !backend.canRead()) {
-            throw new InvalidConfigurationException("invalid backend configuration file: " + backend);
-        }
-        
-        Properties props = new Properties();
-        try {
-            props.load(new FileInputStream(backend));
-        } catch (IOException e) {
-            throw new InvalidConfigurationException("invalid backend configuration file", e);
-        }
-        
-        return getStartupBackendConfigMap(props);
-    }
-
-    private static Map<String, String> getStartupBackendConfigMap(Properties props) {
-
-        Map<String, String> configMap = new HashMap<>();
-        for (Entry<Object, Object> e : props.entrySet()) {
-            String key = (String) e.getKey();
-            String value = (String) e.getValue();
-            
-            configMap.put(key, value);
-        }
-        return configMap;
-    }
-}
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatDataExtractor.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatDataExtractor.java	Wed Apr 04 21:49:29 2012 +0200
@@ -134,6 +134,8 @@
     }
 
     public String getGenerationCollector(long generation) throws MonitorException {
+        // this is just re-implementing getCollectorName()
+        // TODO check generation number and collector number are always associated
         Monitor m = vm.findByName("sun.gc.collector." + generation + ".name");
         if (m == null) {
             return Generation.COLLECTOR_NONE;
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Wed Apr 04 21:49:29 2012 +0200
@@ -129,7 +129,7 @@
                         extractor.getMainClass(), extractor.getCommandLine(),
                         extractor.getVmName(), extractor.getVmInfo(), extractor.getVmVersion(), extractor.getVmArguments(),
                         properties, environment, loadedNativeLibraries);
-                backend.store(new VmInfoConverter().vmInfoToChunk(info));
+                backend.store(new VmInfoConverter().toChunk(info));
                 logger.finer("Sent VM_STARTED messsage");
             } catch (MonitorException me) {
                 logger.log(Level.WARNING, "error getting vm info for " + vmId, me);
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmClassListener.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmClassListener.java	Wed Apr 04 21:49:29 2012 +0200
@@ -80,7 +80,7 @@
             long timestamp = System.currentTimeMillis();
             VmClassStat stat = new VmClassStat(vmId, timestamp, loadedClasses);
             VmClassStatConverter dao = new VmClassStatConverter();
-            backend.store(dao.vmClassStatToChunk(stat));
+            backend.store(dao.toChunk(stat));
         } catch (MonitorException e) {
             logger.log(Level.WARNING, "error gathering class info for vm " + vmId, e);
         }
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java	Wed Apr 04 21:49:29 2012 +0200
@@ -97,7 +97,7 @@
                         extractor.getCollectorName(i),
                         extractor.getCollectorInvocations(i),
                         extractor.getCollectorTime(i));
-                backend.store(new VmGcStatConverter().vmGcStatToChunk(stat));
+                backend.store(new VmGcStatConverter().toChunk(stat));
             }
         } catch (MonitorException e) {
             logger.log(Level.WARNING, "error gathering gc info for vm " + vmId, e);
@@ -132,7 +132,7 @@
                     s.used = extractor.getSpaceUsed(generation, space);
                 }
             }
-            backend.store(new VmMemoryStatConverter().vmMemoryStatToChunk(stat));
+            backend.store(new VmMemoryStatConverter().toChunk(stat));
         } catch (MonitorException e) {
             logger.log(Level.WARNING, "error gathering memory info for vm " + vmId, e);
         }
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Wed Apr 04 21:49:29 2012 +0200
@@ -102,7 +102,7 @@
         categories.add(NetworkInterfaceInfoDAO.networkInfoCategory);
         categories.add(VmClassStatDAO.vmClassStatsCategory);
         categories.add(VmCpuStatDAO.vmCpuStatCategory);
-        categories.add(VmGcStatDAO.vmGcStatsCategory);
+        categories.add(VmGcStatDAO.vmGcStatCategory);
         categories.add(VmInfoDAO.vmInfoCategory);
         categories.add(VmMemoryStatDAO.vmMemoryStatsCategory);
 
@@ -123,22 +123,22 @@
         if (!getObserveNewJvm()) {
             logger.fine("not monitoring new vms");
         }
-        store(new HostInfoConverter().hostInfoToChunk(new HostInfoBuilder(new ProcDataSource()).build()));
+        store(new HostInfoConverter().toChunk(new HostInfoBuilder(new ProcDataSource()).build()));
 
         timer = new Timer();
         timer.scheduleAtFixedRate(new TimerTask() {
             @Override
             public void run() {
                 ProcDataSource dataSource = new ProcDataSource();
-                store(new CpuStatConverter().cpuStatToChunk(new CpuStatBuilder(dataSource).build()));
+                store(new CpuStatConverter().toChunk(new CpuStatBuilder(dataSource).build()));
                 for (NetworkInterfaceInfo info: NetworkInfoBuilder.build()) {
-                    store(new NetworkInterfaceInfoConverter().networkInfoToChunk(info));
+                    store(new NetworkInterfaceInfoConverter().toChunk(info));
                 }
-                store(new MemoryStatConverter().memoryStatToChunk(new MemoryStatBuilder(dataSource).build()));
+                store(new MemoryStatConverter().toChunk(new MemoryStatBuilder(dataSource).build()));
 
                 for (Integer pid : pidsToMonitor) {
                     if (vmCpuBuilder.knowsAbout(pid)) {
-                        store(new VmCpuStatConverter().vmCpuStatToChunk(vmCpuBuilder.build(pid)));
+                        store(new VmCpuStatConverter().toChunk(vmCpuBuilder.build(pid)));
                     } else {
                         vmCpuBuilder.learnAbout(pid);
                     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/test/java/com/redhat/thermostat/backend/BackendConfigurationLoaderTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,66 @@
+/*
+ * 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.backend;
+
+import java.io.IOException;
+import java.util.Map;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.TestUtils;
+import com.redhat.thermostat.backend.system.SystemBackend;
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+
+public class BackendConfigurationLoaderTest {
+    
+    @Before
+    public void setUp() throws IOException {
+        TestUtils.setupAgentConfigs();
+    }
+    
+    @Test
+    public void test() throws InvalidConfigurationException {
+        Map<String, String> backendProps = new BackendConfigurationLoader().retrieveBackendConfigs("system");
+        Assert.assertTrue(backendProps.containsKey(BackendsProperties.BACKEND_CLASS.name()));
+        
+        String className = backendProps.get(BackendsProperties.BACKEND_CLASS.name());
+        Assert.assertEquals(SystemBackend.class.getCanonicalName(), className);
+    }
+}
--- a/agent/src/test/java/com/redhat/thermostat/backend/BackendRegistryTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/test/java/com/redhat/thermostat/backend/BackendRegistryTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,41 +36,108 @@
 
 package com.redhat.thermostat.backend;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 
-import org.junit.Assert;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.redhat.thermostat.TestUtils;
 import com.redhat.thermostat.agent.config.AgentStartupConfiguration;
-import com.redhat.thermostat.backend.system.SystemBackend;
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Storage;
 
 public class BackendRegistryTest {
 
+    public static class MockBackend extends Backend {
+        @Override
+        protected Collection<Category> getCategories() {
+            return Collections.emptyList();
+        }
+        @Override
+        public String getConfigurationValue(String key) {
+            return null;
+        }
+        @Override
+        public boolean activate() {
+            return true;
+        }
+        @Override
+        public boolean deactivate() {
+            return false;
+        }
+        @Override
+        public boolean isActive() {
+            return false;
+        }
+        @Override
+        public boolean attachToNewProcessByDefault() {
+            return false;
+        }
+    }
+
+    private List<BackendID> backends;
+    private AgentStartupConfiguration config;
+    private BackendConfigurationLoader configLoader;
+    private Storage storage;
+
     @Before
-    public void setUp() throws IOException {
-        TestUtils.setupAgentConfigs();
+    public void setUp() throws InvalidConfigurationException {
+        backends = new ArrayList<>();
+
+        storage = mock(Storage.class);
+        config = mock(AgentStartupConfiguration.class);
+        when(config.getBackends()).thenReturn(backends);
+
+        configLoader = mock(BackendConfigurationLoader.class);
+        when(configLoader.retrieveBackendConfigs(any(String.class))).thenReturn(new HashMap<String,String>());
     }
-    
+
+    @After
+    public void tearDown() {
+        backends = null;
+        config = null;
+        configLoader = null;
+        storage = null;
+    }
+
     @Test
-    public void test() throws BackendLoadException {
-        
-        List<BackendID> backends = new ArrayList<>();
-        backends.add(new BackendID("system", SystemBackend.class.getCanonicalName()));
-        
-        Storage storage = mock(Storage.class);        
-        AgentStartupConfiguration config = mock(AgentStartupConfiguration.class);
-        when(config.getBackends()).thenReturn(backends);
-        
-        BackendRegistry registry = new BackendRegistry(config, storage);
-        Assert.assertEquals(1, registry.getAll().size());
-        Assert.assertNotNull(registry.getByName("system"));
+    public void testRegisterBackend() throws BackendLoadException, InvalidConfigurationException {
+        /* setup fake backend */
+        backends.add(new BackendID("mock", MockBackend.class.getName()));
+
+        BackendRegistry registry = new BackendRegistry(config, configLoader, storage);
+        assertEquals(1, registry.getAll().size());
+        assertNotNull(registry.getByName("mock"));
     }
+
+    @Test
+    public void testNoBackendsRegistered() throws InvalidConfigurationException, BackendLoadException {
+        BackendRegistry registry = new BackendRegistry(config, configLoader, storage);
+        assertEquals(0, registry.getAll().size());
+        assertEquals(null, registry.getByName("system"));
+        assertEquals(null, registry.getByName("mock"));
+    }
+
+    @Test (expected=BackendLoadException.class)
+    public void testRegisterBackendTwice() throws BackendLoadException, InvalidConfigurationException {
+        /* setup fake backends */
+
+        backends.add(new BackendID("mock", MockBackend.class.getClass().getName()));
+        backends.add(new BackendID("mock", MockBackend.class.getClass().getName()));
+
+        /* load the backends */
+        new BackendRegistry(config, configLoader, storage);
+    }
+
 }
--- a/agent/src/test/java/com/redhat/thermostat/backend/BackendRegistryUtilsTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +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.backend;
-
-import java.io.IOException;
-import java.util.Map;
-
-import junit.framework.Assert;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.TestUtils;
-import com.redhat.thermostat.backend.system.SystemBackend;
-import com.redhat.thermostat.common.config.InvalidConfigurationException;
-
-public class BackendRegistryUtilsTest {
-    
-    @Before
-    public void setUp() throws IOException {
-        TestUtils.setupAgentConfigs();
-    }
-    
-    @Test
-    public void test() throws InvalidConfigurationException {
-        Map<String, String> backendProps = BackendRegistryUtils.retrieveBackendConfigs("system");
-        Assert.assertTrue(backendProps.containsKey(BackendsProperties.BACKEND_CLASS.name()));
-        
-        String className = backendProps.get(BackendsProperties.BACKEND_CLASS.name());
-        Assert.assertEquals(SystemBackend.class.getCanonicalName(), className);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/test/java/com/redhat/thermostat/backend/system/JvmStatDataExtractorTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,375 @@
+/*
+ * 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.backend.system;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+
+import sun.jvmstat.monitor.LongMonitor;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.StringMonitor;
+
+public class JvmStatDataExtractorTest {
+
+    private MonitoredVm buildStringMonitoredVm(String monitorName, String monitorReturn) throws MonitorException {
+        final StringMonitor monitor = mock(StringMonitor.class);
+        when(monitor.stringValue()).thenReturn(monitorReturn);
+        when(monitor.getValue()).thenReturn(monitorReturn);
+        MonitoredVm vm = mock(MonitoredVm.class);
+        when(vm.findByName(monitorName)).thenReturn(monitor);
+        return vm;
+    }
+
+    private MonitoredVm buildLongMonitoredVm(String monitorName, Long monitorReturn) throws MonitorException {
+        final LongMonitor monitor = mock(LongMonitor.class);
+        when(monitor.longValue()).thenReturn(monitorReturn);
+        when(monitor.getValue()).thenReturn(monitorReturn);
+        MonitoredVm vm = mock(MonitoredVm.class);
+        when(vm.findByName(monitorName)).thenReturn(monitor);
+        return vm;
+    }
+
+    @Test
+    public void testCommandLine() throws MonitorException {
+        final String MONITOR_NAME = "sun.rt.javaCommand";
+        final String MONITOR_VALUE = "command line java";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getCommandLine();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testMainClass() throws MonitorException {
+        final String MONITOR_NAME = "sun.rt.javaCommand";
+        final String MONITOR_VALUE = "some.package.Main";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getMainClass();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testJavaVersion() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.version";
+        final String MONITOR_VALUE = "some java version";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getJavaVersion();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testJavaHome() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.home";
+        final String MONITOR_VALUE = "${java.home}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getJavaHome();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testVmName() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.vm.name";
+        final String MONITOR_VALUE = "${vm.name}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getVmName();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testVmInfo() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.vm.info";
+        final String MONITOR_VALUE = "${vm.info}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getVmInfo();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testVmVersion() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.vm.version";
+        final String MONITOR_VALUE = "${vm.version}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getVmVersion();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testVmArguments() throws MonitorException {
+        final String MONITOR_NAME = "java.rt.vmArgs";
+        final String MONITOR_VALUE = "${vm.arguments}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getVmArguments();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testTotalCollectors() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.policy.collectors";
+        final Long MONITOR_VALUE = 9l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getTotalCollectors();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testCollectorName() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.collector.0.name";
+        final String COLLECTOR_NAME = "SomeMemoryCollector";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, COLLECTOR_NAME);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getCollectorName(0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(COLLECTOR_NAME, returned);
+    }
+
+    @Test
+    public void testCollectorTime() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.collector.0.time";
+        final Long COLLECTOR_TIME = 99l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, COLLECTOR_TIME);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getCollectorTime(0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(COLLECTOR_TIME, returned);
+    }
+
+    @Test
+    public void testCollectorInvocations() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.collector.0.invocations";
+        final Long COLLECTOR_INVOCATIONS = 99l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, COLLECTOR_INVOCATIONS);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getCollectorInvocations(0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(COLLECTOR_INVOCATIONS, returned);
+    }
+
+    @Test
+    public void testTotalGcGenerations() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.policy.generations";
+        final Long GC_GENERATIONS = 99l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, GC_GENERATIONS);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getTotalGcGenerations();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(GC_GENERATIONS, returned);
+    }
+
+    @Test
+    public void testGenerationName() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.generation.0.name";
+        final String GENERATION_NAME = "Youth";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, GENERATION_NAME);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getGenerationName(0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(GENERATION_NAME, returned);
+    }
+
+    @Test
+    public void testGenerationCapacity() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.generation.0.capacity";
+        final Long GENERATION_CAPACITY = 99l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, GENERATION_CAPACITY);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getGenerationCapacity(0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(GENERATION_CAPACITY, returned);
+    }
+
+    @Test
+    public void testGenerationMaxCapacity() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.generation.0.maxCapacity";
+        final Long GENERATION_MAX_CAPACITY = 99l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, GENERATION_MAX_CAPACITY);
+
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getGenerationMaxCapacity(0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(GENERATION_MAX_CAPACITY, returned);
+    }
+
+    @Test
+    public void testGenerationCollector() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.collector.0.name";
+        final String GENERATION_COLLECTOR = "generation collector";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, GENERATION_COLLECTOR);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getGenerationCollector(0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(GENERATION_COLLECTOR, returned);
+    }
+
+    @Test
+    public void testTotalSpaces() throws MonitorException {
+        final Long TOTAL_SPACES = 99l;
+        final LongMonitor monitor = mock(LongMonitor.class);
+        when(monitor.getValue()).thenReturn(TOTAL_SPACES);
+        MonitoredVm vm = mock(MonitoredVm.class);
+        when(vm.findByName("sun.gc.generation.0.spaces")).thenReturn(monitor);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getTotalSpaces(0);
+
+        verify(vm).findByName(eq("sun.gc.generation.0.spaces"));
+        assertEquals(TOTAL_SPACES, returned);
+    }
+
+
+    @Test
+    public void testSpaceName() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.generation.0.space.0.name";
+        final String SPACE_NAME = "Hilbert";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, SPACE_NAME);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getSpaceName(0,0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(SPACE_NAME, returned);
+    }
+
+    @Test
+    public void testSpaceCapacity() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.generation.0.space.0.capacity";
+        final Long SPACE_CAPACITY = 99l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, SPACE_CAPACITY);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getSpaceCapacity(0,0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(SPACE_CAPACITY, returned);
+    }
+
+    @Test
+    public void testSpaceMaxCapacity() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.generation.0.space.0.maxCapacity";
+        final Long SPACE_MAX_CAPACITY = 99l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, SPACE_MAX_CAPACITY);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getSpaceMaxCapacity(0,0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(SPACE_MAX_CAPACITY, returned);
+    }
+
+    @Test
+    public void testSpaceUsed() throws MonitorException {
+        final String MONITOR_NAME = "sun.gc.generation.0.space.0.used";
+        final Long SPACE_USED = 99l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, SPACE_USED);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getSpaceUsed(0,0);
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(SPACE_USED, returned);
+    }
+
+    @Test
+    public void testLoadedClasses() throws MonitorException {
+        final String MONITOR_NAME = "java.cls.loadedClasses";
+        final Long LOADED_CLASSES = 99l;
+        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, LOADED_CLASSES);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        Long returned = extractor.getLoadedClasses();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(LOADED_CLASSES, returned);
+    }
+
+}
--- a/agent/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/agent/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -101,7 +101,7 @@
         assertTrue(categories.contains(NetworkInterfaceInfoDAO.networkInfoCategory));
         assertTrue(categories.contains(VmClassStatDAO.vmClassStatsCategory));
         assertTrue(categories.contains(VmCpuStatDAO.vmCpuStatCategory));
-        assertTrue(categories.contains(VmGcStatDAO.vmGcStatsCategory));
+        assertTrue(categories.contains(VmGcStatDAO.vmGcStatCategory));
         assertTrue(categories.contains(VmInfoDAO.vmInfoCategory));
         assertTrue(categories.contains(VmMemoryStatDAO.vmMemoryStatsCategory));
     }
--- a/client/pom.xml	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/pom.xml	Wed Apr 04 21:49:29 2012 +0200
@@ -76,10 +76,6 @@
       <groupId>org.jfree</groupId>
       <artifactId>jfreechart</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.mongodb</groupId>
-      <artifactId>mongo-java-driver</artifactId>
-    </dependency>
   </dependencies>
 
 </project>
--- a/client/src/main/java/com/redhat/thermostat/client/Main.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/Main.java	Wed Apr 04 21:49:29 2012 +0200
@@ -52,9 +52,7 @@
 import com.redhat.thermostat.client.locale.LocaleResources;
 import com.redhat.thermostat.client.ui.ConnectionSelectionDialog;
 import com.redhat.thermostat.client.ui.LayoutDebugHelper;
-import com.redhat.thermostat.client.ui.MainWindow;
 import com.redhat.thermostat.common.Constants;
-import com.redhat.thermostat.common.LaunchException;
 import com.redhat.thermostat.common.ThreadPoolTimerFactory;
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.config.StartupConfiguration;
@@ -63,7 +61,6 @@
 import com.redhat.thermostat.common.dao.Connection.ConnectionStatus;
 import com.redhat.thermostat.common.dao.ConnectionProvider;
 import com.redhat.thermostat.common.dao.DAOFactory;
-import com.redhat.thermostat.common.dao.MongoConnection;
 import com.redhat.thermostat.common.dao.MongoConnectionProvider;
 import com.redhat.thermostat.common.dao.MongoDAOFactory;
 import com.redhat.thermostat.common.utils.LoggingUtils;
@@ -123,7 +120,7 @@
         connection.connect();
         connection.removeListener(connectionListener);
 
-        uiFacadeFactory = new UiFacadeFactoryImpl((MongoConnection) connection);
+        uiFacadeFactory = new UiFacadeFactoryImpl();
 
         MainWindowController mainController = uiFacadeFactory.getMainWindow();
         mainController.showMainMainWindow();
--- a/client/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -45,10 +45,10 @@
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
 import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.HostRefDAO;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
 import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.dao.VmRefDAO;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 public class MainWindowControllerImpl implements MainWindowController {
@@ -59,15 +59,15 @@
 
     private String filter;
 
-    private HostRefDAO hostRefDAO;
-    private VmRefDAO vmRefDAO;
+    private final HostInfoDAO hostsDAO;
+    private final VmInfoDAO vmsDAO;
 
     public MainWindowControllerImpl(MainView view) {
 
         ApplicationContext ctx = ApplicationContext.getInstance();
         DAOFactory daoFactory = ctx.getDAOFactory();
-        hostRefDAO = daoFactory.getHostRefDAO();
-        vmRefDAO = daoFactory.getVmRefDAO();
+        hostsDAO = daoFactory.getHostInfoDAO();
+        vmsDAO = daoFactory.getVmInfoDAO();
 
         initView(view);
         initializeTimer();
@@ -78,12 +78,12 @@
 
         @Override
         public Collection<HostRef> getHosts() {
-            return hostRefDAO.getHosts();
+            return hostsDAO.getHosts();
         }
 
         @Override
         public Collection<VmRef> getVMs(HostRef host) {
-            return vmRefDAO.getVMs(host);
+            return vmsDAO.getVMs(host);
         }
         
     }
--- a/client/src/main/java/com/redhat/thermostat/client/SummaryPanelFacade.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/SummaryPanelFacade.java	Wed Apr 04 21:49:29 2012 +0200
@@ -40,9 +40,9 @@
 
 public interface SummaryPanelFacade extends AsyncUiFacade {
 
-    public ChangeableText getTotalConnectedVms();
+    public ChangeableText getTotalMonitoredVms();
 
-    public ChangeableText getTotalConnectedAgents();
+    public ChangeableText getTotalMonitoredHosts();
 
     public List<String> getIssues();
 
--- a/client/src/main/java/com/redhat/thermostat/client/SummaryPanelFacadeImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/SummaryPanelFacadeImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -40,36 +40,40 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import com.mongodb.DB;
-import com.mongodb.DBCollection;
 import com.redhat.thermostat.client.appctx.ApplicationContext;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
 
 public class SummaryPanelFacadeImpl implements SummaryPanelFacade {
 
-    private final DBCollection agentConfigCollection;
-    private final DBCollection vmInfoCollection;
+    private final HostInfoDAO hostsDAO;
+    private final VmInfoDAO vmsDAO;
 
-    private final ChangeableText connectedAgentText;
-    private final ChangeableText connectedVmText;
+    private final ChangeableText totalHostsText;
+    private final ChangeableText totalVmsText;
 
     private final Timer backgroundUpdateTimer;
 
-    public SummaryPanelFacadeImpl(DB db) {
-        this.agentConfigCollection = db.getCollection("agent-config");
-        this.vmInfoCollection = db.getCollection("vm-info");
+    public SummaryPanelFacadeImpl() {
+        
+        ApplicationContext ctx = ApplicationContext.getInstance();
+        DAOFactory daoFactory = ctx.getDAOFactory();
+        hostsDAO = daoFactory.getHostInfoDAO();
+        vmsDAO = daoFactory.getVmInfoDAO();
 
-        this.connectedVmText = new ChangeableText("");
-        this.connectedAgentText = new ChangeableText("");
+        this.totalVmsText = new ChangeableText("");
+        this.totalHostsText = new ChangeableText("");
 
         backgroundUpdateTimer = ApplicationContext.getInstance().getTimerFactory().createTimer();
         backgroundUpdateTimer.setAction(new Runnable() {
             
             @Override
             public void run() {
-                connectedVmText.setText(String.valueOf(vmInfoCollection.getCount()));
-                connectedAgentText.setText(String.valueOf(agentConfigCollection.getCount()));
+                totalVmsText.setText(String.valueOf(vmsDAO.getCount()));
+                totalHostsText.setText(String.valueOf(hostsDAO.getCount()));
             }
         });
         backgroundUpdateTimer.setInitialDelay(0);
@@ -89,13 +93,13 @@
     }
 
     @Override
-    public ChangeableText getTotalConnectedVms() {
-        return connectedVmText;
+    public ChangeableText getTotalMonitoredVms() {
+        return totalVmsText;
     }
 
     @Override
-    public ChangeableText getTotalConnectedAgents() {
-        return connectedAgentText;
+    public ChangeableText getTotalMonitoredHosts() {
+        return totalHostsText;
     }
 
     @Override
--- a/client/src/main/java/com/redhat/thermostat/client/UiFacadeFactoryImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/UiFacadeFactoryImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -38,18 +38,10 @@
 
 import com.redhat.thermostat.client.ui.MainWindow;
 import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.MongoConnection;
 import com.redhat.thermostat.common.dao.VmRef;
 
 public class UiFacadeFactoryImpl implements UiFacadeFactory {
 
-    // TODO: Eventually, this should disappear and be completely provided by the DAOFactory.
-    private MongoConnection connection;
-
-    public UiFacadeFactoryImpl(MongoConnection connection) {
-        this.connection = connection;
-    }
-
     @Override
     public MainWindowController getMainWindow() {
         MainView mainView = new MainWindow(this);
@@ -58,7 +50,7 @@
 
     @Override
     public SummaryPanelFacade getSummaryPanel() {
-        return new SummaryPanelFacadeImpl(connection.getDB());
+        return new SummaryPanelFacadeImpl();
 
     }
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Wed Apr 04 21:49:29 2012 +0200
@@ -60,13 +60,15 @@
 
     private final HostInfoDAO hostInfoDAO;
     private final CpuStatDAO cpuStatDAO;
+    private final HostRef ref;
 
     public HostCpuController(HostRef ref) {
+        this.ref = ref;
         view = createView();
         view.clearCpuLoadData();
         DAOFactory daos = ApplicationContext.getInstance().getDAOFactory();
-        hostInfoDAO = daos.getHostInfoDAO(ref);
-        cpuStatDAO = daos.getCpuStatDAO(ref);
+        hostInfoDAO = daos.getHostInfoDAO();
+        cpuStatDAO = daos.getCpuStatDAO();
 
         backgroundUpdateTimer = ApplicationContext.getInstance().getTimerFactory().createTimer();
         backgroundUpdateTimer.setAction(new Runnable() {
@@ -85,7 +87,7 @@
 
     // TODO: Consider doing this in a background thread (move to view and use SwingWorker or such).
     private void updateView() {
-        HostInfo hostInfo = hostInfoDAO.getHostInfo();
+        HostInfo hostInfo = hostInfoDAO.getHostInfo(ref);
 
         view.setCpuCount(String.valueOf(hostInfo.getCpuCount()));
         view.setCpuModel(hostInfo.getCpuModel());
@@ -104,7 +106,7 @@
     }
 
     private void doCpuChartUpdate() {
-        List<CpuStat> cpuStats = cpuStatDAO.getLatestCpuStats();
+        List<CpuStat> cpuStats = cpuStatDAO.getLatestCpuStats(ref);
         List<DiscreteTimeData<Double>> result = new ArrayList<DiscreteTimeData<Double>>();
         for (CpuStat stat : cpuStats) {
             result.add(new DiscreteTimeData<Double>(stat.getTimeStamp(), stat.getLoad5()));
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java	Wed Apr 04 21:49:29 2012 +0200
@@ -63,14 +63,16 @@
 
     private final HostInfoDAO hostInfoDAO;
     private final MemoryStatDAO memoryStatDAO;
+    private final HostRef ref;
 
     private final Timer backgroundUpdateTimer;
     private final GraphVisibilityChangeListener listener = new ShowHideGraph();
 
-    public HostMemoryController(HostRef hostRef) {
+    public HostMemoryController(HostRef ref) {
+        this.ref = ref;
         DAOFactory daos = ApplicationContext.getInstance().getDAOFactory();
-        hostInfoDAO = daos.getHostInfoDAO(hostRef);
-        memoryStatDAO = daos.getMemoryStatDAO(hostRef);
+        hostInfoDAO = daos.getHostInfoDAO();
+        memoryStatDAO = daos.getMemoryStatDAO();
 
         view = createView();
 
@@ -95,7 +97,7 @@
         backgroundUpdateTimer.scheduleAtFixedRate(new TimerTask() {
             @Override
             public void run() {
-                view.setTotalMemory(String.valueOf(hostInfoDAO.getHostInfo().getTotalMemory()));
+                view.setTotalMemory(String.valueOf(hostInfoDAO.getHostInfo(ref).getTotalMemory()));
                 doMemoryChartUpdate();
             }
 
@@ -127,7 +129,7 @@
         List<DiscreteTimeData<? extends Number>> swapTotal = new LinkedList<>();
         List<DiscreteTimeData<? extends Number>> swapFree = new LinkedList<>();
         
-        for (MemoryStat stat : memoryStatDAO.getLatestMemoryStats()) {
+        for (MemoryStat stat : memoryStatDAO.getLatestMemoryStats(ref)) {
             long timeStamp = stat.getTimeStamp();
             memFree.add(new DiscreteTimeData<Long>(timeStamp, stat.getFree()));
             memTotal.add(new DiscreteTimeData<Long>(timeStamp, stat.getTotal()));
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewController.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewController.java	Wed Apr 04 21:49:29 2012 +0200
@@ -66,7 +66,7 @@
 
     private static final Logger logger = LoggingUtils.getLogger(HostOverviewController.class);
 
-    private final HostRef hostRef;
+    private final HostRef ref;
     private final HostInfoDAO hostInfoDAO;
     private final NetworkInterfaceInfoDAO networkInfoDAO;
 
@@ -75,10 +75,10 @@
     private final HostOverviewView view;
 
     public HostOverviewController(HostRef ref) {
-        this.hostRef = ref;
+        this.ref = ref;
         DAOFactory df = ApplicationContext.getInstance().getDAOFactory();
-        hostInfoDAO = df.getHostInfoDAO(hostRef);
-        networkInfoDAO = df.getNetworkInterfaceInfoDAO(hostRef);
+        hostInfoDAO = df.getHostInfoDAO();
+        networkInfoDAO = df.getNetworkInterfaceInfoDAO();
 
         final Vector<String> networkTableColumnVector;
         networkTableColumnVector = new Vector<String>();
@@ -104,7 +104,7 @@
 
         @Override
         protected List<NetworkInterfaceInfo> doInBackground() throws Exception {
-            return networkInfoDAO.getNetworkInterfaces();
+            return networkInfoDAO.getNetworkInterfaces(ref);
         }
 
         @Override
@@ -137,7 +137,7 @@
         backgroundUpdateTimer.scheduleAtFixedRate(new TimerTask() {
             @Override
             public void run() {
-                HostInfo hostInfo = hostInfoDAO.getHostInfo();
+                HostInfo hostInfo = hostInfoDAO.getHostInfo(ref);
                 view.setHostName(hostInfo.getHostname());
                 view.setOsName(hostInfo.getOsName());
                 view.setOsKernel(hostInfo.getOsKernel());
--- a/client/src/main/java/com/redhat/thermostat/client/ui/SummaryPanel.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/SummaryPanel.java	Wed Apr 04 21:49:29 2012 +0200
@@ -70,9 +70,9 @@
         Section summarySection = new Section(localize(LocaleResources.HOME_PANEL_SECTION_SUMMARY));
         sections.add(summarySection);
 
-        entry = new TableEntry(localize(LocaleResources.HOME_PANEL_TOTAL_MACHINES), this.facade.getTotalConnectedAgents());
+        entry = new TableEntry(localize(LocaleResources.HOME_PANEL_TOTAL_MACHINES), this.facade.getTotalMonitoredHosts());
         summarySection.add(entry);
-        entry = new TableEntry(localize(LocaleResources.HOME_PANEL_TOTAL_JVMS), this.facade.getTotalConnectedVms());
+        entry = new TableEntry(localize(LocaleResources.HOME_PANEL_TOTAL_JVMS), this.facade.getTotalMonitoredVms());
         summarySection.add(entry);
 
         SimpleTable simpleTable = new SimpleTable();
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatController.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatController.java	Wed Apr 04 21:49:29 2012 +0200
@@ -55,10 +55,10 @@
     private class UpdateChartData extends TimerTask {
         @Override
         public void run() {
-            List<VmClassStat> latestClassStats = dao.getLatestClassStats();
+            List<VmClassStat> latestClassStats = dao.getLatestClassStats(ref);
             List<DiscreteTimeData<Long>> timeData = new ArrayList<>();
             for (VmClassStat stat : latestClassStats) {
-                timeData.add(new DiscreteTimeData<Long>(stat.getTimestamp(), stat.getLoadedClasses()));
+                timeData.add(new DiscreteTimeData<Long>(stat.getTimeStamp(), stat.getLoadedClasses()));
             }
             classesView.addClassCount(timeData);
         }
@@ -66,14 +66,15 @@
     }
 
     private VmClassStatView classesView;
+    private VmRef ref;
+    private VmClassStatDAO dao;
 
     // TODO: Use application wide ScheduledExecutorService thread pool.
     private Timer timer;
 
-    private VmClassStatDAO dao;
-
     public VmClassStatController(VmRef ref) {
-        dao = ApplicationContext.getInstance().getDAOFactory().getVmClassStatsDAO(ref);
+        this.ref = ref;
+        dao = ApplicationContext.getInstance().getDAOFactory().getVmClassStatsDAO();
         classesView = createView();
     }
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Wed Apr 04 21:49:29 2012 +0200
@@ -52,13 +52,15 @@
 
 public class VmCpuController implements AsyncUiFacade {
 
+    private final VmRef ref;
     private final VmCpuStatDAO dao;
     private final VmCpuView view;
 
     private final Timer timer = new Timer();
 
     public VmCpuController(VmRef ref) {
-        dao = ApplicationContext.getInstance().getDAOFactory().getVmCpuStatDAO(ref);
+        this.ref = ref;
+        dao = ApplicationContext.getInstance().getDAOFactory().getVmCpuStatDAO();
         view = createView();
     }
 
@@ -79,7 +81,7 @@
     }
 
     private void doUpdateVmCpuCharts() {
-        List<VmCpuStat> stats = dao.getLatestVmCpuStats();
+        List<VmCpuStat> stats = dao.getLatestVmCpuStats(ref);
         List<DiscreteTimeData<? extends Number>> toDisplay = new ArrayList<>(stats.size());
         for (VmCpuStat stat: stats) {
             DiscreteTimeData<? extends Number> data =
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Wed Apr 04 21:49:29 2012 +0200
@@ -63,7 +63,7 @@
 
 public class VmGcController implements AsyncUiFacade {
 
-    private final VmRef vmRef;
+    private final VmRef ref;
     private final VmGcView view;
 
     private final VmGcStatDAO gcDao;
@@ -74,12 +74,12 @@
     private final Timer timer = new Timer();
 
     public VmGcController(VmRef ref) {
-        this.vmRef = ref;
+        this.ref = ref;
         this.view = createView();
 
         DAOFactory df = ApplicationContext.getInstance().getDAOFactory();
-        gcDao = df.getVmGcStatDAO(vmRef);
-        memDao = df.getVmMemoryStatDAO(vmRef);
+        gcDao = df.getVmGcStatDAO();
+        memDao = df.getVmMemoryStatDAO();
     }
 
     protected VmGcView createView() {
@@ -114,7 +114,7 @@
 
     private void doUpdateCollectorData() {
         Map<String, List<DiscreteTimeData<? extends Number>>> dataToAdd = new HashMap<>();
-        for (VmGcStat stat : gcDao.getLatestVmGcStats()) {
+        for (VmGcStat stat : gcDao.getLatestVmGcStats(ref)) {
             double walltime = 1.0E-6 * stat.getWallTime();
             String collector = stat.getCollectorName();
             List<DiscreteTimeData<? extends Number>> data = dataToAdd.get(collector);
@@ -135,7 +135,7 @@
     }
 
     public String getCollectorGeneration(String collectorName) {
-        VmMemoryStat info = memDao.getLatestMemoryStat();
+        VmMemoryStat info = memDao.getLatestMemoryStat(ref);
 
         for (Generation g: info.getGenerations()) {
             if (g.collector.equals(collectorName)) {
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryController.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryController.java	Wed Apr 04 21:49:29 2012 +0200
@@ -52,15 +52,15 @@
 
 public class VmMemoryController implements AsyncUiFacade {
 
-    private final VmRef vmRef;
+    private final VmRef ref;
     private final VmMemoryView view;
     private final VmMemoryStatDAO dao;
 
     private final Timer timer = new Timer();
 
-    public VmMemoryController(VmRef vmRef) {
-        this.vmRef = vmRef;
-        dao = ApplicationContext.getInstance().getDAOFactory().getVmMemoryStatDAO(this.vmRef);
+    public VmMemoryController(VmRef ref) {
+        this.ref = ref;
+        dao = ApplicationContext.getInstance().getDAOFactory().getVmMemoryStatDAO();
         view = createView();
     }
 
@@ -69,7 +69,7 @@
         timer.scheduleAtFixedRate(new TimerTask() {
             @Override
             public void run() {
-                VmMemoryStat info = dao.getLatestMemoryStat();
+                VmMemoryStat info = dao.getLatestMemoryStat(ref);
                 List<Generation> generations = info.getGenerations();
                 for (Generation generation: generations) {
                     List<Space> spaces = generation.spaces;
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewController.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewController.java	Wed Apr 04 21:49:29 2012 +0200
@@ -54,7 +54,7 @@
 
 public class VmOverviewController implements AsyncUiFacade {
 
-    private final VmRef vmRef;
+    private final VmRef ref;
     private final VmInfoDAO dao;
     private final DateFormat vmRunningTimeFormat;
 
@@ -63,10 +63,10 @@
     private final VmOverviewView view;
 
     public VmOverviewController(VmRef vmRef) {
-        this.vmRef = vmRef;
+        this.ref = vmRef;
         this.view = createView();
 
-        dao = ApplicationContext.getInstance().getDAOFactory().getVmInfoDAO(this.vmRef);
+        dao = ApplicationContext.getInstance().getDAOFactory().getVmInfoDAO();
 
         vmRunningTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.FULL);
         timer = new Timer();
@@ -78,7 +78,7 @@
 
             @Override
             public void run() {
-                VmInfo info = dao.getVmInfo();
+                VmInfo info = dao.getVmInfo(ref);
                 view.setVmPid(((Integer) info.getVmPid()).toString());
                 long actualStartTime = info.getStartTimeStamp();
                 view.setVmStartTimeStamp(vmRunningTimeFormat.format(new Date(actualStartTime)));
--- a/client/src/test/java/com/redhat/thermostat/client/MainWindowControllerImplTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/test/java/com/redhat/thermostat/client/MainWindowControllerImplTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -61,10 +61,10 @@
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
 import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.HostRefDAO;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
 import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.dao.VmRefDAO;
 
 public class MainWindowControllerImplTest {
 
@@ -76,8 +76,8 @@
 
     private Timer mainWindowTimer;
 
-    private HostRefDAO mockHostRefDAO;
-    private VmRefDAO mockVmRefDAO;
+    private HostInfoDAO mockHostsDAO;
+    private VmInfoDAO mockVmsDAO;
 
     @Before
     public void setUp() {
@@ -98,13 +98,13 @@
     }
 
     private void setupDAOs() {
-        mockHostRefDAO = mock(HostRefDAO.class);
+        mockHostsDAO = mock(HostInfoDAO.class);
 
-        mockVmRefDAO = mock(VmRefDAO.class);
+        mockVmsDAO = mock(VmInfoDAO.class);
 
         DAOFactory daoFactory = mock(DAOFactory.class);
-        when(daoFactory.getHostRefDAO()).thenReturn(mockHostRefDAO);
-        when(daoFactory.getVmRefDAO()).thenReturn(mockVmRefDAO);
+        when(daoFactory.getHostInfoDAO()).thenReturn(mockHostsDAO);
+        when(daoFactory.getVmInfoDAO()).thenReturn(mockVmsDAO);
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
 
     }
@@ -113,8 +113,8 @@
     public void tearDown() {
         view = null;
         controller = null;
-        mockHostRefDAO = null;
-        mockVmRefDAO = null;
+        mockHostsDAO = null;
+        mockVmsDAO = null;
         l = null;
         ApplicationContextUtil.resetApplicationContext();
     }
@@ -157,7 +157,7 @@
         expectedHosts.add(new HostRef("123", "fluffhost1"));
         expectedHosts.add(new HostRef("456", "fluffhost2"));
 
-        when(mockHostRefDAO.getHosts()).thenReturn(expectedHosts);
+        when(mockHostsDAO.getHosts()).thenReturn(expectedHosts);
 
         controller.doUpdateTreeAsync();
 
@@ -177,7 +177,7 @@
         expectedVMs.add(new VmRef(host, 123, "vm1"));
         expectedVMs.add(new VmRef(host, 456, "vm2"));
 
-        when(mockVmRefDAO.getVMs(any(HostRef.class))).thenReturn(expectedVMs);
+        when(mockVmsDAO.getVMs(any(HostRef.class))).thenReturn(expectedVMs);
 
         controller.doUpdateTreeAsync();
 
--- a/client/src/test/java/com/redhat/thermostat/client/SummaryPanelFacadeImplTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/test/java/com/redhat/thermostat/client/SummaryPanelFacadeImplTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -47,12 +47,15 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import com.mongodb.DB;
 import com.redhat.thermostat.client.appctx.ApplicationContext;
 import com.redhat.thermostat.client.appctx.ApplicationContextUtil;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.MongoDAOFactory;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
 
 public class SummaryPanelFacadeImplTest {
 
@@ -64,7 +67,17 @@
         timer = mock(Timer.class);
         TimerFactory timerFactory = mock(TimerFactory.class);
         when(timerFactory.createTimer()).thenReturn(timer);
-        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+        ApplicationContext ctx = ApplicationContext.getInstance();
+        ctx.setTimerFactory(timerFactory);
+
+        HostInfoDAO hDAO = mock(HostInfoDAO.class);
+        VmInfoDAO vDAO = mock(VmInfoDAO.class);
+
+        DAOFactory daoFactory = mock(MongoDAOFactory.class);
+        when(daoFactory.getHostInfoDAO()).thenReturn(hDAO);
+        when(daoFactory.getVmInfoDAO()).thenReturn(vDAO);
+
+        ctx.setDAOFactory(daoFactory);
     }
 
     @After
@@ -76,9 +89,7 @@
     @Test
     public void testTimer() {
 
-        DB db = mock(DB.class);
-
-        SummaryPanelFacadeImpl summaryPanelCtrl = new SummaryPanelFacadeImpl(db);
+        SummaryPanelFacadeImpl summaryPanelCtrl = new SummaryPanelFacadeImpl();
         summaryPanelCtrl.start();
 
         verify(timer).setAction(isNotNull(Runnable.class));
--- a/client/src/test/java/com/redhat/thermostat/client/VmClassStatControllerTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/test/java/com/redhat/thermostat/client/VmClassStatControllerTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -66,10 +66,10 @@
         stats.add(stat1);
 
         VmClassStatDAO vmClassStatDAO = mock(VmClassStatDAO.class);
-        when(vmClassStatDAO.getLatestClassStats()).thenReturn(stats).thenReturn(new ArrayList<VmClassStat>());
+        when(vmClassStatDAO.getLatestClassStats(any(VmRef.class))).thenReturn(stats).thenReturn(new ArrayList<VmClassStat>());
 
         DAOFactory daoFactory = mock(MongoDAOFactory.class);
-        when(daoFactory.getVmClassStatsDAO(any(VmRef.class))).thenReturn(vmClassStatDAO);
+        when(daoFactory.getVmClassStatsDAO()).thenReturn(vmClassStatDAO);
 
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
         VmRef ref = mock(VmRef.class);
--- a/client/src/test/java/com/redhat/thermostat/client/appctx/ApplicationContextUtil.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/test/java/com/redhat/thermostat/client/appctx/ApplicationContextUtil.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,6 +36,8 @@
 
 package com.redhat.thermostat.client.appctx;
 
+import com.redhat.thermostat.client.appctx.ApplicationContext;
+
 public class ApplicationContextUtil {
 
     /**
--- a/client/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -93,16 +93,16 @@
         // Setup DAOs.
         HostInfo hostInfo = new HostInfo("fluffhost1", "fluffOs1", "fluffKernel1", "fluffCpu1", 12345, 98765);
         HostInfoDAO hostInfoDAO = mock(HostInfoDAO.class);
-        when(hostInfoDAO.getHostInfo()).thenReturn(hostInfo);
+        when(hostInfoDAO.getHostInfo(any(HostRef.class))).thenReturn(hostInfo);
 
         CpuStat cpuStat1 = new CpuStat(1l, 10.0, 20.0, 30.0);
         CpuStat cpuStat2 = new CpuStat(2l, 15.0, 25.0, 35.0);
         CpuStatDAO cpuStatDAO = mock(CpuStatDAO.class);
-        when(cpuStatDAO.getLatestCpuStats()).thenReturn(Arrays.asList(cpuStat1, cpuStat2));
+        when(cpuStatDAO.getLatestCpuStats(any(HostRef.class))).thenReturn(Arrays.asList(cpuStat1, cpuStat2));
 
         DAOFactory daoFactory = mock(DAOFactory.class);
-        when(daoFactory.getHostInfoDAO(any(HostRef.class))).thenReturn(hostInfoDAO);
-        when(daoFactory.getCpuStatDAO(any(HostRef.class))).thenReturn(cpuStatDAO);
+        when(daoFactory.getHostInfoDAO()).thenReturn(hostInfoDAO);
+        when(daoFactory.getCpuStatDAO()).thenReturn(cpuStatDAO);
 
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
 
--- a/client/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -62,17 +62,17 @@
     public void testUpdate() {
         HostInfo hostInfo = new HostInfo("someHost", "someOS", "linux_0.0.1", "lreally_fast_cpu", 2, 1024);
         HostInfoDAO hostInfoDAO = mock(HostInfoDAO.class);
-        when(hostInfoDAO.getHostInfo()).thenReturn(hostInfo);
+        when(hostInfoDAO.getHostInfo(any(HostRef.class))).thenReturn(hostInfo);
 
         MemoryStat memoryStat = new MemoryStat(1, 2, 3, 4, 5, 6, 7, 8);
         List<MemoryStat> memoryStats = new LinkedList<>();
         memoryStats.add(memoryStat);
         MemoryStatDAO memoryStatDAO = mock(MemoryStatDAO.class);
-        when(memoryStatDAO.getLatestMemoryStats()).thenReturn(memoryStats);
+        when(memoryStatDAO.getLatestMemoryStats(any(HostRef.class))).thenReturn(memoryStats);
 
         DAOFactory daoFactory = mock(MongoDAOFactory.class);
-        when(daoFactory.getHostInfoDAO(any(HostRef.class))).thenReturn(hostInfoDAO);
-        when(daoFactory.getMemoryStatDAO(any(HostRef.class))).thenReturn(memoryStatDAO);
+        when(daoFactory.getHostInfoDAO()).thenReturn(hostInfoDAO);
+        when(daoFactory.getMemoryStatDAO()).thenReturn(memoryStatDAO);
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
 
         HostRef ref = mock(HostRef.class);
--- a/client/src/test/java/com/redhat/thermostat/client/ui/MainWindowTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/MainWindowTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -98,8 +98,8 @@
     public void setUp() {
 
         SummaryPanelFacade summaryPanelFacade = mock(SummaryPanelFacade.class);
-        when(summaryPanelFacade.getTotalConnectedAgents()).thenReturn(new ChangeableText("totalConnectedAgents"));
-        when(summaryPanelFacade.getTotalConnectedVms()).thenReturn(new ChangeableText("connectedVms"));
+        when(summaryPanelFacade.getTotalMonitoredHosts()).thenReturn(new ChangeableText("totalConnectedAgents"));
+        when(summaryPanelFacade.getTotalMonitoredVms()).thenReturn(new ChangeableText("connectedVms"));
 
         UiFacadeFactory uiFacadeFactory = mock(UiFacadeFactory.class);
         when(uiFacadeFactory.getSummaryPanel()).thenReturn(summaryPanelFacade);
--- a/client/src/test/java/com/redhat/thermostat/client/ui/VmCpuControllerTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/VmCpuControllerTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -50,7 +50,7 @@
 import com.redhat.thermostat.client.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.MongoDAOFactory;
-import com.redhat.thermostat.common.dao.VmCpuStatDAOImpl;
+import com.redhat.thermostat.common.dao.VmCpuStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.model.VmCpuStat;
 
@@ -64,11 +64,11 @@
         List<VmCpuStat> stats = new ArrayList<VmCpuStat>();
         stats.add(stat1);
 
-        VmCpuStatDAOImpl vmCpuStatDAO = mock(VmCpuStatDAOImpl.class);
-        when(vmCpuStatDAO.getLatestVmCpuStats()).thenReturn(stats).thenReturn(new ArrayList<VmCpuStat>());
+        VmCpuStatDAO vmCpuStatDAO = mock(VmCpuStatDAO.class);
+        when(vmCpuStatDAO.getLatestVmCpuStats(any(VmRef.class))).thenReturn(stats).thenReturn(new ArrayList<VmCpuStat>());
 
         DAOFactory daoFactory = mock(MongoDAOFactory.class);
-        when(daoFactory.getVmCpuStatDAO(any(VmRef.class))).thenReturn(vmCpuStatDAO);
+        when(daoFactory.getVmCpuStatDAO()).thenReturn(vmCpuStatDAO);
 
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
         VmRef ref = mock(VmRef.class);
--- a/common/src/main/java/com/redhat/thermostat/common/config/ConfigUtils.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/config/ConfigUtils.java	Wed Apr 04 21:49:29 2012 +0200
@@ -94,10 +94,6 @@
         File backendsConfigDir = ConfigUtils.getBackendsBaseDirectory();
         File backendConfig = new File(backendsConfigDir, backendName);
         backendConfig = new File(backendConfig, "backend.properties");
-        if (!backendConfig.exists())
-            throw new InvalidConfigurationException("backends configuration " +
-                                                    "directory doesn't exist: " + 
-                                                    backendConfig);
         return backendConfig;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/Converter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.Pojo;
+import com.redhat.thermostat.common.storage.Chunk;
+
+interface Converter<T extends Pojo> {
+
+    Chunk toChunk(T pojo);
+
+    T fromChunk(Chunk chunk);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/Countable.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+interface Countable {
+
+    public long getCount();
+
+}
--- a/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -40,9 +40,10 @@
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Key;
 
-public class CpuStatConverter {
+public class CpuStatConverter implements Converter<CpuStat> {
 
-    public Chunk cpuStatToChunk(CpuStat cpuStat) {
+    @Override
+    public Chunk toChunk(CpuStat cpuStat) {
         Chunk chunk = new Chunk(CpuStatDAO.cpuStatCategory, false);
         chunk.put(Key.TIMESTAMP, cpuStat.getTimeStamp());
         chunk.put(CpuStatDAO.cpu5LoadKey, cpuStat.getLoad5());
@@ -51,7 +52,8 @@
         return chunk;
     }
 
-    public CpuStat chunkToCpuStat(Chunk chunk) {
+    @Override
+    public CpuStat fromChunk(Chunk chunk) {
         long timestamp = chunk.get(Key.TIMESTAMP);
         double load5 = chunk.get(CpuStatDAO.cpu5LoadKey);
         double load10 = chunk.get(CpuStatDAO.cpu10LoadKey);
--- a/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAO.java	Wed Apr 04 21:49:29 2012 +0200
@@ -42,14 +42,15 @@
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
 
-public interface CpuStatDAO {
+public interface CpuStatDAO extends Countable {
 
     static Key<Double> cpu5LoadKey = new Key<>("5load", false);
     static Key<Double> cpu10LoadKey = new Key<>("10load", false);
     static Key<Double> cpu15LoadKey = new Key<>("15load", false);
 
-    public static final Category cpuStatCategory = new Category("cpu-stats",
-            Key.TIMESTAMP, cpu5LoadKey, cpu10LoadKey, cpu15LoadKey);
+    static final Category cpuStatCategory = new Category("cpu-stats",
+            Key.AGENT_ID, Key.TIMESTAMP, cpu5LoadKey, cpu10LoadKey, cpu15LoadKey);
 
-    public List<CpuStat> getLatestCpuStats();
+    List<CpuStat> getLatestCpuStats(HostRef ref);
+
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,46 +36,37 @@
 
 package com.redhat.thermostat.common.dao;
 
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import com.redhat.thermostat.common.model.CpuStat;
-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;
 
 class CpuStatDAOImpl implements CpuStatDAO {
 
     private Storage storage;
-    private HostRef hostRef;
 
-    private long lastUpdate = Long.MIN_VALUE;
+    private Converter<CpuStat> converter = new CpuStatConverter();;
 
-    public CpuStatDAOImpl(Storage storage, HostRef hostRef) {
+    private Map<HostRef, HostLatestPojoListGetter<CpuStat>> getters = new HashMap<>();
+
+    CpuStatDAOImpl(Storage storage) {
         this.storage = storage;
-        this.hostRef = hostRef;
     }
 
     @Override
-    public List<CpuStat> getLatestCpuStats() {
-        ArrayList<CpuStat> result = new ArrayList<>();
-        Chunk query = new Chunk(CpuStatDAO.cpuStatCategory, false);
-        query.put(Key.AGENT_ID, hostRef.getAgentId());
-        if (lastUpdate != Long.MIN_VALUE) {
-            // TODO once we have an index and the 'column' is of type long, use
-            // a query which can utilize an index. this one doesn't
-            query.put(Key.WHERE, "this.timestamp > " + lastUpdate);
+    public List<CpuStat> getLatestCpuStats(HostRef ref) {
+        HostLatestPojoListGetter<CpuStat> getter = getters.get(ref);
+        if (getter == null) {
+            getter = new HostLatestPojoListGetter<CpuStat>(storage, cpuStatCategory, converter, ref);
+            getters.put(ref, getter);
         }
-        Cursor cursor = storage.findAll(query);
-        CpuStatConverter converter = new CpuStatConverter();
-        while (cursor.hasNext()) {
-            Chunk chunk = cursor.next();
-            CpuStat stat = converter.chunkToCpuStat(chunk);
-            result.add(stat);
-            lastUpdate = Math.max(stat.getTimeStamp(), lastUpdate);
-        }
-        return result;
+        return getter.getLatest();
     }
 
+    @Override
+    public long getCount() {
+        return storage.getCount(cpuStatCategory);
+    }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,37 +36,29 @@
 
 package com.redhat.thermostat.common.dao;
 
-import com.redhat.thermostat.common.storage.Storage;
 
 public interface DAOFactory {
-
-    public Storage getStorage();
-
     /**
      * TODO: This will be replaced by getStorage() as soon as Storage and Connection have been merged.
      */
     public Connection getConnection();
 
-    public VmCpuStatDAO getVmCpuStatDAO(VmRef ref);
+    public HostInfoDAO getHostInfoDAO();
 
-    public VmClassStatDAO getVmClassStatsDAO(VmRef ref);
+    public CpuStatDAO getCpuStatDAO();
 
-    public VmGcStatDAO getVmGcStatDAO(VmRef ref);
+    public MemoryStatDAO getMemoryStatDAO();
 
-    public VmInfoDAO getVmInfoDAO(VmRef ref);
-
-    public VmMemoryStatDAO getVmMemoryStatDAO(VmRef ref);
+    public NetworkInterfaceInfoDAO getNetworkInterfaceInfoDAO();
 
-    public HostInfoDAO getHostInfoDAO(HostRef ref);
+    public VmInfoDAO getVmInfoDAO();
 
-    public CpuStatDAO getCpuStatDAO(HostRef ref);
-
-    public MemoryStatDAO getMemoryStatDAO(HostRef ref);
+    public VmCpuStatDAO getVmCpuStatDAO();
 
-    public NetworkInterfaceInfoDAO getNetworkInterfaceInfoDAO(HostRef ref);
+    public VmMemoryStatDAO getVmMemoryStatDAO();
 
-    public HostRefDAO getHostRefDAO();
+    public VmClassStatDAO getVmClassStatsDAO();
 
-    public VmRefDAO getVmRefDAO();
+    public VmGcStatDAO getVmGcStatDAO();
 
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/HostInfoConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/HostInfoConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -39,9 +39,10 @@
 import com.redhat.thermostat.common.model.HostInfo;
 import com.redhat.thermostat.common.storage.Chunk;
 
-public class HostInfoConverter {
+public class HostInfoConverter implements Converter<HostInfo> {
 
-    public Chunk hostInfoToChunk(HostInfo hostInfo) {
+    @Override
+    public Chunk toChunk(HostInfo hostInfo) {
         Chunk chunk = new Chunk(HostInfoDAO.hostInfoCategory, false);
         chunk.put(HostInfoDAO.hostNameKey, hostInfo.getHostname());
         chunk.put(HostInfoDAO.osNameKey, hostInfo.getOsName());
@@ -52,7 +53,8 @@
         return chunk;
     }
 
-    public HostInfo chunkToHostInfo(Chunk chunk) {
+    @Override
+    public HostInfo fromChunk(Chunk chunk) {
         String hostName = chunk.get(HostInfoDAO.hostNameKey);
         String osName = chunk.get(HostInfoDAO.osNameKey);
         String osKernel = chunk.get(HostInfoDAO.osKernelKey);
--- a/common/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAO.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,11 +36,13 @@
 
 package com.redhat.thermostat.common.dao;
 
+import java.util.Collection;
+
 import com.redhat.thermostat.common.model.HostInfo;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
 
-public interface HostInfoDAO {
+public interface HostInfoDAO extends Countable {
 
     static Key<String> hostNameKey = new Key<>("hostname", true);
     static Key<String> osNameKey = new Key<>("os_name", false);
@@ -49,9 +51,11 @@
     static Key<String> cpuModelKey = new Key<>("cpu_model", false);
     static Key<Long> hostMemoryTotalKey = new Key<>("memory_total", false);
 
-    public static final Category hostInfoCategory = new Category("host-info",
-            hostNameKey, osNameKey, osKernelKey,
+    static final Category hostInfoCategory = new Category("host-info",
+            Key.AGENT_ID, hostNameKey, osNameKey, osKernelKey,
             cpuCountKey, cpuModelKey, hostMemoryTotalKey);
 
-    public HostInfo getHostInfo();
+    HostInfo getHostInfo(HostRef ref);
+
+    Collection<HostRef> getHosts();
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,27 +36,47 @@
 
 package com.redhat.thermostat.common.dao;
 
+import java.util.ArrayList;
+import java.util.Collection;
+
 import com.redhat.thermostat.common.model.HostInfo;
 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;
 
 class HostInfoDAOImpl implements HostInfoDAO {
-    private HostRef ref;
     private Storage storage;
     private HostInfoConverter converter;
 
-    public HostInfoDAOImpl(Storage storage, HostRef hostRef) {
-        ref = hostRef;
+    public HostInfoDAOImpl(Storage storage) {
         this.storage = storage;
         converter = new HostInfoConverter();
     }
 
     @Override
-    public HostInfo getHostInfo() {
-        Chunk query = new Chunk(HostInfoDAO.hostInfoCategory, false);
+    public HostInfo getHostInfo(HostRef ref) {
+        Chunk query = new Chunk(hostInfoCategory, false);
         query.put(Key.AGENT_ID, ref.getAgentId());
         Chunk result = storage.find(query);
-        return result == null ? null : converter.chunkToHostInfo(result);
+        return result == null ? null : converter.fromChunk(result);
+    }
+
+    @Override
+    public Collection<HostRef> getHosts() {
+        Collection<HostRef> hosts = new ArrayList<HostRef>();
+        Cursor hostsCursor = storage.findAllFromCategory(hostInfoCategory);
+        while(hostsCursor.hasNext()) {
+            Chunk hostChunk = hostsCursor.next();
+            String agentId = hostChunk.get(Key.AGENT_ID);
+            String hostName = hostChunk.get(hostNameKey);
+            hosts.add(new HostRef(agentId, hostName));
+        }
+        return hosts;
+    }
+
+    @Override
+    public long getCount() {
+        return storage.getCount(hostInfoCategory);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,101 @@
+/*
+ * 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.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.redhat.thermostat.common.model.TimeStampedPojo;
+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;
+
+class HostLatestPojoListGetter<T extends TimeStampedPojo> implements LatestPojoListGetter<T> {
+
+    private Storage storage;
+    private Category cat;
+    private Converter<T> converter;
+    private HostRef ref;
+
+    private Map<HostRef, Long> lastUpdateTimes = new HashMap<>();
+
+    HostLatestPojoListGetter(Storage storage, Category cat, Converter<T> converter, HostRef ref) {
+        this.storage = storage;
+        this.cat = cat;
+        this.converter = converter;
+        this.ref = ref;
+    }
+
+    @Override
+    public List<T> getLatest() {
+        Chunk query = buildQuery();
+        return getLatest(query);
+    }
+
+    private List<T> getLatest(Chunk query) {
+        // TODO if multiple threads will be using this utility class, there may be some issues
+        // with the updateTimes
+        Long lastUpdate = lastUpdateTimes.get(ref);
+        Cursor cursor = storage.findAll(query);
+        List<T> result = new ArrayList<>();
+        while (cursor.hasNext()) {
+            Chunk chunk = cursor.next();
+            T pojo = converter.fromChunk(chunk);
+            result.add(pojo);
+            lastUpdateTimes.put(ref, Math.max(pojo.getTimeStamp(), lastUpdate));
+        }
+        return result;
+    }
+
+    protected Chunk buildQuery() {
+        Chunk query = new Chunk(cat, false);
+        query.put(Key.AGENT_ID, ref.getAgentId());
+        Long lastUpdate = lastUpdateTimes.get(ref);
+        if (lastUpdate != null) {
+            // TODO once we have an index and the 'column' is of type long, use
+            // a query which can utilize an index. this one doesn't
+            query.put(Key.WHERE, "this.timestamp > " + lastUpdate);
+        } else {
+            lastUpdateTimes.put(ref, Long.MIN_VALUE);
+        }
+        return query;
+    }
+}
--- a/common/src/main/java/com/redhat/thermostat/common/dao/HostRefDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +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.dao;
-
-import java.util.Collection;
-
-import com.redhat.thermostat.common.storage.Category;
-import com.redhat.thermostat.common.storage.Key;
-
-public interface HostRefDAO {
-
-    static final Key<String> agentIdKey = new Key<>("agent-id", false);
-    static final Category agentConfigCategory = new Category("agent-config", agentIdKey);
-
-    Collection<HostRef> getHosts();
-
-}
--- a/common/src/main/java/com/redhat/thermostat/common/dao/HostRefDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +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.dao;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-import com.redhat.thermostat.common.storage.Chunk;
-import com.redhat.thermostat.common.storage.Cursor;
-import com.redhat.thermostat.common.storage.Storage;
-
-class HostRefDAOImpl implements HostRefDAO {
-
-    private Storage storage;
-
-    HostRefDAOImpl(Storage storage) {
-        this.storage = storage;
-    }
-
-    @Override
-    public Collection<HostRef> getHosts() {
-        Collection<HostRef> hosts = new ArrayList<HostRef>();
-        Cursor agentsCursor = storage.findAllFromCategory(agentConfigCategory);
-        while (agentsCursor.hasNext()) {
-            Chunk agentConfig = agentsCursor.next();
-            HostRef host = getHostFromAgent(agentConfig);
-            hosts.add(host);
-        }
-        return hosts;
-    }
-
-    private HostRef getHostFromAgent(Chunk agentConfig) {
-        String agentId = agentConfig.get(agentIdKey);
-        Chunk hostQuery = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        hostQuery.put(agentIdKey, agentId);
-        Chunk host = storage.find(hostQuery);
-        String hostname = host.get(HostInfoDAO.hostNameKey);
-        return new HostRef(agentId, hostname);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/LatestPojoListGetter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,45 @@
+/*
+ * 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.Pojo;
+
+interface LatestPojoListGetter<T extends Pojo> {
+    List<T> getLatest();
+}
--- a/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -40,9 +40,10 @@
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Key;
 
-public class MemoryStatConverter {
+public class MemoryStatConverter implements Converter<MemoryStat> {
 
-    public Chunk memoryStatToChunk(MemoryStat mem) {
+    @Override
+    public Chunk toChunk(MemoryStat mem) {
         Chunk chunk = new Chunk(MemoryStatDAO.memoryStatCategory, false);
         chunk.put(Key.TIMESTAMP, mem.getTimeStamp());
         chunk.put(MemoryStatDAO.memoryTotalKey, mem.getTotal());
@@ -55,7 +56,8 @@
         return chunk;
     }
 
-    public MemoryStat chunkToMemoryStat(Chunk chunk) {
+    @Override
+    public MemoryStat fromChunk(Chunk chunk) {
         long timestamp = chunk.get(Key.TIMESTAMP);
         long total = chunk.get(MemoryStatDAO.memoryTotalKey);
         long free = chunk.get(MemoryStatDAO.memoryFreeKey);
--- a/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAO.java	Wed Apr 04 21:49:29 2012 +0200
@@ -42,7 +42,7 @@
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
 
-public interface MemoryStatDAO {
+public interface MemoryStatDAO extends Countable {
 
     static Key<Long> memoryTotalKey = new Key<>("total", false);
     static Key<Long> memoryFreeKey = new Key<>("free", false);
@@ -52,9 +52,9 @@
     static Key<Long> memorySwapFreeKey = new Key<>("swap-free", false);
     static Key<Long> memoryCommitLimitKey = new Key<>("commit-limit", false);
 
-    public static final Category memoryStatCategory = new Category("memory-stats",
-            Key.TIMESTAMP, memoryTotalKey, memoryFreeKey, memoryBuffersKey,
+    static final Category memoryStatCategory = new Category("memory-stats",
+            Key.AGENT_ID, Key.TIMESTAMP, memoryTotalKey, memoryFreeKey, memoryBuffersKey,
             memoryCachedKey, memorySwapTotalKey, memorySwapFreeKey, memoryCommitLimitKey);
 
-    public List<MemoryStat> getLatestMemoryStats();
+    public List<MemoryStat> getLatestMemoryStats(HostRef ref);
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,45 +36,37 @@
 
 package com.redhat.thermostat.common.dao;
 
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import com.redhat.thermostat.common.model.MemoryStat;
-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;
 
 class MemoryStatDAOImpl implements MemoryStatDAO {
 
     private Storage storage;
-    private HostRef hostRef;
 
-    private long lastUpdate = Long.MIN_VALUE;
+    private Converter<MemoryStat> converter = new MemoryStatConverter();
 
-    public MemoryStatDAOImpl(Storage storage, HostRef hostRef) {
+    private Map<HostRef, HostLatestPojoListGetter<MemoryStat>> getters = new HashMap<>();
+
+    MemoryStatDAOImpl(Storage storage) {
         this.storage = storage;
-        this.hostRef = hostRef;
     }
 
     @Override
-    public List<MemoryStat> getLatestMemoryStats() {
-        Chunk query = new Chunk(MemoryStatDAO.memoryStatCategory, false);
-        query.put(Key.AGENT_ID, hostRef.getAgentId());
-        if (lastUpdate != Long.MIN_VALUE) {
-            // TODO once we have an index and the 'column' is of type long, use
-            // a query which can utilize an index. this one doesn't
-            query.put(Key.WHERE, "this.timestamp > " + lastUpdate);
+    public List<MemoryStat> getLatestMemoryStats(HostRef ref) {
+        HostLatestPojoListGetter<MemoryStat> getter = getters.get(ref);
+        if (getter == null) {
+            getter = new HostLatestPojoListGetter<MemoryStat>(storage, memoryStatCategory, converter, ref);
+            getters.put(ref, getter);
         }
-        Cursor cursor = storage.findAll(query);
-        MemoryStatConverter converter = new MemoryStatConverter();
-        List<MemoryStat> result = new ArrayList<>();
-        while (cursor.hasNext()) {
-            Chunk chunk = cursor.next();
-            MemoryStat stat = converter.chunkToMemoryStat(chunk);
-            result.add(stat);
-            lastUpdate = Math.max(stat.getTimeStamp(), lastUpdate);
-        }
-        return result;
+        return getter.getLatest();
+    }
+
+    @Override
+    public long getCount() {
+        return storage.getCount(memoryStatCategory);
     }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java	Wed Apr 04 21:49:29 2012 +0200
@@ -43,13 +43,14 @@
 
 public class MongoDAOFactory implements DAOFactory {
 
-    private Storage storage;
-    private Connection connection;
+    private final Connection connection;
+    private final Storage storage;
 
     public MongoDAOFactory(ConnectionProvider connProv) {
 
         connection = connProv.createConnection();
         final MongoStorage mongoStorage = new MongoStorage(connection);
+        storage = mongoStorage;
         connection.addListener(new ConnectionListener() {
 
             @Override
@@ -59,22 +60,6 @@
                 }
             }
         });
-        storage = mongoStorage;
-    }
-
-    @Override
-    public Storage getStorage() {
-        return storage;
-    }
-
-    @Override
-    public VmCpuStatDAO getVmCpuStatDAO(VmRef ref) {
-        return new VmCpuStatDAOImpl(storage, ref);
-    }
-
-    @Override
-    public VmClassStatDAO getVmClassStatsDAO(VmRef ref) {
-        return new VmClassStatDAOImpl(storage, ref);
     }
 
     @Override
@@ -83,46 +68,46 @@
     }
 
     @Override
-    public HostInfoDAO getHostInfoDAO(HostRef ref) {
-        return new HostInfoDAOImpl(storage, ref);
+    public HostInfoDAO getHostInfoDAO() {
+        return new HostInfoDAOImpl(storage);
     }
 
     @Override
-    public CpuStatDAO getCpuStatDAO(HostRef ref) {
-        return new CpuStatDAOImpl(storage, ref);
+    public CpuStatDAO getCpuStatDAO() {
+        return new CpuStatDAOImpl(storage);
     }
 
     @Override
-    public MemoryStatDAO getMemoryStatDAO(HostRef ref) {
-        return new MemoryStatDAOImpl(storage, ref);
+    public MemoryStatDAO getMemoryStatDAO() {
+        return new MemoryStatDAOImpl(storage);
     }
 
     @Override
-    public NetworkInterfaceInfoDAO getNetworkInterfaceInfoDAO(HostRef ref) {
-        return new NetworkInterfaceInfoDAOImpl(storage, ref);
+    public NetworkInterfaceInfoDAO getNetworkInterfaceInfoDAO() {
+        return new NetworkInterfaceInfoDAOImpl(storage);
     }
 
     @Override
-    public VmGcStatDAO getVmGcStatDAO(VmRef ref) {
-        return new VmGcStatDAOImpl(storage, ref);
+    public VmInfoDAO getVmInfoDAO() {
+        return new VmInfoDAOImpl(storage);
     }
 
     @Override
-    public VmInfoDAO getVmInfoDAO(VmRef ref) {
-        return new VmInfoDAOImpl(storage, ref);
+    public VmCpuStatDAO getVmCpuStatDAO() {
+        return new VmCpuStatDAOImpl(storage);
     }
 
-    public VmMemoryStatDAO getVmMemoryStatDAO(VmRef ref) {
-        return new VmMemoryStatDAOImpl(storage, ref);
+    public VmMemoryStatDAO getVmMemoryStatDAO() {
+        return new VmMemoryStatDAOImpl(storage);
     }
 
     @Override
-    public HostRefDAO getHostRefDAO() {
-        return new HostRefDAOImpl(storage);
+    public VmClassStatDAO getVmClassStatsDAO() {
+        return new VmClassStatDAOImpl(storage);
     }
 
     @Override
-    public VmRefDAO getVmRefDAO() {
-        return new VmRefDAOImpl(storage);
+    public VmGcStatDAO getVmGcStatDAO() {
+        return new VmGcStatDAOImpl(storage);
     }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -39,9 +39,10 @@
 import com.redhat.thermostat.common.model.NetworkInterfaceInfo;
 import com.redhat.thermostat.common.storage.Chunk;
 
-public class NetworkInterfaceInfoConverter {
+public class NetworkInterfaceInfoConverter implements Converter<NetworkInterfaceInfo> {
 
-    public Chunk networkInfoToChunk(NetworkInterfaceInfo info) {
+    @Override
+    public Chunk toChunk(NetworkInterfaceInfo info) {
         Chunk chunk = new Chunk(NetworkInterfaceInfoDAO.networkInfoCategory, true);
         chunk.put(NetworkInterfaceInfoDAO.ifaceKey, info.getInterfaceName());
         String ip4 = info.getIp4Addr();
@@ -55,7 +56,8 @@
         return chunk;
     }
 
-    public NetworkInterfaceInfo chunkToNetworkInfo(Chunk chunk) {
+    @Override
+    public NetworkInterfaceInfo fromChunk(Chunk chunk) {
         NetworkInterfaceInfo info = new NetworkInterfaceInfo(chunk.get(NetworkInterfaceInfoDAO.ifaceKey));
         info.setIp4Addr(chunk.get(NetworkInterfaceInfoDAO.ip4AddrKey));
         info.setIp6Addr(chunk.get(NetworkInterfaceInfoDAO.ip6AddrKey));
--- a/common/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAO.java	Wed Apr 04 21:49:29 2012 +0200
@@ -48,8 +48,8 @@
     static Key<String> ip4AddrKey = new Key<>("ipv4addr", false);
     static Key<String> ip6AddrKey = new Key<>("ipv6addr", false);
 
-    public static final Category networkInfoCategory = new Category("network-info",
-            Key.TIMESTAMP, ifaceKey, ip4AddrKey, ip6AddrKey);
+    static final Category networkInfoCategory = new Category("network-info",
+            Key.AGENT_ID, Key.TIMESTAMP, ifaceKey, ip4AddrKey, ip6AddrKey);
 
-    public List<NetworkInterfaceInfo> getNetworkInterfaces();
+    public List<NetworkInterfaceInfo> getNetworkInterfaces(HostRef ref);
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -45,19 +45,17 @@
 import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.storage.Storage;
 
-public class NetworkInterfaceInfoDAOImpl implements NetworkInterfaceInfoDAO {
+class NetworkInterfaceInfoDAOImpl implements NetworkInterfaceInfoDAO {
 
     private Storage storage;
-    private HostRef ref;
 
-    public NetworkInterfaceInfoDAOImpl(Storage storage, HostRef ref) {
+    NetworkInterfaceInfoDAOImpl(Storage storage) {
         this.storage = storage;
-        this.ref = ref;
     }
 
     @Override
-    public List<NetworkInterfaceInfo> getNetworkInterfaces() {
-        Chunk query = new Chunk(NetworkInterfaceInfoDAO.networkInfoCategory, false);
+    public List<NetworkInterfaceInfo> getNetworkInterfaces(HostRef ref) {
+        Chunk query = new Chunk(networkInfoCategory, false);
         query.put(Key.AGENT_ID, ref.getAgentId());
 
         Cursor cursor = storage.findAll(query);
@@ -65,7 +63,7 @@
         List<NetworkInterfaceInfo> result = new ArrayList<>();
         while (cursor.hasNext()) {
             Chunk chunk = cursor.next();
-            NetworkInterfaceInfo stat = converter.chunkToNetworkInfo(chunk);
+            NetworkInterfaceInfo stat = converter.fromChunk(chunk);
             result.add(stat);
         }
         return result;
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -40,20 +40,22 @@
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Key;
 
-public class VmClassStatConverter {
+public class VmClassStatConverter implements Converter<VmClassStat> {
 
-    public Chunk vmClassStatToChunk(VmClassStat vmClassStat) {
+    @Override
+    public Chunk toChunk(VmClassStat vmClassStat) {
         Chunk chunk = new Chunk(VmClassStatDAO.vmClassStatsCategory, false);
-        chunk.put(VmClassStatDAO.vmIdKey, vmClassStat.getVmId());
-        chunk.put(Key.TIMESTAMP, vmClassStat.getTimestamp());
+        chunk.put(Key.VM_ID, vmClassStat.getVmId());
+        chunk.put(Key.TIMESTAMP, vmClassStat.getTimeStamp());
         chunk.put(VmClassStatDAO.loadedClassesKey, vmClassStat.getLoadedClasses());
         return chunk;
     }
 
-    public VmClassStat chunkToVmClassStat(Chunk chunk) {
+    @Override
+    public VmClassStat fromChunk(Chunk chunk) {
         long timestamp = chunk.get(Key.TIMESTAMP);
         long loadedClasses = chunk.get(VmClassStatDAO.loadedClassesKey);
-        int vmId = chunk.get(VmClassStatDAO.vmIdKey);
+        int vmId = chunk.get(Key.VM_ID);
         return new VmClassStat(vmId, timestamp, loadedClasses);
     }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAO.java	Wed Apr 04 21:49:29 2012 +0200
@@ -44,12 +44,11 @@
 
 public interface VmClassStatDAO {
 
-    static final Key<Integer> vmIdKey = new Key<>("vm-id", false);
     static final Key<Long> loadedClassesKey = new Key<>("loadedClasses", false);
 
-    public static final Category vmClassStatsCategory = new Category(
-            "vm-class-stats", vmIdKey, Key.TIMESTAMP, loadedClassesKey);
+    static final Category vmClassStatsCategory = new Category(
+            "vm-class-stats", Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, loadedClassesKey);
 
-    public List<VmClassStat> getLatestClassStats();
+    public List<VmClassStat> getLatestClassStats(VmRef ref);
 
 }
\ No newline at end of file
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,47 +36,32 @@
 
 package com.redhat.thermostat.common.dao;
 
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import com.redhat.thermostat.common.model.VmClassStat;
-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;
 
 class VmClassStatDAOImpl implements VmClassStatDAO {
 
-    private VmRef ref;
     private Storage storage;
 
-    private long lastUpdate = Long.MIN_VALUE;
+    private Converter<VmClassStat> converter = new VmClassStatConverter();
 
-    public VmClassStatDAOImpl(Storage storage, VmRef vmRef) {
-        ref = vmRef;
+    private Map<VmRef, VmLatestPojoListGetter<VmClassStat>> getters = new HashMap<>();
+
+    VmClassStatDAOImpl(Storage storage) {
         this.storage = storage;
     }
 
     @Override
-    public List<VmClassStat> getLatestClassStats() {
-        ArrayList<VmClassStat> result = new ArrayList<>();
-        Chunk query = new Chunk(VmClassStatDAO.vmClassStatsCategory, false);
-        query.put(Key.AGENT_ID, ref.getAgent().getAgentId());
-        query.put(VmClassStatDAO.vmIdKey, ref.getId());
-        if (lastUpdate != Long.MIN_VALUE) {
-            // TODO once we have an index and the 'column' is of type long, use
-            // a query which can utilize an index. this one doesn't
-            query.put(Key.WHERE, "this.timestamp > " + lastUpdate);
+    public List<VmClassStat> getLatestClassStats(VmRef ref) {
+        VmLatestPojoListGetter<VmClassStat> getter = getters.get(ref);
+        if (getter == null) {
+            getter = new VmLatestPojoListGetter<VmClassStat>(storage, vmClassStatsCategory, converter, ref);
+            getters.put(ref, getter);
         }
-        Cursor cursor = storage.findAll(query);
-        VmClassStatConverter converter = new VmClassStatConverter();
-        while (cursor.hasNext()) {
-            Chunk current = cursor.next();
-            VmClassStat stat = converter.chunkToVmClassStat(current);
-            result.add(stat);
-            lastUpdate = Math.max(stat.getTimestamp(), lastUpdate);
-        }
-
-        return result;
+        return getter.getLatest();
     }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -40,19 +40,21 @@
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Key;
 
-public class VmCpuStatConverter {
+public class VmCpuStatConverter implements Converter<VmCpuStat> {
 
-    public Chunk vmCpuStatToChunk(VmCpuStat vmCpuStat) {
+    @Override
+    public Chunk toChunk(VmCpuStat vmCpuStat) {
         Chunk chunk = new Chunk(VmCpuStatDAO.vmCpuStatCategory, false);
         chunk.put(Key.TIMESTAMP, vmCpuStat.getTimeStamp());
-        chunk.put(VmCpuStatDAO.vmIdKey, vmCpuStat.getVmId());
+        chunk.put(Key.VM_ID, vmCpuStat.getVmId());
         chunk.put(VmCpuStatDAO.vmCpuLoadKey, vmCpuStat.getCpuLoad());
         return chunk;
     }
 
-    public VmCpuStat chunkToVmCpuStat(Chunk chunk) {
+    @Override
+    public VmCpuStat fromChunk(Chunk chunk) {
         long timestamp = chunk.get(Key.TIMESTAMP);
-        int vmId = chunk.get(VmCpuStatDAO.vmIdKey);
+        int vmId = chunk.get(Key.VM_ID);
         double processorUsage = chunk.get(VmCpuStatDAO.vmCpuLoadKey);
         return new VmCpuStat(timestamp, vmId, processorUsage);
     }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java	Wed Apr 04 21:49:29 2012 +0200
@@ -42,14 +42,13 @@
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
 
-public abstract class VmCpuStatDAO {
+public interface VmCpuStatDAO {
 
-    static final Key<Integer> vmIdKey = new Key<>("vm-id", false);
     static final Key<Double> vmCpuLoadKey = new Key<>("processor-usage", false);
 
-    public static final Category vmCpuStatCategory = new Category("vm-cpu-stats",
-            Key.TIMESTAMP, vmCpuLoadKey, vmIdKey);
+    static final Category vmCpuStatCategory = new Category("vm-cpu-stats",
+            Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, vmCpuLoadKey);
 
-    public abstract List<VmCpuStat> getLatestVmCpuStats();
+    public abstract List<VmCpuStat> getLatestVmCpuStats(VmRef ref);
 
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,47 +36,32 @@
 
 package com.redhat.thermostat.common.dao;
 
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import com.redhat.thermostat.common.model.VmCpuStat;
-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;
 
-public class VmCpuStatDAOImpl extends VmCpuStatDAO {
+class VmCpuStatDAOImpl implements VmCpuStatDAO {
 
     private final Storage storage;
-    private final VmRef vmRef;
 
-    private long lastUpdate = Long.MIN_VALUE;;
+    private Converter<VmCpuStat> converter = new VmCpuStatConverter();
 
-    public VmCpuStatDAOImpl(Storage storage, VmRef vmRef) {
+    private Map<VmRef, VmLatestPojoListGetter<VmCpuStat>> getters = new HashMap<>();
+
+    VmCpuStatDAOImpl(Storage storage) {
         this.storage = storage;
-        this.vmRef = vmRef;
     }
 
     @Override
-    public List<VmCpuStat> getLatestVmCpuStats() {
-        ArrayList<VmCpuStat> result = new ArrayList<>();
-        Chunk query = new Chunk(VmCpuStatDAO.vmCpuStatCategory, false);
-        query.put(Key.AGENT_ID, vmRef.getAgent().getAgentId());
-        query.put(VmCpuStatDAO.vmIdKey, vmRef.getId());
-        if (lastUpdate != Long.MIN_VALUE) {
-            // TODO once we have an index and the 'column' is of type long, use
-            // a query which can utilize an index. this one doesn't
-            query.put(Key.WHERE, "this.timestamp > " + lastUpdate);
+    public List<VmCpuStat> getLatestVmCpuStats(VmRef ref) {
+        VmLatestPojoListGetter<VmCpuStat> getter = getters.get(ref);
+        if (getter == null) {
+            getter = new VmLatestPojoListGetter<VmCpuStat>(storage, vmCpuStatCategory, converter, ref);
+            getters.put(ref, getter);
         }
-        Cursor cursor = storage.findAll(query);
-        while (cursor.hasNext()) {
-            Chunk current = cursor.next();
-            VmCpuStat stat = new VmCpuStatConverter().chunkToVmCpuStat(current);
-            result.add(stat);
-            lastUpdate = Math.max(stat.getTimeStamp(), lastUpdate);
-        }
-
-        return result;
-
+        return getter.getLatest();
     }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmGcStatConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmGcStatConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -40,12 +40,13 @@
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Key;
 
-public class VmGcStatConverter {
+public class VmGcStatConverter implements Converter<VmGcStat> {
 
-    public Chunk vmGcStatToChunk(VmGcStat vmGcStat) {
-        Chunk chunk = new Chunk(VmGcStatDAO.vmGcStatsCategory, false);
+    @Override
+    public Chunk toChunk(VmGcStat vmGcStat) {
+        Chunk chunk = new Chunk(VmGcStatDAO.vmGcStatCategory, false);
 
-        chunk.put(VmGcStatDAO.vmIdKey, vmGcStat.getVmId());
+        chunk.put(Key.VM_ID, vmGcStat.getVmId());
         chunk.put(Key.TIMESTAMP, vmGcStat.getTimeStamp());
         chunk.put(VmGcStatDAO.collectorKey, vmGcStat.getCollectorName());
         chunk.put(VmGcStatDAO.runCountKey, vmGcStat.getRunCount());
@@ -54,8 +55,9 @@
         return chunk;
     }
 
-    public VmGcStat chunkToVmGcStat(Chunk chunk) {
-        int vmId = chunk.get(VmGcStatDAO.vmIdKey);
+    @Override
+    public VmGcStat fromChunk(Chunk chunk) {
+        int vmId = chunk.get(Key.VM_ID);
         long timestamp = chunk.get(Key.TIMESTAMP);
         String collectorName = chunk.get(VmGcStatDAO.collectorKey);
         long runCount = chunk.get(VmGcStatDAO.runCountKey);
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAO.java	Wed Apr 04 21:49:29 2012 +0200
@@ -44,15 +44,14 @@
 
 public interface VmGcStatDAO {
 
-    static final Key<Integer> vmIdKey = new Key<>("vm-id", false);
     static final Key<String> collectorKey = new Key<>("collector", false);
     static final Key<Long> runCountKey = new Key<>("runtime-count", false);
     /** time in microseconds */
     static final Key<Long> wallTimeKey = new Key<>("wall-time", false);
 
-    public static final Category vmGcStatsCategory = new Category("vm-gc-stats",
-            vmIdKey, Key.TIMESTAMP, collectorKey,
+    static final Category vmGcStatCategory = new Category("vm-gc-stats",
+            Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, collectorKey,
             runCountKey, wallTimeKey);
 
-    public List<VmGcStat> getLatestVmGcStats();
+    public List<VmGcStat> getLatestVmGcStats(VmRef ref);
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAOImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,47 +36,33 @@
 
 package com.redhat.thermostat.common.dao;
 
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import com.redhat.thermostat.common.model.VmGcStat;
-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;
 
-public class VmGcStatDAOImpl implements VmGcStatDAO {
+class VmGcStatDAOImpl implements VmGcStatDAO {
 
     private Storage storage;
-    private VmRef ref;
 
-    private long lastUpdate = Long.MIN_VALUE;
+    private Converter<VmGcStat> converter = new VmGcStatConverter();
 
-    public VmGcStatDAOImpl(Storage storage, VmRef ref) {
+    private Map<VmRef, VmLatestPojoListGetter<VmGcStat>> getters = new HashMap<>();
+
+    VmGcStatDAOImpl(Storage storage) {
         this.storage = storage;
-        this.ref = ref;
     }
 
     @Override
-    public List<VmGcStat> getLatestVmGcStats() {
-        List<VmGcStat> result = new ArrayList<>();
-        Chunk query = new Chunk(VmGcStatDAO.vmGcStatsCategory, false);
-        query.put(Key.AGENT_ID, ref.getAgent().getAgentId());
-        query.put(VmGcStatDAO.vmIdKey, ref.getId());
-        if (lastUpdate != Long.MIN_VALUE) {
-            // TODO once we have an index and the 'column' is of type long, use
-            // a query which can utilize an index. this one doesn't
-            query.put(Key.WHERE, "this.timestamp > " + lastUpdate);
+    public List<VmGcStat> getLatestVmGcStats(VmRef ref) {
+        VmLatestPojoListGetter<VmGcStat> getter = getters.get(ref);
+        if (getter == null) {
+            getter = new VmLatestPojoListGetter<VmGcStat>(storage, vmGcStatCategory, converter, ref);
+            getters.put(ref, getter);
         }
-        Cursor cursor = storage.findAll(query);
-        VmGcStatConverter converter = new VmGcStatConverter();
-        while (cursor.hasNext()) {
-            Chunk current = cursor.next();
-            VmGcStat stat = converter.chunkToVmGcStat(current);
-            result.add(stat);
-            lastUpdate = Math.max(stat.getTimeStamp(), lastUpdate);
-        }
-        return result;
+        return getter.getLatest();
     }
 
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmInfoConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmInfoConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -42,9 +42,10 @@
 import com.redhat.thermostat.common.model.VmInfo;
 import com.redhat.thermostat.common.storage.Chunk;
 
-public class VmInfoConverter {
+public class VmInfoConverter implements Converter<VmInfo> {
 
-    public Chunk vmInfoToChunk(VmInfo info) {
+    @Override
+    public Chunk toChunk(VmInfo info) {
         Chunk chunk = new Chunk(VmInfoDAO.vmInfoCategory, true);
 
         chunk.put(VmInfoDAO.vmIdKey, info.getVmId());
@@ -65,7 +66,8 @@
         return chunk;
     }
 
-    public VmInfo chunkToVmInfo(Chunk chunk) {
+    @Override
+    public VmInfo fromChunk(Chunk chunk) {
         int vmId = chunk.get(VmInfoDAO.vmIdKey);
         long startTime = chunk.get(VmInfoDAO.startTimeKey);
         long stopTime = chunk.get(VmInfoDAO.stopTimeKey);
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.common.dao;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -43,10 +44,9 @@
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
 
-public interface VmInfoDAO {
+public interface VmInfoDAO extends Countable {
 
-    // FIXME make it non-public
-    public static final Key<Integer> vmIdKey = new Key<>("vm-id", true);
+    static final Key<Integer> vmIdKey = new Key<>("vm-id", true);
     static final Key<Integer> vmPidKey = new Key<>("vm-pid", false);
     static final Key<String> runtimeVersionKey = new Key<>("runtime-version", false);
     static final Key<String> javaHomeKey = new Key<>("java-home", false);
@@ -60,15 +60,16 @@
     static final Key<Map<String, String>> environmentKey = new Key<>("environment", false);
     static final Key<List<String>> librariesKey = new Key<>("libraries", false);
     static final Key<Long> startTimeKey = new Key<>("start-time", false);
-    // FIXME make it non-public
-    public static final Key<Long> stopTimeKey = new Key<>("stop-time", false);
+    static final Key<Long> stopTimeKey = new Key<>("stop-time", false);
 
-    public static final Category vmInfoCategory = new Category("vm-info",
-            vmIdKey, vmPidKey, runtimeVersionKey, javaHomeKey,
+    static final Category vmInfoCategory = new Category("vm-info",
+            Key.AGENT_ID, vmIdKey, vmPidKey, runtimeVersionKey, javaHomeKey,
             mainClassKey, commandLineKey,
             vmArgumentsKey, vmNameKey, vmInfoKey, vmVersionKey,
             propertiesKey, environmentKey, librariesKey,
             startTimeKey, stopTimeKey);
 
-    public VmInfo getVmInfo();
+    public VmInfo getVmInfo(VmRef ref);
+
+    Collection<VmRef> getVMs(HostRef host);
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,30 +36,70 @@
 
 package com.redhat.thermostat.common.dao;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
 import com.redhat.thermostat.common.model.VmInfo;
 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;
 
-public class VmInfoDAOImpl implements VmInfoDAO {
+class VmInfoDAOImpl implements VmInfoDAO {
 
     private Storage storage;
-    private VmRef ref;
     private VmInfoConverter converter;
 
-    public VmInfoDAOImpl(Storage storage, VmRef ref) {
+    VmInfoDAOImpl(Storage storage) {
         this.storage = storage;
-        this.ref = ref;
         this.converter = new VmInfoConverter();
     }
 
     @Override
-    public VmInfo getVmInfo() {
-        Chunk query = new Chunk(VmInfoDAO.vmInfoCategory, false);
+    public VmInfo getVmInfo(VmRef ref) {
+        Chunk query = new Chunk(vmInfoCategory, false);
         query.put(Key.AGENT_ID, ref.getAgent().getAgentId());
-        query.put(VmInfoDAO.vmIdKey, ref.getId());
+        query.put(vmIdKey, ref.getId());
         Chunk result = storage.find(query);
-        return converter.chunkToVmInfo(result);
+        return converter.fromChunk(result);
+    }
+
+    @Override
+    public Collection<VmRef> getVMs(HostRef host) {
+
+        Chunk query = buildQuery(host);
+        Cursor cursor = storage.findAll(query);
+        return buildVMsFromQuery(cursor, host);
+    }
+
+    private Chunk buildQuery(HostRef host) {
+        Chunk query = new Chunk(vmInfoCategory, false);
+        query.put(Key.AGENT_ID, host.getAgentId());
+        return query;
     }
 
+    private Collection<VmRef> buildVMsFromQuery(Cursor cursor, HostRef host) {
+        List<VmRef> vmRefs = new ArrayList<VmRef>();
+        while (cursor.hasNext()) {
+            Chunk vmChunk = cursor.next();
+            VmRef vm = buildVmRefFromChunk(vmChunk, host);
+            vmRefs.add(vm);
+        }
+
+        return vmRefs;
+    }
+
+    private VmRef buildVmRefFromChunk(Chunk vmChunk, HostRef host) {
+        Integer id = vmChunk.get(vmIdKey);
+        // TODO can we do better than the main class?
+        String mainClass = vmChunk.get(mainClassKey);
+        VmRef ref = new VmRef(host, id, mainClass);
+        return ref;
+    }
+
+    @Override
+    public long getCount() {
+        return storage.getCount(vmInfoCategory);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.TimeStampedPojo;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Storage;
+
+class VmLatestPojoListGetter<T extends TimeStampedPojo> extends HostLatestPojoListGetter<T> {
+
+    private VmRef vmRef;
+
+    VmLatestPojoListGetter(Storage storage, Category cat, Converter<T> converter, VmRef ref) {
+        super(storage, cat, converter, ref.getAgent());
+        vmRef = ref;
+    }
+
+    @Override
+    protected Chunk buildQuery() {
+        Chunk query = super.buildQuery();
+        query.put(Key.VM_ID, vmRef.getId());
+        return query;
+    }
+}
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -39,19 +39,19 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import com.mongodb.DBObject;
 import com.redhat.thermostat.common.model.VmMemoryStat;
 import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
 import com.redhat.thermostat.common.model.VmMemoryStat.Space;
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Key;
 
-public class VmMemoryStatConverter {
+public class VmMemoryStatConverter implements Converter<VmMemoryStat> {
 
-    public Chunk vmMemoryStatToChunk(VmMemoryStat vmMemStat) {
+    @Override
+    public Chunk toChunk(VmMemoryStat vmMemStat) {
         Chunk chunk = new Chunk(VmMemoryStatDAO.vmMemoryStatsCategory, false);
 
-        chunk.put(VmMemoryStatDAO.vmIdKey, vmMemStat.getVmId());
+        chunk.put(Key.VM_ID, vmMemStat.getVmId());
         chunk.put(Key.TIMESTAMP, vmMemStat.getTimeStamp());
 
         Generation newGen = vmMemStat.getGeneration("new");
@@ -98,7 +98,8 @@
         return chunk;
     }
 
-    public VmMemoryStat chunkToVmMemoryStat(Chunk chunk) {
+    @Override
+    public VmMemoryStat fromChunk(Chunk chunk) {
         Space space = null;
         List<Space> spaces = null;
 
@@ -176,6 +177,6 @@
 
         gens.add(permGen);
 
-        return new VmMemoryStat(chunk.get(Key.TIMESTAMP), chunk.get(VmMemoryStatDAO.vmIdKey), gens);
+        return new VmMemoryStat(chunk.get(Key.TIMESTAMP), chunk.get(Key.VM_ID), gens);
     }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAO.java	Wed Apr 04 21:49:29 2012 +0200
@@ -42,8 +42,6 @@
 
 public interface VmMemoryStatDAO {
 
-    static final Key<Integer> vmIdKey = new Key<>("vm-id", false);
-
     static final Key<String> edenGenKey = new Key<>("eden.gen", false);
     static final Key<String> edenCollectorKey = new Key<>("eden.collector", false);
     static final Key<Long> edenCapacityKey = new Key<>("eden.capacity", false);
@@ -74,8 +72,8 @@
     static final Key<Long> permMaxCapacityKey = new Key<>("perm.max-capacity", false);
     static final Key<Long> permUsedKey = new Key<>("perm.used", false);
 
-    public static final Category vmMemoryStatsCategory = new Category("vm-memory-stats",
-            vmIdKey, Key.TIMESTAMP,
+    static final Category vmMemoryStatsCategory = new Category("vm-memory-stats",
+            Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP,
             edenGenKey, edenCollectorKey,
             edenCapacityKey, edenMaxCapacityKey,edenUsedKey,
             s0GenKey, s0CollectorKey, s0CapacityKey,
@@ -87,6 +85,6 @@
             permGenKey, permCollectorKey, permCapacityKey,
             permMaxCapacityKey, permUsedKey);
 
-    public VmMemoryStat getLatestMemoryStat();
+    public VmMemoryStat getLatestMemoryStat(VmRef ref);
 
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOImpl.java	Wed Apr 04 21:49:29 2012 +0200
@@ -42,24 +42,22 @@
 import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.storage.Storage;
 
-public class VmMemoryStatDAOImpl implements VmMemoryStatDAO {
+class VmMemoryStatDAOImpl implements VmMemoryStatDAO {
 
     private final Storage storage;
-    private final VmRef ref;
 
-    public VmMemoryStatDAOImpl(Storage storage, VmRef ref) {
+    VmMemoryStatDAOImpl(Storage storage) {
         this.storage = storage;
-        this.ref = ref;
     }
 
     @Override
-    public VmMemoryStat getLatestMemoryStat() {
-        Chunk query = new Chunk(VmMemoryStatDAO.vmMemoryStatsCategory, false);
+    public VmMemoryStat getLatestMemoryStat(VmRef ref) {
+        Chunk query = new Chunk(vmMemoryStatsCategory, false);
         query.put(Key.AGENT_ID, ref.getAgent().getAgentId());
-        query.put(VmMemoryStatDAO.vmIdKey, ref.getId());
+        query.put(Key.VM_ID, ref.getId());
         Cursor cursor = storage.findAll(query).sort(Key.TIMESTAMP, Cursor.SortDirection.DESCENDING).limit(1);
         if (cursor.hasNext()) {
-            return new VmMemoryStatConverter().chunkToVmMemoryStat(cursor.next());
+            return new VmMemoryStatConverter().fromChunk(cursor.next());
         }
         return null;
     }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmRefDAO.java	Wed Apr 04 21:47:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +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.dao;
-
-import java.util.Collection;
-
-public interface VmRefDAO {
-
-    Collection<VmRef> getVMs(HostRef host);
-
-}
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmRefDAOImpl.java	Wed Apr 04 21:47:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +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.dao;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import com.redhat.thermostat.common.storage.Chunk;
-import com.redhat.thermostat.common.storage.Cursor;
-import com.redhat.thermostat.common.storage.Storage;
-
-class VmRefDAOImpl implements VmRefDAO {
-
-    private Storage storage;
-
-    VmRefDAOImpl(Storage storage) {
-        this.storage = storage;
-    }
-
-    @Override
-    public Collection<VmRef> getVMs(HostRef host) {
-
-        Chunk query = buildQuery(host);
-        Cursor cursor = storage.findAll(query);
-        return buildVMsFromQuery(cursor, host);
-    }
-
-    private Chunk buildQuery(HostRef host) {
-        Chunk query = new Chunk(VmInfoDAO.vmInfoCategory, false);
-        query.put(HostRefDAO.agentIdKey, host.getAgentId());
-        return query;
-    }
-
-    private Collection<VmRef> buildVMsFromQuery(Cursor cursor, HostRef host) {
-        List<VmRef> vmRefs = new ArrayList<VmRef>();
-        while (cursor.hasNext()) {
-            Chunk vmChunk = cursor.next();
-            VmRef vm = buildVmRefFromChunk(vmChunk, host);
-            vmRefs.add(vm);
-        }
-
-        return vmRefs;
-    }
-
-    private VmRef buildVmRefFromChunk(Chunk vmChunk, HostRef host) {
-        Integer id = vmChunk.get(VmInfoDAO.vmIdKey);
-        // TODO can we do better than the main class?
-        String mainClass = vmChunk.get(VmInfoDAO.mainClassKey);
-        VmRef ref = new VmRef(host, id, mainClass);
-        return ref;
-    }
-}
--- a/common/src/main/java/com/redhat/thermostat/common/model/CpuStat.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/model/CpuStat.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,7 +36,7 @@
 
 package com.redhat.thermostat.common.model;
 
-public class CpuStat {
+public class CpuStat implements TimeStampedPojo {
 
     public static final double INVALID_LOAD = Double.MIN_VALUE;
 
@@ -68,6 +68,7 @@
         return new double[] { load5, load10, load15 };
     }
 
+    @Override
     public long getTimeStamp() {
         return timeStamp;
     }
--- a/common/src/main/java/com/redhat/thermostat/common/model/HostInfo.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/model/HostInfo.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,7 +36,7 @@
 
 package com.redhat.thermostat.common.model;
 
-public class HostInfo {
+public class HostInfo implements Pojo {
 
     private final String hostname;
     private final String osName;
--- a/common/src/main/java/com/redhat/thermostat/common/model/MemoryStat.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/model/MemoryStat.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,7 +36,7 @@
 
 package com.redhat.thermostat.common.model;
 
-public class MemoryStat {
+public class MemoryStat implements TimeStampedPojo {
     private final long timestamp;
     private final long total;
     private final long free;
@@ -57,6 +57,7 @@
         this.commitLimit = commitLimit;
     }
 
+    @Override
     public long getTimeStamp() {
         return timestamp;
     }
--- a/common/src/main/java/com/redhat/thermostat/common/model/NetworkInterfaceInfo.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/model/NetworkInterfaceInfo.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,7 +36,7 @@
 
 package com.redhat.thermostat.common.model;
 
-public class NetworkInterfaceInfo {
+public class NetworkInterfaceInfo implements Pojo {
 
     private String iFace;
     private String ip4Addr;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/model/Pojo.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+/**
+ * All data types should implement this empty interface, to support the
+ * generalization of DAO code where possible.
+ */
+public interface Pojo {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/model/TimeStampedPojo.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+/**
+ * Any Pojo which is taken as a timestamped piece of data should
+ * implement this interface.
+ */
+public interface TimeStampedPojo extends Pojo {
+
+    public long getTimeStamp();
+
+}
--- a/common/src/main/java/com/redhat/thermostat/common/model/VmClassStat.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/model/VmClassStat.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,7 +36,7 @@
 
 package com.redhat.thermostat.common.model;
 
-public class VmClassStat {
+public class VmClassStat implements TimeStampedPojo {
 
     private int vmId;
     private long timestamp;
@@ -52,7 +52,8 @@
         return vmId;
     }
 
-    public long getTimestamp() {
+    @Override
+    public long getTimeStamp() {
         return timestamp;
     }
 
--- a/common/src/main/java/com/redhat/thermostat/common/model/VmCpuStat.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/model/VmCpuStat.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,7 +36,7 @@
 
 package com.redhat.thermostat.common.model;
 
-public class VmCpuStat {
+public class VmCpuStat implements TimeStampedPojo {
 
     private final long timestamp;
     private final int vmId;
@@ -48,6 +48,7 @@
         this.cpuLoad = cpuLoad;
     }
 
+    @Override
     public long getTimeStamp() {
         return timestamp;
     }
--- a/common/src/main/java/com/redhat/thermostat/common/model/VmGcStat.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/model/VmGcStat.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,7 +36,7 @@
 
 package com.redhat.thermostat.common.model;
 
-public class VmGcStat {
+public class VmGcStat implements TimeStampedPojo {
 
     private final long timestamp;
     private final int vmId;
@@ -64,6 +64,7 @@
         return wallTime;
     }
 
+    @Override
     public long getTimeStamp() {
         return timestamp;
     }
--- a/common/src/main/java/com/redhat/thermostat/common/model/VmInfo.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/model/VmInfo.java	Wed Apr 04 21:49:29 2012 +0200
@@ -40,7 +40,7 @@
 import java.util.List;
 import java.util.Map;
 
-public class VmInfo {
+public class VmInfo implements Pojo {
 
     private int vmPid = 0;
     private long startTime = System.currentTimeMillis();
--- a/common/src/main/java/com/redhat/thermostat/common/model/VmMemoryStat.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/model/VmMemoryStat.java	Wed Apr 04 21:49:29 2012 +0200
@@ -38,7 +38,7 @@
 
 import java.util.List;
 
-public class VmMemoryStat {
+public class VmMemoryStat implements TimeStampedPojo {
 
     public static class Generation {
         public static final String COLLECTOR_NONE = "none";
@@ -80,6 +80,7 @@
         return vmId;
     }
 
+    @Override
     public long getTimeStamp() {
         return timestamp;
     }
--- a/common/src/main/java/com/redhat/thermostat/common/storage/ChunkConverter.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/ChunkConverter.java	Wed Apr 04 21:49:29 2012 +0200
@@ -38,12 +38,16 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.logging.Logger;
 
 import com.mongodb.BasicDBObject;
 import com.mongodb.DBObject;
+import com.redhat.thermostat.common.utils.LoggingUtils;
 
 class ChunkConverter {
 
+    private static final Logger logger = LoggingUtils.getLogger(ChunkConverter.class);
+
     DBObject chunkToDBObject(Chunk chunk) {
         BasicDBObject dbObject = new BasicDBObject();
         Map<String, DBObject> dbObjectMap = null;
@@ -101,13 +105,15 @@
 
     private void dbObjectToChunkRecurse(Chunk chunk, DBObject dbObject, Category category, String fullKey) {
         for (String dbKey : dbObject.keySet()) {
-            String newFullKey;
-            if (fullKey == null) {
-                newFullKey = dbKey;
-            } else {
-                newFullKey = fullKey + "." + dbKey;
+            if (!dbKey.equals("_id")) { // Mongo adds this to any stored document.
+                String newFullKey;
+                if (fullKey == null) {
+                    newFullKey = dbKey;
+                } else {
+                    newFullKey = fullKey + "." + dbKey;
+                }
+                dbObjectToChunkRecursively(chunk, dbObject, category, dbKey, newFullKey);
             }
-            dbObjectToChunkRecursively(chunk, dbObject, category, dbKey, newFullKey);
         }
     }
 
@@ -118,7 +124,11 @@
             dbObjectToChunkRecurse(chunk, dbObj, category, fullKey);
         } else {
             Key key = category.getKey(fullKey);
-            chunk.put(key, value);
+            if (key != null) {
+                chunk.put(key, value);
+            } else {
+                logger.warning("No key matching \"" + fullKey + "\" in category \"" + category + "\"");
+            }
         }
     }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/storage/Key.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/Key.java	Wed Apr 04 21:49:29 2012 +0200
@@ -45,6 +45,7 @@
     // Keys used by most Categories.
     public static final Key<Long> TIMESTAMP = new Key<>("timestamp", false);
     public static final Key<String> AGENT_ID = new Key<>("agent-id", false);
+    public static final Key<Integer> VM_ID = new Key<>("vm-id", false);
     public static final Key<String> WHERE = new Key<>("$where", false);
 
     private String name;
--- a/common/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Wed Apr 04 21:49:29 2012 +0200
@@ -161,14 +161,16 @@
                     replaceKeyNested.append(entryParts[1], replaceKeyNested);
                 }
             } else {
-                String mongoKey = key.getName();
-                Object value = chunk.get(key);
-                if ((value == null) && isKey) {
-                    throwMissingKey(key.getName());
-                }
-                toInsert.append(mongoKey, value);
-                if (replace && isKey) {
-                    replaceKey.append(mongoKey, value);
+                if (!key.equals(Key.AGENT_ID)) {
+                    String mongoKey = key.getName();
+                    Object value = chunk.get(key);
+                    if ((value == null) && isKey) {
+                        throwMissingKey(key.getName());
+                    }
+                    toInsert.append(mongoKey, value);
+                    if (replace && isKey) {
+                        replaceKey.append(mongoKey, value);
+                    }
                 }
             }
         }
@@ -245,7 +247,7 @@
 
     private DBCollection getCachedCollection(String collName) {
         DBCollection coll = collectionCache.get(collName);
-        if (coll == null) {
+        if (coll == null && db.collectionExists(collName)) {
             coll = db.getCollection(collName);
             if (coll != null) {
                 collectionCache.put(collName, coll);
@@ -294,6 +296,11 @@
 
     @Override
     public ConnectionKey createConnectionKey(Category category) {
+        // TODO: There is probably some better place to do this, perhaps related to the inner class
+        // idea mentioned below.
+        if (!db.collectionExists(category.getName())) {
+            db.createCollection(category.getName(), new BasicDBObject("capped", false));
+        }
         // TODO: We want to return an instance of an inner class here that carries the actual connection
         // and replace the collectionCache. For now this is good enough though.
         return new ConnectionKey(){};
@@ -330,4 +337,13 @@
         DBCursor dbCursor = coll.find();
         return new MongoCursor(dbCursor, category);
     }
+
+    @Override
+    public long getCount(Category category) {
+        DBCollection coll = getCachedCollection(category.getName());
+        if (coll != null) {
+            return coll.getCount();
+        }
+        return 0L;
+    }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Wed Apr 04 21:49:29 2012 +0200
@@ -84,4 +84,6 @@
     public abstract Chunk find(Chunk query);
 
     public abstract Cursor findAllFromCategory(Category category);
+
+    public abstract long getCount(Category category);
 }
--- a/common/src/main/java/com/redhat/thermostat/tools/BasicApplication.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/tools/BasicApplication.java	Wed Apr 04 21:49:29 2012 +0200
@@ -48,20 +48,9 @@
     public BasicApplication() {
         this.notifier = new ActionNotifier<>(this);
     }
-  
-    protected void notifyFail() {
-        notifier.fireAction(ApplicationState.FAIL);
-    }
-    
-    protected void notifySuccess() {
-        notifier.fireAction(ApplicationState.SUCCESS);
-    }
-    
+
     @Override
     public ActionNotifier<ApplicationState> getNotifier() {
         return notifier;
     }
-    
-    @Override
-    public void printHelp() {}
 }
--- a/common/src/test/java/com/redhat/thermostat/common/config/ConfigUtilsTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/config/ConfigUtilsTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -38,23 +38,17 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.Random;
 
 import junit.framework.Assert;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.redhat.thermostat.common.TestUtils;
-
 public class ConfigUtilsTest {
-
-    private String oldLocation;
     
     @Before
     public void setUp() throws IOException {
-        TestUtils.setupAgentConfigs();
+        System.setProperty("THERMOSTAT_HOME", "/tmp/");
     }
     
     @Test
@@ -64,6 +58,8 @@
         
         Assert.assertEquals(path, ConfigUtils.getThermostatHome());
         
+        Assert.assertEquals(path + "agent" + s + "agent.properties",
+                            ConfigUtils.getAgentConfigurationFile().getCanonicalPath());
         Assert.assertEquals(path + "backends", ConfigUtils.getBackendsBaseDirectory().getCanonicalPath());
         Assert.assertEquals(path + "storage", ConfigUtils.getStorageBaseDirectory().getCanonicalPath());
         Assert.assertEquals(path + "storage" + s + "db.properties",
--- a/common/src/test/java/com/redhat/thermostat/common/dao/CpuStatConverterTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/CpuStatConverterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -47,9 +47,9 @@
 public class CpuStatConverterTest {
 
     @Test
-    public void testCpuStatToChunk() {
+    public void testToChunk() {
         CpuStat stat = new CpuStat(10, 5.0, 10.0, 15.0);
-        Chunk chunk = new CpuStatConverter().cpuStatToChunk(stat);
+        Chunk chunk = new CpuStatConverter().toChunk(stat);
         assertNotNull(chunk);
         assertEquals("cpu-stats", chunk.getCategory().getName());
         assertEquals((Long) 10L, chunk.get(Key.TIMESTAMP));
@@ -59,13 +59,13 @@
     }
 
     @Test
-    public void testChunkToCpuStat() {
+    public void testFromChunk() {
         Chunk chunk = new Chunk(CpuStatDAO.cpuStatCategory, false);
         chunk.put(Key.TIMESTAMP, 10L);
         chunk.put(CpuStatDAO.cpu5LoadKey, 5.0);
         chunk.put(CpuStatDAO.cpu10LoadKey, 10.0);
         chunk.put(CpuStatDAO.cpu15LoadKey, 15.0);
-        CpuStat stat = new CpuStatConverter().chunkToCpuStat(chunk);
+        CpuStat stat = new CpuStatConverter().fromChunk(chunk);
         assertNotNull(stat);
         assertEquals(10L, stat.getTimeStamp());
         assertEquals(5.0, stat.getLoad5(), 0.001);
--- a/common/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -52,6 +52,7 @@
 import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.common.model.CpuStat;
+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;
@@ -67,29 +68,29 @@
         assertTrue(keys.contains(new Key<Double>("5load", false)));
         assertTrue(keys.contains(new Key<Double>("10load", false)));
         assertTrue(keys.contains(new Key<Double>("15load", false)));
-        assertEquals(4, keys.size());
+        assertEquals(5, keys.size());
     }
 
     @Test
     public void testGetLatestCpuStats() {
+
+        Cursor cursor = mock(Cursor.class);
+        Storage storage = mock(Storage.class);
+        HostRef hostRef = mock(HostRef.class);
+        CpuStatDAO dao = new CpuStatDAOImpl(storage);
+
         Chunk chunk = new Chunk(CpuStatDAO.cpuStatCategory, false);
         chunk.put(Key.TIMESTAMP, 1234L);
         chunk.put(CpuStatDAO.cpu5LoadKey, 5.0);
         chunk.put(CpuStatDAO.cpu10LoadKey, 10.0);
         chunk.put(CpuStatDAO.cpu15LoadKey, 15.0);
 
-        Cursor cursor = mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(chunk);
-
-        Storage storage = mock(Storage.class);
         when(storage.findAll(any(Chunk.class))).thenReturn(cursor);
-
-        HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
 
-        CpuStatDAO dao = new CpuStatDAOImpl(storage, hostRef);
-        List<CpuStat> cpuStats = dao.getLatestCpuStats();
+        List<CpuStat> cpuStats = dao.getLatestCpuStats(hostRef);
 
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage).findAll(arg.capture());
@@ -105,29 +106,38 @@
 
     @Test
     public void testGetLatestCpuStatsTwice() {
+
+        Cursor cursor = mock(Cursor.class);
+        Storage storage = mock(Storage.class);
+        HostRef hostRef = mock(HostRef.class);
+
+        CpuStatDAO dao = new CpuStatDAOImpl(storage);
+
         Chunk chunk = new Chunk(CpuStatDAO.cpuStatCategory, false);
         chunk.put(Key.TIMESTAMP, 1234L);
         chunk.put(CpuStatDAO.cpu5LoadKey, 5.0);
         chunk.put(CpuStatDAO.cpu10LoadKey, 10.0);
         chunk.put(CpuStatDAO.cpu15LoadKey, 15.0);
 
-        Cursor cursor = mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(chunk);
-
-        Storage storage = mock(Storage.class);
         when(storage.findAll(any(Chunk.class))).thenReturn(cursor);
-
-        HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
 
-        CpuStatDAO dao = new CpuStatDAOImpl(storage, hostRef);
-        dao.getLatestCpuStats();
-        dao.getLatestCpuStats();
+        dao.getLatestCpuStats(hostRef);
+        dao.getLatestCpuStats(hostRef);
 
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage, times(2)).findAll(arg.capture());
-        assertEquals("this.timestamp > 1234", arg.getValue().get(new Key<String>("$where", false)));
+        assertEquals("this.timestamp > 1234", arg.getValue().get(Key.WHERE));
     }
 
+    @Test
+    public void testGetCount() {
+        Storage storage = mock(Storage.class);
+        when(storage.getCount(any(Category.class))).thenReturn(5L);
+        CpuStatDAO dao = new CpuStatDAOImpl(storage);
+        Long count = dao.getCount();
+        assertEquals((Long) 5L, count);
+    }
 }
--- a/common/src/test/java/com/redhat/thermostat/common/dao/HostInfoConverterTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/HostInfoConverterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -51,7 +51,7 @@
     public void testHostInfoToChunk() {
         HostInfo info = new HostInfo("a-host", "an-os", "a-kernel", "a-cpu", 9, 99);
 
-        Chunk chunk = new HostInfoConverter().hostInfoToChunk(info);
+        Chunk chunk = new HostInfoConverter().toChunk(info);
 
         assertEquals("host-info", chunk.getCategory().getName());
         assertEquals("a-host", chunk.get(new Key<String>("hostname", true)));
@@ -80,7 +80,7 @@
         chunk.put(HostInfoDAO.cpuCountKey, CPU_NUM);
         chunk.put(HostInfoDAO.hostMemoryTotalKey, MEMORY_TOTAL);
 
-        HostInfo info = new HostInfoConverter().chunkToHostInfo(chunk);
+        HostInfo info = new HostInfoConverter().fromChunk(chunk);
         assertNotNull(info);
         assertEquals(HOST_NAME, info.getHostname());
         assertEquals(OS_NAME, info.getOsName());
--- a/common/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -36,7 +36,9 @@
 
 package com.redhat.thermostat.common.dao;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import java.util.Collection;
 
@@ -47,7 +49,9 @@
 import static org.mockito.Mockito.when;
 
 import com.redhat.thermostat.common.model.HostInfo;
+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;
 
@@ -63,7 +67,7 @@
         assertTrue(keys.contains(new Key<String>("cpu_model", false)));
         assertTrue(keys.contains(new Key<Integer>("cpu_num", false)));
         assertTrue(keys.contains(new Key<Long>("memory_total", false)));
-        assertEquals(6, keys.size());
+        assertEquals(7, keys.size());
     }
 
     @Test
@@ -86,7 +90,7 @@
         Storage storage = mock(Storage.class);
         when(storage.find(any(Chunk.class))).thenReturn(chunk);
 
-        HostInfo info = new HostInfoDAOImpl(storage, new HostRef("some uid", HOST_NAME)).getHostInfo();
+        HostInfo info = new HostInfoDAOImpl(storage).getHostInfo(new HostRef("some uid", HOST_NAME));
         assertNotNull(info);
         assertEquals(HOST_NAME, info.getHostname());
         assertEquals(OS_NAME, info.getOsName());
@@ -95,4 +99,77 @@
         assertEquals(CPU_NUM, info.getCpuCount());
         assertEquals(MEMORY_TOTAL, info.getTotalMemory());
     }
+
+    @Test
+    public void testGetHostsSingleHost() {
+
+        Storage storage = setupStorageForSingleHost();
+
+        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage);
+        Collection<HostRef> hosts = hostsDAO.getHosts();
+
+        assertEquals(1, hosts.size());
+        assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
+    }
+
+    private Storage setupStorageForSingleHost() {
+
+        Chunk hostConfig = new Chunk(HostInfoDAO.hostInfoCategory, false);
+        hostConfig.put(HostInfoDAO.hostNameKey, "fluffhost1");
+        hostConfig.put(Key.AGENT_ID, "123");
+
+        Cursor cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(hostConfig);
+
+        Storage storage = mock(Storage.class);
+        when(storage.findAllFromCategory(HostInfoDAO.hostInfoCategory)).thenReturn(cursor);
+
+        return storage;
+    }
+
+    @Test
+    public void testGetHosts3Hosts() {
+
+        Storage storage = setupStorageFor3Hosts();
+
+        HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage);
+        Collection<HostRef> hosts = hostsDAO.getHosts();
+
+        assertEquals(3, hosts.size());
+        assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
+        assertTrue(hosts.contains(new HostRef("456", "fluffhost2")));
+        assertTrue(hosts.contains(new HostRef("789", "fluffhost3")));
+    }
+
+    private Storage setupStorageFor3Hosts() {
+
+        Chunk hostConfig1 = new Chunk(HostInfoDAO.hostInfoCategory, false);
+        hostConfig1.put(HostInfoDAO.hostNameKey, "fluffhost1");
+        hostConfig1.put(Key.AGENT_ID, "123");
+        Chunk hostConfig2 = new Chunk(HostInfoDAO.hostInfoCategory, false);
+        hostConfig2.put(HostInfoDAO.hostNameKey, "fluffhost2");
+        hostConfig2.put(Key.AGENT_ID, "456");
+        Chunk hostConfig3 = new Chunk(HostInfoDAO.hostInfoCategory, false);
+        hostConfig3.put(HostInfoDAO.hostNameKey, "fluffhost3");
+        hostConfig3.put(Key.AGENT_ID, "789");
+
+        Cursor cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(hostConfig1).thenReturn(hostConfig2).thenReturn(hostConfig3);
+
+        Storage storage = mock(Storage.class);
+        when(storage.findAllFromCategory(HostInfoDAO.hostInfoCategory)).thenReturn(cursor);
+
+        return storage;
+    }
+
+    @Test
+    public void testGetCount() {
+        Storage storage = mock(Storage.class);
+        when(storage.getCount(any(Category.class))).thenReturn(5L);
+        HostInfoDAO dao = new HostInfoDAOImpl(storage);
+        Long count = dao.getCount();
+        assertEquals((Long) 5L, count);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,207 @@
+/*
+ * 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 org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.model.CpuStat;
+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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.any;
+
+public class HostLatestPojoListGetterTest {
+    private static final String AGENT_ID = "agentid";
+    private static final String HOSTNAME = "host.example.com";
+    private static final String CATEGORY_NAME = "hostcategory";
+    // Make this one static so we don't get IllegalStateException from trying
+    // to make category of same name while running tests in same classloader.
+    private static final Category cat =  new Category(CATEGORY_NAME);
+
+    private static long t1 = 1;
+    private static long t2 = 5;
+    private static long t3 = 10;
+
+    private static double load5_1 = 2.0;
+    private static double load5_2 = 6.0;
+    private static double load5_3 = 11.0;
+
+    private static double load10_1 = 3.0;
+    private static double load10_2 = 7.0;
+    private static double load10_3 = 12.0;
+
+    private static double load15_1 = 4.0;
+    private static double load15_2 = 8.0;
+    private static double load15_3 = 13.0;
+
+    private HostRef ref;
+    private Converter<CpuStat> converter;
+    private Chunk result1, result2, result3;
+
+    @Before
+    public void setUp() {
+        ref = new HostRef(AGENT_ID, HOSTNAME);
+        converter = new CpuStatConverter();
+        result1 = new Chunk(cat, false);
+        result1.put(Key.AGENT_ID, AGENT_ID);
+        result1.put(Key.TIMESTAMP, t1);
+        result1.put(CpuStatDAO.cpu5LoadKey, load5_1);
+        result1.put(CpuStatDAO.cpu10LoadKey, load10_1);
+        result1.put(CpuStatDAO.cpu15LoadKey, load15_1);
+        result2 = new Chunk(cat, false);
+        result2.put(Key.AGENT_ID, AGENT_ID);
+        result2.put(Key.TIMESTAMP, t2);
+        result2.put(CpuStatDAO.cpu5LoadKey, load5_2);
+        result2.put(CpuStatDAO.cpu10LoadKey, load10_2);
+        result2.put(CpuStatDAO.cpu15LoadKey, load15_2);
+        result3 = new Chunk(cat, false);
+        result3.put(Key.AGENT_ID, AGENT_ID);
+        result3.put(Key.TIMESTAMP, t3);
+        result3.put(CpuStatDAO.cpu5LoadKey, load5_3);
+        result3.put(CpuStatDAO.cpu10LoadKey, load10_3);
+        result3.put(CpuStatDAO.cpu15LoadKey, load15_3);
+    }
+
+    @Test
+    public void testBuildQuery() {
+        Storage storage = mock(Storage.class);
+        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, converter, ref);
+        Chunk query = getter.buildQuery();
+
+        assertNotNull(query);
+        assertEquals(cat, query.getCategory());
+        assertEquals(1, query.getKeys().size());
+        assertTrue(query.getKeys().contains(Key.AGENT_ID));
+        assertFalse(query.getKeys().contains(Key.WHERE));
+        assertEquals(AGENT_ID, query.get(Key.AGENT_ID));
+    }
+
+    @Test
+    public void testBuildQueryPopulatesUpdateTimes() {
+        Storage storage = mock(Storage.class);
+        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, converter, ref);
+        getter.buildQuery(); // Ignore first return value.
+        Chunk query = getter.buildQuery();
+
+        assertNotNull(query);
+        assertEquals(cat, query.getCategory());
+        assertEquals(2, query.getKeys().size());
+        assertTrue(query.getKeys().contains(Key.AGENT_ID));
+        assertTrue(query.getKeys().contains(Key.WHERE));
+        assertEquals("this.timestamp > " + Long.MIN_VALUE, query.get(Key.WHERE));
+    }
+
+    @Test
+    public void testGetLatest() {
+        Cursor cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
+
+        Storage storage = mock(Storage.class);
+        when(storage.findAll(any(Chunk.class))).thenReturn(cursor);
+
+        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, converter, ref);
+
+        List<CpuStat> stats = getter.getLatest();
+
+        assertNotNull(stats);
+        assertEquals(2, stats.size());
+        CpuStat stat1 = stats.get(0);
+        assertEquals(t1, stat1.getTimeStamp());
+        assertEquals(load5_1, stat1.getLoad5(), 0.001);
+        assertEquals(load10_1, stat1.getLoad10(), 0.001);
+        assertEquals(load15_1, stat1.getLoad15(), 0.001);
+        CpuStat stat2 = stats.get(1);
+        assertEquals(t2, stat2.getTimeStamp());
+        assertEquals(load5_2, stat2.getLoad5(), 0.001);
+        assertEquals(load10_2, stat2.getLoad10(), 0.001);
+        assertEquals(load15_2, stat2.getLoad15(), 0.001);
+    }
+
+    @Test
+    public void testGetLatestMultipleCalls() {
+        Cursor cursor1 = mock(Cursor.class);
+        when(cursor1.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(cursor1.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
+
+        Cursor cursor2 = mock(Cursor.class);
+        when(cursor2.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor2.next()).thenReturn(result3);
+
+        Storage storage = mock(Storage.class);
+        when(storage.findAll(any(Chunk.class))).thenReturn(cursor1);
+
+        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, converter, ref);
+        getter.getLatest();
+        getter.getLatest();
+
+        ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
+        verify(storage, times(2)).findAll(arg.capture());
+        List<Chunk> queries = arg.getAllValues();
+
+        assertEquals(2, queries.size());
+        Chunk query = queries.get(1);
+        assertNotNull(query);
+        assertEquals(AGENT_ID, query.get(Key.AGENT_ID));
+        assertEquals("this.timestamp > " + t2, query.get(Key.WHERE));
+    }
+
+    @After
+    public void tearDown() {
+        ref = null;
+        converter = null;
+        result1 = null;
+        result2 = null;
+        result3 = null;
+    }
+}
--- a/common/src/test/java/com/redhat/thermostat/common/dao/HostRefDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +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.dao;
-
-import static org.junit.Assert.*;
-
-import java.util.Collection;
-
-import org.junit.Test;
-
-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 static org.mockito.Mockito.*;
-
-public class HostRefDAOTest {
-
-    @Test
-    public void testKeys() {
-        assertEquals(new Key<String>("agent-id", false), HostRefDAO.agentIdKey);
-    }
-
-    @Test
-    public void testAgentConfigCategory() {
-        assertEquals("agent-config", HostRefDAO.agentConfigCategory.getName());
-        assertEquals(1, HostRefDAO.agentConfigCategory.getKeys().size());
-        assertTrue(HostRefDAO.agentConfigCategory.getKeys().contains(HostRefDAO.agentIdKey));
-    }
-
-    @Test
-    public void testGetHostsSingleHost() {
-
-        Storage storage = setupStorageForSingleHost();
-
-        HostRefDAO hostsVMsDAO = new HostRefDAOImpl(storage);
-        Collection<HostRef> hosts = hostsVMsDAO.getHosts();
-
-        assertEquals(1, hosts.size());
-        assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
-    }
-
-    private Storage setupStorageForSingleHost() {
-        
-        Chunk agentConfig = new Chunk(HostRefDAO.agentConfigCategory, false);
-        agentConfig.put(HostRefDAO.agentIdKey, "123");
-
-        Cursor agentsCursor = mock(Cursor.class);
-        when(agentsCursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(agentsCursor.next()).thenReturn(agentConfig);
-
-        Chunk hostConfig = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        hostConfig.put(HostInfoDAO.hostNameKey, "fluffhost1");
-        hostConfig.put(HostRefDAO.agentIdKey, "123");
-
-        Storage storage = mock(Storage.class);
-        when(storage.findAllFromCategory(HostRefDAO.agentConfigCategory)).thenReturn(agentsCursor);
-        Chunk hostsQuery = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        hostsQuery.put(HostRefDAO.agentIdKey, "123");
-        when(storage.find(hostsQuery)).thenReturn(hostConfig);
-
-        return storage;
-    }
-
-    @Test
-    public void testGetHosts3Hosts() {
-
-        Storage storage = setupStorageFor3Hosts();
-
-        HostRefDAO hostsVMsDAO = new HostRefDAOImpl(storage);
-        Collection<HostRef> hosts = hostsVMsDAO.getHosts();
-
-        assertEquals(3, hosts.size());
-        assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
-        assertTrue(hosts.contains(new HostRef("456", "fluffhost2")));
-        assertTrue(hosts.contains(new HostRef("789", "fluffhost3")));
-    }
-
-    private Storage setupStorageFor3Hosts() {
-        Chunk agentConfig1 = new Chunk(HostRefDAO.agentConfigCategory, false);
-        agentConfig1.put(HostRefDAO.agentIdKey, "123");
-        Chunk agentConfig2 = new Chunk(HostRefDAO.agentConfigCategory, false);
-        agentConfig2.put(HostRefDAO.agentIdKey, "456");
-        Chunk agentConfig3 = new Chunk(HostRefDAO.agentConfigCategory, false);
-        agentConfig3.put(HostRefDAO.agentIdKey, "789");
-
-        Cursor agentsCursor = mock(Cursor.class);
-        when(agentsCursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(agentsCursor.next()).thenReturn(agentConfig1).thenReturn(agentConfig2).thenReturn(agentConfig3);
-
-        Chunk hostConfig1 = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        hostConfig1.put(HostInfoDAO.hostNameKey, "fluffhost1");
-        hostConfig1.put(HostRefDAO.agentIdKey, "123");
-        Chunk hostConfig2 = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        hostConfig2.put(HostInfoDAO.hostNameKey, "fluffhost2");
-        hostConfig2.put(HostRefDAO.agentIdKey, "456");
-        Chunk hostConfig3 = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        hostConfig3.put(HostInfoDAO.hostNameKey, "fluffhost3");
-        hostConfig3.put(HostRefDAO.agentIdKey, "789");
-
-        Storage storage = mock(Storage.class);
-        when(storage.findAllFromCategory(HostRefDAO.agentConfigCategory)).thenReturn(agentsCursor);
-        Chunk hostsQuery1 = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        hostsQuery1.put(HostRefDAO.agentIdKey, "123");
-        when(storage.find(hostsQuery1)).thenReturn(hostConfig1);
-        Chunk hostsQuery2 = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        hostsQuery2.put(HostRefDAO.agentIdKey, "456");
-        when(storage.find(hostsQuery2)).thenReturn(hostConfig2);
-        Chunk hostsQuery3 = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        hostsQuery3.put(HostRefDAO.agentIdKey, "789");
-        when(storage.find(hostsQuery3)).thenReturn(hostConfig3);
-
-        return storage;
-    }
-}
--- a/common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatConverterTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatConverterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -50,7 +50,7 @@
     public void testMemoryStatToChunk() {
         MemoryStat stat = new MemoryStat(0, 1, 2, 3, 4, 5, 6, 7);
 
-        Chunk chunk = new MemoryStatConverter().memoryStatToChunk(stat);
+        Chunk chunk = new MemoryStatConverter().toChunk(stat);
 
         assertEquals((Long) 0l, chunk.get(Key.TIMESTAMP));
         assertEquals((Long) 1l, chunk.get(new Key<Long>("total", false)));
@@ -83,7 +83,7 @@
         chunk.put(MemoryStatDAO.memorySwapFreeKey, SWAP_FREE);
         chunk.put(MemoryStatDAO.memoryCommitLimitKey, COMMIT_LIMIT);
 
-        MemoryStat stat = new MemoryStatConverter().chunkToMemoryStat(chunk);
+        MemoryStat stat = new MemoryStatConverter().fromChunk(chunk);
 
         assertEquals(TIMESTAMP, stat.getTimeStamp());
         assertEquals(TOTAL, stat.getTotal());
--- a/common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -52,6 +52,7 @@
 import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.common.model.MemoryStat;
+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;
@@ -70,7 +71,7 @@
         assertTrue(keys.contains(new Key<Long>("swap-total", false)));
         assertTrue(keys.contains(new Key<Long>("swap-free", false)));
         assertTrue(keys.contains(new Key<Long>("commit-limit", false)));
-        assertEquals(8, keys.size());
+        assertEquals(9, keys.size());
 
     }
 
@@ -105,8 +106,8 @@
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
 
-        MemoryStatDAO dao = new MemoryStatDAOImpl(storage, hostRef);
-        List<MemoryStat> memoryStats = dao.getLatestMemoryStats();
+        MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
+        List<MemoryStat> memoryStats = dao.getLatestMemoryStats(hostRef);
 
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage).findAll(arg.capture());
@@ -156,12 +157,21 @@
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
 
-        MemoryStatDAO dao = new MemoryStatDAOImpl(storage, hostRef);
-        dao.getLatestMemoryStats();
-        dao.getLatestMemoryStats();
+        MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
+        dao.getLatestMemoryStats(hostRef);
+        dao.getLatestMemoryStats(hostRef);
 
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage, times(2)).findAll(arg.capture());
         assertEquals("this.timestamp > 1", arg.getValue().get(new Key<String>("$where", false)));
     }
+
+    @Test
+    public void testGetCount() {
+        Storage storage = mock(Storage.class);
+        when(storage.getCount(any(Category.class))).thenReturn(5L);
+        MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
+        Long count = dao.getCount();
+        assertEquals((Long) 5L, count);
+    }
 }
--- a/common/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -73,61 +73,49 @@
 
     @Test
     public void testGetVmClassStatsDAO() {
-        VmClassStatDAO dao = daoFactory.getVmClassStatsDAO(vmRef);
+        VmClassStatDAO dao = daoFactory.getVmClassStatsDAO();
         assertNotNull(dao);
     }
 
     @Test
     public void testGetVmGcStatDAO() {
-        VmGcStatDAO dao = daoFactory.getVmGcStatDAO(vmRef);
+        VmGcStatDAO dao = daoFactory.getVmGcStatDAO();
         assertNotNull(dao);
     }
 
     @Test
     public void testGetVmInfoDAO() {
-        VmInfoDAO dao = daoFactory.getVmInfoDAO(vmRef);
+        VmInfoDAO dao = daoFactory.getVmInfoDAO();
         assertNotNull(dao);
     }
 
     @Test
     public void testGetVmMemoryStatDAO() {
-        VmMemoryStatDAO dao = daoFactory.getVmMemoryStatDAO(vmRef);
+        VmMemoryStatDAO dao = daoFactory.getVmMemoryStatDAO();
         assertNotNull(dao);
     }
 
     @Test
     public void testGetHostInfoDAO() {
-        HostInfoDAO dao = daoFactory.getHostInfoDAO(hostRef);
+        HostInfoDAO dao = daoFactory.getHostInfoDAO();
         assertNotNull(dao);
     }
 
     @Test
     public void testGetCpuStatDAO() {
-        CpuStatDAO dao = daoFactory.getCpuStatDAO(hostRef);
+        CpuStatDAO dao = daoFactory.getCpuStatDAO();
         assertNotNull(dao);
     }
 
     @Test
     public void testGetMemoryStatDAO() {
-        MemoryStatDAO dao = daoFactory.getMemoryStatDAO(hostRef);
+        MemoryStatDAO dao = daoFactory.getMemoryStatDAO();
         assertNotNull(dao);
     }
 
     @Test
     public void testGetNetworkInterfaceInfoDAO() {
-        NetworkInterfaceInfoDAO dao = daoFactory.getNetworkInterfaceInfoDAO(hostRef);
-        assertNotNull(dao);
-    }
-
-    @Test
-    public void testGetHostRefDAO() {
-        HostRefDAO dao = daoFactory.getHostRefDAO();
-        assertNotNull(dao);
-    }
-
-    @Test
-    public void testGetVmRefDAO() {
-        VmRefDAO dao = daoFactory.getVmRefDAO();
+        NetworkInterfaceInfoDAO dao = daoFactory.getNetworkInterfaceInfoDAO();
         assertNotNull(dao);
     }
 }
--- a/common/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoConverterTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoConverterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -53,7 +53,7 @@
         info.setIp4Addr("4");
         info.setIp6Addr("6");
 
-        Chunk chunk = new NetworkInterfaceInfoConverter().networkInfoToChunk(info);
+        Chunk chunk = new NetworkInterfaceInfoConverter().toChunk(info);
 
         assertEquals("network-info", chunk.getCategory().getName());
         assertEquals("eth0", chunk.get(new Key<String>("iface", true)));
@@ -73,7 +73,7 @@
         chunk.put(NetworkInterfaceInfoDAO.ip4AddrKey, IPV4_ADDR);
         chunk.put(NetworkInterfaceInfoDAO.ip6AddrKey, IPV6_ADDR);
 
-        NetworkInterfaceInfo info = new NetworkInterfaceInfoConverter().chunkToNetworkInfo(chunk);
+        NetworkInterfaceInfo info = new NetworkInterfaceInfoConverter().fromChunk(chunk);
         assertNotNull(info);
         assertEquals(INTERFACE_NAME, info.getInterfaceName());
         assertEquals(IPV4_ADDR, info.getIp4Addr());
--- a/common/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -69,7 +69,7 @@
         assertTrue(keys.contains(new Key<String>("iface", true)));
         assertTrue(keys.contains(new Key<String>("ipv4addr", false)));
         assertTrue(keys.contains(new Key<String>("ipv6addr", false)));
-        assertEquals(4, keys.size());
+        assertEquals(5, keys.size());
     }
 
     @Test
@@ -93,8 +93,8 @@
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
 
-        NetworkInterfaceInfoDAO dao = new NetworkInterfaceInfoDAOImpl(storage, hostRef);
-        List<NetworkInterfaceInfo> netInfo = dao.getNetworkInterfaces();
+        NetworkInterfaceInfoDAO dao = new NetworkInterfaceInfoDAOImpl(storage);
+        List<NetworkInterfaceInfo> netInfo = dao.getNetworkInterfaces(hostRef);
 
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage).findAll(arg.capture());
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmClassStatConverterTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmClassStatConverterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -51,7 +51,7 @@
         VmClassStat stat = new VmClassStat(123, 1234L, 12345L);
 
         VmClassStatConverter dao = new VmClassStatConverter();
-        Chunk chunk = dao.vmClassStatToChunk(stat);
+        Chunk chunk = dao.toChunk(stat);
 
         assertEquals("vm-class-stats", chunk.getCategory().getName());
         assertEquals((Long) 1234L, chunk.get(Key.TIMESTAMP));
@@ -62,14 +62,14 @@
     @Test
     public void testChunkToVmClassStat() {
         Chunk chunk = new Chunk(VmClassStatDAO.vmClassStatsCategory, false);
-        chunk.put(VmClassStatDAO.vmIdKey, 123);
+        chunk.put(Key.VM_ID, 123);
         chunk.put(Key.TIMESTAMP, 1234L);
         chunk.put(VmClassStatDAO.loadedClassesKey, 12345L);
 
-        VmClassStat stat = new VmClassStatConverter().chunkToVmClassStat(chunk);
+        VmClassStat stat = new VmClassStatConverter().fromChunk(chunk);
 
         assertEquals(123, stat.getVmId());
-        assertEquals(1234L, stat.getTimestamp());
+        assertEquals(1234L, stat.getTimeStamp());
         assertEquals(12345L, stat.getLoadedClasses());
     }
 }
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmClassStatDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmClassStatDAOTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -66,7 +66,7 @@
         assertTrue(keys.contains(new Key<Integer>("vm-id", false)));
         assertTrue(keys.contains(new Key<Long>("timestamp", false)));
         assertTrue(keys.contains(new Key<Long>("loadedClasses", false)));
-        assertEquals(3, keys.size());
+        assertEquals(4, keys.size());
 
     }
 
@@ -75,7 +75,7 @@
 
         Chunk chunk = new Chunk(VmClassStatDAO.vmClassStatsCategory, false);
         chunk.put(Key.TIMESTAMP, 1234L);
-        chunk.put(VmClassStatDAO.vmIdKey, 321);
+        chunk.put(Key.VM_ID, 321);
         chunk.put(VmClassStatDAO.loadedClassesKey, 12345L);
 
         Cursor cursor = mock(Cursor.class);
@@ -93,8 +93,8 @@
         when(vmRef.getId()).thenReturn(321);
 
 
-        VmClassStatDAO dao = new VmClassStatDAOImpl(storage, vmRef);
-        List<VmClassStat> vmClassStats = dao.getLatestClassStats();
+        VmClassStatDAO dao = new VmClassStatDAOImpl(storage);
+        List<VmClassStat> vmClassStats = dao.getLatestClassStats(vmRef);
 
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage).findAll(arg.capture());
@@ -102,7 +102,7 @@
 
         assertEquals(1, vmClassStats.size());
         VmClassStat stat = vmClassStats.get(0);
-        assertEquals(1234L, stat.getTimestamp());
+        assertEquals(1234L, stat.getTimeStamp());
         assertEquals(12345L, stat.getLoadedClasses());
         assertEquals(321, stat.getVmId());
     }
@@ -112,7 +112,7 @@
 
         Chunk chunk = new Chunk(VmClassStatDAO.vmClassStatsCategory, false);
         chunk.put(Key.TIMESTAMP, 1234L);
-        chunk.put(VmClassStatDAO.vmIdKey, 321);
+        chunk.put(Key.VM_ID, 321);
         chunk.put(VmClassStatDAO.loadedClassesKey, 12345L);
 
         Cursor cursor = mock(Cursor.class);
@@ -130,10 +130,10 @@
         when(vmRef.getId()).thenReturn(321);
 
 
-        VmClassStatDAO dao = new VmClassStatDAOImpl(storage, vmRef);
-        dao.getLatestClassStats();
+        VmClassStatDAO dao = new VmClassStatDAOImpl(storage);
+        dao.getLatestClassStats(vmRef);
 
-        dao.getLatestClassStats();
+        dao.getLatestClassStats(vmRef);
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage, times(2)).findAll(arg.capture());
         assertEquals("this.timestamp > 1234", arg.getValue().get(new Key<String>("$where", false)));
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatConverterTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatConverterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -54,7 +54,7 @@
     public void testVmCpuStatToChunk() {
 
         VmCpuStat vmCpuStat = new VmCpuStat(TIMESTAMP, VM_ID, PROCESSOR_USAGE);
-        Chunk chunk = new VmCpuStatConverter().vmCpuStatToChunk(vmCpuStat);
+        Chunk chunk = new VmCpuStatConverter().toChunk(vmCpuStat);
         assertNotNull(chunk);
         assertEquals("vm-cpu-stats", chunk.getCategory().getName());
         assertEquals((Long)TIMESTAMP, chunk.get(Key.TIMESTAMP));
@@ -67,10 +67,10 @@
     public void testChunkToVmCpuStat() {
         Chunk chunk = new Chunk(VmCpuStatDAO.vmCpuStatCategory, false);
         chunk.put(Key.TIMESTAMP, TIMESTAMP);
-        chunk.put(VmCpuStatDAO.vmIdKey, VM_ID);
+        chunk.put(Key.VM_ID, VM_ID);
         chunk.put(VmCpuStatDAO.vmCpuLoadKey, PROCESSOR_USAGE);
 
-        VmCpuStat stat = new VmCpuStatConverter().chunkToVmCpuStat(chunk);
+        VmCpuStat stat = new VmCpuStatConverter().fromChunk(chunk);
         assertNotNull(stat);
         assertEquals(TIMESTAMP, stat.getTimeStamp());
         assertEquals(VM_ID, stat.getVmId());
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatDAOTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -66,7 +66,7 @@
         assertTrue(keys.contains(new Key<Long>("timestamp", false)));
         assertTrue(keys.contains(new Key<Integer>("vm-id", false)));
         assertTrue(keys.contains(new Key<Integer>("processor-usage", false)));
-        assertEquals(3, keys.size());
+        assertEquals(4, keys.size());
     }
 
     @Test
@@ -75,7 +75,7 @@
         Chunk chunk = new Chunk(VmCpuStatDAO.vmCpuStatCategory, false);
         chunk.put(Key.TIMESTAMP, 1234L);
         chunk.put(Key.AGENT_ID, "test-agent-id");
-        chunk.put(VmCpuStatDAO.vmIdKey, 321);
+        chunk.put(Key.VM_ID, 321);
         chunk.put(VmCpuStatDAO.vmCpuLoadKey, 9.9);
 
         Cursor cursor = mock(Cursor.class);
@@ -93,8 +93,8 @@
         when(vmRef.getId()).thenReturn(321);
 
 
-        VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage, vmRef);
-        List<VmCpuStat> vmCpuStats = dao.getLatestVmCpuStats();
+        VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage);
+        List<VmCpuStat> vmCpuStats = dao.getLatestVmCpuStats(vmRef);
 
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage).findAll(arg.capture());
@@ -113,7 +113,7 @@
         Chunk chunk = new Chunk(VmCpuStatDAO.vmCpuStatCategory, false);
         chunk.put(Key.AGENT_ID, "test-agent-id");
         chunk.put(Key.TIMESTAMP, 1234L);
-        chunk.put(VmCpuStatDAO.vmIdKey, 321);
+        chunk.put(Key.VM_ID, 321);
         chunk.put(VmCpuStatDAO.vmCpuLoadKey, 9.9);
 
         Cursor cursor = mock(Cursor.class);
@@ -130,10 +130,10 @@
         when(vmRef.getAgent()).thenReturn(hostRef);
         when(vmRef.getId()).thenReturn(321);
 
-        VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage, vmRef);
-        dao.getLatestVmCpuStats();
+        VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage);
+        dao.getLatestVmCpuStats(vmRef);
 
-        dao.getLatestVmCpuStats();
+        dao.getLatestVmCpuStats(vmRef);
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage, times(2)).findAll(arg.capture());
         assertEquals("this.timestamp > 1234", arg.getValue().get(new Key<String>("$where", false)));
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmGcStatConverterTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmGcStatConverterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -55,7 +55,7 @@
         final Long WALL_TIME = 9L;
 
         VmGcStat stat = new VmGcStat(VM_ID, TIMESTAMP, COLLECTOR, RUN_COUNT, WALL_TIME);
-        Chunk chunk = new VmGcStatConverter().vmGcStatToChunk(stat);
+        Chunk chunk = new VmGcStatConverter().toChunk(stat);
 
         assertNotNull(chunk);
         assertEquals("vm-gc-stats", chunk.getCategory().getName());
@@ -74,13 +74,13 @@
         final Long RUN_COUNT = 10L;
         final Long WALL_TIME = 9L;
 
-        Chunk chunk = new Chunk(VmGcStatDAO.vmGcStatsCategory, false);
+        Chunk chunk = new Chunk(VmGcStatDAO.vmGcStatCategory, false);
         chunk.put(Key.TIMESTAMP, TIMESTAMP);
-        chunk.put(VmGcStatDAO.vmIdKey, VM_ID);
+        chunk.put(Key.VM_ID, VM_ID);
         chunk.put(VmGcStatDAO.collectorKey, COLLECTOR);
         chunk.put(VmGcStatDAO.runCountKey, RUN_COUNT);
         chunk.put(VmGcStatDAO.wallTimeKey, WALL_TIME);
-        VmGcStat stat = new VmGcStatConverter().chunkToVmGcStat(chunk);
+        VmGcStat stat = new VmGcStatConverter().fromChunk(chunk);
 
         assertNotNull(stat);
         assertEquals(TIMESTAMP, (Long) stat.getTimeStamp());
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmGcStatDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmGcStatDAOTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -62,14 +62,14 @@
 
     @Test
     public void testCategory() {
-        assertEquals("vm-gc-stats", VmGcStatDAO.vmGcStatsCategory.getName());
-        Collection<Key<?>> keys = VmGcStatDAO.vmGcStatsCategory.getKeys();
+        assertEquals("vm-gc-stats", VmGcStatDAO.vmGcStatCategory.getName());
+        Collection<Key<?>> keys = VmGcStatDAO.vmGcStatCategory.getKeys();
         assertTrue(keys.contains(new Key<Integer>("vm-id", false)));
         assertTrue(keys.contains(new Key<Long>("timestamp", false)));
         assertTrue(keys.contains(new Key<String>("collector", false)));
         assertTrue(keys.contains(new Key<Long>("runtime-count", false)));
         assertTrue(keys.contains(new Key<Long>("wall-time", false)));
-        assertEquals(5, keys.size());
+        assertEquals(6, keys.size());
     }
 
     @Test
@@ -81,9 +81,9 @@
         final Long RUN_COUNT = 10L;
         final Long WALL_TIME = 9L;
 
-        Chunk chunk = new Chunk(VmGcStatDAO.vmGcStatsCategory, false);
+        Chunk chunk = new Chunk(VmGcStatDAO.vmGcStatCategory, false);
         chunk.put(Key.TIMESTAMP, TIMESTAMP);
-        chunk.put(VmGcStatDAO.vmIdKey, VM_ID);
+        chunk.put(Key.VM_ID, VM_ID);
         chunk.put(VmGcStatDAO.collectorKey, COLLECTOR);
         chunk.put(VmGcStatDAO.runCountKey, RUN_COUNT);
         chunk.put(VmGcStatDAO.wallTimeKey, WALL_TIME);
@@ -103,8 +103,8 @@
         when(vmRef.getId()).thenReturn(321);
 
 
-        VmGcStatDAO dao = new VmGcStatDAOImpl(storage, vmRef);
-        List<VmGcStat> vmGcStats = dao.getLatestVmGcStats();
+        VmGcStatDAO dao = new VmGcStatDAOImpl(storage);
+        List<VmGcStat> vmGcStats = dao.getLatestVmGcStats(vmRef);
 
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage).findAll(arg.capture());
@@ -128,9 +128,9 @@
         final Long RUN_COUNT = 10L;
         final Long WALL_TIME = 9L;
 
-        Chunk chunk = new Chunk(VmGcStatDAO.vmGcStatsCategory, false);
+        Chunk chunk = new Chunk(VmGcStatDAO.vmGcStatCategory, false);
         chunk.put(Key.TIMESTAMP, TIMESTAMP);
-        chunk.put(VmGcStatDAO.vmIdKey, VM_ID);
+        chunk.put(Key.VM_ID, VM_ID);
         chunk.put(VmGcStatDAO.collectorKey, COLLECTOR);
         chunk.put(VmGcStatDAO.runCountKey, RUN_COUNT);
         chunk.put(VmGcStatDAO.wallTimeKey, WALL_TIME);
@@ -149,10 +149,10 @@
         when(vmRef.getAgent()).thenReturn(hostRef);
         when(vmRef.getId()).thenReturn(321);
 
-        VmGcStatDAO dao = new VmGcStatDAOImpl(storage, vmRef);
-        dao.getLatestVmGcStats();
+        VmGcStatDAO dao = new VmGcStatDAOImpl(storage);
+        dao.getLatestVmGcStats(vmRef);
 
-        dao.getLatestVmGcStats();
+        dao.getLatestVmGcStats(vmRef);
         ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
         verify(storage, times(2)).findAll(arg.capture());
         assertEquals("this.timestamp > 456", arg.getValue().get(new Key<String>("$where", false)));
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmInfoConverterTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmInfoConverterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -91,7 +91,7 @@
                 vmName, vmInfo, vmVersion, vmArgs,
                 props, env, libs);
 
-        Chunk chunk = new VmInfoConverter().vmInfoToChunk(info);
+        Chunk chunk = new VmInfoConverter().toChunk(info);
 
         assertNotNull(chunk);
         assertEquals((Integer) vmId, chunk.get(VmInfoDAO.vmIdKey));
@@ -130,7 +130,7 @@
         chunk.put(VmInfoDAO.environmentKey, env);
         chunk.put(VmInfoDAO.librariesKey, libs);
 
-        VmInfo info = new VmInfoConverter().chunkToVmInfo(chunk);
+        VmInfo info = new VmInfoConverter().fromChunk(chunk);
 
         assertNotNull(info);
         assertEquals((Integer) vmId, (Integer) info.getVmId());
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -49,11 +49,14 @@
 import java.util.List;
 import java.util.Map;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
 import com.redhat.thermostat.common.model.VmInfo;
+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;
 
@@ -73,6 +76,7 @@
     private Map<String, String> props;
     private Map<String, String> env;
     private List<String> libs;
+    private VmInfoDAO dao;
 
     @Before
     public void setUp() {
@@ -90,6 +94,13 @@
         props = new HashMap<>();
         env = new HashMap<>();
         libs = new ArrayList<>();
+        Storage storage = setupStorageForSingleVM();
+        dao = new VmInfoDAOImpl(storage);
+    }
+
+    @After
+    public void tearDown() {
+        dao = null;
     }
 
     @Test
@@ -111,7 +122,7 @@
         assertTrue(keys.contains(new Key<List<String>>("libraries", false)));
         assertTrue(keys.contains(new Key<Long>("start-time", false)));
         assertTrue(keys.contains(new Key<Long>("stop-time", false)));
-        assertEquals(15, keys.size());
+        assertEquals(16, keys.size());
     }
 
     @Test
@@ -143,8 +154,8 @@
         when(vmRef.getAgent()).thenReturn(hostRef);
         when(vmRef.getId()).thenReturn(321);
 
-        VmInfoDAO dao = new VmInfoDAOImpl(storage, vmRef);
-        VmInfo info = dao.getVmInfo();
+        VmInfoDAO dao = new VmInfoDAOImpl(storage);
+        VmInfo info = dao.getVmInfo(vmRef);
 
         assertNotNull(info);
         assertEquals((Integer) vmId, (Integer) info.getVmId());
@@ -162,4 +173,67 @@
 
         // FIXME test environment, properties and loaded native libraries later
     }
+
+    private Storage setupStorageForSingleVM() {
+        Chunk query1 = new Chunk(VmInfoDAO.vmInfoCategory, false);
+        query1.put(Key.AGENT_ID, "123");
+
+        Chunk query2 = new Chunk(VmInfoDAO.vmInfoCategory, false);
+        query2.put(Key.AGENT_ID, "456");
+
+        Chunk vm1 = new Chunk(VmInfoDAO.vmInfoCategory, false);
+        vm1.put(VmInfoDAO.vmIdKey, 123);
+        vm1.put(VmInfoDAO.mainClassKey, "mainClass1");
+
+        Chunk vm2 = new Chunk(VmInfoDAO.vmInfoCategory, false);
+        vm2.put(VmInfoDAO.vmIdKey, 456);
+        vm2.put(VmInfoDAO.mainClassKey, "mainClass2");
+
+        Cursor singleVMCursor = mock(Cursor.class);
+        when(singleVMCursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(singleVMCursor.next()).thenReturn(vm1);
+
+        Cursor multiVMsCursor = mock(Cursor.class);
+        when(multiVMsCursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(multiVMsCursor.next()).thenReturn(vm1).thenReturn(vm2);
+
+        Storage storage = mock(Storage.class);
+        when(storage.findAll(query1)).thenReturn(singleVMCursor);
+        when(storage.findAll(query2)).thenReturn(multiVMsCursor);
+        return storage;
+    }
+
+    @Test
+    public void testSingleVM() {
+        HostRef host = new HostRef("123", "fluffhost");
+
+        Collection<VmRef> vms = dao.getVMs(host);
+
+        assertCollection(vms, new VmRef(host, 123, "mainClass1"));
+    }
+
+    @Test
+    public void testMultiVMs() {
+        HostRef host = new HostRef("456", "fluffhost");
+
+        Collection<VmRef> vms = dao.getVMs(host);
+
+        assertCollection(vms, new VmRef(host, 123, "mainClass1"), new VmRef(host, 456, "mainClass2"));
+    }
+
+    private void assertCollection(Collection<VmRef> vms, VmRef... expectedVMs) {
+        assertEquals(expectedVMs.length, vms.size());
+        for (VmRef expectedVM : expectedVMs) {
+            assertTrue(vms.contains(expectedVM));
+        }
+    }
+
+    @Test
+    public void testGetCount() {
+        Storage storage = mock(Storage.class);
+        when(storage.getCount(any(Category.class))).thenReturn(5L);
+        VmInfoDAO dao = new VmInfoDAOImpl(storage);
+        Long count = dao.getCount();
+        assertEquals((Long) 5L, count);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,190 @@
+/*
+ * 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 org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.model.VmClassStat;
+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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class VmLatestPojoListGetterTest {
+    private static final String AGENT_ID = "agentid";
+    private static final String HOSTNAME = "host.example.com";
+    private static final int VM_PID = 123;
+    private static final String MAIN_CLASS = "Foo.class";
+    private static final String CATEGORY_NAME = "vmcategory";
+    // Make this one static so we don't get IllegalStateException from trying
+    // to make category of same name while running tests in same classloader.
+    private static final Category cat =  new Category(CATEGORY_NAME);
+
+    private static long t1 = 1;
+    private static long t2 = 5;
+    private static long t3 = 10;
+
+    private static long lc1 = 10;
+    private static long lc2 = 20;
+    private static long lc3 = 30;
+
+    private HostRef hostRef;
+    private VmRef vmRef;
+    private Converter<VmClassStat> converter;
+    private Chunk result1, result2, result3;
+
+    @Before
+    public void setUp() {
+        hostRef = new HostRef(AGENT_ID, HOSTNAME);
+        vmRef = new VmRef(hostRef, VM_PID, MAIN_CLASS);
+        converter = new VmClassStatConverter();
+        result1 = new Chunk(cat, false);
+        result1.put(Key.AGENT_ID, AGENT_ID);
+        result1.put(Key.VM_ID, VM_PID);
+        result1.put(Key.TIMESTAMP, t1);
+        result1.put(VmClassStatDAO.loadedClassesKey, lc1);
+        result2 = new Chunk(cat, false);
+        result2.put(Key.AGENT_ID, AGENT_ID);
+        result2.put(Key.VM_ID, VM_PID);
+        result2.put(Key.TIMESTAMP, t2);
+        result2.put(VmClassStatDAO.loadedClassesKey, lc2);
+        result3 = new Chunk(cat, false);
+        result3.put(Key.AGENT_ID, AGENT_ID);
+        result3.put(Key.VM_ID, VM_PID);
+        result3.put(Key.TIMESTAMP, t3);
+        result3.put(VmClassStatDAO.loadedClassesKey, lc3);
+    }
+
+    @Test
+    public void testBuildQuery() {
+        Storage storage = mock(Storage.class);
+        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, converter, vmRef);
+        Chunk query = getter.buildQuery();
+
+        assertNotNull(query);
+        assertEquals(cat, query.getCategory());
+        assertEquals(2, query.getKeys().size());
+        assertTrue(query.getKeys().contains(Key.AGENT_ID));
+        assertTrue(query.getKeys().contains(Key.VM_ID));
+        assertFalse(query.getKeys().contains(Key.WHERE));
+        assertEquals(AGENT_ID, query.get(Key.AGENT_ID));
+        assertEquals((Integer) VM_PID, query.get(Key.VM_ID));
+    }
+
+    @Test
+    public void testBuildQueryPopulatesUpdateTimes() {
+        Storage storage = mock(Storage.class);
+        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, converter, vmRef);
+        getter.buildQuery(); // Ignore first return value.
+        Chunk query = getter.buildQuery();
+
+        assertNotNull(query);
+        assertEquals(cat, query.getCategory());
+        assertEquals(3, query.getKeys().size());
+        assertTrue(query.getKeys().contains(Key.AGENT_ID));
+        assertTrue(query.getKeys().contains(Key.VM_ID));
+        assertTrue(query.getKeys().contains(Key.WHERE));
+        assertEquals("this.timestamp > " + Long.MIN_VALUE, query.get(Key.WHERE));
+    }
+
+    @Test
+    public void testGetLatest() {
+        Cursor cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
+
+        Storage storage = mock(Storage.class);
+        when(storage.findAll(any(Chunk.class))).thenReturn(cursor);
+
+        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, converter, vmRef);
+
+        List<VmClassStat> stats = getter.getLatest();
+
+        assertNotNull(stats);
+        assertEquals(2, stats.size());
+        VmClassStat stat1 = stats.get(0);
+        assertEquals(t1, stat1.getTimeStamp());
+        assertEquals(lc1, stat1.getLoadedClasses());
+        VmClassStat stat2 = stats.get(1);
+        assertEquals(t2, stat2.getTimeStamp());
+        assertEquals(lc2, stat2.getLoadedClasses());
+    }
+
+    @Test
+    public void testGetLatestMultipleCalls() {
+        Cursor cursor1 = mock(Cursor.class);
+        when(cursor1.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(cursor1.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
+
+        Cursor cursor2 = mock(Cursor.class);
+        when(cursor2.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor2.next()).thenReturn(result3);
+
+        Storage storage = mock(Storage.class);
+        when(storage.findAll(any(Chunk.class))).thenReturn(cursor1);
+
+        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, converter, vmRef);
+        getter.getLatest();
+        getter.getLatest();
+
+        ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
+        verify(storage, times(2)).findAll(arg.capture());
+        List<Chunk> queries = arg.getAllValues();
+
+        assertEquals(2, queries.size());
+        Chunk query = queries.get(1);
+        assertNotNull(query);
+        assertEquals(AGENT_ID, query.get(Key.AGENT_ID));
+        assertEquals((Integer) VM_PID, query.get(Key.VM_ID));
+        assertEquals("this.timestamp > " + t2, query.get(Key.WHERE));
+    }
+}
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatConverterTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatConverterTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -84,7 +84,7 @@
 
         VmMemoryStat stat = new VmMemoryStat(1, 2, generations);
 
-        Chunk chunk = new VmMemoryStatConverter().vmMemoryStatToChunk(stat);
+        Chunk chunk = new VmMemoryStatConverter().toChunk(stat);
 
         assertNotNull(chunk);
         assertEquals((Long) 1l, chunk.get(new Key<Long>("timestamp", false)));
@@ -125,7 +125,7 @@
         Chunk chunk = new Chunk(VmMemoryStatDAO.vmMemoryStatsCategory, false);
 
         chunk.put(Key.TIMESTAMP, TIMESTAMP);
-        chunk.put(VmMemoryStatDAO.vmIdKey, VM_ID);
+        chunk.put(Key.VM_ID, VM_ID);
 
         chunk.put(VmMemoryStatDAO.edenGenKey, "new");
         chunk.put(VmMemoryStatDAO.edenCollectorKey, "new-collector");
@@ -157,7 +157,7 @@
         chunk.put(VmMemoryStatDAO.permCapacityKey, 14l);
         chunk.put(VmMemoryStatDAO.permMaxCapacityKey, 15l);
 
-        VmMemoryStat stat = new VmMemoryStatConverter().chunkToVmMemoryStat(chunk);
+        VmMemoryStat stat = new VmMemoryStatConverter().fromChunk(chunk);
 
         assertNotNull(stat);
         assertEquals(TIMESTAMP, stat.getTimeStamp());
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -91,7 +91,7 @@
         assertTrue(keys.contains(new Key<Long>("perm.capacity", false)));
         assertTrue(keys.contains(new Key<Long>("perm.max-capacity", false)));
         assertTrue(keys.contains(new Key<Long>("perm.used", false)));
-        assertEquals(27, keys.size());
+        assertEquals(28, keys.size());
     }
 
     @Test
@@ -122,8 +122,8 @@
         when(cursor.limit(any(Integer.class))).thenReturn(cursor);
         when(cursor.hasNext()).thenReturn(false);
 
-        VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage, vmRef);
-        impl.getLatestMemoryStat();
+        VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage);
+        impl.getLatestMemoryStat(vmRef);
 
         ArgumentCaptor<Key> sortKey = ArgumentCaptor.forClass(Key.class);
         ArgumentCaptor<SortDirection> sortDirection = ArgumentCaptor.forClass(SortDirection.class);
@@ -131,7 +131,7 @@
 
         Chunk query = (Chunk) savedQuery[0];
         assertEquals(AGENT_ID, query.get(Key.AGENT_ID));
-        assertEquals((Integer)VM_ID, query.get(VmMemoryStatDAO.vmIdKey));
+        assertEquals((Integer)VM_ID, query.get(Key.VM_ID));
 
         assertTrue(sortKey.getValue().equals(Key.TIMESTAMP));
         assertTrue(sortDirection.getValue().equals(SortDirection.DESCENDING));
@@ -158,8 +158,8 @@
         Storage storage = mock(Storage.class);
         when(storage.findAll(any(Chunk.class))).thenReturn(cursor);
 
-        VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage, vmRef);
-        VmMemoryStat latest = impl.getLatestMemoryStat();
+        VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage);
+        VmMemoryStat latest = impl.getLatestMemoryStat(vmRef);
         assertTrue(latest == null);
     }
 }
--- a/common/src/test/java/com/redhat/thermostat/common/dao/VmRefDAOTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +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.dao;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Collection;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.storage.Chunk;
-import com.redhat.thermostat.common.storage.Cursor;
-import com.redhat.thermostat.common.storage.Storage;
-
-public class VmRefDAOTest {
-
-    private VmRefDAO dao;
-
-    @Before
-    public void setUp() {
-        Storage storage = setupStorageForSingleVM();
-        dao = new VmRefDAOImpl(storage);
-    }
-
-    @After
-    public void tearDown() {
-        dao = null;
-    }
-
-    private Storage setupStorageForSingleVM() {
-        Chunk query1 = new Chunk(VmInfoDAO.vmInfoCategory, false);
-        query1.put(HostRefDAO.agentIdKey, "123");
-
-        Chunk query2 = new Chunk(VmInfoDAO.vmInfoCategory, false);
-        query2.put(HostRefDAO.agentIdKey, "456");
-
-        Chunk vm1 = new Chunk(VmInfoDAO.vmInfoCategory, false);
-        vm1.put(VmInfoDAO.vmIdKey, 123);
-        vm1.put(VmInfoDAO.mainClassKey, "mainClass1");
-
-        Chunk vm2 = new Chunk(VmInfoDAO.vmInfoCategory, false);
-        vm2.put(VmInfoDAO.vmIdKey, 456);
-        vm2.put(VmInfoDAO.mainClassKey, "mainClass2");
-
-        Cursor singleVMCursor = mock(Cursor.class);
-        when(singleVMCursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(singleVMCursor.next()).thenReturn(vm1);
-
-        Cursor multiVMsCursor = mock(Cursor.class);
-        when(multiVMsCursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(multiVMsCursor.next()).thenReturn(vm1).thenReturn(vm2);
-
-        Storage storage = mock(Storage.class);
-        when(storage.findAll(query1)).thenReturn(singleVMCursor);
-        when(storage.findAll(query2)).thenReturn(multiVMsCursor);
-        return storage;
-    }
-
-    @Test
-    public void testSingleVM() {
-        HostRef host = new HostRef("123", "fluffhost");
-
-        Collection<VmRef> vms = dao.getVMs(host);
-
-        assertCollection(vms, new VmRef(host, 123, "mainClass1"));
-    }
-
-    @Test
-    public void testMultiVMs() {
-        HostRef host = new HostRef("456", "fluffhost");
-
-        Collection<VmRef> vms = dao.getVMs(host);
-
-        assertCollection(vms, new VmRef(host, 123, "mainClass1"), new VmRef(host, 456, "mainClass2"));
-    }
-
-    private void assertCollection(Collection<VmRef> vms, VmRef... expectedVMs) {
-        assertEquals(expectedVMs.length, vms.size());
-        for (VmRef expectedVM : expectedVMs) {
-            assertTrue(vms.contains(expectedVM));
-        }
-    }
-
-}
--- a/common/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/common/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -43,6 +43,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -57,12 +58,13 @@
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
 import com.mongodb.DBCollection;
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
 
 @RunWith(PowerMockRunner.class)
-@PrepareForTest(DBCollection.class)
+@PrepareForTest({DBCollection.class, DB.class})
 public class MongoStorageTest {
 
     private static final Key<String> key1 = new Key<>("key1", false);
@@ -71,15 +73,19 @@
     private static final Key<String> key4 = new Key<>("key4", false);
     private static final Key<String> key5 = new Key<>("key5", false);
     private static final Category testCategory = new Category("MongoStorageTest", key1, key2, key3, key4, key5);
+    private static final Category emptyTestCategory = new Category("MongoEmptyCategory");
 
     private Chunk multiKeyQuery;
 
     private MongoStorage storage;
-    private DBCollection testCollection;
+    private DB db;
+    private DBCollection testCollection, emptyTestCollection;
 
     @Before
     public void setUp() {
         storage = new MongoStorage(null);
+        db = PowerMockito.mock(DB.class);
+        storage.connect(db);
 
         BasicDBObject value1 = new BasicDBObject();
         value1.put("key1", "test1");
@@ -103,7 +109,13 @@
         when(testCollection.find(any(DBObject.class))).thenReturn(cursor);
         when(testCollection.find()).thenReturn(cursor);
         when(testCollection.findOne(any(DBObject.class))).thenReturn(value1);
+        when(testCollection.getCount()).thenReturn(2L);
         storage.mapCategoryToDBCollection(testCategory, testCollection);
+        emptyTestCollection = PowerMockito.mock(DBCollection.class);
+        when(emptyTestCollection.getCount()).thenReturn(0L);
+        storage.mapCategoryToDBCollection(emptyTestCategory, emptyTestCollection);
+        when(db.collectionExists(anyString())).thenReturn(false);
+        when(db.createCollection(anyString(), any(DBObject.class))).thenReturn(testCollection);
     }
 
     @After
@@ -116,6 +128,7 @@
     @Test
     public void testCreateConnectionKey() {
         MongoStorage mongoStorage = new MongoStorage(null);
+        mongoStorage.connect(db);
         Category category = new Category("testCreateConnectionKey");
         ConnectionKey connKey = mongoStorage.createConnectionKey(category);
         assertNotNull(connKey);
@@ -248,6 +261,24 @@
         verifyDefaultCursor(cursor);
     }
 
+    @Test
+    public void verifyGetCount() {
+        long count = storage.getCount(testCategory);
+        assertEquals(2, count);
+    }
+
+    @Test
+    public void verifyGetCountForEmptyCategory() {
+        long count = storage.getCount(emptyTestCategory);
+        assertEquals(0, count);
+    }
+
+    @Test
+    public void verifyGetCountForNonexistentCategory() {
+        long count = storage.getCount(new Category("NonExistent"));
+        assertEquals(0, count);
+    }
+
     private void verifyDefaultCursor(Cursor cursor) {
         assertTrue(cursor.hasNext());
         Chunk chunk1 = cursor.next();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/tools/BasicApplicationTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.tools;
+
+import static org.junit.Assert.*;
+
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+import com.redhat.thermostat.common.config.StartupConfiguration;
+
+public class BasicApplicationTest {
+
+    private BasicApplication application;
+
+    @Before
+    public void setUp() {
+        application = new BasicApplication() {
+            @Override
+            public void parseArguments(List<String> args)
+                    throws InvalidConfigurationException { }
+
+            @Override
+            public void run() {}
+
+            @Override
+            public StartupConfiguration getConfiguration() {
+                return null;
+            }
+
+            @Override
+            public void printHelp() {}
+        };
+    }
+
+    @After
+    public void tearDown() {
+        application = null;
+    }
+
+    @Test
+    public void testNotfier() {
+        assertNotNull(application.getNotifier());
+    }
+}
--- a/tools/src/main/java/com/redhat/thermostat/tools/ThermostatService.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/tools/src/main/java/com/redhat/thermostat/tools/ThermostatService.java	Wed Apr 04 21:49:29 2012 +0200
@@ -112,7 +112,9 @@
     public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
         if (actionEvent.getSource().equals(database)) {
             switch (actionEvent.getActionId()) {
-            case SUCCESS:
+            // we are only interested in starting the agent if
+            // we started the service
+            case START:
                 String dbUrl = database.getConfiguration().getDBConnectionString();
                 List<String> args = new ArrayList<>();
                 args.add("--dbUrl");
--- a/tools/src/main/java/com/redhat/thermostat/tools/db/DBService.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBService.java	Wed Apr 04 21:49:29 2012 +0200
@@ -46,6 +46,7 @@
 import com.redhat.thermostat.common.config.ConfigUtils;
 import com.redhat.thermostat.common.config.InvalidConfigurationException;
 import com.redhat.thermostat.tools.ApplicationException;
+import com.redhat.thermostat.tools.ApplicationState;
 import com.redhat.thermostat.tools.BasicApplication;
 
 public class DBService extends BasicApplication {
@@ -69,7 +70,6 @@
         
         parser = new DBOptionParser(configuration, args);
         parser.parse();
-        
     }
     
     private void readAndSetProperties(File propertyFile) throws InvalidConfigurationException {
@@ -115,19 +115,20 @@
     
     private void startService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException {
         runner.startService();
-        notifySuccess();
+        getNotifier().fireAction(ApplicationState.START);
     }
     
     
     private void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException {
         check();
         runner.stopService();
-        notifySuccess();
+        getNotifier().fireAction(ApplicationState.STOP);
     }
     
     @Override
     public void run() {
         
+        // dry run means we don't do anything at all
         if (parser.isDryRun()) return;
         
         runner = createRunner();
@@ -140,10 +141,13 @@
             case STOP:
                 stopService();
                 break;
+             default:
+                break;
             }
+            getNotifier().fireAction(ApplicationState.SUCCESS);
+            
         } catch (Exception e) {
-            // TODO: exception should be at least logged
-            notifyFail();
+            getNotifier().fireAction(ApplicationState.FAIL);
         }
     }
     
--- a/tools/src/test/java/com/redhat/thermostat/tools/db/DBServiceTest.java	Wed Apr 04 21:47:57 2012 +0200
+++ b/tools/src/test/java/com/redhat/thermostat/tools/db/DBServiceTest.java	Wed Apr 04 21:49:29 2012 +0200
@@ -157,20 +157,29 @@
     {
         DBService service = prepareService(true);
         
-        final CountDownLatch latch = new CountDownLatch(0);
-        final boolean[] result = new boolean[1];
+        final CountDownLatch latch = new CountDownLatch(2);
+        
+        final boolean[] result = new boolean[2];
         service.getNotifier().addActionListener(new ActionListener<ApplicationState>() {
             @Override
             public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
                 switch (actionEvent.getActionId()) {
                 case FAIL:
                     result[0] = false;
+                    latch.countDown();
+                    latch.countDown();
                     break;
+                    
                 case SUCCESS:
                     result[0] = true;
+                    latch.countDown();
                     break;
+
+                case START:
+                    result[1] = true;
+                    latch.countDown();
+                    break;                    
                 }
-                latch.countDown();
             }
         });
         
@@ -178,16 +187,16 @@
         latch.await();
         
         Assert.assertTrue(result[0]);
+        Assert.assertTrue(result[1]);
     }
     
-    
     @Test
     public void testListenersFail() throws InvalidConfigurationException,
             InterruptedException, IOException, ApplicationException
     {
         DBService service = prepareService(false);
         
-        final CountDownLatch latch = new CountDownLatch(0);
+        final CountDownLatch latch = new CountDownLatch(1);
         final boolean[] result = new boolean[1];
         service.getNotifier().addActionListener(new ActionListener<ApplicationState>() {
             @Override
@@ -196,6 +205,7 @@
                 case FAIL:
                     result[0] = true;
                     break;
+                    
                 case SUCCESS:
                     result[0] = false;
                     break;