changeset 749:769d409c83b6

Overhaul and improvement of pojo conversion. Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-October/003939.html
author Roman Kennke <rkennke@redhat.com>
date Fri, 26 Oct 2012 13:13:42 +0200
parents 9a66968f2bcb
children bc6fadf5ceaa
files client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java client/core/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/VmGcControllerTest.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsController.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsControllerTest.java common/core/src/main/java/com/redhat/thermostat/common/dao/Converter.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatConverter.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAO.java common/core/src/main/java/com/redhat/thermostat/common/model/AgentIdPojo.java common/core/src/main/java/com/redhat/thermostat/common/model/BasePojo.java common/core/src/main/java/com/redhat/thermostat/common/model/CpuStat.java common/core/src/main/java/com/redhat/thermostat/common/model/Pojo.java common/core/src/main/java/com/redhat/thermostat/common/model/VmGcStat.java common/core/src/main/java/com/redhat/thermostat/common/model/VmInfo.java common/core/src/main/java/com/redhat/thermostat/common/model/VmMemoryStat.java common/core/src/main/java/com/redhat/thermostat/common/storage/Chunk.java common/core/src/main/java/com/redhat/thermostat/common/storage/ChunkAdapter.java common/core/src/main/java/com/redhat/thermostat/common/storage/ChunkConverter.java common/core/src/main/java/com/redhat/thermostat/common/storage/ChunkToPojoConverter.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoCursor.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoPojoConverter.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoRemove.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoUpdate.java common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java common/core/src/main/java/com/redhat/thermostat/common/storage/StorageException.java common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatConverterTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/ChunkAdapterTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/ChunkConverterTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/ChunkTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/MongoCursorTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/MongoPojoConverterTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java system-backend/src/main/java/com/redhat/thermostat/backend/system/CpuStatBuilder.java system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java system-backend/src/test/java/com/redhat/thermostat/backend/system/CpuStatBuilderTest.java thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/VMCapsSummaryPanel.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterTest.java tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatPrinter.java tools/src/test/java/com/redhat/thermostat/tools/cli/VMInfoCommandTest.java tools/src/test/java/com/redhat/thermostat/tools/cli/VmStatCommandTest.java web/client/src/main/java/com/redhat/thermostat/web/client/RESTStorage.java web/client/src/main/java/com/redhat/thermostat/web/client/WebCursor.java web/client/src/test/java/com/redhat/thermostat/web/client/TestObj.java web/common/pom.xml web/common/src/main/java/com/redhat/thermostat/web/common/ThermostatGSONConverter.java web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java web/server/src/main/java/com/redhat/thermostat/web/server/RESTStorageEndPoint.java web/server/src/test/java/com/redhat/thermostat/web/server/RESTStorageEndpointTest.java
diffstat 65 files changed, 1321 insertions(+), 2513 deletions(-) [+]
line wrap: on
line diff
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Fri Oct 26 13:13:42 2012 +0200
@@ -134,12 +134,12 @@
         List<CpuStat> cpuStats = cpuStatDAO.getLatestCpuStats(ref, lastSeenTimeStamp);
         List<List<DiscreteTimeData<Double>>> results = new ArrayList<>();
         for (CpuStat stat : cpuStats) {
-            List<Double> data = stat.getPerProcessorUsage();
-            for (int i = 0 ; i < data.size(); i++) {
+            double[] data = stat.getPerProcessorUsage();
+            for (int i = 0 ; i < data.length; i++) {
                 if (results.size() == i) {
                     results.add(new ArrayList<DiscreteTimeData<Double>>());
                 }
-                results.get(i).add(new DiscreteTimeData<Double>(stat.getTimeStamp(), data.get(i)));
+                results.get(i).add(new DiscreteTimeData<Double>(stat.getTimeStamp(), data[i]));
                 lastSeenTimeStamp = Math.max(lastSeenTimeStamp, stat.getTimeStamp());
             }
         }
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Fri Oct 26 13:13:42 2012 +0200
@@ -183,8 +183,8 @@
         VmMemoryStat info = memDao.getLatestMemoryStat(ref);
 
         for (Generation g: info.getGenerations()) {
-            if (g.collector.equals(collectorName)) {
-                return g.name;
+            if (g.getCollector().equals(collectorName)) {
+                return g.getName();
             }
         }
         return translator.localize(LocaleResources.UNKNOWN_GEN);
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -71,7 +71,6 @@
 import com.redhat.thermostat.common.model.CpuStat;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 import com.redhat.thermostat.common.model.HostInfo;
-import com.redhat.thermostat.common.utils.ArrayUtils;
 
 public class HostCpuControllerTest {
 
@@ -103,8 +102,8 @@
         HostInfoDAO hostInfoDAO = mock(HostInfoDAO.class);
         when(hostInfoDAO.getHostInfo(any(HostRef.class))).thenReturn(hostInfo);
 
-        CpuStat cpuStat1 = new CpuStat(1l, ArrayUtils.toDoubleList(new double[] {10.0, 20.0, 30.0}));
-        CpuStat cpuStat2 = new CpuStat(2l, ArrayUtils.toDoubleList(new double[] {15.0, 25.0, 35.0}));
+        CpuStat cpuStat1 = new CpuStat(1l, new double[] {10.0, 20.0, 30.0});
+        CpuStat cpuStat2 = new CpuStat(2l, new double[] {15.0, 25.0, 35.0});
         CpuStatDAO cpuStatDAO = mock(CpuStatDAO.class);
         when(cpuStatDAO.getLatestCpuStats(any(HostRef.class), anyLong())).thenReturn(Arrays.asList(cpuStat1, cpuStat2));
 
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/VmGcControllerTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/VmGcControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -98,12 +98,10 @@
         stats.add(stat2);
 
         Generation gen;
-        List<Generation> gens = new ArrayList<>();
         gen = new Generation();
-        gen.name = "generation 1";
-        gen.collector = "collector1";
-        gens.add(gen);
-        VmMemoryStat memoryStat = new VmMemoryStat(1, 42, gens);
+        gen.setName("generation 1");
+        gen.setCollector("collector1");
+        VmMemoryStat memoryStat = new VmMemoryStat(1, 42, new Generation[] { gen });
 
         // Setup DAO
         VmGcStatDAO vmGcStatDAO = mock(VmGcStatDAO.class);
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java	Fri Oct 26 13:13:42 2012 +0200
@@ -232,21 +232,21 @@
                 long used = 0l;
                 long capacity = 0l;
                 long max = 0l;
-                List<Generation> generations = memoryStats.getGenerations();
+                Generation[] generations = memoryStats.getGenerations();
                 for (Generation generation : generations) {
                     
                     // non heap
-                    if (generation.name.equals("perm")) {
+                    if (generation.getName().equals("perm")) {
                         continue;
                     }
                     
-                    List<Space> spaces = generation.spaces;
+                    Space[] spaces = generation.getSpaces();
                     for (Space space: spaces) {
-                        used += space.used;
-                        capacity += space.capacity;
+                        used += space.getUsed();
+                        capacity += space.getCapacity();
                         
                         // TODO
-                        max =+ space.maxCapacity;
+                        max =+ space.getMaxCapacity();
                     }
                 }
                 model.addData(memoryStats.getTimeStamp(), used, capacity);
--- a/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -326,14 +326,14 @@
         final long CAPACITY = 10;
         final long USED = 5;
         Space space = new Space();
-        space.capacity = CAPACITY;
-        space.maxCapacity = 20;
-        space.used = USED;
+        space.setCapacity(CAPACITY);
+        space.setMaxCapacity(20);
+        space.setUsed(USED);
         Generation gen = new Generation();
-        gen.name = "foobar";
-        gen.spaces = Arrays.asList(space);
+        gen.setName("foobar");
+        gen.setSpaces(new Space[] { space });
         VmMemoryStat stat = new VmMemoryStat();
-        stat.setGenerations(Arrays.asList(gen));
+        stat.setGenerations(new Generation[] { gen });
 
         when(vmDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong())).thenReturn(Arrays.asList(stat));
 
@@ -351,15 +351,15 @@
 
         final long DATA_TIMESTAMP = System.currentTimeMillis() + 1000000000;
         Space space = new Space();
-        space.capacity = 10;
-        space.maxCapacity = 20;
-        space.used = 5;
+        space.setCapacity(10);
+        space.setMaxCapacity(20);
+        space.setUsed(5);
         Generation gen = new Generation();
-        gen.name = "foobar";
-        gen.spaces = Arrays.asList(space);
+        gen.setName("foobar");
+        gen.setSpaces(new Space[] { space });
         VmMemoryStat stat = new VmMemoryStat();
         stat.setTimeStamp(DATA_TIMESTAMP);
-        stat.setGenerations(Arrays.asList(gen));
+        stat.setGenerations(new Generation[] { gen });
 
         when(vmDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong())).thenReturn(Arrays.asList(stat));
 
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsController.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsController.java	Fri Oct 26 13:13:42 2012 +0200
@@ -79,34 +79,34 @@
         public void run() {
             List<VmMemoryStat> vmInfo = vmDao.getLatestVmMemoryStats(ref, desiredUpdateTimeStamp);
             for (VmMemoryStat memoryStats: vmInfo) {
-                List<Generation> generations = memoryStats.getGenerations();
+                Generation[] generations = memoryStats.getGenerations();
                 
                 for (Generation generation : generations) {
-                    List<Space> spaces = generation.spaces;
+                    Space[] spaces = generation.getSpaces();
                     for (Space space: spaces) {
-                        Payload payload = regions.get(space.name);
+                        Payload payload = regions.get(space.getName());
                         if (payload == null) {
                             payload = new Payload();
-                            payload.setName(space.name);
+                            payload.setName(space.getName());
                         }
 
-                        Scale usedScale = normalizeScale(space.used, space.capacity);
-                        double used = Scale.convertTo(usedScale, space.used, 100);
-                        double maxUsed = Scale.convertTo(usedScale, space.capacity, 100);
+                        Scale usedScale = normalizeScale(space.getUsed(), space.getCapacity());
+                        double used = Scale.convertTo(usedScale, space.getUsed(), 100);
+                        double maxUsed = Scale.convertTo(usedScale, space.getCapacity(), 100);
                         
                         payload.setUsed(used);
                         payload.setMaxUsed(maxUsed);
                         payload.setUsedUnit(usedScale);
                         
-                        Scale maxScale = normalizeScale(space.capacity, space.maxCapacity);
-                        double capacity = Scale.convertTo(maxScale, space.capacity, 100);
-                        double maxCapacity = Scale.convertTo(maxScale, space.maxCapacity, 100);
+                        Scale maxScale = normalizeScale(space.getCapacity(), space.getMaxCapacity());
+                        double capacity = Scale.convertTo(maxScale, space.getCapacity(), 100);
+                        double maxCapacity = Scale.convertTo(maxScale, space.getMaxCapacity(), 100);
                         
                         payload.setCapacity(capacity);
                         payload.setMaxCapacity(maxCapacity);
                         payload.setCapacityUnit(maxScale);
                         
-                        String tooltip = space.name + ": used: " + used + " " + usedScale +
+                        String tooltip = space.getName() + ": used: " + used + " " + usedScale +
                                 ", capacity: " + capacity + " " + maxScale +
                                 ", max capacity: " + maxCapacity + " " + maxScale;
                         
@@ -115,20 +115,20 @@
                         StatsModel model = payload.getModel();
                         if (model == null) {
                             model = new StatsModel();
-                            model.setName(space.name);
+                            model.setName(space.getName());
                             model.setRange(3600);
                         }
                         
                         // normalize this always in the same unit
                         model.addData(memoryStats.getTimeStamp(),
-                                      Scale.convertTo(Scale.MiB, space.used, 100));
+                                      Scale.convertTo(Scale.MiB, space.getUsed(), 100));
                         
                         payload.setModel(model);
-                        if (regions.containsKey(space.name)) {
+                        if (regions.containsKey(space.getName())) {
                             view.updateRegion(payload.clone());
                         } else {
                             view.addRegion(payload.clone());
-                            regions.put(space.name, payload);
+                            regions.put(space.getName(), payload);
                         }
                         
                         view.requestRepaint();
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsControllerTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -73,7 +73,7 @@
 
 public class MemoryStatsControllerTest {
 
-    private List<Generation> generations = new ArrayList<>();
+    private Generation[] generations = new Generation[2];
     
     private VmMemoryStatDAO memoryStatDao;
     private MemoryStatsView view;
@@ -101,27 +101,29 @@
         
         for (int i = 0; i < 2; i++) {
             Generation generation = new Generation();
-            generation.name = "fluff" + i;
-            generation.spaces = new ArrayList<>();
+            generation.setName("fluff" + i);
+            VmMemoryStat.Space[] spaces = new VmMemoryStat.Space[2 + (1 - i)]; 
             for (int j = 0; j < 2; j++) {
                 Space space = new Space();
-                space.name = "fluffer" + i + j;
-                space.used = 100;
-                space.capacity = 1000;
-                space.maxCapacity = 10000;
-                
-                generation.spaces.add(space);
+                space.setName("fluffer" + i + j);
+                space.setUsed(100);
+                space.setCapacity(1000);
+                space.setMaxCapacity(10000);
+                spaces[j] = space;
             }
-            generations.add(generation);
+            if (i == 0) {
+                // special payload because the others have all the same values
+                canary = new Space();
+                canary.setName("canary");
+                canary.setUsed(1);
+                canary.setCapacity(2);
+                canary.setMaxCapacity(3);
+                spaces[2] = canary;
+            }
+            generation.setSpaces(spaces);
+            generations[i] = generation;
         }
         
-        // special payload because the others have all the same values
-        canary = new Space();
-        canary.name = "canary";
-        canary.used = 1;
-        canary.capacity = 2;
-        canary.maxCapacity = 3;
-        
         long timestamp = 1;
         int vmID = 1;
         for (int i = 0; i < 5; i++) {
@@ -129,8 +131,6 @@
             vmInfo.add(vmMemory);
         }
         
-        generations.get(0).spaces.add(canary);
-        
         memoryStatDao = mock(VmMemoryStatDAO.class);
         when(memoryStatDao.getLatestVmMemoryStats(any(VmRef.class), anyLong())).thenReturn(vmInfo);
         
@@ -213,15 +213,15 @@
 
         final long DATA_TIMESTAMP = System.currentTimeMillis() + 1000000000;
         Space space = new Space();
-        space.capacity = 10;
-        space.maxCapacity = 20;
-        space.used = 5;
+        space.setCapacity(10);
+        space.setMaxCapacity(20);
+        space.setUsed(5);
         Generation gen = new Generation();
-        gen.name = "foobar";
-        gen.spaces = Arrays.asList(space);
+        gen.setName("foobar");
+        gen.setSpaces(new Space[] { space });
         VmMemoryStat stat = new VmMemoryStat();
         stat.setTimeStamp(DATA_TIMESTAMP);
-        stat.setGenerations(Arrays.asList(gen));
+        stat.setGenerations(new Generation[] { gen });
 
         when(memoryStatDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong())).thenReturn(Arrays.asList(stat));
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/Converter.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +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 com.redhat.thermostat.common.model.Pojo;
-import com.redhat.thermostat.common.storage.Chunk;
-
-public interface Converter<T extends Pojo> {
-
-    Chunk toChunk(T pojo);
-
-    T fromChunk(Chunk chunk);
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatConverter.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +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.List;
-
-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 implements Converter<VmMemoryStat> {
-
-    @Override
-    public Chunk toChunk(VmMemoryStat vmMemStat) {
-        Chunk chunk = new Chunk(VmMemoryStatDAO.vmMemoryStatsCategory, false);
-
-        chunk.put(Key.AGENT_ID, vmMemStat.getAgentId());
-        chunk.put(Key.VM_ID, vmMemStat.getVmId());
-        chunk.put(Key.TIMESTAMP, vmMemStat.getTimeStamp());
-
-        Generation newGen = vmMemStat.getGeneration("new");
-
-        Space eden = newGen.getSpace("eden");
-        chunk.put(VmMemoryStatDAO.edenGenKey, newGen.name);
-        chunk.put(VmMemoryStatDAO.edenCollectorKey, newGen.collector);
-        chunk.put(VmMemoryStatDAO.edenCapacityKey, eden.capacity);
-        chunk.put(VmMemoryStatDAO.edenMaxCapacityKey, eden.maxCapacity);
-        chunk.put(VmMemoryStatDAO.edenUsedKey, eden.used);
-
-        Space s0 = newGen.getSpace("s0");
-        chunk.put(VmMemoryStatDAO.s0GenKey, newGen.name);
-        chunk.put(VmMemoryStatDAO.s0CollectorKey, newGen.collector);
-        chunk.put(VmMemoryStatDAO.s0CapacityKey, s0.capacity);
-        chunk.put(VmMemoryStatDAO.s0MaxCapacityKey, s0.maxCapacity);
-        chunk.put(VmMemoryStatDAO.s0UsedKey, s0.used);
-
-        Space s1 = newGen.getSpace("s1");
-        chunk.put(VmMemoryStatDAO.s1GenKey, newGen.name);
-        chunk.put(VmMemoryStatDAO.s1CollectorKey, newGen.collector);
-        chunk.put(VmMemoryStatDAO.s1CapacityKey, s1.capacity);
-        chunk.put(VmMemoryStatDAO.s1MaxCapacityKey, s1.maxCapacity);
-        chunk.put(VmMemoryStatDAO.s1UsedKey, s1.used);
-
-        Generation oldGen = vmMemStat.getGeneration("old");
-
-        Space old = oldGen.getSpace("old");
-        chunk.put(VmMemoryStatDAO.oldGenKey, oldGen.name);
-        chunk.put(VmMemoryStatDAO.oldCollectorKey, oldGen.collector);
-        chunk.put(VmMemoryStatDAO.oldCapacityKey, old.capacity);
-        chunk.put(VmMemoryStatDAO.oldMaxCapacityKey, old.maxCapacity);
-        chunk.put(VmMemoryStatDAO.oldUsedKey, old.used);
-
-        Generation permGen = vmMemStat.getGeneration("perm");
-
-        Space perm = permGen.getSpace("perm");
-        chunk.put(VmMemoryStatDAO.permGenKey, permGen.name);
-        chunk.put(VmMemoryStatDAO.permCollectorKey, permGen.collector);
-        chunk.put(VmMemoryStatDAO.permCapacityKey, perm.capacity);
-        chunk.put(VmMemoryStatDAO.permMaxCapacityKey, perm.maxCapacity);
-        chunk.put(VmMemoryStatDAO.permUsedKey, perm.used);
-
-        return chunk;
-    }
-
-    @Override
-    public VmMemoryStat fromChunk(Chunk chunk) {
-        Space space = null;
-        List<Space> spaces = null;
-
-        List<Generation> gens = new ArrayList<>();
-        Generation newGen = new Generation();
-        spaces = new ArrayList<>();
-        newGen.spaces = spaces;
-        newGen.name = "new";
-        newGen.capacity = 0;
-        newGen.maxCapacity = 0;
-        // FIXME Something is wrong here when we have the collector stored
-        // as part of 3 spaces in Chunk but is only one thing in Stat
-        newGen.collector = chunk.get(VmMemoryStatDAO.edenCollectorKey);
-
-        space = new Space();
-        space.name = VmMemoryStatDAO.edenKey.getName();
-        space.capacity = chunk.get(VmMemoryStatDAO.edenCapacityKey);
-        space.maxCapacity = chunk.get(VmMemoryStatDAO.edenMaxCapacityKey);
-        space.used = chunk.get(VmMemoryStatDAO.edenUsedKey);
-        spaces.add(space);
-        newGen.capacity += space.capacity;
-        newGen.maxCapacity += space.maxCapacity;
-
-        space = new Space();
-        space.name = VmMemoryStatDAO.s0Key.getName();
-        space.capacity = chunk.get(VmMemoryStatDAO.s0CapacityKey);
-        space.maxCapacity = chunk.get(VmMemoryStatDAO.s0MaxCapacityKey);
-        space.used = chunk.get(VmMemoryStatDAO.s0UsedKey);
-        spaces.add(space);
-        newGen.capacity += space.capacity;
-        newGen.maxCapacity += space.maxCapacity;
-
-        space = new Space();
-        space.name = VmMemoryStatDAO.s1Key.getName();
-        space.capacity = chunk.get(VmMemoryStatDAO.s1CapacityKey);
-        space.maxCapacity = chunk.get(VmMemoryStatDAO.s1MaxCapacityKey);
-        space.used = chunk.get(VmMemoryStatDAO.s1UsedKey);
-        spaces.add(space);
-        newGen.capacity += space.capacity;
-        newGen.maxCapacity += space.maxCapacity;
-
-        gens.add(newGen);
-
-        Generation oldGen = new Generation();
-        spaces = new ArrayList<>();
-        oldGen.spaces = spaces;
-        oldGen.name = "old";
-        oldGen.collector = chunk.get(VmMemoryStatDAO.oldCollectorKey);
-
-        space = new Space();
-        space.name = VmMemoryStatDAO.oldKey.getName();
-        space.capacity = chunk.get(VmMemoryStatDAO.oldCapacityKey);
-        space.maxCapacity = chunk.get(VmMemoryStatDAO.oldMaxCapacityKey);
-        space.used = chunk.get(VmMemoryStatDAO.oldUsedKey);
-        spaces.add(space);
-        oldGen.capacity = space.capacity;
-        oldGen.maxCapacity = space.capacity;
-
-        gens.add(oldGen);
-
-        Generation permGen = new Generation();
-        spaces = new ArrayList<>();
-        permGen.spaces = spaces;
-        permGen.name = "perm";
-        permGen.collector = chunk.get(VmMemoryStatDAO.permCollectorKey);
-
-        space = new Space();
-        space.name = VmMemoryStatDAO.permKey.getName();
-        space.capacity = chunk.get(VmMemoryStatDAO.permCapacityKey);
-        space.maxCapacity = chunk.get(VmMemoryStatDAO.permMaxCapacityKey);
-        space.used = chunk.get(VmMemoryStatDAO.permUsedKey);
-        spaces.add(space);
-        permGen.capacity = space.capacity;
-        permGen.maxCapacity = space.capacity;
-
-        gens.add(permGen);
-        VmMemoryStat stat = new VmMemoryStat(chunk.get(Key.TIMESTAMP), chunk.get(Key.VM_ID), gens);
-        stat.setAgentId(chunk.get(Key.AGENT_ID));
-        return stat;
-    }
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAO.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAO.java	Fri Oct 26 13:13:42 2012 +0200
@@ -39,58 +39,16 @@
 import java.util.List;
 
 import com.redhat.thermostat.common.model.VmMemoryStat;
+import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
 
 public interface VmMemoryStatDAO {
 
-    static final Key<String> edenKey = new Key<>("eden", 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);
-    static final Key<Long> edenMaxCapacityKey = new Key<>("eden.max-capacity", false);
-    static final Key<Long> edenUsedKey = new Key<>("eden.used", false);
-
-    static final Key<String> s0Key = new Key<>("s0", false);
-    static final Key<String> s0GenKey = new Key<>("s0.gen", false);
-    static final Key<String> s0CollectorKey = new Key<>("s0.collector", false);
-    static final Key<Long> s0CapacityKey = new Key<>("s0.capacity", false);
-    static final Key<Long> s0MaxCapacityKey = new Key<>("s0.max-capacity", false);
-    static final Key<Long> s0UsedKey = new Key<>("s0.used", false);
-
-    static final Key<String> s1Key = new Key<>("s1", false);
-    static final Key<String> s1GenKey = new Key<>("s1.gen", false);
-    static final Key<String> s1CollectorKey = new Key<>("s1.collector", false);
-    static final Key<Long> s1CapacityKey = new Key<>("s1.capacity", false);
-    static final Key<Long> s1MaxCapacityKey = new Key<>("s1.max-capacity", false);
-    static final Key<Long> s1UsedKey = new Key<>("s1.used", false);
-
-    static final Key<String> oldKey = new Key<>("old", false);
-    static final Key<String> oldGenKey = new Key<>("old.gen", false);
-    static final Key<String> oldCollectorKey = new Key<>("old.collector", false);
-    static final Key<Long> oldCapacityKey = new Key<>("old.capacity", false);
-    static final Key<Long> oldMaxCapacityKey = new Key<>("old.max-capacity", false);
-    static final Key<Long> oldUsedKey = new Key<>("old.used", false);
-
-    static final Key<String> permKey = new Key<>("perm", false);
-    static final Key<String> permGenKey = new Key<>("perm.gen", false);
-    static final Key<String> permCollectorKey = new Key<>("perm.collector", false);
-    static final Key<Long> permCapacityKey = new Key<>("perm.capacity", false);
-    static final Key<Long> permMaxCapacityKey = new Key<>("perm.max-capacity", false);
-    static final Key<Long> permUsedKey = new Key<>("perm.used", false);
+    static final Key<Generation[]> generationsKey = new Key<>("generations", false);
 
     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,
-            s0MaxCapacityKey, s0UsedKey,
-            s1GenKey, s1CollectorKey, s1CapacityKey,
-            s1MaxCapacityKey, s1UsedKey,
-            oldGenKey, oldCollectorKey, oldCapacityKey,
-            oldMaxCapacityKey, oldUsedKey,
-            permGenKey, permCollectorKey, permCapacityKey,
-            permMaxCapacityKey, permUsedKey);
+            Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, generationsKey);
 
     public VmMemoryStat getLatestMemoryStat(VmRef ref);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/AgentIdPojo.java	Fri Oct 26 13:13:42 2012 +0200
@@ -0,0 +1,44 @@
+/*
+ * 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 interface AgentIdPojo extends Pojo {
+
+    void setAgentId(String agentId);
+    String getAgentId();
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/BasePojo.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/BasePojo.java	Fri Oct 26 13:13:42 2012 +0200
@@ -41,7 +41,7 @@
 
 import com.redhat.thermostat.common.storage.Persist;
 
-public class BasePojo implements Pojo {
+public class BasePojo implements AgentIdPojo {
 
     private String agentId;
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/CpuStat.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/CpuStat.java	Fri Oct 26 13:13:42 2012 +0200
@@ -36,8 +36,6 @@
 
 package com.redhat.thermostat.common.model;
 
-import java.util.List;
-
 import com.redhat.thermostat.common.storage.Entity;
 import com.redhat.thermostat.common.storage.Persist;
 
@@ -47,24 +45,24 @@
     public static final double INVALID_LOAD = Double.MIN_VALUE;
 
     private long timeStamp;
-    private List<Double> perProcessorUsage;
+    private double[] perProcessorUsage;
 
     public CpuStat() {
         this(-1, null);
     }
 
-    public CpuStat(long timestamp, List<Double> perProcessorUsage) {
+    public CpuStat(long timestamp, double[] perProcessorUsage) {
         this.timeStamp = timestamp;
         this.perProcessorUsage = perProcessorUsage;
     }
 
     @Persist
-    public List<Double> getPerProcessorUsage() {
+    public double[] getPerProcessorUsage() {
         return perProcessorUsage;
     }
 
     @Persist
-    public void setPerProcessorUsage(List<Double> perProcessorUsage) {
+    public void setPerProcessorUsage(double[] perProcessorUsage) {
         this.perProcessorUsage = perProcessorUsage;
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/Pojo.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/Pojo.java	Fri Oct 26 13:13:42 2012 +0200
@@ -39,9 +39,30 @@
 /**
  * All data types should implement this empty interface, to support the
  * generalization of DAO code where possible.
+ *
+ * In order to enable fully automatic serialization and deserialization of
+ * data objects, an implementation of this interface needs to adhere to
+ * a certain set of rules, that essentially boil down to compliance with
+ * JavaBeans specification plus Thermostat's @Entity and @Persist annotation.
+ * In detail those rules are:
+ *
+ * - A Pojo class needs to be annotated with @Entity (in addition to it implementing
+ *   Pojo).
+ * - Only properties will be (de-)serialized, other method or fields will not
+ *   be looked at.
+ * - Properties that should be (de-)serialized need to be annotated with @Persist,
+ *   both on the getter and the setter method.
+ * - Serializable properties need to either be of primitive type, or String or
+ *   other Pojos or arrays (indexed properties) of those types. (The reason for supporting
+ *   only arrays as opposed to collections is that arrays carry type information,
+ *   while collections don't, due to type erasure in Java generics. The type information
+ *   is needed in order to re-construct the objects when deserializing.)
+ * - The properties need to be of the same type that its signatures declare. Specifically,
+ *   they must not be of a subclass of that type. The reason for that is that
+ *   the type information of the signature is used in deserialization. This also implies
+ *   that such properties cannot be of abstract types.
+ * 
  */
 public interface Pojo {
 
-    void setAgentId(String agentId);
-    String getAgentId();
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/VmGcStat.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/VmGcStat.java	Fri Oct 26 13:13:42 2012 +0200
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.common.model;
 
 import com.redhat.thermostat.common.storage.Entity;
+import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
 public class VmGcStat extends BasePojo implements TimeStampedPojo {
@@ -59,43 +60,53 @@
         this.wallTime = wallTime;
     }
 
+    @Persist
     public int getVmId() {
         return vmId;
     }
 
+    @Persist
     public void setVmId(int vmId) {
         this.vmId = vmId;
     }
 
+    @Persist
     public String getCollectorName() {
         return collectorName;
     }
 
+    @Persist
     public void setCollectorName(String collectorName) {
         this.collectorName = collectorName;
     }
 
+    @Persist
     public long getRunCount() {
         return runCount;
     }
 
+    @Persist
     public void setRunCount(long runCount) {
         this.runCount = runCount;
     }
 
+    @Persist
     public long getWallTime() {
         return wallTime;
     }
 
+    @Persist
     public void setWallTime(long wallTime) {
         this.wallTime = wallTime;
     }
 
     @Override
+    @Persist
     public long getTimeStamp() {
         return timeStamp;
     }
 
+    @Persist
     public void setTimeStamp(long timeStamp) {
         this.timeStamp = timeStamp;
     }
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/VmInfo.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/VmInfo.java	Fri Oct 26 13:13:42 2012 +0200
@@ -37,8 +37,8 @@
 package com.redhat.thermostat.common.model;
 
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import com.redhat.thermostat.common.storage.Entity;
 import com.redhat.thermostat.common.storage.Persist;
@@ -46,6 +46,44 @@
 @Entity
 public class VmInfo extends BasePojo {
 
+    @Entity
+    public static class KeyValuePair implements Pojo {
+    
+        private String key;
+        private String value;
+
+        public KeyValuePair() {
+            this(null, null);
+        }
+
+        public KeyValuePair(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        @Persist
+        public String getKey() {
+            return key;
+        }
+
+        @Persist
+        public void setKey(String key) {
+            this.key = key;
+        }
+
+        @Persist
+        public String getValue() {
+            return value;
+        }
+
+        @Persist
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        
+    }
+
     private int vmPid = 0;
     private long startTime = System.currentTimeMillis();
     private long stopTime = Long.MIN_VALUE;
@@ -59,7 +97,7 @@
     private String vmArguments = "unknown";
     private Map<String, String> properties = new HashMap<String, String>();
     private Map<String, String> environment = new HashMap<String, String>();
-    private List<String> loadedNativeLibraries;
+    private String[] loadedNativeLibraries;
 
     public VmInfo() {
         /* use defaults */
@@ -69,7 +107,7 @@
             String javaVersion, String javaHome,
             String mainClass, String commandLine,
             String vmName, String vmInfo, String vmVersion, String vmArguments,
-            Map<String, String> properties, Map<String, String> environment, List<String> loadedNativeLibraries) {
+            Map<String, String> properties, Map<String, String> environment, String[] loadedNativeLibraries) {
         this.vmPid = vmPid;
         this.startTime = startTime;
         this.stopTime = stopTime;
@@ -210,33 +248,74 @@
         return getStartTimeStamp() > getStopTimeStamp();
     }
     
-    @Persist
     public Map<String, String> getProperties() {
         return properties;
     }
 
-    @Persist
     public void setProperties(Map<String, String> properties) {
         this.properties = properties;
     }
 
     @Persist
+    public KeyValuePair[] getPropertiesAsArray() {
+        return getMapAsArray(properties);
+    }
+
+    @Persist
+    public void setPropertiesAsArray(KeyValuePair[] properties) {
+        this.properties = getArrayAsMap(properties);
+    }
+
     public Map<String, String> getEnvironment() {
         return environment;
     }
 
-    @Persist
     public void setEnvironment(Map<String, String> environment) {
         this.environment = environment;
     }
 
     @Persist
-    public List<String> getLoadedNativeLibraries() {
+    public KeyValuePair[] getEnvironmentAsArray() {
+        return getMapAsArray(environment);
+    }
+
+    @Persist
+    public void setEnvironmentAsArray(KeyValuePair[] environment) {
+        this.environment = getArrayAsMap(environment);
+    }
+
+    private KeyValuePair[] getMapAsArray(Map<String, String> map) {
+        if (map == null) {
+            return null;
+        }
+        Set<String> keys = map.keySet();
+        KeyValuePair[] tuples = new KeyValuePair[keys.size()];
+        int i = 0;
+        for (String key: keys) {
+            tuples[i] = new KeyValuePair(key, map.get(key));
+            i++;
+        }
+        return tuples;
+    }
+
+    private Map<String,String> getArrayAsMap(KeyValuePair[] tuples) {
+        if (tuples == null) {
+            return null;
+        }
+        Map<String,String> map = new HashMap<>();
+        for (KeyValuePair tuple : tuples) {
+            map.put(tuple.getKey(), tuple.getValue());
+        }
+        return map;
+    }
+
+    @Persist
+    public String[] getLoadedNativeLibraries() {
         return loadedNativeLibraries;
     }
 
     @Persist
-    public void setLoadedNativeLibraries(List<String> loadedNativeLibraries) {
+    public void setLoadedNativeLibraries(String[] loadedNativeLibraries) {
         this.loadedNativeLibraries = loadedNativeLibraries;
     }
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/VmMemoryStat.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/VmMemoryStat.java	Fri Oct 26 13:13:42 2012 +0200
@@ -36,17 +36,70 @@
 
 package com.redhat.thermostat.common.model;
 
-import java.util.List;
+import com.redhat.thermostat.common.storage.Entity;
+import com.redhat.thermostat.common.storage.Persist;
 
+@Entity
 public class VmMemoryStat extends BasePojo implements TimeStampedPojo {
 
-    public static class Generation {
+    @Entity
+    public static class Generation implements Pojo {
         public static final String COLLECTOR_NONE = "none";
-        public String name;
-        public long capacity;
-        public long maxCapacity;
-        public List<Space> spaces;
-        public String collector;
+        private String name;
+        private long capacity;
+        private long maxCapacity;
+        private Space[] spaces;
+        private String collector;
+
+        @Persist
+        public String getName() {
+            return name;
+        }
+
+        @Persist
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        @Persist
+        public long getCapacity() {
+            return capacity;
+        }
+
+        @Persist
+        public void setCapacity(long capacity) {
+            this.capacity = capacity;
+        }
+
+        @Persist
+        public long getMaxCapacity() {
+            return maxCapacity;
+        }
+
+        @Persist
+        public void setMaxCapacity(long maxCapacity) {
+            this.maxCapacity = maxCapacity;
+        }
+
+        @Persist
+        public Space[] getSpaces() {
+            return spaces;
+        }
+
+        @Persist
+        public void setSpaces(Space[] spaces) {
+            this.spaces = spaces;
+        }
+
+        @Persist
+        public String getCollector() {
+            return collector;
+        }
+
+        @Persist
+        public void setCollector(String collector) {
+            this.collector = collector;
+        }
 
         public Space getSpace(String string) {
             for (Space s : spaces) {
@@ -58,15 +111,68 @@
         }
     }
 
-    public static class Space {
-        public int index;
-        public String name;
-        public long capacity;
-        public long maxCapacity;
-        public long used;
+    @Entity
+    public static class Space implements Pojo {
+
+        private int index;
+        private String name;
+        private long capacity;
+        private long maxCapacity;
+        private long used;
+
+        @Persist
+        public int getIndex() {
+            return index;
+        }
+
+        @Persist
+        public void setIndex(int index) {
+            this.index = index;
+        }
+
+        @Persist
+        public String getName() {
+            return name;
+        }
+
+        @Persist
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        @Persist
+        public long getCapacity() {
+            return capacity;
+        }
+
+        @Persist
+        public void setCapacity(long capacity) {
+            this.capacity = capacity;
+        }
+
+        @Persist
+        public long getMaxCapacity() {
+            return maxCapacity;
+        }
+
+        @Persist
+        public void setMaxCapacity(long maxCapacity) {
+            this.maxCapacity = maxCapacity;
+        }
+
+        @Persist
+        public long getUsed() {
+            return used;
+        }
+
+        @Persist
+        public void setUsed(long used) {
+            this.used = used;
+        }
+
     }
 
-    private List<Generation> generations;
+    private Generation[] generations;
     private long timestamp;
     private int vmId;
 
@@ -74,34 +180,42 @@
         this(-1, -1, null);
     }
 
-    public VmMemoryStat(long timestamp, int vmId, List<Generation> generations) {
+    public VmMemoryStat(long timestamp, int vmId, Generation[] generations) {
         this.timestamp = timestamp;
         this.vmId = vmId;
-        this.generations = generations;
+        if (generations != null) {
+            this.generations = generations;
+        }
     }
 
+    @Persist
     public int getVmId() {
         return vmId;
     }
 
+    @Persist
     public void setVmId(int vmId) {
         this.vmId = vmId;
     }
 
+    @Persist
     @Override
     public long getTimeStamp() {
         return timestamp;
     }
 
+    @Persist
     public void setTimeStamp(long timeStamp) {
         this.timestamp = timeStamp;
     }
 
-    public List<Generation> getGenerations() {
+    @Persist
+    public Generation[] getGenerations() {
         return generations;
     }
 
-    public void setGenerations(List<Generation> generations) {
+    @Persist
+    public void setGenerations(Generation[] generations) {
         this.generations = generations;
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/Chunk.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.storage;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * A Chunk is a unit containing a set of data that can be added as a whole to the dataset
- * that exists behind the storage layer.
- */
-public class Chunk {
-    protected final boolean replace;
-
-    protected Category category;
-
-    private Map<Key<?>, Object> values = new LinkedHashMap<Key<?>, Object>();
-
-    protected Chunk() {
-        // FIXME this replace is wrong. it depends on the type of data we are interested in
-        replace = false;
-    }
-
-    /**
-     *
-     * @param category The {@link Category} of this data.  This should be a Category that the {@link Backend}
-     * who is producing this Chunk has registered via {@link Storage#registerCategory()}
-     * @param replace whether this chunk should replace the values based on the keys for this category,
-     * or be added to a set of values in this category
-     */
-    public Chunk(Category category, boolean replace) {
-        // FIXME the insertion behaviour should not be part of the data structure itself
-        this.category = category;
-        this.replace = replace;
-    }
-
-    public Category getCategory() {
-        return category;
-    }
-
-    public boolean getReplace() {
-        return replace;
-    }
-
-    public <T> void put(Key<T> entry, T value) {
-        values.put(entry, value);
-    }
-
-    @SuppressWarnings("unchecked")
-    public <T> T get(Key<T> entry) {
-        // We only allow matching types in put(), so this cast should be fine.
-        return (T) values.get(entry);
-    }
-
-    public Set<Key<?>> getKeys() {
-        return values.keySet();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (! (o instanceof Chunk)) {
-            return false;
-        }
-        Chunk other = (Chunk) o;
-        return Objects.equals(this.category, other.category) && Objects.equals(this.values, other.values);
-    }
-
-    @Override
-    public String toString() {
-        return "Chunk: " + category.getName() + values.toString();
-    }
-
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/ChunkAdapter.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.storage;
-
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.commons.beanutils.BeanUtils;
-import org.apache.commons.beanutils.PropertyUtils;
-
-/**
- * Adapts a bean into a Chunk. The bean must be annotated with {@link Entity}.
- * All methods to persist must be annotated with {@link Persist}
- */
-public class ChunkAdapter extends Chunk {
-
-    private final Object adaptee;
-
-    public ChunkAdapter(Object obj) {
-        this(obj, null, false);
-        Set<Key<?>> keys = identifyKeys(obj);
-        category = createCategory(obj, keys);
-    }
-
-    public ChunkAdapter(Object obj, Category category, boolean replace) {
-        super(category, replace);
-        checkForAnnotation(obj);
-        adaptee = obj;
-    }
-
-    public Object getAdaptee() {
-        return adaptee;
-    }
-
-    private void checkForAnnotation(Object toCheck) {
-        if (!toCheck.getClass().isAnnotationPresent(Entity.class)) {
-            throw new IllegalArgumentException("object to adapt must be annotated with Entity");
-        }
-    }
-
-    private Set<Key<?>> identifyKeys(Object obj) {
-        Set<Key<?>> keys = new HashSet<>();
-
-        PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(obj);
-        for (PropertyDescriptor descriptor : descriptors) {
-            if (hasValidGetAndSetMethods(descriptor)) {
-                // FIXME this is sometimes a partial key
-                Key<?> key = new Key<>(findKeyName(descriptor), false);
-                keys.add(key);
-            }
-        }
-        return keys;
-    }
-
-    private boolean hasValidGetAndSetMethods(PropertyDescriptor descriptor) {
-        Method readMethod = descriptor.getReadMethod();
-        Method writeMethod = descriptor.getWriteMethod();
-
-        if (readMethod != null && writeMethod != null) {
-            if (readMethod.isAnnotationPresent(Persist.class) &&
-                    writeMethod.isAnnotationPresent(Persist.class)) {
-                return true;
-            } else if (readMethod.isAnnotationPresent(Persist.class) ^
-                    writeMethod.isAnnotationPresent(Persist.class)) {
-                throw new IllegalArgumentException("annotation only present on one of get/set method");
-            }
-        }
-        return false;
-    }
-
-    private String findKeyName(PropertyDescriptor descriptor) {
-        final String NAME_UNSPECIFIED = "";
-
-        String computedName = descriptor.getName();
-        String nameOnGetMethod = descriptor.getReadMethod().getAnnotation(Persist.class).name();
-        String nameOnSetMethod = descriptor.getWriteMethod().getAnnotation(Persist.class).name();
-
-        String attributeName;
-        if (nameOnGetMethod.equals(NAME_UNSPECIFIED) && nameOnSetMethod.equals(NAME_UNSPECIFIED)) {
-            attributeName = computedName;
-        } else {
-            if (!nameOnGetMethod.equals(nameOnSetMethod) && nameOnSetMethod.equals(NAME_UNSPECIFIED)) {
-                attributeName = nameOnGetMethod;
-            } else if (!nameOnSetMethod.equals(nameOnGetMethod) && nameOnGetMethod.equals(NAME_UNSPECIFIED)) {
-                attributeName = nameOnSetMethod;
-            } else {
-                throw new IllegalArgumentException("set/get methods have mismatching names in annotation");
-            }
-        }
-
-        return attributeName;
-    }
-
-    private Category createCategory(Object obj, Set<Key<?>> keys) {
-        String newCategoryName = findCategoryName(obj);
-        Category category;
-        if (Categories.contains(newCategoryName)) {
-            Set<Key<?>> existingKeys= new HashSet<>(Categories.getByName(newCategoryName).getKeys());
-            if (!keys.equals(existingKeys)) {
-                throw new IllegalArgumentException("this class, with a differet organization was seen previously");
-            }
-            category = Categories.getByName(newCategoryName);
-        } else {
-            category = new Category(newCategoryName, keys.toArray(new Key<?>[0]));
-        }
-        return category;
-    }
-
-    private String findCategoryName(Object obj) {
-        Entity categoryAnnotation = obj.getClass().getAnnotation(Entity.class);
-        String desiredName = categoryAnnotation.name();
-        if (desiredName.equals("")) {
-            desiredName = obj.getClass().getSimpleName();
-        }
-        return desiredName;
-    }
-
-    @Override
-    public <T> T get(Key<T> entry) {
-        try {
-            return (T) PropertyUtils.getProperty(adaptee, entry.getName());
-        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
-            e.printStackTrace();
-            try {
-                System.err.println(BeanUtils.describe(adaptee));
-            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e1) {
-                e1.printStackTrace();
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public <T> void put(Key<T> entry, T value) {
-        String keyName = entry.getName();
-        try {
-            BeanUtils.setProperty(adaptee, keyName, value);
-        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-            e.printStackTrace();
-            try {
-                System.err.println(BeanUtils.describe(adaptee));
-            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e1) {
-                e1.printStackTrace();
-            }
-        }
-    }
-
-    @Override
-    public Set<Key<?>> getKeys() {
-        Category category = getCategory();
-        return new HashSet<>(category.getKeys());
-    }
-
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/ChunkConverter.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.storage;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.logging.Logger;
-
-import org.bson.types.ObjectId;
-
-import com.mongodb.BasicDBList;
-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;
-        for (Key<?> key : chunk.getKeys()) {
-            dbObjectMap = convertChunkKey(chunk, key, dbObject, dbObjectMap);
-        }
-        return dbObject;
-    }
-
-    private Map<String, DBObject> convertChunkKey(Chunk chunk, Key<?> key, DBObject dbObject, Map<String,DBObject> dbObjectMap) {
-        String[] keyParts = key.getName().split("\\.");
-        String initialName = keyParts[0];
-        return convertChunkKeyRecursively(chunk, key, dbObject, keyParts, 0, initialName, dbObjectMap);
-    }
-
-    private Map<String, DBObject> convertChunkKeyRecursively(Chunk chunk, Key<?> key, DBObject dbObject, String[] keyParts, int partIndex,
-                                            String partialKeyName, Map<String, DBObject> dbObjectMap) {
-        if (partIndex == keyParts.length - 1) {
-            String dbKey = keyParts[partIndex];
-            Object value = chunk.get(key);
-            if (dbKey.equals("_id")) {
-                value = new ObjectId((String) value);
-            }
-            dbObject.put(dbKey, value);
-        } else {
-            dbObjectMap = lazyCreateDBObjectMap(dbObjectMap);
-            DBObject nestedDbObject = getOrCreateSubObject(partialKeyName, dbObjectMap);
-            dbObject.put(keyParts[partIndex], nestedDbObject);
-            partIndex++;
-            String nextSubKey = keyParts[partIndex];
-            partialKeyName = partialKeyName + "." + nextSubKey;
-            convertChunkKeyRecursively(chunk, key, nestedDbObject, keyParts, partIndex, partialKeyName, dbObjectMap);
-        }
-        return dbObjectMap;
-    }
-
-
-    private Map<String, DBObject> lazyCreateDBObjectMap(Map<String, DBObject> dbObjectMap) {
-        if (dbObjectMap == null) {
-            dbObjectMap = new HashMap<String, DBObject>();
-        }
-        return dbObjectMap;
-    }
-
-    private DBObject getOrCreateSubObject(String partialKeyName,
-            Map<String, DBObject> dbObjectMap) {
-        DBObject dbObject = dbObjectMap.get(partialKeyName);
-        if (dbObject == null) {
-            dbObject = new BasicDBObject();
-            dbObjectMap.put(partialKeyName, dbObject);
-        }
-        return dbObject;
-    }
-
-    public Chunk dbObjectToChunk(DBObject dbObject, Category category) {
-        Chunk chunk = new Chunk(category, false);
-        dbObjectToChunkRecurse(chunk, dbObject, category, null);
-        return chunk;
-    }
-
-    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;
-            }
-            dbObjectToChunkRecursively(chunk, dbObject, category, dbKey,
-                    newFullKey);
-        }
-    }
-
-    private void dbObjectToChunkRecursively(Chunk chunk, DBObject dbObject, Category category, String dbKey, String fullKey) {
-        Object value = dbObject.get(dbKey);
-        Key key = category.getKey(fullKey);
-        if (value instanceof BasicDBList) {
-            if (key != null) {
-                chunk.put(key, value);
-            } else {
-                logger.warning("No key matching \"" + fullKey + "\" in category \"" + category + "\"");
-            }
-        } else if (value instanceof DBObject) {
-            DBObject dbObj = (DBObject) value;
-            dbObjectToChunkRecurse(chunk, dbObj, category, fullKey);
-        } else if (value instanceof ObjectId) {
-            chunk.put(key, objectIdToString((ObjectId) value));
-        } else {
-            if (key != null) {
-                chunk.put(key, value);
-            } else {
-                logger.warning("No key matching \"" + fullKey + "\" in category \"" + category + "\"");
-            }
-        }
-    }
-
-    private String objectIdToString(ObjectId value) {
-        return value.toString();
-    }
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/ChunkToPojoConverter.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.storage;
-
-import java.util.Map;
-import java.util.Set;
-
-import com.redhat.thermostat.common.dao.Converter;
-import com.redhat.thermostat.common.model.Pojo;
-
-class ChunkToPojoConverter {
-
-    static <T extends Pojo> T convertChunkToPojo(Chunk resultChunk, Class<T> resultClass, Map<Class<?>, Converter<?>> converters) {
-        try {
-            if (converters != null) {
-                Converter<?> converter = converters.get(resultClass);
-                if (converter != null) {
-                    return (T) converter.fromChunk(resultChunk);
-                }
-            }
-            Pojo pojo = resultClass.newInstance();
-            ChunkAdapter chunk = new ChunkAdapter(pojo, resultChunk.getCategory(), resultChunk.getReplace());
-            Set<Key<?>> keys = resultChunk.getKeys();
-            for (Key key : keys) {
-                if (key == null) {
-                    continue;
-                }
-                chunk.put(key, resultChunk.get(key));
-            }
-            return (T) chunk.getAdaptee();
-        } catch (InstantiationException | IllegalAccessException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoCursor.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoCursor.java	Fri Oct 26 13:13:42 2012 +0200
@@ -36,26 +36,18 @@
 
 package com.redhat.thermostat.common.storage;
 
-import java.util.Map;
-
-import com.mongodb.BasicDBObject;
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
-import com.redhat.thermostat.common.dao.Converter;
 import com.redhat.thermostat.common.model.Pojo;
 
 class MongoCursor<T extends Pojo> implements Cursor<T> {
 
     private DBCursor cursor;
-    private Category category;
     private Class<T> resultClass;
-    private Map<Class<?>, Converter<?>> converters;
 
-    MongoCursor(DBCursor cursor, Category category, Class<T> resultClass, Map<Class<?>, Converter<?>> converters) {
+    MongoCursor(DBCursor cursor, Class<T> resultClass) {
         this.cursor = cursor;
-        this.category = category;
         this.resultClass = resultClass;
-        this.converters = converters;
     }
 
     @Override
@@ -69,9 +61,8 @@
         if (next == null) {
             return null;
         }
-        ChunkConverter converter = new ChunkConverter();
-        Chunk resultChunk = converter.dbObjectToChunk(next, category);
-        return ChunkToPojoConverter.convertChunkToPojo(resultChunk, resultClass, converters);
+        MongoPojoConverter converter = new MongoPojoConverter();
+        return converter.convertMongoToPojo(next, resultClass);
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoPojoConverter.java	Fri Oct 26 13:13:42 2012 +0200
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+
+package com.redhat.thermostat.common.storage;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+import com.redhat.thermostat.common.model.Pojo;
+
+class MongoPojoConverter {
+
+    public DBObject convertPojoToMongo(Pojo obj) {
+        try {
+            return convertPojoToMongoImpl(obj);
+        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) {
+            throw new StorageException(ex);
+        }
+    }
+
+    private DBObject convertPojoToMongoImpl(Pojo obj) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        BasicDBObject dbObj = new BasicDBObject();
+        PropertyDescriptor[] descs = PropertyUtils.getPropertyDescriptors(obj);
+        for (PropertyDescriptor desc : descs) {
+            storePropertyToDBObject(obj, dbObj, desc);
+        }
+        return dbObj;
+    }
+
+    private void storePropertyToDBObject(Pojo obj, BasicDBObject dbObj, PropertyDescriptor desc) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        if (hasPersistentAnnotation(desc)) {
+            String name = desc.getName();
+            Object value = PropertyUtils.getProperty(obj, name);
+            if (desc.getPropertyType().isArray()) {
+                value = convertIndexedProperty(value);
+            }
+            if (value instanceof Pojo) {
+                value = convertPojoToMongoImpl((Pojo) value);
+            }
+            dbObj.put(name, value);
+        }
+    }
+
+    private Object convertIndexedProperty(Object values) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        int length = Array.getLength(values);
+        List list = new ArrayList(length);
+        for (int i = 0; i < length; i++) {
+            Object value = Array.get(values, i);
+            if (value instanceof Pojo) {
+                value = convertPojoToMongoImpl((Pojo) value);
+            }
+            list.add(value);
+        }
+        return list;
+    }
+
+    public <T extends Pojo> T convertMongoToPojo(DBObject dbObj, Class<T> pojoClass) {
+        try {
+            return convertMongoToPojoImpl(dbObj, pojoClass);
+        } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException ex) {
+            throw new StorageException(ex);
+        }
+    }
+
+    private <T extends Pojo> T convertMongoToPojoImpl(DBObject dbObj, Class pojoClass) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        if (dbObj == null) {
+            return null;
+        }
+        T pojo = (T) pojoClass.newInstance();
+        Set<String> keys = dbObj.keySet();
+        for (String name : keys) {
+            if (! name.equals("_id")) {
+                storePropertyToPojo(dbObj, pojo, name);
+            }
+        }
+        return pojo;
+    }
+
+    private <T extends Pojo> void storePropertyToPojo(DBObject dbObj, T pojo, String name)
+            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException {
+
+        PropertyDescriptor desc = PropertyUtils.getPropertyDescriptor(pojo, name);
+        if (hasPersistentAnnotation(desc)) {
+            Object value = dbObj.get(name);
+            if (desc.getPropertyType().isArray()) {
+                value = convertIndexedPropertyFromMongo(desc, (List) value);
+            }
+            if (value instanceof DBObject) {
+                value = convertMongoToPojoImpl((DBObject) value, desc.getPropertyType());
+            }
+            PropertyUtils.setProperty(pojo, name, value);
+        } else {
+            throw new StorageException("no available mapping for extra property: '" + name + "' in " + pojo.getClass().getName());
+        }
+    }
+
+    private Object convertIndexedPropertyFromMongo(PropertyDescriptor desc, List values) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        Class componentType = desc.getPropertyType().getComponentType();
+        Object array = Array.newInstance(componentType, values.size());
+        int i = 0;
+        for (Object value : values) {
+            if (value instanceof DBObject) {
+                value = convertMongoToPojoImpl((DBObject) value, componentType);
+            }
+            Array.set(array, i, value);
+            i++;
+        }
+        return array;
+    }
+
+    private boolean hasPersistentAnnotation(PropertyDescriptor desc) {
+        if (desc == null) {
+            return false;
+        }
+        Method writeMethod = desc.getWriteMethod();
+        Method readMethod = desc.getReadMethod();
+        return writeMethod != null && writeMethod.isAnnotationPresent(Persist.class)
+               && readMethod != null && readMethod.isAnnotationPresent(Persist.class);
+    }
+
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoRemove.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoRemove.java	Fri Oct 26 13:13:42 2012 +0200
@@ -37,29 +37,37 @@
 
 package com.redhat.thermostat.common.storage;
 
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+
 class MongoRemove implements Remove {
 
-    private Chunk query;
+    private Category category;
+    private DBObject query;
 
     @Override
     public Remove from(Category category) {
         if (query != null) {
             throw new IllegalStateException();
         }
-        query = new Chunk(category, false);
+        this.category = category;
         return this;
     }
 
+    Category getCategory() {
+        return category;
+    }
+
     @Override
     public <T> Remove where(Key<T> key, T value) {
         if (query == null) {
-            throw new IllegalStateException();
+            query = new BasicDBObject();
         }
-        query.put(key, value);
+        query.put(key.getName(), value);
         return this;
     }
 
-    Chunk getChunk() {
+    DBObject getQuery() {
         return query;
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Fri Oct 26 13:13:42 2012 +0200
@@ -37,10 +37,10 @@
 package com.redhat.thermostat.common.storage;
 
 import java.io.InputStream;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.UUID;
 
 import com.mongodb.BasicDBObject;
@@ -52,10 +52,8 @@
 import com.mongodb.gridfs.GridFSDBFile;
 import com.mongodb.gridfs.GridFSInputFile;
 import com.redhat.thermostat.common.config.StartupConfiguration;
-import com.redhat.thermostat.common.dao.Converter;
-import com.redhat.thermostat.common.dao.VmMemoryStatConverter;
+import com.redhat.thermostat.common.model.AgentIdPojo;
 import com.redhat.thermostat.common.model.Pojo;
-import com.redhat.thermostat.common.model.VmMemoryStat;
 import com.redhat.thermostat.common.storage.AbstractQuery.Sort;
 import com.redhat.thermostat.common.storage.Connection.ConnectionListener;
 import com.redhat.thermostat.common.storage.Connection.ConnectionStatus;
@@ -75,10 +73,7 @@
 
     private UUID agentId;
 
-    private Map<Class<?>, Converter<?>> converters;
-
     public MongoStorage(StartupConfiguration conf) {
-        setupConverters();
         conn = new MongoConnection(conf);
         conn.addListener(new ConnectionListener() {
             @Override
@@ -95,11 +90,6 @@
         });
     }
 
-    private void setupConverters() {
-        converters = new HashMap<>();
-        converters.put(VmMemoryStat.class, new VmMemoryStatConverter());
-    }
-
     @Override
     public Connection getConnection() {
         return conn;
@@ -115,82 +105,42 @@
         return agentId.toString();
     }
 
-    private BasicDBObject getAgentQueryKeyFromGlobalAgent() {
+    private String getAgentQueryKeyFromGlobalAgent() {
         if (agentId != null) {
-            return new BasicDBObject(Key.AGENT_ID.getName(), agentId.toString());
+            return agentId.toString();
         } else {
             return null;
         }
     }
 
-    private BasicDBObject getAgentQueryKeyFromChunkOrGlobalAgent(Chunk chunk) {
-        BasicDBObject queryKey = getAgentQueryKeyFromGlobalAgent();
+    private String getAgentQueryKeyFromChunkOrGlobalAgent(AgentIdPojo pojo) {
+        String queryKey = getAgentQueryKeyFromGlobalAgent();
         if (queryKey != null) {
             return queryKey;
-        } else if (chunk.get(Key.AGENT_ID) != null) {
-            return new BasicDBObject(Key.AGENT_ID.getName(), chunk.get(Key.AGENT_ID));
         } else {
-            return new BasicDBObject();
+            return pojo.getAgentId();
         }
     }
 
-    // TODO: Make this private, and change the testcase to test putPojo() instead.
-    void putChunk(Chunk chunk) {
-        Category cat = chunk.getCategory();
+    @Override
+    public void putPojo(Category cat, boolean replace, AgentIdPojo pojo) {
         DBCollection coll = getCachedCollection(cat);
-        BasicDBObject toInsert = getAgentQueryKeyFromChunkOrGlobalAgent(chunk);
-        BasicDBObject replaceKey = null;
-        boolean replace = chunk.getReplace();
-        Map<String, BasicDBObject> nestedParts = new HashMap<String, BasicDBObject>();
-        Map<String, BasicDBObject> replaceKeyNestedParts = null;
+        MongoPojoConverter converter = new MongoPojoConverter();
+        DBObject toInsert = converter.convertPojoToMongo(pojo);
+        String agentId = getAgentQueryKeyFromChunkOrGlobalAgent(pojo);
+        toInsert.put(Key.AGENT_ID.getName(), agentId);
         if (replace) {
-            replaceKey = getAgentQueryKeyFromChunkOrGlobalAgent(chunk);
-            replaceKeyNestedParts = new HashMap<String, BasicDBObject>();
-        }
-        for (Key<?> key : cat.getKeys()) {
-            boolean isKey = key.isPartialCategoryKey();
-            String[] entryParts = key.getName().split("\\.");
-            if (entryParts.length == 2) {
-                BasicDBObject nested = nestedParts.get(entryParts[0]);
-                if (nested == null) {
-                    if (isKey) {
-                        throwMissingKey(key.getName(), chunk);
-                    }
-                    nested = new BasicDBObject();
-                    nestedParts.put(entryParts[0], nested);
-                }
-                nested.append(entryParts[1], chunk.get(key));
-                if (replace && isKey) {
-                    BasicDBObject replaceKeyNested = replaceKeyNestedParts.get(entryParts[0]);
-                    if (replaceKeyNested == null) {
-                        replaceKeyNested = new BasicDBObject();
-                        replaceKeyNestedParts.put(entryParts[0], replaceKeyNested);
-                    }
-                    replaceKeyNested.append(entryParts[1], replaceKeyNested);
-                }
-            } else {
-                /* we dont modify agent id, and it's already used as key in updateKey */
-                if (!key.equals(Key.AGENT_ID)) {
-                    String mongoKey = key.getName();
-                    Object value = chunk.get(key);
-                    if ((value == null) && isKey) {
-                        throwMissingKey(key.getName(), chunk);
-                    }
-                    toInsert.append(mongoKey, value);
-                    if (replace && isKey) {
-                        replaceKey.append(mongoKey, value);
-                    }
+            // TODO: Split this part out into a separate method. It is a very bad practice to
+            // completely change the behaviour of a method based on a boolean flag.
+            DBObject query = new BasicDBObject();
+            Collection<Key<?>> keys = cat.getKeys();
+            for (Key<?> key : keys) {
+                if (key.isPartialCategoryKey()) {
+                    String name = key.getName();
+                    query.put(name, toInsert.get(name));
                 }
             }
-        }
-        for (Entry<String, BasicDBObject> entry: nestedParts.entrySet()) {
-            toInsert.append(entry.getKey(), entry.getValue());
-        }
-        if (replace) {
-            for (Entry<String, BasicDBObject> entry: replaceKeyNestedParts.entrySet()) {
-                replaceKey.append(entry.getKey(), entry.getValue());
-            }
-            coll.update(replaceKey, toInsert, true, false);
+            coll.update(query, toInsert);
         } else {
             coll.insert(toInsert);
         }
@@ -200,95 +150,27 @@
     public void updatePojo(Update update) {
         assert update instanceof MongoUpdate;
         MongoUpdate mongoUpdate = (MongoUpdate) update;
-        Chunk chunk = mongoUpdate.getChunk();
-        updateChunk(chunk);
-    }
-
-    void updateChunk(Chunk chunk) {
-        Category cat = chunk.getCategory();
+        Category cat = mongoUpdate.getCategory();
         DBCollection coll = getCachedCollection(cat);
-        BasicDBObject toUpdate = new BasicDBObject();
-        BasicDBObject updateKey = getAgentQueryKeyFromChunkOrGlobalAgent(chunk);
-        BasicDBObject setObj = null;
-        Map<String, BasicDBObject> nestedParts = new HashMap<String, BasicDBObject>();
-        Map<String, BasicDBObject> updateKeyNestedParts = new HashMap<String, BasicDBObject>();
-        for (Key<?> key : cat.getKeys()) {
-            boolean isKey = key.isPartialCategoryKey();
-            String[] entryParts = key.getName().split("\\.");
-            if (entryParts.length == 2) {
-                BasicDBObject nested = nestedParts.get(entryParts[0]);
-                if (nested == null) {
-                    if (isKey) {
-                        throwMissingKey(key.getName(), chunk);
-                    }
-                } else {
-                    if (isKey) {
-                        BasicDBObject updateKeyNested = updateKeyNestedParts.get(entryParts[0]);
-                        if (updateKeyNested == null) {
-                            updateKeyNested = new BasicDBObject();
-                            updateKeyNestedParts.put(entryParts[0], updateKeyNested);
-                        }
-                        updateKeyNested.append(entryParts[1], updateKeyNested);
-                    } else {
-                        if (setObj == null) {
-                            setObj = new BasicDBObject();
-                            nested.append(SET_MODIFIER, setObj);
-                        }
-                        setObj.append(entryParts[1], chunk.get(key));
-                    }
-                }
-            } else {
-                String mongoKey = key.getName();
-                /* we dont modify agent id, and it's already used as key in updateKey */
-                if (!key.equals(Key.AGENT_ID)) {
-                    Object value = chunk.get(key);
-                    if (value == null) {
-                        if (isKey) {
-                            throwMissingKey(key.getName(), chunk);
-                        }
-                    } else {
-                        if (isKey) {
-                            updateKey.append(mongoKey, value);
-                        } else {
-                            if (setObj == null) {
-                                setObj = new BasicDBObject();
-                                toUpdate.append(SET_MODIFIER, setObj);
-                            }
-                            setObj.append(mongoKey, value);
-                        }
-                    }
-                }
-            }
-        }
-        for (Entry<String, BasicDBObject> entry: nestedParts.entrySet()) {
-            toUpdate.append(entry.getKey(), entry.getValue());
-        }
-        for (Entry<String, BasicDBObject> entry: updateKeyNestedParts.entrySet()) {
-            updateKey.append(entry.getKey(), entry.getValue());
-        }
-        coll.update(updateKey, toUpdate);
-    }
-
-    private void throwMissingKey(String keyName, Chunk chunk) {
-        throw new IllegalArgumentException("Attempt to insert chunk with incomplete partial key.  Missing: '" + keyName + "' in " + chunk);
+        DBObject query = mongoUpdate.getQuery();
+        DBObject values = mongoUpdate.getValues();
+        coll.update(query, values);
     }
 
     @Override
     public void removePojo(Remove remove) {
         assert (remove instanceof MongoRemove);
         MongoRemove mongoRemove = (MongoRemove) remove;
-        Chunk query = mongoRemove.getChunk();
-        Category category = query.getCategory();
+        DBObject query = mongoRemove.getQuery();
+        Category category = mongoRemove.getCategory();
         DBCollection coll = getCachedCollection(category);
 
-        BasicDBObject toRemove = getAgentQueryKeyFromChunkOrGlobalAgent(query);
-        for (Key<?> key : category.getKeys()) {
-            if (key.isPartialCategoryKey()) {
-                toRemove.put(key.getName(), query.get(key));
-            }
+        String agentId = getAgentQueryKeyFromGlobalAgent();
+        if (agentId != null) {
+            query.put(Key.AGENT_ID.getName(), agentId);
         }
 
-        coll.remove(toRemove);
+        coll.remove(query);
     }
 
     private DBCollection getCachedCollection(Category category) {
@@ -310,9 +192,10 @@
 
     @Override
     public void purge() {
-        BasicDBObject deleteKey = getAgentQueryKeyFromGlobalAgent();
+        String deleteKey = getAgentQueryKeyFromGlobalAgent();
+        BasicDBObject query = new BasicDBObject(Key.AGENT_ID.getName(), deleteKey);
         for (DBCollection coll : collectionCache.values()) {
-            coll.remove(deleteKey);
+            coll.remove(query);
         }
     }
     
@@ -358,7 +241,7 @@
             dbCursor = coll.find();
         }
         dbCursor = applySortAndLimit(mongoQuery, dbCursor);
-        return new MongoCursor<T>(dbCursor, mongoQuery.getCategory(), resultClass, converters);
+        return new MongoCursor<T>(dbCursor, resultClass);
     }
 
     private DBCursor applySortAndLimit(MongoQuery query, DBCursor dbCursor) {
@@ -375,22 +258,14 @@
         return dbCursor;
     }
 
+
     @Override
     public <T extends Pojo> T findPojo(Query query, Class<T> resultClass) {
-        Chunk resultChunk = find(query);
-        if (resultChunk == null) {
-            return null;
-        }
-        return ChunkToPojoConverter.convertChunkToPojo(resultChunk, resultClass, converters);
-    }
-
-    // TODO: Make this private, and change the testcase to test putPojo() instead.
-    Chunk find(Query query) {
         MongoQuery mongoQuery = checkAndCastQuery(query);
         DBCollection coll = getCachedCollection(mongoQuery.getCategory());
         DBObject dbResult = coll.findOne(mongoQuery.getGeneratedQuery());
-        ChunkConverter converter = new ChunkConverter();
-        return dbResult == null ? null : converter.dbObjectToChunk(dbResult, mongoQuery.getCategory());
+        MongoPojoConverter conv = new MongoPojoConverter();
+        return conv.convertMongoToPojo(dbResult, resultClass);
     }
 
     private MongoQuery checkAndCastQuery(Query query) {
@@ -429,21 +304,4 @@
         }
     }
 
-    @Override
-    public void putPojo(Category category, boolean replace, Pojo pojo) {
-        Chunk chunk = convertPojoToChunk(category, replace, pojo);
-        putChunk(chunk);
-    }
-
-    private Chunk convertPojoToChunk(Category category, boolean replace, Pojo pojo) {
-        Converter customConverter = converters.get(pojo.getClass());
-        Chunk chunk;
-        if (customConverter != null) {
-            chunk = customConverter.toChunk(pojo);
-        } else {
-            chunk = new ChunkAdapter(pojo, category, replace);
-        }
-        return chunk;
-    }
-
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoUpdate.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoUpdate.java	Fri Oct 26 13:13:42 2012 +0200
@@ -37,42 +37,54 @@
 
 package com.redhat.thermostat.common.storage;
 
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+
 // TODO: For now we utilize the Chunk based conversion, and rely on MongoStorage to
 // actually resolve the $set fields. Eventually, we want to convert to DBObject
 // directly, and take advantage of improved semantics of this class.
 class MongoUpdate implements Update {
 
-    private Chunk updateChunk;
+    private DBObject query;
+    private DBObject values;
+    private Category category;
 
     @Override
     public Update from(Category category) {
-        if (updateChunk != null) {
+        if (query != null || values != null) {
             throw new IllegalStateException();
         }
-        updateChunk = new Chunk(category, false);
+        this.category = category;
         return this;
     }
 
+    Category getCategory() {
+        return category;
+    }
+
     @Override
     public <T> Update where(Key<T> key, T value) {
-        if (updateChunk == null) {
-            throw new IllegalStateException();
+        if (query == null) {
+            query = new BasicDBObject();
         }
-        updateChunk.put(key, value);
+        query.put(key.getName(), value);
         return this;
     }
 
+    DBObject getQuery() {
+        return query;
+    }
+
     @Override
     public <T> Update set(Key<T> key, T value) {
-        if (updateChunk == null) {
-            throw new IllegalStateException();
+        if (values == null) {
+            values = new BasicDBObject();
         }
-        updateChunk.put(key, value);
+        values.put(key.getName(), value);
         return this;
     }
 
-    Chunk getChunk() {
-        return updateChunk;
+    DBObject getValues() {
+        return new BasicDBObject("$set", values);
     }
-
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Fri Oct 26 13:13:42 2012 +0200
@@ -39,6 +39,7 @@
 import java.io.InputStream;
 import java.util.UUID;
 
+import com.redhat.thermostat.common.model.AgentIdPojo;
 import com.redhat.thermostat.common.model.Pojo;
 
 public abstract class Storage {
@@ -51,7 +52,7 @@
 
     public abstract Connection getConnection();
 
-    public abstract void putPojo(Category category, boolean replace, Pojo pojo);
+    public abstract void putPojo(Category category, boolean replace, AgentIdPojo pojo);
 
     public abstract void updatePojo(Update update);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/StorageException.java	Fri Oct 26 13:13:42 2012 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+
+package com.redhat.thermostat.common.storage;
+
+@SuppressWarnings("serial")
+public class StorageException extends RuntimeException {
+
+    public StorageException() {
+        super();
+    }
+    public StorageException(String message) {
+        super(message);
+    }
+
+    public StorageException(Throwable cause) {
+        super(cause);
+    }
+
+    public StorageException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -38,9 +38,10 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
 import java.util.Collection;
@@ -52,11 +53,10 @@
 
 import com.redhat.thermostat.common.model.BackendInformation;
 import com.redhat.thermostat.common.storage.Category;
-import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Cursor;
 import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.QueryTestHelper;
-import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Remove;
 import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.test.MockQuery;
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -46,7 +46,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
@@ -59,7 +58,6 @@
 import com.redhat.thermostat.common.storage.Query;
 import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Storage;
-import com.redhat.thermostat.common.utils.ArrayUtils;
 import com.redhat.thermostat.test.MockQuery;
 
 public class CpuStatDAOTest {
@@ -86,8 +84,7 @@
         CpuStatDAO dao = new CpuStatDAOImpl(storage);
 
         Double LOAD = 5.0;
-        List<Double> loadList = Arrays.asList(LOAD);
-        CpuStat cpuStat = new CpuStat(1234L, loadList);
+        CpuStat cpuStat = new CpuStat(1234L, new double[] { LOAD });
 
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(cpuStat);
@@ -103,7 +100,7 @@
         assertEquals(1, cpuStats.size());
         CpuStat stat = cpuStats.get(0);
         assertEquals(1234L, stat.getTimeStamp());
-        assertArrayEquals(new double[] { LOAD }, ArrayUtils.toPrimitiveDoubleArray(stat.getPerProcessorUsage()), 0.001);
+        assertArrayEquals(new double[] { LOAD }, stat.getPerProcessorUsage(), 0.001);
 
     }
 
@@ -118,7 +115,7 @@
 
         CpuStatDAO dao = new CpuStatDAOImpl(storage);
 
-        CpuStat cpuStat = new CpuStat(1234L, Arrays.asList(5.0));
+        CpuStat cpuStat = new CpuStat(1234L, new double[] { 5.0 });
 
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(cpuStat);
@@ -138,7 +135,7 @@
     @Test
     public void testPutCpuStat() {
         Storage storage = mock(Storage.class);
-        CpuStat stat = new CpuStat(1,  ArrayUtils.toDoubleList(new double[] {5.0, 10.0, 15.0}));
+        CpuStat stat = new CpuStat(1,  new double[] {5.0, 10.0, 15.0});
         CpuStatDAO dao = new CpuStatDAOImpl(storage);
         dao.putCpuStat(stat);
 
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -56,7 +56,6 @@
 import com.redhat.thermostat.common.model.AgentInformation;
 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.Query;
@@ -99,14 +98,6 @@
     @Test
     public void testGetHostInfo() {
 
-        Chunk chunk = new Chunk(HostInfoDAO.hostInfoCategory, false);
-        chunk.put(HostInfoDAO.hostNameKey, HOST_NAME);
-        chunk.put(HostInfoDAO.osNameKey, OS_NAME);
-        chunk.put(HostInfoDAO.osKernelKey, OS_KERNEL);
-        chunk.put(HostInfoDAO.cpuModelKey, CPU_MODEL);
-        chunk.put(HostInfoDAO.cpuCountKey, CPU_NUM);
-        chunk.put(HostInfoDAO.hostMemoryTotalKey, MEMORY_TOTAL);
-
         Storage storage = mock(Storage.class);
         when(storage.createQuery()).thenReturn(new MockQuery());
         HostInfo info = new HostInfo(HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
@@ -305,10 +296,6 @@
         agentInfo2.setAgentId("456");
         agentInfo2.setAlive(true);
 
-        Chunk agentConfig3 = new Chunk(AgentInfoDAO.CATEGORY, false);
-        agentConfig3.put(Key.AGENT_ID, "678");
-        agentConfig3.put(AgentInfoDAO.ALIVE_KEY, true);
-
         AgentInformation agentInfo3 = new AgentInformation();
         agentInfo3.setAgentId("678");
         agentInfo3.setAlive(true);
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -43,7 +43,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.util.Arrays;
 import java.util.List;
 
 import org.junit.After;
@@ -56,7 +55,6 @@
 import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Storage;
-import com.redhat.thermostat.common.utils.ArrayUtils;
 import com.redhat.thermostat.test.MockQuery;
 
 public class HostLatestPojoListGetterTest {
@@ -89,9 +87,9 @@
     @Before
     public void setUp() {
         ref = new HostRef(AGENT_ID, HOSTNAME);
-        result1 = new CpuStat(t1, Arrays.asList(load5_1, load10_1, load15_1));
-        result2 = new CpuStat(t2, Arrays.asList(load5_2, load10_2, load15_2));
-        result3 = new CpuStat(t3, Arrays.asList(load5_3, load10_3, load15_3));
+        result1 = new CpuStat(t1, new double[] { load5_1, load10_1, load15_1 } );
+        result2 = new CpuStat(t2, new double[] { load5_2, load10_2, load15_2 } );
+        result3 = new CpuStat(t3, new double[] { load5_3, load10_3, load15_3 } );
     }
 
     @Test
@@ -152,10 +150,10 @@
         assertEquals(2, stats.size());
         CpuStat stat1 = stats.get(0);
         assertEquals(t1, stat1.getTimeStamp());
-        assertArrayEquals(new double[] {load5_1, load10_1, load15_1}, ArrayUtils.toPrimitiveDoubleArray(stat1.getPerProcessorUsage()), 0.001);
+        assertArrayEquals(new double[] {load5_1, load10_1, load15_1}, stat1.getPerProcessorUsage(), 0.001);
         CpuStat stat2 = stats.get(1);
         assertEquals(t2, stat2.getTimeStamp());
-        assertArrayEquals(new double[] {load5_2, load10_2, load15_2}, ArrayUtils.toPrimitiveDoubleArray(stat2.getPerProcessorUsage()), 0.001);
+        assertArrayEquals(new double[] {load5_2, load10_2, load15_2}, stat2.getPerProcessorUsage(), 0.001);
     }
 
     @After
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -45,7 +45,6 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -56,12 +55,11 @@
 
 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.Query;
+import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.QueryTestHelper;
-import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.storage.Update;
 import com.redhat.thermostat.test.MockQuery;
@@ -81,7 +79,7 @@
     private String vmArgs;
     private Map<String, String> props;
     private Map<String, String> env;
-    private List<String> libs;
+    private String[] libs;
 
     @Before
     public void setUp() {
@@ -98,7 +96,7 @@
         vmVersion = "1.0";
         props = new HashMap<>();
         env = new HashMap<>();
-        libs = new ArrayList<>();
+        libs = new String[0];
     }
 
     @Test
@@ -126,22 +124,6 @@
 
     @Test
     public void testGetVmInfo() {
-        Chunk chunk = new Chunk(VmInfoDAO.vmInfoCategory, true);
-        chunk.put(Key.VM_ID, vmId);
-        chunk.put(VmInfoDAO.vmPidKey, vmId);
-        chunk.put(VmInfoDAO.startTimeKey, startTime);
-        chunk.put(VmInfoDAO.stopTimeKey, stopTime);
-        chunk.put(VmInfoDAO.runtimeVersionKey, jVersion);
-        chunk.put(VmInfoDAO.javaHomeKey, jHome);
-        chunk.put(VmInfoDAO.mainClassKey, mainClass);
-        chunk.put(VmInfoDAO.commandLineKey, commandLine);
-        chunk.put(VmInfoDAO.vmNameKey, vmName);
-        chunk.put(VmInfoDAO.vmInfoKey, vmInfo);
-        chunk.put(VmInfoDAO.vmVersionKey, vmVersion);
-        chunk.put(VmInfoDAO.vmArgumentsKey, vmArgs);
-        chunk.put(VmInfoDAO.propertiesKey, props);
-        chunk.put(VmInfoDAO.environmentKey, env);
-        chunk.put(VmInfoDAO.librariesKey, libs);
 
         Storage storage = mock(Storage.class);
         Query query = new MockQuery();
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatConverterTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +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.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-
-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 VmMemoryStatConverterTest {
-
-    @Test
-    public void testVmMemoryStatToChunk() {
-        List<Generation> generations = new ArrayList<Generation>();
-
-        int i = 0;
-        for (String genName: new String[] { "new", "old", "perm" }) {
-            Generation gen = new Generation();
-            gen.name = genName;
-            gen.collector = gen.name;
-            generations.add(gen);
-            List<Space> spaces = new ArrayList<Space>();
-            gen.spaces = spaces;
-            String[] spaceNames = null;
-            if (genName.equals("new")) {
-                spaceNames = new String[] { "eden", "s0", "s1" };
-            } else if (genName.equals("old")) {
-                spaceNames = new String[] { "old" };
-            } else {
-                spaceNames = new String[] { "perm" };
-            }
-            for (String spaceName: spaceNames) {
-                Space space = new Space();
-                space.name = spaceName;
-                space.index = 0;
-                space.used = i++;
-                space.capacity = i++;
-                space.maxCapacity = i++;
-                spaces.add(space);
-            }
-        }
-
-        VmMemoryStat stat = new VmMemoryStat(1, 2, generations);
-
-        Chunk chunk = new VmMemoryStatConverter().toChunk(stat);
-
-        assertNotNull(chunk);
-        assertEquals((Long) 1l, chunk.get(new Key<Long>("timeStamp", false)));
-        assertEquals((Integer) 2, chunk.get(new Key<Integer>("vmId", true)));
-        assertEquals("new", chunk.get(new Key<String>("eden.gen", false)));
-        assertEquals("new", chunk.get(new Key<String>("eden.collector", false)));
-        assertEquals((Long) 0l, chunk.get(new Key<Long>("eden.used", false)));
-        assertEquals((Long) 1l, chunk.get(new Key<Long>("eden.capacity", false)));
-        assertEquals((Long) 2l, chunk.get(new Key<Long>("eden.max-capacity", false)));
-        assertEquals("new", chunk.get(new Key<String>("s0.gen", false)));
-        assertEquals("new", chunk.get(new Key<String>("s0.collector", false)));
-        assertEquals((Long) 3l, chunk.get(new Key<Long>("s0.used", false)));
-        assertEquals((Long) 4l, chunk.get(new Key<Long>("s0.capacity", false)));
-        assertEquals((Long) 5l, chunk.get(new Key<Long>("s0.max-capacity", false)));
-        assertEquals("new", chunk.get(new Key<String>("s1.gen", false)));
-        assertEquals("new", chunk.get(new Key<String>("s1.collector", false)));
-        assertEquals((Long) 6l, chunk.get(new Key<Long>("s1.used", false)));
-        assertEquals((Long) 7l, chunk.get(new Key<Long>("s1.capacity", false)));
-        assertEquals((Long) 8l, chunk.get(new Key<Long>("s1.max-capacity", false)));
-        assertEquals("old", chunk.get(new Key<String>("old.gen", false)));
-        assertEquals("old", chunk.get(new Key<String>("old.collector", false)));
-        assertEquals((Long) 9l, chunk.get(new Key<Long>("old.used", false)));
-        assertEquals((Long) 10l, chunk.get(new Key<Long>("old.capacity", false)));
-        assertEquals((Long) 11l, chunk.get(new Key<Long>("old.max-capacity", false)));
-        assertEquals("perm", chunk.get(new Key<String>("perm.gen", false)));
-        assertEquals("perm", chunk.get(new Key<String>("perm.collector", false)));
-        assertEquals((Long) 12l, chunk.get(new Key<Long>("perm.used", false)));
-        assertEquals((Long) 13l, chunk.get(new Key<Long>("perm.capacity", false)));
-        assertEquals((Long) 14l, chunk.get(new Key<Long>("perm.max-capacity", false)));
-
-    }
-
-    @Test
-    public void testChunkToVmMemoryStat() {
-        final long TIMESTAMP = 1234l;
-        final int VM_ID = 4567;
-
-        final long EDEN_USED = 1;
-        final long EDEN_CAPACITY = 2;
-        final long EDEN_MAX_CAPACITY = 3;
-        
-        final long S0_USED = 4;
-        final long S0_CAPACITY = 5;
-        final long S0_MAX_CAPACITY = 6;
-        
-        final long S1_USED = 7;
-        final long S1_CAPACITY = 8;
-        final long S1_MAX_CAPACITY = 9;
-        
-        final long OLD_USED = 10;
-        final long OLD_CAPACITY = 11;
-        final long OLD_MAX_CAPACITY = 12;
-        
-        final long PERM_USED = 13;
-        final long PERM_CAPACITY = 14;
-        final long PERM_MAX_CAPACITY = 15;
-        
-        Chunk chunk = new Chunk(VmMemoryStatDAO.vmMemoryStatsCategory, false);
-
-        chunk.put(Key.TIMESTAMP, TIMESTAMP);
-        chunk.put(Key.VM_ID, VM_ID);
-
-        chunk.put(VmMemoryStatDAO.edenGenKey, "new");
-        chunk.put(VmMemoryStatDAO.edenCollectorKey, "new-collector");
-        chunk.put(VmMemoryStatDAO.edenUsedKey, EDEN_USED);
-        chunk.put(VmMemoryStatDAO.edenCapacityKey, EDEN_CAPACITY);
-        chunk.put(VmMemoryStatDAO.edenMaxCapacityKey, EDEN_MAX_CAPACITY);
-
-        chunk.put(VmMemoryStatDAO.s0GenKey, "new");
-        chunk.put(VmMemoryStatDAO.s0CollectorKey, "new-collector");
-        chunk.put(VmMemoryStatDAO.s0UsedKey, S0_USED);
-        chunk.put(VmMemoryStatDAO.s0CapacityKey, S0_CAPACITY);
-        chunk.put(VmMemoryStatDAO.s0MaxCapacityKey, S0_MAX_CAPACITY);
-
-        chunk.put(VmMemoryStatDAO.s1GenKey, "new");
-        chunk.put(VmMemoryStatDAO.s1CollectorKey, "new-collector");
-        chunk.put(VmMemoryStatDAO.s1UsedKey, S1_USED);
-        chunk.put(VmMemoryStatDAO.s1CapacityKey, S1_CAPACITY);
-        chunk.put(VmMemoryStatDAO.s1MaxCapacityKey, S1_MAX_CAPACITY);
-
-        chunk.put(VmMemoryStatDAO.oldGenKey, "old");
-        chunk.put(VmMemoryStatDAO.oldCollectorKey, "old-collector");
-        chunk.put(VmMemoryStatDAO.oldUsedKey, OLD_USED);
-        chunk.put(VmMemoryStatDAO.oldCapacityKey, OLD_CAPACITY);
-        chunk.put(VmMemoryStatDAO.oldMaxCapacityKey, OLD_MAX_CAPACITY);
-
-        chunk.put(VmMemoryStatDAO.permGenKey, "perm");
-        chunk.put(VmMemoryStatDAO.permCollectorKey, "perm-collector");
-        chunk.put(VmMemoryStatDAO.permUsedKey, PERM_USED);
-        chunk.put(VmMemoryStatDAO.permCapacityKey, PERM_CAPACITY);
-        chunk.put(VmMemoryStatDAO.permMaxCapacityKey, PERM_MAX_CAPACITY);
-
-        VmMemoryStat stat = new VmMemoryStatConverter().fromChunk(chunk);
-
-        assertNotNull(stat);
-        assertEquals(TIMESTAMP, stat.getTimeStamp());
-        assertEquals(VM_ID, stat.getVmId());
-
-        assertEquals(3, stat.getGenerations().size());
-
-        Generation newGen = stat.getGeneration("new");
-        assertNotNull(newGen);
-        assertEquals(3, newGen.spaces.size());
-        assertEquals("new-collector", newGen.collector);
-        
-        Space eden = newGen.getSpace("eden");
-        assertNotNull(eden);
-        assertEquals(EDEN_USED, eden.used);
-        assertEquals(EDEN_CAPACITY, eden.capacity);
-        assertEquals(EDEN_MAX_CAPACITY, eden.maxCapacity);
-        
-        Space s0 = newGen.getSpace("s0");
-        assertNotNull(s0);
-        assertEquals(S0_USED, s0.used);
-        assertEquals(S0_CAPACITY, s0.capacity);
-        assertEquals(S0_MAX_CAPACITY, s0.maxCapacity);
-        
-        Space s1 = newGen.getSpace("s1");
-        assertNotNull(s1);
-        assertEquals(S1_USED, s1.used);
-        assertEquals(S1_CAPACITY, s1.capacity);
-        assertEquals(S1_MAX_CAPACITY, s1.maxCapacity);
-        
-        Generation oldGen = stat.getGeneration("old");
-        assertNotNull(oldGen);
-        assertEquals(1, oldGen.spaces.size());
-        assertEquals("old-collector", oldGen.collector);
-
-        Space old = oldGen.getSpace("old");
-        assertNotNull(old);
-        assertEquals(OLD_USED, old.used);
-        assertEquals(OLD_CAPACITY, old.capacity);
-        assertEquals(OLD_MAX_CAPACITY, old.maxCapacity);
-        
-        Generation permGen = stat.getGeneration("perm");
-        assertNotNull(permGen);
-        assertEquals(1, permGen.spaces.size());
-        assertEquals("perm-collector", permGen.collector);
-        
-        Space permSpace = permGen.getSpace("perm");
-        assertNotNull(permSpace);
-        assertEquals(PERM_USED, permSpace.used);
-        assertEquals(PERM_CAPACITY, permSpace.capacity);
-        assertEquals(PERM_MAX_CAPACITY, permSpace.maxCapacity);
-    }
-}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -113,32 +113,8 @@
         assertTrue(keys.contains(new Key<>("agentId", true)));
         assertTrue(keys.contains(new Key<Integer>("vmId", true)));
         assertTrue(keys.contains(new Key<Long>("timeStamp", false)));
-        assertTrue(keys.contains(new Key<String>("eden.gen", false)));
-        assertTrue(keys.contains(new Key<String>("eden.collector", false)));
-        assertTrue(keys.contains(new Key<Long>("eden.capacity", false)));
-        assertTrue(keys.contains(new Key<Long>("eden.max-capacity", false)));
-        assertTrue(keys.contains(new Key<Long>("eden.used", false)));
-        assertTrue(keys.contains(new Key<String>("s0.gen", false)));
-        assertTrue(keys.contains(new Key<String>("s0.collector", false)));
-        assertTrue(keys.contains(new Key<Long>("s0.capacity", false)));
-        assertTrue(keys.contains(new Key<Long>("s0.max-capacity", false)));
-        assertTrue(keys.contains(new Key<Long>("s0.used", false)));
-        assertTrue(keys.contains(new Key<String>("s1.gen", false)));
-        assertTrue(keys.contains(new Key<String>("s1.collector", false)));
-        assertTrue(keys.contains(new Key<Long>("s1.capacity", false)));
-        assertTrue(keys.contains(new Key<Long>("s1.max-capacity", false)));
-        assertTrue(keys.contains(new Key<Long>("s1.used", false)));
-        assertTrue(keys.contains(new Key<String>("old.gen", false)));
-        assertTrue(keys.contains(new Key<String>("old.collector", false)));
-        assertTrue(keys.contains(new Key<Long>("old.capacity", false)));
-        assertTrue(keys.contains(new Key<Long>("old.max-capacity", false)));
-        assertTrue(keys.contains(new Key<Long>("old.used", false)));
-        assertTrue(keys.contains(new Key<String>("perm.gen", false)));
-        assertTrue(keys.contains(new Key<String>("perm.collector", false)));
-        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(28, keys.size());
+        assertTrue(keys.contains(new Key<Generation[]>("generations", false)));
+        assertEquals(4, keys.size());
     }
 
     @Test
@@ -188,11 +164,10 @@
         int i = 0;
         for (String genName: new String[] { "new", "old", "perm" }) {
             Generation gen = new Generation();
-            gen.name = genName;
-            gen.collector = gen.name;
+            gen.setName(genName);
+            gen.setCollector(gen.getName());
             generations.add(gen);
             List<Space> spaces = new ArrayList<Space>();
-            gen.spaces = spaces;
             String[] spaceNames = null;
             if (genName.equals("new")) {
                 spaceNames = new String[] { "eden", "s0", "s1" };
@@ -203,15 +178,16 @@
             }
             for (String spaceName: spaceNames) {
                 Space space = new Space();
-                space.name = spaceName;
-                space.index = 0;
-                space.used = i++;
-                space.capacity = i++;
-                space.maxCapacity = i++;
+                space.setName(spaceName);
+                space.setIndex(0);
+                space.setUsed(i++);
+                space.setCapacity(i++);
+                space.setMaxCapacity(i++);
                 spaces.add(space);
             }
+            gen.setSpaces(spaces.toArray(new Space[spaces.size()]));
         }
-        VmMemoryStat stat = new VmMemoryStat(1, 2, generations);
+        VmMemoryStat stat = new VmMemoryStat(1, 2, generations.toArray(new Generation[generations.size()]));
 
         Storage storage = mock(Storage.class);
         VmMemoryStatDAO dao = new VmMemoryStatDAOImpl(storage);
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/ChunkAdapterTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,319 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-package com.redhat.thermostat.common.storage;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import org.junit.Test;
-
-public class ChunkAdapterTest {
-
-    @Entity
-    public static class SomeData {
-
-        private long[] arrayData;
-        private List<String> listData;
-        private long longData;
-        private String stringData;
-        private NestedData nestedData;
-
-        @Persist
-        public long[] getArrayData() {
-            return arrayData;
-        }
-
-        @Persist
-        public void setArrayData(long[] arrayData) {
-            this.arrayData = arrayData;
-        }
-
-        public void setListData(List<String> data) {
-            this.listData = data;
-        }
-
-        public List<String> getListData() {
-            return listData;
-        }
-
-        public long getLongData() {
-            return longData;
-        }
-
-        public void setLongData(long newValue) {
-            longData = newValue;
-        }
-
-        public void setStringData(String newStringData) {
-            stringData = newStringData;
-        }
-
-        public String getStringData() {
-            return stringData;
-        }
-
-        public NestedData getNestedData() {
-            return nestedData;
-        }
-
-        public void setNestedData(NestedData nestedData) {
-            this.nestedData = nestedData;
-        }
-    }
-
-    public static class NestedData {
-        private String data;
-        public void setData(String data) {
-            this.data = data;
-        }
-        public String getData() {
-            return data;
-        }
-    }
-
-    // the expected keys for each 'property' in the SomeData bean
-    private static final Key<long[]> arrayData = new Key<>("arrayData", false);
-    private static final Key<List<String>> listData = new Key<>("listData", false);
-    private static final Key<Long> longData = new Key<>("longData", false);
-    private static final Key<String> stringData = new Key<>("stringData", false);
-    private static final Key<String> nestedData = new Key<>("nestedData.data", false);
-
-    @Test
-    public void verifyAdapaterCanBeUsedInPlaceOfChunk() {
-        SomeData testObject = new SomeData();
-        ChunkAdapter adapter = new ChunkAdapter(testObject);
-
-        assertTrue(adapter instanceof Chunk);
-    }
-
-    @Test
-    public void verifyCategoryName() {
-        SomeData testObject = new SomeData();
-        ChunkAdapter adapter = new ChunkAdapter(testObject);
-        Category category = adapter.getCategory();
-        assertNotNull(category);
-        assertEquals("SomeData", category.getName());
-    }
-
-    @Test
-    public void verifyKeys() throws InterruptedException {
-        SomeData testObject = new SomeData();
-        Chunk chunk = new ChunkAdapter(testObject);
-        testObject.setArrayData(new long[] { 0xADD });
-
-        Set<Key<?>> recognizedKeys = chunk.getKeys();
-        // only one method is annotated with @Persist
-        assertEquals(1, recognizedKeys.size());
-        // verify that single key can be read
-        Key<?> onlyRecognizedKey = recognizedKeys.iterator().next();
-        assertArrayEquals(new long[] { 0xADD }, (long[]) chunk.get(onlyRecognizedKey));
-    }
-
-    @Test
-    public void verifyGetAndPutLongValue() {
-        SomeData testObject = new SomeData();
-        Chunk chunk = new ChunkAdapter(testObject);
-        testObject.setLongData(1l);
-
-        assertEquals((Long) 1l, chunk.get(longData));
-
-        chunk.put(longData, 2l);
-
-        assertEquals((Long) 2l, chunk.get(longData));
-        assertEquals(2, testObject.longData);
-    }
-
-    @Test
-    public void verifyGetAndPutStringValue() {
-        SomeData testObject = new SomeData();
-        Chunk chunk = new ChunkAdapter(testObject);
-        testObject.setStringData("stringData");
-
-        assertEquals("stringData", chunk.get(stringData));
-
-        chunk.put(stringData, "some-new-data");
-
-        assertEquals("some-new-data", chunk.get(stringData));
-        assertEquals("some-new-data", testObject.stringData);
-    }
-
-    @Test
-    public void verifyGetAndPutArrayValue() {
-        SomeData testObject = new SomeData();
-        Chunk chunk = new ChunkAdapter(testObject);
-        testObject.setArrayData(new long[] { 0xADD } );
-
-        assertArrayEquals(new long[] { 0xADD }, chunk.get(arrayData));
-
-        chunk.put(arrayData, new long[] { 0xC0FFEE });
-
-        assertArrayEquals(new long[] { 0xC0FFEE }, chunk.get(arrayData));
-        assertArrayEquals(new long[] { 0xC0FFEE }, testObject.arrayData);
-    }
-
-    @Test
-    public void verifyGetAndPutListValue() {
-        SomeData testObject = new SomeData();
-        Chunk chunk = new ChunkAdapter(testObject);
-        List<String> newList = new ArrayList<>();
-        testObject.setListData(newList);
-
-        assertEquals(newList, chunk.get(listData));
-
-        chunk.put(listData, Collections.<String>emptyList());
-
-        assertSame(Collections.<String>emptyList(), chunk.get(listData));
-        assertSame(Collections.<String>emptyList(), testObject.listData);
-    }
-
-    @Test (expected=IllegalArgumentException.class)
-    public void verifyNonEntityIsNotAcceptable() {
-        // missing @Entity annotation
-        class NonEntity {
-            public void setInteger(int integer) { /* no op */ }
-            public int getInteger() { return 42; }
-        }
-
-        NonEntity toAdapt = new NonEntity();
-        new ChunkAdapter(toAdapt);
-    }
-
-    @Test (expected=IllegalArgumentException.class)
-    public void verifyMissingPersistAnnotationOnOneMethodThrowsException() {
-        @Entity
-        class DataWithMissingAnnotationOnOneMethod {
-            @Persist public void setInteger(int integer) { /* no op */ }
-            public int getInteger() { return 42; }
-        }
-
-        DataWithMissingAnnotationOnOneMethod toAdapt = new DataWithMissingAnnotationOnOneMethod();
-        new ChunkAdapter(toAdapt);
-    }
-
-    @Test
-    public void verifyCustomEntityNameIsCategoryName() {
-        final String ENTITY_NAME = "custom-data-name";
-
-        @Entity (name=ENTITY_NAME)
-        class DataWithCustomName {
-            public void setData(String data) { /* no-op */ }
-            public String getData() { return "ignore this value" ; }
-        }
-
-        Chunk chunk = new ChunkAdapter(new DataWithCustomName());
-
-        assertEquals(ENTITY_NAME, chunk.getCategory().getName());
-    }
-
-    @Test
-    public void verifyCustomAttributeNameOnGetIsKeyName() {
-        final String ATTRIBUTE_NAME = "custom-attribute";
-        Key<?> expectedKey = new Key<>(ATTRIBUTE_NAME, false);
-
-        @Entity
-        class DataWithCustomAttributeNameOnGet {
-            @Persist (name=ATTRIBUTE_NAME)
-            public String getCustomAttribute() { return "ignore this value" ; }
-            @Persist
-            public void setCustomAttribute(String attribute) { /* no op */ }
-        }
-
-        Chunk chunk = new ChunkAdapter(new DataWithCustomAttributeNameOnGet());
-
-        assertTrue(chunk.getKeys().contains(expectedKey));
-
-        assertTrue(chunk.getCategory().getKeys().contains(expectedKey));
-        assertNotNull(chunk.getCategory().getKey(ATTRIBUTE_NAME));
-    }
-
-    @Test
-    public void verifyCustomAttributeNameOnSetIsKeyName() {
-        final String ATTRIBUTE_NAME = "custom-attribute";
-        Key<?> expectedKey = new Key<>(ATTRIBUTE_NAME, false);
-
-        @Entity
-        class DataWithCustomAttributeNameOnSet {
-            @Persist
-            public String getCustomAttribute() { return "ignore this value" ; }
-            @Persist (name=ATTRIBUTE_NAME)
-            public void setCustomAttribute(String attribute) { /* no op */ }
-        }
-
-        Chunk chunk = new ChunkAdapter(new DataWithCustomAttributeNameOnSet());
-
-        assertTrue(chunk.getKeys().contains(expectedKey));
-
-        assertTrue(chunk.getCategory().getKeys().contains(expectedKey));
-        assertNotNull(chunk.getCategory().getKey(ATTRIBUTE_NAME));
-    }
-
-    @Test (expected=IllegalArgumentException.class)
-    public void verifyExceptionOnCustomAttributeNameMismatch() {
-        @Entity
-        class DataWithCustomAttributeNameMismatch {
-            @Persist (name="one-name")
-            public String getCustomAttribute() { return "ignore this value" ; }
-            @Persist (name="different-name")
-            public void setCustomAttribute(String attribute) { /* no op */ }
-        }
-
-        new ChunkAdapter(new DataWithCustomAttributeNameMismatch());
-    }
-
-    @Test
-    public void verifyGetAndPutNestedValue() {
-        NestedData nested = new NestedData();
-        nested.setData("stringData");
-        SomeData testObject = new SomeData();
-        testObject.setNestedData(nested);
-        Chunk chunk = new ChunkAdapter(testObject);
-
-        assertEquals("stringData", chunk.get(nestedData));
-
-        chunk.put(nestedData, "some-new-data");
-
-        assertEquals("some-new-data", chunk.get(nestedData));
-        assertEquals("some-new-data", testObject.getNestedData().getData());
-    }
-}
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/ChunkConverterTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,370 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.storage;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Test;
-
-import com.mongodb.BasicDBObject;
-import com.mongodb.DBObject;
-
-public class ChunkConverterTest {
-
-    private static final Key<String> key1 = new Key<>("key1", false);
-    private static final Key<String> key2 = new Key<>("key2", false);
-    private static final Key<String> key3 = new Key<>("key3", false);
-    private static final Key<String> key4 = new Key<>("key4", false);
-    private static final Key<String> key5 = new Key<>("key5", false);
-
-    private static final Key<String> key1_key1 = new Key<>("key1.key1", false);
-    private static final Key<String> key1_key2 = new Key<>("key1.key2", false);
-    private static final Key<String> key1_key2_key1 = new Key<>("key1.key2.key1", false);
-    private static final Key<String> key1_key2_key2 = new Key<>("key1.key2.key2", false);
-    private static final Key<String> key1_key2_key3 = new Key<>("key1.key2.key3", false);
-    private static final Key<String> key2_key1 = new Key<>("key2.key1", false);
-    private static final Key<String> key2_key2 = new Key<>("key2.key2", false);
-    private static final Key<String> key2_key3 = new Key<>("key2.key3", false);
-
-    private static final Key<List<Integer>> listKey = new Key<>("list", false);
-
-    private static final String mongoId = "_id";
-    private static final Key<String> invalidMongoIdKey = new Key<>(mongoId, false);
-
-    private static final Category testCategory = new Category("ChunkConverterTest", key1, key2, key3, key4, key5,
-                                                             key1_key1, key1_key2, key2_key1, key2_key2, key2_key3,
-                                                             key1_key2_key1, key1_key2_key2, key1_key2_key3);
-    private static final Category smallerCategory = new Category("SmallerTest", key1, key2);
-
-    private static final Category listCategory = new Category("something-with-lists", listKey);
-
-    @Test
-    public void verifyBasicChunkToDBObject() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key1, "test1");
-
-        ChunkConverter converter = new ChunkConverter();
-        DBObject dbObject = converter.chunkToDBObject(chunk);
-
-        assertEquals(1, dbObject.keySet().size());
-        assertTrue(dbObject.keySet().contains("key1"));
-        assertEquals("test1", dbObject.get("key1"));
-    }
-
-    @Test
-    public void verifyChunkToDBObjectInOrder() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key5, "test1");
-        chunk.put(key4, "test2");
-        chunk.put(key3, "test3");
-        chunk.put(key2, "test4");
-        chunk.put(key1, "test5");
-
-        ChunkConverter converter = new ChunkConverter();
-        DBObject dbObject = converter.chunkToDBObject(chunk);
-
-        assertEquals(5, dbObject.keySet().size());
-        assertArrayEquals(new String[]{"key5", "key4", "key3", "key2", "key1"}, dbObject.keySet().toArray());
-    }
-
-    @Test
-    public void verifyChunkToDBObjectWithLists() {
-        Chunk chunk = new Chunk(listCategory, false);
-        chunk.put(listKey, Arrays.asList(1, 2, 3, 4));
-
-        ChunkConverter converter = new ChunkConverter();
-        DBObject dbObj = converter.chunkToDBObject(chunk);
-
-        assertEquals(Arrays.asList(1,2,3,4), dbObj.get("list"));
-
-    }
-
-    @Test
-    public void verifyBasicDBObjectToChunk() {
-        BasicDBObject dbObject = new BasicDBObject();
-        dbObject.put("key1", "test1");
-
-        ChunkConverter converter = new ChunkConverter();
-        Chunk chunk = converter.dbObjectToChunk(dbObject, testCategory);
-
-        assertSame(testCategory, chunk.getCategory());
-        assertEquals(1, chunk.getKeys().size());
-        assertTrue(chunk.getKeys().contains(key1));
-        assertEquals("test1", chunk.get(key1));
-
-    }
-
-    @Test
-    public void verifyDBObjectToChunkInOrder() {
-        BasicDBObject dbObject = new BasicDBObject();
-        dbObject.put("key5", "test1");
-        dbObject.put("key4", "test2");
-        dbObject.put("key3", "test3");
-        dbObject.put("key2", "test4");
-        dbObject.put("key1", "test5");
-
-        ChunkConverter converter = new ChunkConverter();
-        Chunk chunk = converter.dbObjectToChunk(dbObject, testCategory);
-
-        assertSame(testCategory, chunk.getCategory());
-        assertEquals(5, chunk.getKeys().size());
-        assertArrayEquals(new Key<?>[]{ key5, key4, key3, key2, key1 }, chunk.getKeys().toArray());
-        assertEquals("test5", chunk.get(key1));
-        assertEquals("test4", chunk.get(key2));
-        assertEquals("test3", chunk.get(key3));
-        assertEquals("test2", chunk.get(key4));
-        assertEquals("test1", chunk.get(key5));
-
-    }
-
-    @Test
-    public void verifyDBObjectToChunkWithLists() {
-        BasicDBObject dbObj = new BasicDBObject();
-        dbObj.put("list", Arrays.asList(1, 2, 3, 4));
-
-        ChunkConverter converter = new ChunkConverter();
-        Chunk chunk = converter.dbObjectToChunk(dbObj, listCategory);
-
-        List<Integer> data = chunk.get(listKey);
-        assertEquals(Arrays.asList(1, 2, 3, 4), data);
-    }
-
-    @Test
-    public void verifySimpleNestedChunkToObject() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key1_key1, "test1");
-
-        ChunkConverter converter = new ChunkConverter();
-        DBObject dbObject = converter.chunkToDBObject(chunk);
-
-        assertEquals(1, dbObject.keySet().size());
-        assertTrue(dbObject.keySet().contains("key1"));
-        DBObject nested = (DBObject) dbObject.get("key1");
-        assertEquals(1, nested.keySet().size());
-        assertTrue(nested.keySet().contains("key1"));
-        assertEquals("test1", nested.get("key1"));
-    }
-
-    @Test
-    public void verifyComplexNestedChunkToObject() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key1_key1, "test1");
-        chunk.put(key1_key2, "test2");
-        chunk.put(key2_key1, "test3");
-        chunk.put(key2_key2, "test4");
-        chunk.put(key2_key3, "test5");
-        chunk.put(key3, "test6");
-
-        ChunkConverter converter = new ChunkConverter();
-        DBObject dbObject = converter.chunkToDBObject(chunk);
-
-        assertEquals(3, dbObject.keySet().size());
-        assertTrue(dbObject.keySet().contains("key1"));
-        assertTrue(dbObject.keySet().contains("key2"));
-        assertTrue(dbObject.keySet().contains("key3"));
-        assertEquals("test6", dbObject.get("key3"));
-
-        DBObject nested1 = (DBObject) dbObject.get("key1");
-        assertEquals(2, nested1.keySet().size());
-        assertTrue(nested1.keySet().contains("key1"));
-        assertTrue(nested1.keySet().contains("key2"));
-        assertEquals("test1", nested1.get("key1"));
-        assertEquals("test2", nested1.get("key2"));
-
-        DBObject nested2 = (DBObject) dbObject.get("key2");
-        assertEquals(3, nested2.keySet().size());
-        assertTrue(nested2.keySet().contains("key1"));
-        assertTrue(nested2.keySet().contains("key2"));
-        assertTrue(nested2.keySet().contains("key3"));
-        assertEquals("test3", nested2.get("key1"));
-        assertEquals("test4", nested2.get("key2"));
-        assertEquals("test5", nested2.get("key3"));
-    }
-
-    @Test
-    public void verifyComplex3LevelChunkToObject() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key1_key1, "test1");
-        chunk.put(key1_key2_key1, "test3");
-        chunk.put(key1_key2_key2, "test4");
-        chunk.put(key1_key2_key3, "test5");
-        chunk.put(key3, "test6");
-
-        ChunkConverter converter = new ChunkConverter();
-        DBObject dbObject = converter.chunkToDBObject(chunk);
-
-        assertEquals(2, dbObject.keySet().size());
-        assertTrue(dbObject.keySet().contains("key1"));
-        assertTrue(dbObject.keySet().contains("key3"));
-        assertEquals("test6", dbObject.get("key3"));
-
-        DBObject nested1 = (DBObject) dbObject.get("key1");
-        assertEquals(2, nested1.keySet().size());
-        assertTrue(nested1.keySet().contains("key1"));
-        assertTrue(nested1.keySet().contains("key2"));
-        assertEquals("test1", nested1.get("key1"));
-
-        DBObject nested2 = (DBObject) nested1.get("key2");
-        assertEquals(3, nested2.keySet().size());
-        assertTrue(nested2.keySet().contains("key1"));
-        assertTrue(nested2.keySet().contains("key2"));
-        assertTrue(nested2.keySet().contains("key3"));
-        assertEquals("test3", nested2.get("key1"));
-        assertEquals("test4", nested2.get("key2"));
-        assertEquals("test5", nested2.get("key3"));
-    }
-
-    @Test
-    public void verifySimpleNestedObjectToChunk() {
-        BasicDBObject nested = new BasicDBObject();
-        nested.put("key1", "test1");
-        BasicDBObject dbObject = new BasicDBObject();
-        dbObject.put("key1", nested);
-
-        ChunkConverter converter = new ChunkConverter();
-        Chunk chunk = converter.dbObjectToChunk(dbObject, testCategory);
-
-        assertSame(testCategory, chunk.getCategory());
-        assertEquals(1, chunk.getKeys().size());
-        assertTrue(chunk.getKeys().contains(key1_key1));
-        assertEquals("test1", chunk.get(key1_key1));
-    }
-
-    @Test
-    public void verifyComplexNestedObjectToChunk() {
-        BasicDBObject nested1 = new BasicDBObject();
-        nested1.put("key1", "test1");
-        nested1.put("key2", "test2");
-
-        BasicDBObject nested2 = new BasicDBObject();
-        nested2.put("key1", "test3");
-        nested2.put("key2", "test4");
-        nested2.put("key3", "test5");
-
-        BasicDBObject dbObject = new BasicDBObject();
-        dbObject.put("key1", nested1);
-        dbObject.put("key2", nested2);
-        dbObject.put("key3", "test6");
-
-        ChunkConverter converter = new ChunkConverter();
-        Chunk chunk = converter.dbObjectToChunk(dbObject, testCategory);
-
-        assertSame(testCategory, chunk.getCategory());
-
-        assertEquals(6, chunk.getKeys().size());
-        assertTrue(chunk.getKeys().contains(key1_key1));
-        assertTrue(chunk.getKeys().contains(key1_key2));
-        assertTrue(chunk.getKeys().contains(key2_key1));
-        assertTrue(chunk.getKeys().contains(key2_key2));
-        assertTrue(chunk.getKeys().contains(key2_key3));
-        assertTrue(chunk.getKeys().contains(key3));
-        assertEquals("test1", chunk.get(key1_key1));
-        assertEquals("test2", chunk.get(key1_key2));
-        assertEquals("test3", chunk.get(key2_key1));
-        assertEquals("test4", chunk.get(key2_key2));
-        assertEquals("test5", chunk.get(key2_key3));
-        assertEquals("test6", chunk.get(key3));
-    }
-
-    @Test
-    public void verifyComplex3LevelObjectToChunk() {
-
-        BasicDBObject nested2 = new BasicDBObject();
-        nested2.put("key1", "test3");
-        nested2.put("key2", "test4");
-        nested2.put("key3", "test5");
-
-        BasicDBObject nested1 = new BasicDBObject();
-        nested1.put("key1", "test1");
-        nested1.put("key2", nested2);
-
-        BasicDBObject dbObject = new BasicDBObject();
-        dbObject.put("key1", nested1);
-        dbObject.put("key3", "test6");
-
-        ChunkConverter converter = new ChunkConverter();
-        Chunk chunk = converter.dbObjectToChunk(dbObject, testCategory);
-
-        assertSame(testCategory, chunk.getCategory());
-
-        assertEquals(5, chunk.getKeys().size());
-        assertTrue(chunk.getKeys().contains(key1_key1));
-        assertTrue(chunk.getKeys().contains(key1_key2_key1));
-        assertTrue(chunk.getKeys().contains(key1_key2_key2));
-        assertTrue(chunk.getKeys().contains(key1_key2_key3));
-        assertTrue(chunk.getKeys().contains(key3));
-
-        assertEquals("test1", chunk.get(key1_key1));
-        assertEquals("test3", chunk.get(key1_key2_key1));
-        assertEquals("test4", chunk.get(key1_key2_key2));
-        assertEquals("test5", chunk.get(key1_key2_key3));
-        assertEquals("test6", chunk.get(key3));
-    }
-
-    @Test
-    public void verifyDBObjectToChunkIgnoresMongoID() {
-        DBObject obj = new BasicDBObject(mongoId, "mongo_private_info");
-        ChunkConverter converter = new ChunkConverter();
-        Chunk chunk = converter.dbObjectToChunk(obj, new Category("invalidCategory", invalidMongoIdKey));
-
-        assertEquals(1, chunk.getKeys().size());
-        assertEquals("mongo_private_info", chunk.get(Key.ID));
-    }
-
-    @Test
-    public void verifyDBObjectToChunkAvoidsNonExistentKeys() {
-        DBObject obj = new BasicDBObject("key1", "data1");
-        obj.put("key2", "data2");
-        obj.put("key3", "data3"); // This one is not a part of smallerCategory
-        ChunkConverter converter = new ChunkConverter();
-        Chunk chunk = converter.dbObjectToChunk(obj, smallerCategory);
-
-        assertEquals(2, chunk.getKeys().size());
-        assertFalse(chunk.getKeys().contains(key3));
-        assertTrue(chunk.getKeys().contains(key1));
-        assertTrue(chunk.getKeys().contains(key2));
-        assertEquals("data1", chunk.get(key1));
-        assertEquals("data2", chunk.get(key2));
-    }
-}
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/ChunkTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,236 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.storage;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class ChunkTest {
-
-    private static final Key<String> key1 = new Key<>("key1", false);
-    private static final Key<String> key2 = new Key<>("key2", false);
-    private static final Key<String> key3 = new Key<>("key3", false);
-    private static final Key<String> key4 = new Key<>("key4", false);
-    private static final Key<String> key5 = new Key<>("key5", false);
-    private static final Key<Integer> key6 = new Key<>("key6", false);
-    private static final Key<Object> key7 = new Key<>("key7", false);
-
-    private static final String value1 = "test1";
-    private static final String value2 = "test2";
-    private static final String value3 = "test3";
-    private static final String value4 = "test4";
-    private static final String value5 = "test5";
-    private static final int value6 = 12345;
-    private static final Object value7 = "test7";
-
-    private static final Category testCategory = new Category("ChunkTest", key1, key2, key3, key4, key5);
-    private static final Category testCategory2 = new Category("ChunkTest2", key1, key2, key3, key4, key5);
-
-    @Test
-    public void verifyGetCategoryNotNull() {
-        Chunk chunk = new Chunk(testCategory, false);
-        Category cat = chunk.getCategory();
-        assertNotNull(cat);
-    }
-
-    @Test
-    public void verifyGetCategoryReturnsCorrectCategory() {
-        Chunk chunk = new Chunk(testCategory, false);
-        Category cat = chunk.getCategory();
-        assertEquals(cat, testCategory);
-    }
-
-    @Test
-    public void verifyGetReplaceReturnsCorrectValue() {
-        Chunk chunk = new Chunk(testCategory, false);
-        boolean replace = chunk.getReplace();
-        assertFalse(replace);
-        chunk = new Chunk(testCategory, true);
-        replace = chunk.getReplace();
-        assertTrue(replace);
-    }
-
-    @Test
-    public void verifyPutActuallyPuts() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key1, value1);
-        int pieces = chunk.getKeys().size();
-        assertEquals(pieces, 1);
-    }
-
-    @Test
-    public void verifyPutPutsCorrectly() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key1, value1);
-        String value = chunk.get(key1);
-        assertEquals(value, value1);
-    }
-
-    @Test
-    public void verifyPutAcceptsVariousTypes() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key1, value1);
-        chunk.put(key5, value5);
-        chunk.put(key6, value6);
-        chunk.put(key7, value7);
-        int pieces = chunk.getKeys().size();
-        assertEquals(pieces, 4);
-    }
-
-    @Test
-    public void verifyEntriesAreKeptInOrder() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key5, value5);
-        chunk.put(key4, value4);
-        chunk.put(key3, value3);
-        chunk.put(key2, value2);
-        chunk.put(key1, value1);
-
-        assertArrayEquals(new Key<?>[]{key5, key4, key3, key2, key1}, chunk.getKeys().toArray());
-    }
-
-    @Test
-    public void verifyGetNotNull() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key1, value1);
-        String value = chunk.get(key1);
-        assertNotNull(value);
-    }
-
-    @Test
-    public void verifyGetNullWhenExpected() {
-        Chunk chunk = new Chunk(testCategory, false);
-        chunk.put(key1, value1);
-        String value = chunk.get(key2);
-        assertNull(value);
-    }
-
-
-    @Test
-    public void testEqualsBasicEquals() {
-        Chunk chunk1 = new Chunk(testCategory, false);
-        Chunk chunk2 = new Chunk(testCategory, false);
-        assertTrue(chunk1.equals(chunk2));
-    }
-
-    @Test
-    public void testEqualsDifferentCategory() {
-        Chunk chunk1 = new Chunk(testCategory, false);
-        Chunk chunk2 = new Chunk(testCategory2, false);
-        assertFalse(chunk1.equals(chunk2));
-    }
-
-    @Test
-    public void testEqualsDifferentReplace() {
-        // TODO: Do we want to differentiate chunks by that flag? I think not. Maybe it doesn't even belong in chunk.
-        Chunk chunk1 = new Chunk(testCategory, false);
-        Chunk chunk2 = new Chunk(testCategory, true);
-        assertTrue(chunk1.equals(chunk2));
-    }
-
-    @Test
-    public void testEqualsDifferentType() {
-        Chunk chunk1 = new Chunk(testCategory, false);
-        assertFalse(chunk1.equals("fluff"));
-    }
-
-    @Test
-    public void testEqualsNull() {
-        Chunk chunk1 = new Chunk(testCategory, false);
-        assertFalse(chunk1.equals(null));
-    }
-
-    @Test
-    public void testEqualsDifferentNumberOfValues() {
-        Chunk chunk1 = new Chunk(testCategory, false);
-        chunk1.put(key1, "value1");
-        chunk1.put(key2, "value2");
-        Chunk chunk2 = new Chunk(testCategory, true);
-        chunk2.put(key1, "value1");
-        assertFalse(chunk1.equals(chunk2));
-    }
-
-    @Test
-    public void testEqualsDifferentKeys() {
-        Chunk chunk1 = new Chunk(testCategory, false);
-        chunk1.put(key1, "value1");
-        chunk1.put(key2, "value2");
-        Chunk chunk2 = new Chunk(testCategory, true);
-        chunk2.put(key1, "value1");
-        chunk2.put(key3, "value2");
-        assertFalse(chunk1.equals(chunk2));
-    }
-
-    @Test
-    public void testEqualsDifferentValues() {
-        Chunk chunk1 = new Chunk(testCategory, false);
-        chunk1.put(key1, "value1");
-        chunk1.put(key2, "value2.1");
-        Chunk chunk2 = new Chunk(testCategory, true);
-        chunk2.put(key1, "value1");
-        chunk2.put(key2, "value2.2");
-        assertFalse(chunk1.equals(chunk2));
-    }
-
-    @Test
-    public void testEqualsSameValues() {
-        Chunk chunk1 = new Chunk(testCategory, false);
-        chunk1.put(key1, "value1");
-        chunk1.put(key2, "value2");
-        Chunk chunk2 = new Chunk(testCategory, true);
-        chunk2.put(key1, "value1");
-        chunk2.put(key2, "value2");
-        assertTrue(chunk1.equals(chunk2));
-    }
-
-    @Test
-    public void testEqualsNullValues() {
-        Chunk chunk1 = new Chunk(testCategory, false);
-        chunk1.put(key1, "value1");
-        chunk1.put(key2, null);
-        Chunk chunk2 = new Chunk(testCategory, true);
-        chunk2.put(key1, "value1");
-        chunk2.put(key2, null);
-        assertTrue(chunk1.equals(chunk2));
-    }
-}
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoCursorTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoCursorTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -121,7 +121,7 @@
         when(dbCursor.next()).thenReturn(value1).thenReturn(value2).thenReturn(null);
         when(dbCursor.sort(any(DBObject.class))).thenReturn(dbCursor);
         when(dbCursor.limit(anyInt())).thenReturn(dbCursor);
-        cursor = new MongoCursor<TestClass>(dbCursor, testCategory, TestClass.class, null);
+        cursor = new MongoCursor<TestClass>(dbCursor, TestClass.class);
 
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoPojoConverterTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+
+package com.redhat.thermostat.common.storage;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+import com.redhat.thermostat.common.model.Pojo;
+
+public class MongoPojoConverterTest {
+
+    @Entity
+    public static class SimplePojo implements Pojo {
+        
+        private String test;
+        private String ignored;
+
+
+        @Persist
+        public String getTest() {
+            return test;
+        }
+
+        @Persist
+        public void setTest(String test) {
+            this.test = test;
+        }
+
+        public String getIgnored() {
+            return ignored;
+        }
+
+        public void setIgnored(String ignored) {
+            this.ignored = ignored;
+        }
+        
+    }
+
+    @Entity
+    public static class NestedPojo extends SimplePojo {
+
+        private SimplePojo nested;
+
+        @Persist
+        public SimplePojo getNested() {
+            return nested;
+        }
+
+        @Persist
+        public void setNested(SimplePojo nested) {
+            this.nested = nested;
+        }
+    }
+
+    @Entity
+    public static class IndexedPojo extends SimplePojo {
+
+        private SimplePojo[] indexed;
+
+        @Persist
+        public SimplePojo[] getIndexed() {
+            return indexed;
+        }
+
+        @Persist
+        public void setIndexed(SimplePojo[] indexed) {
+            this.indexed = indexed;
+        }
+    }
+
+    @Entity
+    public static class PrimitiveIndexedPojo extends SimplePojo {
+
+        private int[] indexed;
+
+        @Persist
+        public int[] getIndexed() {
+            return indexed;
+        }
+
+        @Persist
+        public void setIndexed(int[] indexed) {
+            this.indexed = indexed;
+        }
+    }
+
+    public static class BrokenPojo1 extends SimplePojo {
+        private int broken;
+
+        @Persist
+        public void setBroken(int broken) {
+            this.broken = broken;
+        }
+    }
+
+    public static class BrokenPojo2 extends SimplePojo {
+        private int broken;
+
+        @Persist
+        public void setBroken(int broken) {
+            this.broken = broken;
+        }
+
+        public int getBroken() {
+            return broken;
+        }
+    }
+
+    @Test
+    public void testConvertSimplePojoToMongo() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        SimplePojo obj = new SimplePojo();
+        obj.setTest("fluff");
+        DBObject dbObject = conv.convertPojoToMongo(obj);
+        assertEquals(1, dbObject.keySet().size());
+        assertEquals("fluff", dbObject.get("test"));
+    }
+
+    @Test
+    public void testConvertSimplePojoFromMongo() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        DBObject dbObj = new BasicDBObject();
+        dbObj.put("test", "fluff");
+        SimplePojo obj = conv.convertMongoToPojo(dbObj, SimplePojo.class);
+        assertEquals("fluff", obj.getTest());
+        assertNull(obj.getIgnored());
+    }
+
+    @Test(expected=StorageException.class)
+    public void testConvertSimplePojoFromMongoExtraProperty() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        DBObject dbObj = new BasicDBObject();
+        dbObj.put("test", "fluff");
+        dbObj.put("foo", "bar");
+        conv.convertMongoToPojo(dbObj, SimplePojo.class);
+    }
+
+    @Test(expected=StorageException.class)
+    public void testConvertSimplePojoFromMongoBrokenPojo1() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        DBObject dbObj = new BasicDBObject();
+        dbObj.put("broken", "foo");
+        conv.convertMongoToPojo(dbObj, BrokenPojo1.class);
+    }
+
+
+    @Test(expected=StorageException.class)
+    public void testConvertSimplePojoFromMongoBrokenPojo2() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        DBObject dbObj = new BasicDBObject();
+        dbObj.put("broken", "foo");
+        conv.convertMongoToPojo(dbObj, BrokenPojo2.class);
+    }
+
+    @Test
+    public void testConvertNestedPojoToMongo() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        NestedPojo obj = new NestedPojo();
+        obj.setTest("foo");
+        SimplePojo nested = new SimplePojo();
+        nested.setTest("bar");
+        obj.setNested(nested);
+        DBObject dbObject = conv.convertPojoToMongo(obj);
+        assertEquals(2, dbObject.keySet().size());
+        assertEquals("foo", dbObject.get("test"));
+        DBObject nestedDbObj = (DBObject) dbObject.get("nested");
+        assertEquals(1, nestedDbObj.keySet().size());
+        assertEquals("bar", nestedDbObj.get("test"));
+    }
+
+    @Test
+    public void testConvertNestedPojoFromMongo() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        DBObject nested = new BasicDBObject();
+        nested.put("test", "bar");
+        DBObject dbObj = new BasicDBObject();
+        dbObj.put("test", "foo");
+        dbObj.put("nested", nested);
+        NestedPojo obj = conv.convertMongoToPojo(dbObj, NestedPojo.class);
+        assertEquals("foo", obj.getTest());
+        assertNull(obj.getIgnored());
+        assertNotNull(obj.getNested());
+        assertEquals("bar", obj.getNested().getTest());
+        assertEquals(null, obj.getNested().getIgnored());
+    }
+
+    @Test
+    public void testConvertIndexedPojoToMongo() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        IndexedPojo obj = new IndexedPojo();
+        obj.setTest("test");
+        SimplePojo obj1 = new SimplePojo();
+        obj1.setTest("test1");
+        SimplePojo obj2 = new SimplePojo();
+        obj2.setTest("test2");
+        SimplePojo obj3 = new SimplePojo();
+        obj3.setTest("test3");
+        obj.setIndexed(new SimplePojo[] { obj1, obj2, obj3 });
+
+        DBObject dbObject = conv.convertPojoToMongo(obj);
+        assertEquals(2, dbObject.keySet().size());
+        assertEquals("test", dbObject.get("test"));
+        List<?> indexedDbObj = (List<?>) dbObject.get("indexed");
+        assertEquals(3, indexedDbObj.size());
+
+        DBObject dbObj1 = (DBObject) indexedDbObj.get(0);
+        assertEquals(1, dbObj1.keySet().size());
+        assertEquals("test1", dbObj1.get("test"));
+
+        DBObject dbObj2 = (DBObject) indexedDbObj.get(1);
+        assertEquals(1, dbObj2.keySet().size());
+        assertEquals("test2", dbObj2.get("test"));
+
+        DBObject dbObj3 = (DBObject) indexedDbObj.get(2);
+        assertEquals(1, dbObj3.keySet().size());
+        assertEquals("test3", dbObj3.get("test"));
+    }
+
+    @Test
+    public void testConvertPrimitiveIndexedPojoToMongo() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        PrimitiveIndexedPojo obj = new PrimitiveIndexedPojo();
+        obj.setTest("test");
+        obj.setIndexed(new int[] { 1, 2, 3 });
+
+        DBObject dbObject = conv.convertPojoToMongo(obj);
+        assertEquals(2, dbObject.keySet().size());
+        assertEquals("test", dbObject.get("test"));
+        List<?> indexedDbObj = (List<?>) dbObject.get("indexed");
+        assertEquals(3, indexedDbObj.size());
+
+        assertEquals(1, indexedDbObj.get(0));
+        assertEquals(2, indexedDbObj.get(1));
+        assertEquals(3, indexedDbObj.get(2));
+
+    }
+
+    @Test
+    public void testConvertIndexedPojoFromMongo() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        DBObject indexed = new BasicDBObject();
+        indexed.put("test", "test");
+        DBObject dbObj1 = new BasicDBObject();
+        dbObj1.put("test", "test1");
+        DBObject dbObj2 = new BasicDBObject();
+        dbObj2.put("test", "test2");
+        DBObject dbObj3 = new BasicDBObject();
+        dbObj3.put("test", "test3");
+        indexed.put("indexed", Arrays.asList(dbObj1, dbObj2, dbObj3));
+
+        IndexedPojo obj = conv.convertMongoToPojo(indexed, IndexedPojo.class);
+        assertEquals("test", obj.getTest());
+        assertNull(obj.getIgnored());
+        assertNotNull(obj.getIndexed());
+        SimplePojo[] indexedObj = obj.getIndexed();
+        assertEquals("test1", indexedObj[0].getTest());
+        assertNull(indexedObj[0].getIgnored());
+        assertEquals("test2", indexedObj[1].getTest());
+        assertNull(indexedObj[1].getIgnored());
+        assertEquals("test3", indexedObj[2].getTest());
+        assertNull(indexedObj[2].getIgnored());
+    }
+
+    @Test
+    public void testConvertPrimitiveIndexedPojoFromMongo() {
+        MongoPojoConverter conv = new MongoPojoConverter();
+        DBObject indexed = new BasicDBObject();
+        indexed.put("test", "test");
+        indexed.put("indexed", Arrays.asList(1, 2, 3));
+
+        PrimitiveIndexedPojo obj = conv.convertMongoToPojo(indexed, PrimitiveIndexedPojo.class);
+        assertEquals("test", obj.getTest());
+        assertNull(obj.getIgnored());
+        assertNotNull(obj.getIndexed());
+        int[] indexedObj = obj.getIndexed();
+        assertEquals(1, indexedObj[0]);
+        assertEquals(2, indexedObj[1]);
+        assertEquals(3, indexedObj[2]);
+    }
+}
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -36,7 +36,6 @@
 
 package com.redhat.thermostat.common.storage;
 
-import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -131,8 +130,8 @@
         }
     }
 
-    private static final Key<String> key1 = new Key<>("key1", false);
-    private static final Key<String> key2 = new Key<>("key2", false);
+    private static final Key<String> key1 = new Key<>("key1", true);
+    private static final Key<String> key2 = new Key<>("key2", true);
     private static final Key<String> key3 = new Key<>("key3", false);
     private static final Key<String> key4 = new Key<>("key4", false);
     private static final Key<String> key5 = new Key<>("key5", false);
@@ -140,7 +139,6 @@
     private static final Category emptyTestCategory = new Category("MongoEmptyCategory");
 
     private StartupConfiguration conf;
-    private Chunk multiKeyQuery;
     private Mongo m;
     private DB db;
     private DBCollection testCollection, emptyTestCollection, mockedCollection;
@@ -171,13 +169,6 @@
         value2.put("key3", "test3");
         value2.put("key4", "test4");
 
-        multiKeyQuery = new Chunk(testCategory, false);
-        multiKeyQuery.put(key5, "test1");
-        multiKeyQuery.put(key4, "test2");
-        multiKeyQuery.put(key3, "test3");
-        multiKeyQuery.put(key2, "test4");
-        multiKeyQuery.put(key1, "test5");
-
         cursor = mock(DBCursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(value1).thenReturn(value2).thenReturn(null);
@@ -200,7 +191,6 @@
         db = null;
         testCollection = null;
         emptyTestCollection = null;
-        multiKeyQuery = null;
         cursor = null;
     }
 
@@ -208,7 +198,7 @@
     public void verifyFindOnlyAcceptsMongoQuery() {
         MongoStorage storage = makeStorage();
         Query query = mock(Query.class);
-        storage.find(query);
+        storage.findPojo(query, TestClass.class);
     }
 
     @Test (expected=IllegalArgumentException.class)
@@ -232,7 +222,7 @@
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
         Query query = storage.createQuery().from(testCategory).where(key1, Criteria.EQUALS, "test1");
-        Chunk result = storage.find(query);
+        TestClass result = storage.findPojo(query, TestClass.class);
         assertNotNull(result);
     }
 
@@ -250,7 +240,7 @@
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
         Query query = storage.createQuery().from(testCategory);
-        storage.find(query);
+        storage.findPojo(query, TestClass.class);
         verify(testCollection).findOne(any(DBObject.class));
     }
 
@@ -284,7 +274,7 @@
 
         ArgumentCaptor<DBObject> findArg = ArgumentCaptor.forClass(DBObject.class);
 
-        storage.find(query);
+        storage.findPojo(query, TestClass.class);
 
         verify(testCollection).findOne(findArg.capture());
         assertSame(generatedQuery, findArg.getValue());
@@ -298,12 +288,11 @@
         // Because we mock the DBCollection, the contents of this query don't actually determine the result.
         MongoQuery query = new MongoQuery().from(testCategory);
 
-        Chunk result = storage.find(query);
+        TestClass result = storage.findPojo(query, TestClass.class);
 
         assertNotNull(result);
-        assertArrayEquals(new Key<?>[]{key1, key2}, result.getKeys().toArray());
-        assertEquals("test1", result.get(key1));
-        assertEquals("test2", result.get(key2));
+        assertEquals("test1", result.getKey1());
+        assertEquals("test2", result.getKey2());
     }
 
     @Test
@@ -415,9 +404,9 @@
     public void verifyPutChunkUsesCorrectChunkAgent() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
-        Chunk chunk1 = new Chunk(testCategory, false);
-        chunk1.put(Key.AGENT_ID, "123");
-        storage.putChunk(chunk1);
+        TestClass pojo = new TestClass();
+        pojo.setAgentId("123");
+        storage.putPojo(testCategory, false, pojo);
         ArgumentCaptor<DBObject> dbobj = ArgumentCaptor.forClass(DBObject.class);
         verify(testCollection).insert(dbobj.capture());
         DBObject val = dbobj.getValue();
@@ -429,9 +418,9 @@
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
         storage.setAgentId(new UUID(1, 2));
-        Chunk chunk1 = new Chunk(testCategory, false);
-        chunk1.put(Key.AGENT_ID, "123");
-        storage.putChunk(chunk1);
+        TestClass pojo = new TestClass();
+        pojo.setAgentId("123");
+        storage.putPojo(testCategory, false, pojo);
         ArgumentCaptor<DBObject> dbobj = ArgumentCaptor.forClass(DBObject.class);
         verify(testCollection).insert(dbobj.capture());
         DBObject val = dbobj.getValue();
@@ -493,4 +482,35 @@
         assertEquals("test3", values.get("key3"));
     }
 
+    @Test
+    public void verifyInsertReplaceCallsUpdate() {
+        TestClass pojo = new TestClass();
+        pojo.setAgentId("123");
+        pojo.setKey1("test1");
+        pojo.setKey2("test2");
+        pojo.setKey3("test3");
+        pojo.setKey4("test4");
+        pojo.setKey5("test5");
+
+        MongoStorage storage = makeStorage();
+        storage.putPojo(testCategory, true, pojo);
+
+        ArgumentCaptor<DBObject> queryCaptor = ArgumentCaptor.forClass(DBObject.class);
+        ArgumentCaptor<DBObject> valueCaptor = ArgumentCaptor.forClass(DBObject.class);
+        verify(testCollection).update(queryCaptor.capture(), valueCaptor.capture());
+
+        DBObject query = queryCaptor.getValue();
+        assertEquals(2, query.keySet().size());
+        assertEquals("test1", query.get("key1"));
+        assertEquals("test2", query.get("key2"));
+
+        DBObject value = valueCaptor.getValue();
+        assertEquals(6, value.keySet().size());
+        assertEquals("test1", value.get("key1"));
+        assertEquals("test2", value.get("key2"));
+        assertEquals("test3", value.get("key3"));
+        assertEquals("test4", value.get("key4"));
+        assertEquals("test5", value.get("key5"));
+        assertEquals("123", value.get("agentId"));
+    }
 }
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/CpuStatBuilder.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/CpuStatBuilder.java	Fri Oct 26 13:13:42 2012 +0200
@@ -38,8 +38,6 @@
 
 import java.io.BufferedReader;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -86,13 +84,13 @@
         long currentTime = clock.getMonotonicTimeNanos();
         long[] currentValues = getCurrentCpuTicks();
 
-        List<Double> cpuUsage = new ArrayList<Double>(currentValues.length);
+        double[] cpuUsage = new double[currentValues.length];
 
         double timeDelta = (currentTime - previousTime) * 1E-9;
         for (int i = 0; i < currentValues.length; i++) {
             long cpuTicksDelta = currentValues[i] - previousCpuTicks[i];
             // 100 as in 100 percent.
-            cpuUsage.add(cpuTicksDelta * (100.0 / timeDelta / ticksPerSecond));
+            cpuUsage[i] = cpuTicksDelta * (100.0 / timeDelta / ticksPerSecond);
         }
         previousTime = currentTime;
         previousCpuTicks = currentValues;
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Fri Oct 26 13:13:42 2012 +0200
@@ -152,7 +152,7 @@
                 ProcDataSource dataSource = new ProcDataSource();
                 Map<String, String> environment = new ProcessEnvironmentBuilder(dataSource).build(vmId);
                 // TODO actually figure out the loaded libraries.
-                List<String> loadedNativeLibraries = new ArrayList<String>();
+                String[] loadedNativeLibraries = new String[0];
                 info = new VmInfo(vmId, startTime, stopTime,
                         extractor.getJavaVersion(), extractor.getJavaHome(),
                         extractor.getMainClass(), extractor.getCommandLine(),
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java	Fri Oct 26 13:13:42 2012 +0200
@@ -111,29 +111,29 @@
         try {
             long timestamp = System.currentTimeMillis();
             JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-            long maxGenerations = extractor.getTotalGcGenerations();
-            List<Generation> generations = new ArrayList<Generation>();
-            VmMemoryStat stat = new VmMemoryStat(timestamp, vmId, generations);
-            for (long generation = 0; generation < maxGenerations; generation++) {
+            int maxGenerations = (int) extractor.getTotalGcGenerations();
+            Generation[] generations = new Generation[maxGenerations];
+            for (int generation = 0; generation < maxGenerations; generation++) {
                 Generation g = new Generation();
-                generations.add(g);
-                g.name = extractor.getGenerationName(generation);
-                g.capacity = extractor.getGenerationCapacity(generation);
-                g.maxCapacity = extractor.getGenerationMaxCapacity(generation);
-                g.collector = extractor.getGenerationCollector(generation);
-                long maxSpaces = extractor.getTotalSpaces(generation);
-                List<Space> spaces = new ArrayList<Space>();
-                g.spaces = spaces;
-                for (long space = 0; space < maxSpaces; space++) {
+                g.setName(extractor.getGenerationName(generation));
+                g.setCapacity(extractor.getGenerationCapacity(generation));
+                g.setMaxCapacity(extractor.getGenerationMaxCapacity(generation));
+                g.setCollector(extractor.getGenerationCollector(generation));
+                generations[generation] = g;
+                int maxSpaces = (int) extractor.getTotalSpaces(generation);
+                Space[] spaces = new Space[maxSpaces];
+                for (int space = 0; space < maxSpaces; space++) {
                     Space s = new Space();
-                    spaces.add(s);
-                    s.index = (int) space;
-                    s.name = extractor.getSpaceName(generation, space);
-                    s.capacity = extractor.getSpaceCapacity(generation, space);
-                    s.maxCapacity = extractor.getSpaceMaxCapacity(generation, space);
-                    s.used = extractor.getSpaceUsed(generation, space);
+                    s.setIndex((int) space);
+                    s.setName(extractor.getSpaceName(generation, space));
+                    s.setCapacity(extractor.getSpaceCapacity(generation, space));
+                    s.setMaxCapacity(extractor.getSpaceMaxCapacity(generation, space));
+                    s.setUsed(extractor.getSpaceUsed(generation, space));
+                    spaces[space] = s;
                 }
+                g.setSpaces(spaces);
             }
+            VmMemoryStat stat = new VmMemoryStat(timestamp, vmId, generations);
             memDAO.putVmMemoryStat(stat);
         } catch (MonitorException e) {
             logger.log(Level.WARNING, "error gathering memory info for vm " + vmId, e);
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Fri Oct 26 13:13:42 2012 +0200
@@ -60,7 +60,6 @@
 import com.redhat.thermostat.common.dao.MemoryStatDAO;
 import com.redhat.thermostat.common.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.common.dao.VmCpuStatDAO;
-import com.redhat.thermostat.common.model.BackendInformation;
 import com.redhat.thermostat.common.model.NetworkInterfaceInfo;
 import com.redhat.thermostat.common.model.VmCpuStat;
 import com.redhat.thermostat.common.utils.LoggingUtils;
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/CpuStatBuilderTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/CpuStatBuilderTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -106,7 +106,7 @@
         CpuStat stat = builder.build();
 
         verify(dataSource, times(2)).getStatReader();
-        assertArrayEquals(new double[] {100, 100}, ArrayUtils.toPrimitiveDoubleArray(stat.getPerProcessorUsage()), 0.01);
+        assertArrayEquals(new double[] {100, 100}, stat.getPerProcessorUsage(), 0.01);
     }
 
 }
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/VMCapsSummaryPanel.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/VMCapsSummaryPanel.java	Fri Oct 26 13:13:42 2012 +0200
@@ -37,7 +37,6 @@
 
 import java.awt.Dimension;
 import java.awt.GridLayout;
-import java.util.List;
 
 import javax.swing.DefaultListModel;
 import javax.swing.JList;
@@ -76,7 +75,7 @@
         panel.add(list);
     }
     
-    void addInfo(List<String> infos) {
+    void addInfo(String[] infos) {
         listModel.removeAllElements();
         for (String info : infos) {
             listModel.addElement(info);
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Fri Oct 26 13:13:42 2012 +0200
@@ -46,6 +46,7 @@
 import com.redhat.thermostat.common.storage.Query;
 import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Storage;
+import com.redhat.thermostat.common.storage.Update;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadInfoData;
 import com.redhat.thermostat.thread.model.ThreadSummary;
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java	Fri Oct 26 13:13:42 2012 +0200
@@ -36,11 +36,6 @@
 
 package com.redhat.thermostat.thread.model;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
 import com.redhat.thermostat.common.model.BasePojo;
 import com.redhat.thermostat.common.storage.Entity;
 import com.redhat.thermostat.common.storage.Persist;
@@ -49,7 +44,7 @@
 @Entity
 public class VMThreadCapabilities extends BasePojo {
     
-    private Set<String> features = new HashSet<>();
+    private String[] features;
 
     private int vmId;
 
@@ -64,11 +59,11 @@
     }
 
     public boolean supportCPUTime() {
-        return features.contains(ThreadDao.CPU_TIME);
+        return hasFeature(ThreadDao.CPU_TIME);
     }
 
     public boolean supportContentionMonitor() {
-        return features.contains(ThreadDao.CONTENTION_MONITOR);
+        return hasFeature(ThreadDao.CONTENTION_MONITOR);
     }
 
     public String toString() {
@@ -77,20 +72,26 @@
     }
 
     public boolean supportThreadAllocatedMemory() {
-        return features.contains(ThreadDao.THREAD_ALLOCATED_MEMORY);
+        return hasFeature(ThreadDao.THREAD_ALLOCATED_MEMORY);
     }
 
-    @Persist
-    public List<String> getSupportedFeaturesList() {
-        return new ArrayList<>(features);
+    private boolean hasFeature(String feature) {
+        for (String f : features) {
+            if (f.equals(feature)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     @Persist
-    public void setSupportedFeaturesList(List<String> featuresList) {
-        features = new HashSet<>(featuresList);
+    public String[] getSupportedFeaturesList() {
+        return features;
     }
 
-    public void addFeature(String feature) {
-        features.add(feature);
+    @Persist
+    public void setSupportedFeaturesList(String[] features) {
+        this.features = features;
     }
+
 }
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -42,13 +42,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.util.Arrays;
-
 import org.junit.Test;
 
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.storage.Chunk;
 import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Storage;
@@ -82,12 +79,9 @@
         when(agent.getAgentId()).thenReturn("0xcafe");
         
         when(ref.getAgent()).thenReturn(agent);
-        
-        Chunk answer = mock(Chunk.class);
-        when(answer.get(ThreadDao.SUPPORTED_FEATURES_LIST_KEY)).thenReturn(Arrays.asList(ThreadDao.CPU_TIME, ThreadDao.THREAD_ALLOCATED_MEMORY));
-        
+
         VMThreadCapabilities expected = new VMThreadCapabilities();
-        expected.setSupportedFeaturesList(Arrays.asList(ThreadDao.CPU_TIME, ThreadDao.THREAD_ALLOCATED_MEMORY));
+        expected.setSupportedFeaturesList(new String[] { ThreadDao.CPU_TIME, ThreadDao.THREAD_ALLOCATED_MEMORY });
         when(storage.findPojo(query, VMThreadCapabilities.class)).thenReturn(expected);
         
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
@@ -105,10 +99,6 @@
     public void testSaveVMCapabilities() {
         Storage storage = mock(Storage.class);
         
-        Chunk answer = mock(Chunk.class);
-        when(answer.get(ThreadDao.CONTENTION_MONITOR_KEY)).thenReturn(false);
-        when(answer.get(ThreadDao.CPU_TIME_KEY)).thenReturn(true);
-        
         VMThreadCapabilities caps = mock(VMThreadCapabilities.class);
         when(caps.supportContentionMonitor()).thenReturn(true);
         when(caps.supportCPUTime()).thenReturn(true);
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java	Fri Oct 26 13:13:42 2012 +0200
@@ -40,6 +40,8 @@
 import java.lang.management.ManagementFactory;
 import java.lang.management.ThreadInfo;
 import java.lang.management.ThreadMXBean;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
@@ -247,20 +249,22 @@
             ThreadMXBean bean = getDataCollectorBean(connection);
             VMThreadCapabilities caps = new VMThreadCapabilities();
 
+            List<String> features = new ArrayList<>(3);
             if (bean.isThreadCpuTimeSupported())
-                caps.addFeature(ThreadDao.CPU_TIME);
+                features.add(ThreadDao.CPU_TIME);
             if (bean.isThreadContentionMonitoringSupported())
-                caps.addFeature(ThreadDao.CONTENTION_MONITOR);
+                features.add(ThreadDao.CONTENTION_MONITOR);
 
             if (bean instanceof com.sun.management.ThreadMXBean) {
                 com.sun.management.ThreadMXBean sunBean = (com.sun.management.ThreadMXBean) bean;
                 
                 try {
                     if (sunBean.isThreadAllocatedMemorySupported()) {
-                        caps.addFeature(ThreadDao.THREAD_ALLOCATED_MEMORY);
+                        features.add(ThreadDao.THREAD_ALLOCATED_MEMORY);
                     }
                 } catch (Exception ignore) {};
             }
+            caps.setSupportedFeaturesList(features.toArray(new String[features.size()]));
             caps.setVmId(Integer.parseInt(vmId));
             threadDao.saveCapabilities(caps);
 
--- a/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -385,10 +385,9 @@
         verify(dao, times(1)).saveCapabilities(any(VMThreadCapabilities.class));
         assertEquals(42, capsCapture.getValue().getVmId());
 
-        List<String> features = capsCapture.getValue().getSupportedFeaturesList();
-        assertEquals(2, features.size());
-        assertTrue(features.contains(ThreadDao.CPU_TIME));
-        assertTrue(features.contains(ThreadDao.CONTENTION_MONITOR));
-        assertFalse(features.contains(ThreadDao.THREAD_ALLOCATED_MEMORY));
+        String[] features = capsCapture.getValue().getSupportedFeaturesList();
+        assertEquals(2, features.length);
+        assertEquals(ThreadDao.CPU_TIME, features[0]);
+        assertEquals(ThreadDao.CONTENTION_MONITOR, features[1]);
     }    
 }
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatPrinter.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatPrinter.java	Fri Oct 26 13:13:42 2012 +0200
@@ -41,7 +41,6 @@
 import java.text.DecimalFormat;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
@@ -161,8 +160,8 @@
         }
         int i = 0;
         for (VmMemoryStat.Generation gen : vmMemoryStat.getGenerations()) {
-            for (VmMemoryStat.Space space : gen.spaces) {
-                String[] displayableSize = DisplayableValues.bytes(space.used);
+            for (VmMemoryStat.Space space : gen.getSpaces()) {
+                String[] displayableSize = DisplayableValues.bytes(space.getUsed());
                 memoryUsage[i] = translator.localize(LocaleResources.VALUE_AND_UNIT, displayableSize[0], displayableSize[1]);
                 i++;
             }
@@ -178,8 +177,8 @@
         VmMemoryStat stat = memStats.get(0);
         int i = 0;
         for (VmMemoryStat.Generation gen : stat.getGenerations()) {
-            for (VmMemoryStat.Space space : gen.spaces) {
-                spacesNames[i] = translator.localize(LocaleResources.COLUMN_HEADER_MEMORY_PATTERN, space.name);
+            for (VmMemoryStat.Space space : gen.getSpaces()) {
+                spacesNames[i] = translator.localize(LocaleResources.COLUMN_HEADER_MEMORY_PATTERN, space.getName());
                 i++;
             }
         }
@@ -193,7 +192,7 @@
         VmMemoryStat stat = memStats.get(0);
         int numSpaces = 0;
         for (VmMemoryStat.Generation gen : stat.getGenerations()) {
-            numSpaces += gen.spaces.size();
+            numSpaces += gen.getSpaces().length;
         }
         return numSpaces;
     }
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/VMInfoCommandTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/tools/src/test/java/com/redhat/thermostat/tools/cli/VMInfoCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -43,7 +43,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.HashMap;
@@ -115,7 +114,7 @@
         start.set(2012, 5, 7, 15, 32, 0);
         Calendar end = Calendar.getInstance();
         end.set(2013, 10, 1, 1, 22, 0);
-        VmInfo vmInfo = new VmInfo(234, start.getTimeInMillis(), end.getTimeInMillis(), "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new ArrayList<String>());
+        VmInfo vmInfo = new VmInfo(234, start.getTimeInMillis(), end.getTimeInMillis(), "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0]);
         when(vmsDAO.getVmInfo(vm)).thenReturn(vmInfo);
         when(vmsDAO.getVmInfo(new VmRef(host, 9876, "dummy"))).thenThrow(new DAOException("Unknown VM ID: 9876"));
         when(vmsDAO.getVMs(host)).thenReturn(Arrays.asList(vm));
@@ -191,7 +190,7 @@
     public void testStopTime() throws CommandException {
         Calendar start = Calendar.getInstance();
         start.set(2012, 5, 7, 15, 32, 0);
-        VmInfo vmInfo = new VmInfo(234, start.getTimeInMillis(), Long.MIN_VALUE, "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new ArrayList<String>());
+        VmInfo vmInfo = new VmInfo(234, start.getTimeInMillis(), Long.MIN_VALUE, "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0]);
         when(vmsDAO.getVmInfo(vm)).thenReturn(vmInfo);
 
         SimpleArguments args = new SimpleArguments();
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/VmStatCommandTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/tools/src/test/java/com/redhat/thermostat/tools/cli/VmStatCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -143,57 +143,57 @@
 
         VmMemoryStat.Space space1_1_1 = newSpace("space1", 123456, 12345, 1, 0);
         VmMemoryStat.Space space1_1_2 = newSpace("space2", 123456, 12345, 1, 0);
-        List<VmMemoryStat.Space> spaces1_1 = Arrays.asList(space1_1_1, space1_1_2);
+        VmMemoryStat.Space[] spaces1_1 = new VmMemoryStat.Space[] { space1_1_1, space1_1_2 };
         VmMemoryStat.Generation gen1_1 = newGeneration("gen1", "col1", 123456, 12345, spaces1_1);
 
         VmMemoryStat.Space space1_2_1 = newSpace("space3", 123456, 12345, 1, 0);
         VmMemoryStat.Space space1_2_2 = newSpace("space4", 123456, 12345, 1, 0);
-        List<VmMemoryStat.Space> spaces1_2 = Arrays.asList(space1_2_1, space1_2_2);
+        VmMemoryStat.Space[] spaces1_2 = new VmMemoryStat.Space[] { space1_2_1, space1_2_2 };
         VmMemoryStat.Generation gen1_2 = newGeneration("gen2", "col1", 123456, 12345, spaces1_2);
 
-        List<VmMemoryStat.Generation> gens1 = Arrays.asList(gen1_1, gen1_2);
+        VmMemoryStat.Generation[] gens1 = new VmMemoryStat.Generation[] { gen1_1, gen1_2 };
 
         VmMemoryStat memStat1 = new VmMemoryStat(1, vmId, gens1);
 
         VmMemoryStat.Space space2_1_1 = newSpace("space1", 123456, 12345, 2, 0);
         VmMemoryStat.Space space2_1_2 = newSpace("space2", 123456, 12345, 2, 0);
-        List<VmMemoryStat.Space> spaces2_1 = Arrays.asList(space2_1_1, space2_1_2);
+        VmMemoryStat.Space[] spaces2_1 = new VmMemoryStat.Space[] { space2_1_1, space2_1_2 };
         VmMemoryStat.Generation gen2_1 = newGeneration("gen1", "col1", 123456, 12345, spaces2_1);
 
         VmMemoryStat.Space space2_2_1 = newSpace("space3", 123456, 12345, 3, 0);
         VmMemoryStat.Space space2_2_2 = newSpace("space4", 123456, 12345, 4, 0);
-        List<VmMemoryStat.Space> spaces2_2 = Arrays.asList(space2_2_1, space2_2_2);
+        VmMemoryStat.Space[] spaces2_2 = new VmMemoryStat.Space[] { space2_2_1, space2_2_2 };
         VmMemoryStat.Generation gen2_2 = newGeneration("gen2", "col1", 123456, 12345, spaces2_2);
 
-        List<VmMemoryStat.Generation> gens2 = Arrays.asList(gen2_1, gen2_2);
+        VmMemoryStat.Generation[] gens2 = new VmMemoryStat.Generation[] { gen2_1, gen2_2 };
 
         VmMemoryStat memStat2 = new VmMemoryStat(2, vmId, gens2);
 
         VmMemoryStat.Space space3_1_1 = newSpace("space1", 123456, 12345, 4, 0);
         VmMemoryStat.Space space3_1_2 = newSpace("space2", 123456, 12345, 5, 0);
-        List<VmMemoryStat.Space> spaces3_1 = Arrays.asList(space3_1_1, space3_1_2);
+        VmMemoryStat.Space[] spaces3_1 = new VmMemoryStat.Space[] { space3_1_1, space3_1_2 };
         VmMemoryStat.Generation gen3_1 = newGeneration("gen1", "col1", 123456, 12345, spaces3_1);
 
         VmMemoryStat.Space space3_2_1 = newSpace("space3", 123456, 12345, 6, 0);
         VmMemoryStat.Space space3_2_2 = newSpace("space4", 123456, 12345, 7, 0);
-        List<VmMemoryStat.Space> spaces3_2 = Arrays.asList(space3_2_1, space3_2_2);
+        VmMemoryStat.Space[] spaces3_2 = new VmMemoryStat.Space[] { space3_2_1, space3_2_2 };
         VmMemoryStat.Generation gen3_2 = newGeneration("gen2", "col1", 123456, 12345, spaces3_2);
 
-        List<VmMemoryStat.Generation> gens3 = Arrays.asList(gen3_1, gen3_2);
+        VmMemoryStat.Generation[] gens3 = new VmMemoryStat.Generation[] { gen3_1, gen3_2 };
 
         VmMemoryStat memStat3 = new VmMemoryStat(3, vmId, gens3);
 
         VmMemoryStat.Space space4_1_1 = newSpace("space1", 123456, 12345, 8, 0);
         VmMemoryStat.Space space4_1_2 = newSpace("space2", 123456, 12345, 9, 0);
-        List<VmMemoryStat.Space> spaces4_1 = Arrays.asList(space4_1_1, space4_1_2);
+        VmMemoryStat.Space[] spaces4_1 = new VmMemoryStat.Space[] { space4_1_1, space4_1_2 };
         VmMemoryStat.Generation gen4_1 = newGeneration("gen4", "col1", 123456, 12345, spaces4_1);
 
         VmMemoryStat.Space space4_2_1 = newSpace("space3", 123456, 12345, 10, 0);
         VmMemoryStat.Space space4_2_2 = newSpace("space4", 123456, 12345, 11, 0);
-        List<VmMemoryStat.Space> spaces4_2 = Arrays.asList(space4_2_1, space4_2_2);
+        VmMemoryStat.Space[] spaces4_2 = new VmMemoryStat.Space[] { space4_2_1, space4_2_2 };
         VmMemoryStat.Generation gen4_2 = newGeneration("gen4", "col1", 123456, 12345, spaces4_2);
 
-        List<VmMemoryStat.Generation> gens4 = Arrays.asList(gen4_1, gen4_2);
+        VmMemoryStat.Generation[] gens4 = new VmMemoryStat.Generation[] { gen4_1, gen4_2 };
 
         VmMemoryStat memStat4 = new VmMemoryStat(4, vmId, gens4);
 
@@ -207,20 +207,20 @@
 
     private Space newSpace(String name, long maxCapacity, long capacity, long used, int index) {
         VmMemoryStat.Space space = new VmMemoryStat.Space();
-        space.name = name;
-        space.maxCapacity = maxCapacity;
-        space.capacity = capacity;
-        space.used = used;
-        space.index = index;
+        space.setName(name);
+        space.setMaxCapacity(maxCapacity);
+        space.setCapacity(capacity);
+        space.setUsed(used);
+        space.setIndex(index);
         return space;
     }
 
-    private Generation newGeneration(String name, String collector, long maxCapacity, long capacity, List<Space> spaces) {
+    private Generation newGeneration(String name, String collector, long maxCapacity, long capacity, Space[] spaces) {
         VmMemoryStat.Generation gen = new VmMemoryStat.Generation();
-        gen.name = name;
-        gen.collector = collector;
-        gen.maxCapacity = capacity;
-        gen.spaces = spaces;
+        gen.setName(name);
+        gen.setCollector(collector);
+        gen.setMaxCapacity(capacity);
+        gen.setSpaces(spaces);
         return gen;
     }
 
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/RESTStorage.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/RESTStorage.java	Fri Oct 26 13:13:42 2012 +0200
@@ -65,6 +65,8 @@
 import org.apache.http.message.BasicNameValuePair;
 
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.redhat.thermostat.common.model.AgentIdPojo;
 import com.redhat.thermostat.common.model.Pojo;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Connection;
@@ -74,6 +76,7 @@
 import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.storage.Update;
 import com.redhat.thermostat.web.common.RESTQuery;
+import com.redhat.thermostat.web.common.ThermostatGSONConverter;
 import com.redhat.thermostat.web.common.WebInsert;
 import com.redhat.thermostat.web.common.WebRemove;
 import com.redhat.thermostat.web.common.WebUpdate;
@@ -105,10 +108,12 @@
     private UUID agentId;
 
     private Map<Category, Integer> categoryIds;
+    private Gson gson;
 
     public RESTStorage() {
         endpoint = "http://localhost:8082";
         categoryIds = new HashMap<>();
+        gson = new GsonBuilder().registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()).create();
     }
 
     @Override
@@ -122,7 +127,6 @@
             conn.setDoInput(true);
             conn.setRequestMethod("POST");
             OutputStream out = conn.getOutputStream();
-            Gson gson = new Gson();
             OutputStreamWriter writer = new OutputStreamWriter(out);
             writer.write("name=");
             writer.write(URLEncoder.encode(category.getName(), enc));
@@ -164,7 +168,6 @@
             conn.setDoOutput(true);
             conn.setRequestMethod("POST");
             OutputStream out = conn.getOutputStream();
-            Gson gson = new Gson();
             OutputStreamWriter writer = new OutputStreamWriter(out);
             ((RESTQuery) query).setResultClassName(resultClass.getName());
             gson.toJson(query, writer);
@@ -188,7 +191,6 @@
             conn.setDoOutput(true);
             conn.setRequestMethod("POST");
             OutputStream out = conn.getOutputStream();
-            Gson gson = new Gson();
             OutputStreamWriter writer = new OutputStreamWriter(out);
             gson.toJson(query, writer);
             writer.flush();
@@ -220,7 +222,6 @@
             conn.setDoOutput(true);
             conn.setRequestMethod("POST");
             OutputStream out = conn.getOutputStream();
-            Gson gson = new Gson();
             OutputStreamWriter writer = new OutputStreamWriter(out);
             writer.write("category=");
             gson.toJson(categoryIds.get(category), writer);
@@ -267,7 +268,7 @@
     }
 
     @Override
-    public void putPojo(Category category, boolean replace, Pojo pojo) {
+    public void putPojo(Category category, boolean replace, AgentIdPojo pojo) {
         // TODO: This logic should probably be moved elsewhere. I.e. out of the Storage API.
         if (pojo.getAgentId() == null) {
             pojo.setAgentId(getAgentId());
@@ -281,7 +282,6 @@
             conn.setDoInput(true);
             conn.setRequestMethod("POST");
             OutputStream out = conn.getOutputStream();
-            Gson gson = new Gson();
             OutputStreamWriter writer = new OutputStreamWriter(out);
             writer.write("insert=");
             writer.write(URLEncoder.encode(gson.toJson(insert), "UTF-8"));
@@ -309,7 +309,6 @@
             conn.setDoOutput(true);
             conn.setRequestMethod("POST");
             OutputStream out = conn.getOutputStream();
-            Gson gson = new Gson();
             OutputStreamWriter writer = new OutputStreamWriter(out);
             writer.write("remove=");
             writer.write(URLEncoder.encode(gson.toJson(remove), "UTF-8"));
@@ -354,7 +353,6 @@
             conn.setDoInput(true);
             conn.setRequestMethod("POST");
             OutputStream out = conn.getOutputStream();
-            Gson gson = new Gson();
             OutputStreamWriter writer = new OutputStreamWriter(out);
             writer.write("update=");
             writer.write(URLEncoder.encode(gson.toJson(webUp), "UTF-8"));
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/WebCursor.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/WebCursor.java	Fri Oct 26 13:13:42 2012 +0200
@@ -37,10 +37,8 @@
 
 package com.redhat.thermostat.web.client;
 
-import com.redhat.thermostat.common.NotImplementedException;
 import com.redhat.thermostat.common.model.Pojo;
 import com.redhat.thermostat.common.storage.Cursor;
-import com.redhat.thermostat.common.storage.Key;
 
 class WebCursor<T extends Pojo> implements Cursor<T> {
 
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/TestObj.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/TestObj.java	Fri Oct 26 13:13:42 2012 +0200
@@ -38,16 +38,21 @@
 package com.redhat.thermostat.web.client;
 
 import com.redhat.thermostat.common.model.BasePojo;
+import com.redhat.thermostat.common.storage.Entity;
+import com.redhat.thermostat.common.storage.Persist;
 
+@Entity
 public class TestObj extends BasePojo {
 
     
     private String property1;
 
+    @Persist
     public void setProperty1(String property1) {
         this.property1 = property1;
     }
 
+    @Persist
     public String getProperty1() {
         return property1;
     }
--- a/web/common/pom.xml	Fri Oct 26 13:12:46 2012 +0200
+++ b/web/common/pom.xml	Fri Oct 26 13:13:42 2012 +0200
@@ -59,6 +59,12 @@
     </dependency>
 
     <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>2.2.2</version>
+    </dependency>
+
+    <dependency>
       <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-common-core</artifactId>
       <version>${project.version}</version>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/ThermostatGSONConverter.java	Fri Oct 26 13:13:42 2012 +0200
@@ -0,0 +1,110 @@
+/*
+ * 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.web.common;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.redhat.thermostat.common.model.Pojo;
+import com.redhat.thermostat.common.storage.Entity;
+import com.redhat.thermostat.common.storage.Persist;
+
+public class ThermostatGSONConverter implements JsonSerializer<Pojo>, JsonDeserializer<Pojo> {
+
+    @Override
+    public Pojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+        @SuppressWarnings("unchecked")
+        Class<? extends Pojo> targetType = (Class<Pojo>) typeOfT;
+        try {
+            Pojo pojo = targetType.newInstance();
+            PropertyDescriptor[] descs = PropertyUtils.getPropertyDescriptors(pojo);
+            for (PropertyDescriptor desc : descs) {
+                Method writeMethod = desc.getWriteMethod();
+                if (writeMethod != null && writeMethod.isAnnotationPresent(Persist.class)) {
+                    String name = desc.getName();
+                    JsonElement child = json.getAsJsonObject().get(name);
+                    Object value = context.deserialize(child, desc.getPropertyType());
+                    PropertyUtils.setProperty(pojo, name, value);
+                }
+            }
+            return pojo;
+        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public JsonElement serialize(Pojo src, Type typeOfSrc, JsonSerializationContext context) {
+        Class cls = (Class) typeOfSrc;
+        if (! cls.isAnnotationPresent(Entity.class)) {
+            System.err.println("attempt to serialize non-Entity class: " + cls.getName());
+            throw new IllegalArgumentException("attempt to serialize non-Entity class: " + cls.getName());
+        }
+        JsonObject obj = new JsonObject();
+        PropertyDescriptor[] descs = PropertyUtils.getPropertyDescriptors(src);
+        for (PropertyDescriptor desc : descs) {
+            Method readMethod = desc.getReadMethod();
+            if (readMethod != null && readMethod.isAnnotationPresent(Persist.class)) {
+                String name = desc.getName();
+                
+                try {
+                    Object value = PropertyUtils.getProperty(src, name);
+                    obj.add(name, context.serialize(value));
+                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+                    throw new RuntimeException(e);
+                }
+            } else if (readMethod == null) {
+                System.err.println("WARNING: property without read method: " + src.getClass().getName() + "::" + desc.getName());
+            }
+        }
+        return obj;
+    }
+
+
+}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java	Fri Oct 26 13:13:42 2012 +0200
@@ -62,6 +62,14 @@
         this.categoryId = categoryId;
     }
 
+    public String getPojoClass() {
+        return pojoClass;
+    }
+
+    public void setPojoClass(String pojoClass) {
+        this.pojoClass = pojoClass;
+    }
+
     public boolean isReplace() {
         return replace;
     }
@@ -70,13 +78,5 @@
         this.replace = replace;
     }
 
-    public String getPojoClass() {
-        return pojoClass;
-    }
-
-    public void setPojoClass(String pojoClass) {
-        this.pojoClass = pojoClass;
-    }
-
 
 }
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java	Fri Oct 26 13:13:42 2012 +0200
@@ -42,8 +42,8 @@
 
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Update;
-import com.redhat.thermostat.common.storage.Query.Criteria;
 
 public class WebUpdate implements Update {
 
@@ -135,4 +135,5 @@
     public List<WebUpdate.UpdateValue> getUpdates() {
         return updateValues;
     }
+
 }
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/RESTStorageEndPoint.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/RESTStorageEndPoint.java	Fri Oct 26 13:13:42 2012 +0200
@@ -22,8 +22,10 @@
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonParser;
+import com.redhat.thermostat.common.model.AgentIdPojo;
 import com.redhat.thermostat.common.model.Pojo;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Cursor;
@@ -36,6 +38,7 @@
 import com.redhat.thermostat.web.common.Qualifier;
 import com.redhat.thermostat.web.common.RESTQuery;
 import com.redhat.thermostat.web.common.StorageWrapper;
+import com.redhat.thermostat.web.common.ThermostatGSONConverter;
 import com.redhat.thermostat.web.common.WebInsert;
 import com.redhat.thermostat.web.common.WebRemove;
 import com.redhat.thermostat.web.common.WebUpdate;
@@ -52,7 +55,7 @@
     private Map<Integer, Category> categories;
 
     public void init() {
-        gson = new Gson();
+        gson = new GsonBuilder().registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()).create();
         categoryIds = new HashMap<>();
         categories = new HashMap<>();
     }
@@ -174,9 +177,9 @@
         try {
             String insertParam = req.getParameter("insert");
             WebInsert insert = gson.fromJson(insertParam, WebInsert.class);
-            Class<? extends Pojo> pojoCls = (Class<? extends Pojo>) Class.forName(insert.getPojoClass());
+            Class<? extends AgentIdPojo> pojoCls = (Class<? extends AgentIdPojo>) Class.forName(insert.getPojoClass());
             String pojoParam = req.getParameter("pojo");
-            Pojo pojo = gson.fromJson(pojoParam, pojoCls);
+            AgentIdPojo pojo = gson.fromJson(pojoParam, pojoCls);
             int categoryId = insert.getCategoryId();
             Category category = getCategoryFromId(categoryId);
             storage.putPojo(category, insert.isReplace(), pojo);
@@ -213,17 +216,22 @@
                 assert (qualifier.getCriteria() == Criteria.EQUALS);
                 targetUpdate = targetUpdate.where(qualifier.getKey(), qualifier.getValue());
             }
-            String valuesParam = req.getParameter("values");
-            JsonParser parser = new JsonParser();
-            JsonArray jsonArray = parser.parse(valuesParam).getAsJsonArray();
             List<WebUpdate.UpdateValue> updates = update.getUpdates();
-            int index = 0;
-            for (WebUpdate.UpdateValue updateValue : updates) {
-                Class valueClass = Class.forName(updateValue.getValueClass());
-                Object value = gson.fromJson(jsonArray.get(index), valueClass);
-                index++;
-                Key key = updateValue.getKey();
-                targetUpdate.set(key, value);
+            if (updates != null) {
+                String valuesParam = req.getParameter("values");
+                JsonParser parser = new JsonParser();
+                JsonArray jsonArray = parser.parse(valuesParam)
+                        .getAsJsonArray();
+                int index = 0;
+                for (WebUpdate.UpdateValue updateValue : updates) {
+                    Class valueClass = Class.forName(updateValue
+                            .getValueClass());
+                    Object value = gson.fromJson(jsonArray.get(index),
+                            valueClass);
+                    index++;
+                    Key key = updateValue.getKey();
+                    targetUpdate.set(key, value);
+                }
             }
             storage.updatePojo(targetUpdate);
             resp.setStatus(HttpServletResponse.SC_OK);
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/RESTStorageEndpointTest.java	Fri Oct 26 13:12:46 2012 +0200
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/RESTStorageEndpointTest.java	Fri Oct 26 13:13:42 2012 +0200
@@ -72,7 +72,9 @@
 import com.redhat.thermostat.common.storage.Categories;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Cursor;
+import com.redhat.thermostat.common.storage.Entity;
 import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Persist;
 import com.redhat.thermostat.common.storage.Query;
 import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Remove;
@@ -89,18 +91,23 @@
 
 public class RESTStorageEndpointTest {
 
+    @Entity
     public static class TestClass extends BasePojo {
         private String key1;
         private int key2;
+        @Persist
         public String getKey1() {
             return key1;
         }
+        @Persist
         public void setKey1(String key1) {
             this.key1 = key1;
         }
+        @Persist
         public int getKey2() {
             return key2;
         }
+        @Persist
         public void setKey2(int key2) {
             this.key2 = key2;
         }