changeset 142:bc16cdea4e32

Refactor client MemoryStat to use DAO reviewed-by: omajid review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-March/000438.html
author Jon VanAlten <jon.vanalten@redhat.com>
date Fri, 23 Mar 2012 18:52:27 -0400
parents d13c85f93de6
children 3e71c9cd3f99
files client/src/main/java/com/redhat/thermostat/client/DiscreteTimeData.java client/src/main/java/com/redhat/thermostat/client/HostPanelFacadeImpl.java client/src/main/java/com/redhat/thermostat/client/MemoryType.java client/src/main/java/com/redhat/thermostat/client/TimeSeriesUpdater.java client/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java client/src/main/java/com/redhat/thermostat/client/ui/HostCpuPanel.java client/src/main/java/com/redhat/thermostat/client/ui/HostCpuView.java client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryPanel.java client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryView.java client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatController.java client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatView.java client/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java client/src/main/java/com/redhat/thermostat/client/ui/VmCpuPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmCpuView.java client/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java client/src/main/java/com/redhat/thermostat/client/ui/VmGcPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmGcView.java client/src/test/java/com/redhat/thermostat/client/TimeSeriesUpdaterTest.java client/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java client/src/test/java/com/redhat/thermostat/client/ui/VmClassStatPanelTest.java common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAO.java common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java common/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatConverter.java common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAO.java common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java common/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAO.java common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java common/src/main/java/com/redhat/thermostat/common/model/DiscreteTimeData.java common/src/main/java/com/redhat/thermostat/common/model/MemoryType.java common/src/main/java/com/redhat/thermostat/common/storage/Key.java common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatConverterTest.java common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java common/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java
diffstat 39 files changed, 492 insertions(+), 321 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/main/java/com/redhat/thermostat/client/DiscreteTimeData.java	Fri Mar 23 22:48:13 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +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.client;
-
-/**
- * Represents a data associated with a discrete point in time
- *
- * @param <T> the type data associated with this point in time
- */
-public class DiscreteTimeData<T> {
-
-    private long millis;
-    private T data;
-
-    public DiscreteTimeData(long millis, T data) {
-        this.millis = millis;
-        this.data = data;
-    }
-
-    public long getTimeInMillis() {
-        return millis;
-    }
-
-    public T getData() {
-        return data;
-    }
-
-}
--- a/client/src/main/java/com/redhat/thermostat/client/HostPanelFacadeImpl.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/HostPanelFacadeImpl.java	Fri Mar 23 18:52:27 2012 -0400
@@ -52,7 +52,7 @@
     public HostPanelFacadeImpl(HostRef ref, DB db) {
         overviewController = new HostOverviewController(ref, db);
         cpuController = new HostCpuController(ref);
-        memoryController = new HostMemoryController(ref, db);
+        memoryController = new HostMemoryController(ref);
     }
 
     @Override
--- a/client/src/main/java/com/redhat/thermostat/client/MemoryType.java	Fri Mar 23 22:48:13 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +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.client;
-
-import static com.redhat.thermostat.client.locale.Translate.localize;
-
-import com.redhat.thermostat.client.locale.LocaleResources;
-
-public enum MemoryType {
-    MEMORY_TOTAL("total", localize(LocaleResources.HOST_MEMORY_TOTAL)),
-    MEMORY_FREE("free", localize(LocaleResources.HOST_MEMORY_FREE)),
-    MEMORY_USED("used", localize(LocaleResources.HOST_MEMORY_USED)),
-    SWAP_TOTAL("swap-total", localize(LocaleResources.HOST_SWAP_TOTAL)),
-    SWAP_FREE("swap-free", localize(LocaleResources.HOST_SWAP_FREE)),
-    SWAP_BUFFERS("buffers", localize(LocaleResources.HOST_BUFFERS));
-
-    private String humanReadable;
-    private String internalName;
-
-    private MemoryType(String key, String humanReadable) {
-        this.internalName = key;
-        this.humanReadable = humanReadable;
-    }
-
-    public String getInternalName() {
-        return internalName;
-    }
-
-    public String getLabel() {
-        return humanReadable;
-    }
-
-    @Override
-    public String toString() {
-        return humanReadable;
-    }
-
-}
--- a/client/src/main/java/com/redhat/thermostat/client/TimeSeriesUpdater.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/TimeSeriesUpdater.java	Fri Mar 23 18:52:27 2012 -0400
@@ -45,6 +45,8 @@
 import org.jfree.data.time.FixedMillisecond;
 import org.jfree.data.time.TimeSeries;
 
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+
 /**
  * Updates a TimeSeries by asynchronously fetching data and updating the
  * TimeSeries on the Swing EDT.
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Fri Mar 23 18:52:27 2012 -0400
@@ -44,7 +44,6 @@
 import java.util.concurrent.TimeUnit;
 
 import com.redhat.thermostat.client.AsyncUiFacade;
-import com.redhat.thermostat.client.DiscreteTimeData;
 import com.redhat.thermostat.client.appctx.ApplicationContext;
 import com.redhat.thermostat.common.CpuStat;
 import com.redhat.thermostat.common.HostInfo;
@@ -52,6 +51,7 @@
 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.model.DiscreteTimeData;
 
 public class HostCpuController implements AsyncUiFacade {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuPanel.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuPanel.java	Fri Mar 23 18:52:27 2012 -0400
@@ -54,10 +54,10 @@
 import org.jfree.data.time.TimeSeriesCollection;
 
 import com.redhat.thermostat.client.ChangeableText;
-import com.redhat.thermostat.client.DiscreteTimeData;
 import com.redhat.thermostat.client.locale.LocaleResources;
 import com.redhat.thermostat.client.ui.SimpleTable.Section;
 import com.redhat.thermostat.client.ui.SimpleTable.TableEntry;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class HostCpuPanel extends JPanel implements HostCpuView {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuView.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuView.java	Fri Mar 23 18:52:27 2012 -0400
@@ -39,7 +39,7 @@
 import java.awt.Component;
 import java.util.List;
 
-import com.redhat.thermostat.client.DiscreteTimeData;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface HostCpuView {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java	Fri Mar 23 18:52:27 2012 -0400
@@ -36,80 +36,66 @@
 
 package com.redhat.thermostat.client.ui;
 
+import static com.redhat.thermostat.client.locale.Translate.localize;
+
 import java.awt.Component;
-import java.util.Arrays;
-import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Timer;
 import java.util.TimerTask;
-import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
 
-import com.mongodb.BasicDBObject;
-import com.mongodb.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.DBCursor;
-import com.mongodb.DBObject;
 import com.redhat.thermostat.client.AsyncUiFacade;
-import com.redhat.thermostat.client.DiscreteTimeData;
-import com.redhat.thermostat.client.MemoryType;
 import com.redhat.thermostat.client.appctx.ApplicationContext;
+import com.redhat.thermostat.client.locale.LocaleResources;
 import com.redhat.thermostat.client.ui.HostMemoryView.GraphVisibilityChangeListener;
-import com.redhat.thermostat.common.HostInfo;
 import com.redhat.thermostat.common.MemoryStat;
+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.MemoryStatConverter;
+import com.redhat.thermostat.common.dao.MemoryStatDAO;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.common.model.MemoryType;
 
 public class HostMemoryController implements AsyncUiFacade {
 
     private final HostMemoryView view;
 
-    private final HostRef hostRef;
     private final HostInfoDAO hostInfoDAO;
-    private final DBCollection memoryStatsCollection;
+    private final MemoryStatDAO memoryStatDAO;
 
     private final Timer backgroundUpdateTimer;
-
-    private final Map<MemoryType, Long> lastUpdateTime = new HashMap<>();
-    private final List<MemoryType> currentlyDisplayed = new CopyOnWriteArrayList<>();
-
-    public HostMemoryController(HostRef hostRef, DB db) {
-        this.hostRef = hostRef;
+    private final GraphVisibilityChangeListener listener = new ShowHideGraph();
 
-        currentlyDisplayed.addAll(Arrays.asList(MemoryType.values()));
-
-        hostInfoDAO = ApplicationContext.getInstance().getDAOFactory().getHostInfoDAO(hostRef);
-        memoryStatsCollection = db.getCollection("memory-stats");
-
-        for (MemoryType type: MemoryType.values()) {
-            lastUpdateTime.put(type, Long.MIN_VALUE);
-        }
+    public HostMemoryController(HostRef hostRef) {
+        DAOFactory daos = ApplicationContext.getInstance().getDAOFactory();
+        hostInfoDAO = daos.getHostInfoDAO(hostRef);
+        memoryStatDAO = daos.getMemoryStatDAO(hostRef);
 
         view = createView();
 
-        view.addListener(new ShowHideGraph());
+        view.addMemoryChart(MemoryType.MEMORY_TOTAL.name(), localize(LocaleResources.HOST_MEMORY_TOTAL));
+        view.addMemoryChart(MemoryType.MEMORY_FREE.name(), localize(LocaleResources.HOST_MEMORY_FREE));
+        view.addMemoryChart(MemoryType.MEMORY_USED.name(), localize(LocaleResources.HOST_MEMORY_USED));
+        view.addMemoryChart(MemoryType.SWAP_TOTAL.name(), localize(LocaleResources.HOST_SWAP_TOTAL));
+        view.addMemoryChart(MemoryType.SWAP_FREE.name(), localize(LocaleResources.HOST_SWAP_FREE));
+        view.addMemoryChart(MemoryType.BUFFERS.name(), localize(LocaleResources.HOST_BUFFERS));
+
+        view.addGraphVisibilityListener(listener);
 
         backgroundUpdateTimer = new Timer();
-
     }
 
     @Override
     public void start() {
-        for (MemoryType type: currentlyDisplayed) {
-            view.addMemoryChart(type.name(), type.toString());
+        for (MemoryType type : MemoryType.values()) {
             view.showMemoryChart(type.name());
         }
 
         backgroundUpdateTimer.scheduleAtFixedRate(new TimerTask() {
             @Override
             public void run() {
-
-                HostInfo hostInfo = hostInfoDAO.getHostInfo();
-
-                view.setTotalMemory(String.valueOf(hostInfo.getTotalMemory()));
+                view.setTotalMemory(String.valueOf(hostInfoDAO.getHostInfo().getTotalMemory()));
                 doMemoryChartUpdate();
             }
 
@@ -120,8 +106,8 @@
     @Override
     public void stop() {
         backgroundUpdateTimer.cancel();
-        for (MemoryType type: currentlyDisplayed) {
-            view.removeMemoryChart(type.name());
+        for (MemoryType type : MemoryType.values()) {
+            view.hideMemoryChart(type.name());
         }
     }
 
@@ -129,50 +115,34 @@
         return view.getUiComponent();
     }
 
-    private HostMemoryView createView() {
+    protected HostMemoryView createView() {
         return new HostMemoryPanel();
     }
 
     private void doMemoryChartUpdate() {
-        for (final MemoryType type: currentlyDisplayed) {
-            BasicDBObject query = new BasicDBObject();
-            query.put("agent-id", hostRef.getAgentId());
-            query.put("timestamp", new BasicDBObject("$gt", lastUpdateTime.get(type)));
-            DBCursor cursor = memoryStatsCollection.find(query);
-
-            List<DiscreteTimeData<? extends Number>> toAdd = new LinkedList<>();
-            long lastUpdate = Long.MIN_VALUE;
+        List<DiscreteTimeData<? extends Number>> memFree = new LinkedList<>();
+        List<DiscreteTimeData<? extends Number>> memTotal = new LinkedList<>();
+        List<DiscreteTimeData<? extends Number>> memUsed = new LinkedList<>();
+        List<DiscreteTimeData<? extends Number>> buf = new LinkedList<>();
+        List<DiscreteTimeData<? extends Number>> swapTotal = new LinkedList<>();
+        List<DiscreteTimeData<? extends Number>> swapFree = new LinkedList<>();
+        
+        for (MemoryStat stat : memoryStatDAO.getLatestMemoryStats()) {
+            long timeStamp = stat.getTimeStamp();
+            memFree.add(new DiscreteTimeData<Long>(timeStamp, stat.getFree()));
+            memTotal.add(new DiscreteTimeData<Long>(timeStamp, stat.getTotal()));
+            memUsed.add(new DiscreteTimeData<Long>(timeStamp, stat.getTotal() - stat.getFree()));
+            buf.add(new DiscreteTimeData<Long>(timeStamp, stat.getBuffers()));
+            swapTotal.add(new DiscreteTimeData<Long>(timeStamp, stat.getSwapTotal()));
+            swapFree.add(new DiscreteTimeData<Long>(timeStamp, stat.getSwapFree()));
+        }
 
-            for (DBObject toConvert: cursor) {
-                MemoryStat stat = new MemoryStatConverter().dbObjectToMemoryStat(toConvert);
-                long data = 0;
-                switch (type) {
-                    case MEMORY_FREE:
-                        data = stat.getFree();
-                        break;
-                    case MEMORY_TOTAL:
-                        data = stat.getTotal();
-                        break;
-                    case MEMORY_USED:
-                        data = stat.getTotal() - stat.getFree();
-                        break;
-                    case SWAP_BUFFERS:
-                        data = stat.getBuffers();
-                        break;
-                    case SWAP_FREE:
-                        data = stat.getFree();
-                        break;
-                    case SWAP_TOTAL:
-                        data = stat.getTotal();
-                        break;
-
-                }
-                lastUpdate = Math.max(lastUpdate, stat.getTimeStamp());
-                toAdd.add(new DiscreteTimeData<Long>(stat.getTimeStamp(), data));
-            }
-            view.addMemoryData(type.name(), toAdd);
-            lastUpdateTime.put(type, lastUpdate);
-        }
+        view.addMemoryData(MemoryType.MEMORY_FREE.name(), memFree);
+        view.addMemoryData(MemoryType.MEMORY_TOTAL.name(), memTotal);
+        view.addMemoryData(MemoryType.MEMORY_USED.name(), memUsed);
+        view.addMemoryData(MemoryType.BUFFERS.name(), buf);
+        view.addMemoryData(MemoryType.SWAP_FREE.name(), swapFree);
+        view.addMemoryData(MemoryType.SWAP_TOTAL.name(), swapTotal);
     }
 
     private class ShowHideGraph implements GraphVisibilityChangeListener {
@@ -184,7 +154,5 @@
         public void hide(String tag) {
             view.hideMemoryChart(tag);
         }
-
     }
-
 }
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryPanel.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryPanel.java	Fri Mar 23 18:52:27 2012 -0400
@@ -60,10 +60,10 @@
 import org.jfree.data.time.TimeSeriesCollection;
 
 import com.redhat.thermostat.client.ChangeableText;
-import com.redhat.thermostat.client.DiscreteTimeData;
 import com.redhat.thermostat.client.locale.LocaleResources;
 import com.redhat.thermostat.client.ui.SimpleTable.Section;
 import com.redhat.thermostat.client.ui.SimpleTable.TableEntry;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class HostMemoryPanel extends JPanel implements HostMemoryView, ActionListener {
 
@@ -172,12 +172,12 @@
     }
 
     @Override
-    public void addListener(GraphVisibilityChangeListener listener) {
+    public void addGraphVisibilityListener(GraphVisibilityChangeListener listener) {
         listeners.add(listener);
     }
 
     @Override
-    public void removeListener(GraphVisibilityChangeListener listener) {
+    public void removeGraphVisibilityListener(GraphVisibilityChangeListener listener) {
         listeners.remove(listener);
     }
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryView.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryView.java	Fri Mar 23 18:52:27 2012 -0400
@@ -39,7 +39,7 @@
 import java.awt.Component;
 import java.util.List;
 
-import com.redhat.thermostat.client.DiscreteTimeData;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface HostMemoryView {
 
@@ -63,9 +63,9 @@
 
     void clearMemoryData(String tag);
 
-    void addListener(GraphVisibilityChangeListener listener);
+    void addGraphVisibilityListener(GraphVisibilityChangeListener listener);
 
-    void removeListener(GraphVisibilityChangeListener listener);
+    void removeGraphVisibilityListener(GraphVisibilityChangeListener listener);
 
     Component getUiComponent();
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatController.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatController.java	Fri Mar 23 18:52:27 2012 -0400
@@ -44,11 +44,11 @@
 import java.util.concurrent.TimeUnit;
 
 import com.redhat.thermostat.client.AsyncUiFacade;
-import com.redhat.thermostat.client.DiscreteTimeData;
 import com.redhat.thermostat.client.appctx.ApplicationContext;
 import com.redhat.thermostat.common.VmClassStat;
 import com.redhat.thermostat.common.dao.VmClassStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmClassStatController implements AsyncUiFacade {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatPanel.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatPanel.java	Fri Mar 23 18:52:27 2012 -0400
@@ -52,8 +52,8 @@
 import org.jfree.data.time.TimeSeries;
 import org.jfree.data.time.TimeSeriesCollection;
 
-import com.redhat.thermostat.client.DiscreteTimeData;
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmClassStatPanel extends JPanel implements VmClassStatView {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatView.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatView.java	Fri Mar 23 18:52:27 2012 -0400
@@ -39,7 +39,7 @@
 import java.awt.Component;
 import java.util.List;
 
-import com.redhat.thermostat.client.DiscreteTimeData;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface VmClassStatView {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Fri Mar 23 18:52:27 2012 -0400
@@ -44,11 +44,11 @@
 import java.util.concurrent.TimeUnit;
 
 import com.redhat.thermostat.client.AsyncUiFacade;
-import com.redhat.thermostat.client.DiscreteTimeData;
 import com.redhat.thermostat.client.appctx.ApplicationContext;
 import com.redhat.thermostat.common.VmCpuStat;
 import com.redhat.thermostat.common.dao.VmCpuStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmCpuController implements AsyncUiFacade {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuPanel.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuPanel.java	Fri Mar 23 18:52:27 2012 -0400
@@ -53,8 +53,8 @@
 import org.jfree.data.time.TimeSeries;
 import org.jfree.data.time.TimeSeriesCollection;
 
-import com.redhat.thermostat.client.DiscreteTimeData;
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmCpuPanel extends JPanel implements VmCpuView {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuView.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuView.java	Fri Mar 23 18:52:27 2012 -0400
@@ -39,7 +39,7 @@
 import java.awt.Component;
 import java.util.List;
 
-import com.redhat.thermostat.client.DiscreteTimeData;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface VmCpuView {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Fri Mar 23 18:52:27 2012 -0400
@@ -55,7 +55,6 @@
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
 import com.redhat.thermostat.client.AsyncUiFacade;
-import com.redhat.thermostat.client.DiscreteTimeData;
 import com.redhat.thermostat.client.locale.LocaleResources;
 import com.redhat.thermostat.common.VmGcStat;
 import com.redhat.thermostat.common.VmMemoryStat;
@@ -63,6 +62,7 @@
 import com.redhat.thermostat.common.dao.VmGcStatConverter;
 import com.redhat.thermostat.common.dao.VmMemoryStatConverter;
 import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmGcController implements AsyncUiFacade {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmGcPanel.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmGcPanel.java	Fri Mar 23 18:52:27 2012 -0400
@@ -56,8 +56,8 @@
 import org.jfree.data.time.TimeSeries;
 import org.jfree.data.time.TimeSeriesCollection;
 
-import com.redhat.thermostat.client.DiscreteTimeData;
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmGcPanel extends JPanel implements VmGcView {
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmGcView.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmGcView.java	Fri Mar 23 18:52:27 2012 -0400
@@ -39,7 +39,7 @@
 import java.awt.Component;
 import java.util.List;
 
-import com.redhat.thermostat.client.DiscreteTimeData;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface VmGcView {
 
--- a/client/src/test/java/com/redhat/thermostat/client/TimeSeriesUpdaterTest.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/test/java/com/redhat/thermostat/client/TimeSeriesUpdaterTest.java	Fri Mar 23 18:52:27 2012 -0400
@@ -50,6 +50,7 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.client.TimeSeriesUpdater.LastUpdateTimeCallback;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class TimeSeriesUpdaterTest {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java	Fri Mar 23 18:52:27 2012 -0400
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.client.appctx.ApplicationContext;
+import com.redhat.thermostat.common.HostInfo;
+import com.redhat.thermostat.common.MemoryStat;
+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.MemoryStatDAO;
+import com.redhat.thermostat.common.dao.MongoDAOFactory;
+
+public class HostMemoryControllerTest {
+
+    @Test
+    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);
+
+        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);
+
+        DAOFactory daoFactory = mock(MongoDAOFactory.class);
+        when(daoFactory.getHostInfoDAO(any(HostRef.class))).thenReturn(hostInfoDAO);
+        when(daoFactory.getMemoryStatDAO(any(HostRef.class))).thenReturn(memoryStatDAO);
+        ApplicationContext.getInstance().setDAOFactory(daoFactory);
+
+        HostRef ref = mock(HostRef.class);
+        final HostMemoryView view = mock(HostMemoryView.class);
+        // TODO: Consider to pass the ClassesView or a factory for it to the controller instead.
+        HostMemoryController controller = new HostMemoryController(ref) {
+            @Override
+            protected HostMemoryView createView() {
+                return view;
+            }
+        };
+
+        controller.start();
+
+        try {
+            Thread.sleep(500);
+        } catch (InterruptedException e) {
+            // Get out of here ASAP.
+            return;
+        }
+
+        verify(view, atLeast(1)).setTotalMemory(any(String.class));
+        verify(view, atLeast(6)).addMemoryData(any(String.class), any(List.class));
+    }
+}
--- a/client/src/test/java/com/redhat/thermostat/client/ui/VmClassStatPanelTest.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/VmClassStatPanelTest.java	Fri Mar 23 18:52:27 2012 -0400
@@ -44,7 +44,7 @@
 
 import org.junit.Test;
 
-import com.redhat.thermostat.client.DiscreteTimeData;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmClassStatPanelTest {
 
--- a/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAO.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAO.java	Fri Mar 23 18:52:27 2012 -0400
@@ -48,8 +48,6 @@
     static Key<Double> cpu10LoadKey = new Key<>("10load", false);
     static Key<Double> cpu15LoadKey = new Key<>("15load", false);
 
-    static final Key<String> whereKey = new Key<>("$where", false);
-
     public static final Category cpuStatCategory = new Category("cpu-stats",
             Key.TIMESTAMP, cpu5LoadKey, cpu10LoadKey, cpu15LoadKey);
 
--- a/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java	Fri Mar 23 18:52:27 2012 -0400
@@ -65,7 +65,7 @@
         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(VmClassStatDAO.whereKey, "this.timestamp > " + lastUpdate);
+            query.put(Key.WHERE, "this.timestamp > " + lastUpdate);
         }
         Cursor cursor = storage.findAll(query);
         CpuStatConverter converter = new CpuStatConverter();
--- a/common/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Fri Mar 23 18:52:27 2012 -0400
@@ -40,19 +40,20 @@
 
 public interface DAOFactory {
 
-    public abstract Storage getStorage();
+    public Storage getStorage();
 
     /**
      * TODO: This will be replaced by getStorage() as soon as Storage and Connection have been merged.
      */
-    public abstract Connection getConnection();
+    public Connection getConnection();
 
-    public abstract VmCpuStatDAO getVmCpuStatDAO(VmRef ref);
+    public VmCpuStatDAO getVmCpuStatDAO(VmRef ref);
 
-    public abstract VmClassStatDAO getVmClassStatsDAO(VmRef ref);
+    public VmClassStatDAO getVmClassStatsDAO(VmRef ref);
 
-    public abstract HostInfoDAO getHostInfoDAO(HostRef ref);
+    public HostInfoDAO getHostInfoDAO(HostRef ref);
 
-    public abstract CpuStatDAO getCpuStatDAO(HostRef ref);
+    public CpuStatDAO getCpuStatDAO(HostRef ref);
 
+    public MemoryStatDAO getMemoryStatDAO(HostRef ref);
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatConverter.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatConverter.java	Fri Mar 23 18:52:27 2012 -0400
@@ -36,7 +36,6 @@
 
 package com.redhat.thermostat.common.dao;
 
-import com.mongodb.DBObject;
 import com.redhat.thermostat.common.MemoryStat;
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Key;
@@ -56,17 +55,16 @@
         return chunk;
     }
 
-    public MemoryStat dbObjectToMemoryStat(DBObject dbObj) {
-        long timestamp = (Long) dbObj.get("timestamp");
-        long total = (Long) dbObj.get("total");
-        long free = (Long) dbObj.get("free");
-        long buffers = (Long) dbObj.get("buffers");
-        long cached = (Long) dbObj.get("cached");
-        long swapTotal = (Long) dbObj.get("swap-total");
-        long swapFree = (Long) dbObj.get("swap-free");
-        long commitLimit = (Long) dbObj.get("commit-limit");
+    public MemoryStat chunkToMemoryStat(Chunk chunk) {
+        long timestamp = chunk.get(Key.TIMESTAMP);
+        long total = chunk.get(MemoryStatDAO.memoryTotalKey);
+        long free = chunk.get(MemoryStatDAO.memoryFreeKey);
+        long buffers = chunk.get(MemoryStatDAO.memoryBuffersKey);
+        long cached = chunk.get(MemoryStatDAO.memoryCachedKey);
+        long swapTotal = chunk.get(MemoryStatDAO.memorySwapTotalKey);
+        long swapFree = chunk.get(MemoryStatDAO.memorySwapFreeKey);
+        long commitLimit = chunk.get(MemoryStatDAO.memoryCommitLimitKey);
 
         return new MemoryStat(timestamp, total, free, buffers, cached, swapTotal, swapFree, commitLimit);
     }
-
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAO.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAO.java	Fri Mar 23 18:52:27 2012 -0400
@@ -36,10 +36,13 @@
 
 package com.redhat.thermostat.common.dao;
 
+import java.util.List;
+
+import com.redhat.thermostat.common.MemoryStat;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
 
-public class MemoryStatDAO {
+public interface MemoryStatDAO {
 
     static Key<Long> memoryTotalKey = new Key<>("total", false);
     static Key<Long> memoryFreeKey = new Key<>("free", false);
@@ -53,4 +56,5 @@
             Key.TIMESTAMP, memoryTotalKey, memoryFreeKey, memoryBuffersKey,
             memoryCachedKey, memorySwapTotalKey, memorySwapFreeKey, memoryCommitLimitKey);
 
+    public List<MemoryStat> getLatestMemoryStats();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java	Fri Mar 23 18:52:27 2012 -0400
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.dao;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.redhat.thermostat.common.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;
+
+    public MemoryStatDAOImpl(Storage storage, HostRef hostRef) {
+        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);
+        }
+        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;
+    }
+}
--- a/common/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java	Fri Mar 23 18:52:27 2012 -0400
@@ -92,4 +92,8 @@
         return new CpuStatDAOImpl(storage, ref);
     }
 
+    @Override
+    public MemoryStatDAO getMemoryStatDAO(HostRef ref) {
+        return new MemoryStatDAOImpl(storage, ref);
+    }
 }
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAO.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAO.java	Fri Mar 23 18:52:27 2012 -0400
@@ -47,9 +47,6 @@
     static final Key<Integer> vmIdKey = new Key<>("vm-id", false);
     static final Key<Long> loadedClassesKey = new Key<>("loadedClasses", false);
 
-    static final Key<String> whereKey = new Key<>("$where", false);
-
-
     public static final Category vmClassStatsCategory = new Category(
             "vm-class-stats", vmIdKey, Key.TIMESTAMP, loadedClassesKey);
 
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java	Fri Mar 23 18:52:27 2012 -0400
@@ -66,7 +66,7 @@
         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(VmClassStatDAO.whereKey, "this.timestamp > " + lastUpdate);
+            query.put(Key.WHERE, "this.timestamp > " + lastUpdate);
         }
         Cursor cursor = storage.findAll(query);
         long timestamp;
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java	Fri Mar 23 18:52:27 2012 -0400
@@ -46,7 +46,6 @@
 
     static final Key<Integer> vmIdKey = new Key<>("vm-id", false);
     static final Key<Double> vmCpuLoadKey = new Key<>("processor-usage", false);
-    static final Key<String> whereKey = new Key<>("$where", false);
 
     public static final Category vmCpuStatCategory = new Category("vm-cpu-stats",
             Key.TIMESTAMP, vmCpuLoadKey, vmIdKey);
--- a/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java	Fri Mar 23 18:52:27 2012 -0400
@@ -66,7 +66,7 @@
         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(VmCpuStatDAO.whereKey, "this.timestamp > " + lastUpdate);
+            query.put(Key.WHERE, "this.timestamp > " + lastUpdate);
         }
         Cursor cursor = storage.findAll(query);
         while (cursor.hasNext()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/model/DiscreteTimeData.java	Fri Mar 23 18:52:27 2012 -0400
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+/**
+ * Represents a data associated with a discrete point in time
+ *
+ * @param <T> the type data associated with this point in time
+ */
+public class DiscreteTimeData<T> {
+
+    private long millis;
+    private T data;
+
+    public DiscreteTimeData(long millis, T data) {
+        this.millis = millis;
+        this.data = data;
+    }
+
+    public long getTimeInMillis() {
+        return millis;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/model/MemoryType.java	Fri Mar 23 18:52:27 2012 -0400
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+public enum MemoryType {
+    MEMORY_TOTAL,
+    MEMORY_FREE,
+    MEMORY_USED,
+    SWAP_TOTAL,
+    SWAP_FREE,
+    BUFFERS;
+}
--- a/common/src/main/java/com/redhat/thermostat/common/storage/Key.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/Key.java	Fri Mar 23 18:52:27 2012 -0400
@@ -43,8 +43,9 @@
 public class Key<T> {
 
     // Keys used by most Categories.
-    public static Key<Long> TIMESTAMP = new Key<>("timestamp", false);
-    public static Key<String> AGENT_ID = new Key<>("agent-id", false);
+    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<String> WHERE = new Key<>("$where", false);
 
     private String name;
     private boolean isPartialCategoryKey;
--- a/common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatConverterTest.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatConverterTest.java	Fri Mar 23 18:52:27 2012 -0400
@@ -40,7 +40,6 @@
 
 import org.junit.Test;
 
-import com.mongodb.BasicDBObject;
 import com.redhat.thermostat.common.MemoryStat;
 import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Key;
@@ -64,7 +63,7 @@
     }
 
     @Test
-    public void testDbObjectToMemoryStat() {
+    public void testChunkToMemoryStat() {
         long TIMESTAMP = 1;
         long TOTAL = 2;
         long FREE = 3;
@@ -74,17 +73,17 @@
         long SWAP_FREE = 7;
         long COMMIT_LIMIT = 8;
 
-        BasicDBObject dbObj = new BasicDBObject();
-        dbObj.put("timestamp", TIMESTAMP);
-        dbObj.put("total", TOTAL);
-        dbObj.put("free", FREE);
-        dbObj.put("buffers", BUFFERS);
-        dbObj.put("cached", CACHED);
-        dbObj.put("swap-total", SWAP_TOTAL);
-        dbObj.put("swap-free", SWAP_FREE);
-        dbObj.put("commit-limit", COMMIT_LIMIT);
+        Chunk chunk = new Chunk(MemoryStatDAO.memoryStatCategory, false);
+        chunk.put(Key.TIMESTAMP, TIMESTAMP);
+        chunk.put(MemoryStatDAO.memoryTotalKey, TOTAL);
+        chunk.put(MemoryStatDAO.memoryFreeKey, FREE);
+        chunk.put(MemoryStatDAO.memoryBuffersKey, BUFFERS);
+        chunk.put(MemoryStatDAO.memoryCachedKey, CACHED);
+        chunk.put(MemoryStatDAO.memorySwapTotalKey, SWAP_TOTAL);
+        chunk.put(MemoryStatDAO.memorySwapFreeKey, SWAP_FREE);
+        chunk.put(MemoryStatDAO.memoryCommitLimitKey, COMMIT_LIMIT);
 
-        MemoryStat stat = new MemoryStatConverter().dbObjectToMemoryStat(dbObj);
+        MemoryStat stat = new MemoryStatConverter().chunkToMemoryStat(chunk);
 
         assertEquals(TIMESTAMP, stat.getTimeStamp());
         assertEquals(TOTAL, stat.getTotal());
--- a/common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java	Fri Mar 23 18:52:27 2012 -0400
@@ -37,13 +37,25 @@
 package com.redhat.thermostat.common.dao;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 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;
 import java.util.Collection;
+import java.util.List;
 
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
+import com.redhat.thermostat.common.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;
 
 public class MemoryStatDAOTest {
     @Test
@@ -61,4 +73,55 @@
         assertEquals(8, keys.size());
 
     }
+
+    @Test
+    public void testGetLatestMemoryStats() {
+        long TIMESTAMP = 1;
+        long TOTAL = 2;
+        long FREE = 3;
+        long BUFFERS = 4;
+        long CACHED = 5;
+        long SWAP_TOTAL = 6;
+        long SWAP_FREE = 7;
+        long COMMIT_LIMIT = 8;
+
+        Chunk chunk = new Chunk(MemoryStatDAO.memoryStatCategory, false);
+        chunk.put(Key.TIMESTAMP, TIMESTAMP);
+        chunk.put(MemoryStatDAO.memoryTotalKey, TOTAL);
+        chunk.put(MemoryStatDAO.memoryFreeKey, FREE);
+        chunk.put(MemoryStatDAO.memoryBuffersKey, BUFFERS);
+        chunk.put(MemoryStatDAO.memoryCachedKey, CACHED);
+        chunk.put(MemoryStatDAO.memorySwapTotalKey, SWAP_TOTAL);
+        chunk.put(MemoryStatDAO.memorySwapFreeKey, SWAP_FREE);
+        chunk.put(MemoryStatDAO.memoryCommitLimitKey, COMMIT_LIMIT);
+
+        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");
+
+        MemoryStatDAO dao = new MemoryStatDAOImpl(storage, hostRef);
+        List<MemoryStat> memoryStats = dao.getLatestMemoryStats();
+
+        ArgumentCaptor<Chunk> arg = ArgumentCaptor.forClass(Chunk.class);
+        verify(storage).findAll(arg.capture());
+        assertNull(arg.getValue().get(new Key<String>("$where", false)));
+
+        assertEquals(1, memoryStats.size());
+        MemoryStat stat = memoryStats.get(0);
+
+        assertEquals(TIMESTAMP, stat.getTimeStamp());
+        assertEquals(TOTAL, stat.getTotal());
+        assertEquals(FREE, stat.getFree());
+        assertEquals(BUFFERS, stat.getBuffers());
+        assertEquals(CACHED, stat.getCached());
+        assertEquals(SWAP_TOTAL, stat.getSwapTotal());
+        assertEquals(SWAP_FREE, stat.getSwapFree());
+        assertEquals(COMMIT_LIMIT, stat.getCommitLimit());
+    }
 }
--- a/common/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Fri Mar 23 22:48:13 2012 +0100
+++ b/common/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Fri Mar 23 18:52:27 2012 -0400
@@ -40,76 +40,58 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import org.junit.Before;
 import org.junit.Test;
 
 import com.mongodb.DB;
 
 public class MongoDAOFactoryTest {
 
+    private MongoConnection conn;
+    private ConnectionProvider connProvider;
+    private DAOFactory daoFactory;
+    private DB db;
+    HostRef hostRef;
+    VmRef vmRef;
+
+    @Before
+    public void setUp() {
+        conn = mock(MongoConnection.class);
+        connProvider = mock(ConnectionProvider.class);
+        when(connProvider.createConnection()).thenReturn(conn);
+        db = mock(DB.class);
+        when(conn.getDB()).thenReturn(db);
+        hostRef = mock(HostRef.class);
+        vmRef = mock(VmRef.class);
+        daoFactory = new MongoDAOFactory(connProvider);
+    }
+
     @Test
     public void testGetConnection() {
-        Connection conn = mock(MongoConnection.class);
-
-        ConnectionProvider connProvider = mock(ConnectionProvider.class);
-        when(connProvider.createConnection()).thenReturn(conn);
-
-        DAOFactory daoFactory = new MongoDAOFactory(connProvider);
         assertSame(conn, daoFactory.getConnection());
-
     }
 
     @Test
     public void testGetVmClassStatsDAO() {
-
-        DB db = mock(DB.class);
-
-        MongoConnection conn = mock(MongoConnection.class);
-        when(conn.getDB()).thenReturn(db);
-
-        ConnectionProvider connProv = mock(ConnectionProvider.class);
-        when(connProv.createConnection()).thenReturn(conn);
-
-        DAOFactory instance = new MongoDAOFactory(connProv);
-
-        VmRef ref = mock(VmRef.class);
-        VmClassStatDAO vmClassStatsDAO = instance.getVmClassStatsDAO(ref);
-
+        VmClassStatDAO vmClassStatsDAO = daoFactory.getVmClassStatsDAO(vmRef);
         assertNotNull(vmClassStatsDAO);
     }
 
     @Test
     public void testGetHostInfoDAO() {
-        DB db = mock(DB.class);
-
-        MongoConnection conn = mock(MongoConnection.class);
-        when(conn.getDB()).thenReturn(db);
-
-        ConnectionProvider connProv = mock(ConnectionProvider.class);
-        when(connProv.createConnection()).thenReturn(conn);
-
-        DAOFactory instance = new MongoDAOFactory(connProv);
-
-        HostRef ref = mock(HostRef.class);
-        HostInfoDAO dao = instance.getHostInfoDAO(ref);
-
+        HostInfoDAO dao = daoFactory.getHostInfoDAO(hostRef);
         assertNotNull(dao);
     }
 
     @Test
     public void testGetCpuStatDAO() {
-        DB db = mock(DB.class);
-
-        MongoConnection conn = mock(MongoConnection.class);
-        when(conn.getDB()).thenReturn(db);
+        CpuStatDAO dao = daoFactory.getCpuStatDAO(hostRef);
+        assertNotNull(dao);
+    }
 
-        ConnectionProvider connProv = mock(ConnectionProvider.class);
-        when(connProv.createConnection()).thenReturn(conn);
-
-        DAOFactory instance = new MongoDAOFactory(connProv);
-
-        HostRef ref = mock(HostRef.class);
-        CpuStatDAO dao = instance.getCpuStatDAO(ref);
-
+    @Test
+    public void testGetMemoryStatDAO() {
+        MemoryStatDAO dao = daoFactory.getMemoryStatDAO(hostRef);
         assertNotNull(dao);
     }
 }