changeset 1265:0e0e2b6041ad

Refactor DAOs so as to use prepared writes over direct write operations. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-September/008296.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Mon, 16 Sep 2013 15:28:13 +0200
parents e103fd511693
children d387d381858b
files host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java
diffstat 32 files changed, 1386 insertions(+), 404 deletions(-) [+]
line wrap: on
line diff
--- a/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -37,16 +37,32 @@
 package com.redhat.thermostat.host.cpu.common.internal;
 
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
-import com.redhat.thermostat.storage.core.Add;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.host.cpu.common.CpuStatDAO;
+import com.redhat.thermostat.host.cpu.common.model.CpuStat;
+import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostLatestPojoListGetter;
 import com.redhat.thermostat.storage.core.HostRef;
-import com.redhat.thermostat.host.cpu.common.CpuStatDAO;
-import com.redhat.thermostat.host.cpu.common.model.CpuStat;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.PreparedStatement;
+import com.redhat.thermostat.storage.core.StatementDescriptor;
+import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 
 class CpuStatDAOImpl implements CpuStatDAO {
 
+    private static final Logger logger = LoggingUtils.getLogger(CpuStatDAOImpl.class);
+    // ADD cpu-stats SET 'agentId' = ?s , \
+    //                   'perProcessorUsage' = ?d[ , \
+    //                   'timeStamp' = ?l
+    static final String DESC_ADD_CPU_STAT = "ADD " + cpuStatCategory.getName() +
+                           " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                                "'" + cpuLoadKey.getName() + "' = ?d[ , " +
+                                "'" + Key.TIMESTAMP.getName() + "' = ?l";
+    
     private final Storage storage;
 
     private final HostLatestPojoListGetter<CpuStat> getter;
@@ -64,9 +80,19 @@
 
     @Override
     public void putCpuStat(CpuStat stat) {
-        Add<CpuStat> add = storage.createAdd(cpuStatCategory);
-        add.setPojo(stat);
-        add.apply();
+        StatementDescriptor<CpuStat> desc = new StatementDescriptor<>(cpuStatCategory, DESC_ADD_CPU_STAT);
+        PreparedStatement<CpuStat> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, stat.getAgentId());
+            prepared.setDoubleList(1, stat.getPerProcessorUsage());
+            prepared.setLong(2, stat.getTimeStamp());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 }
 
--- a/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -40,7 +40,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -52,10 +51,10 @@
 import java.util.List;
 
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.host.cpu.common.CpuStatDAO;
 import com.redhat.thermostat.host.cpu.common.model.CpuStat;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -66,6 +65,14 @@
 import com.redhat.thermostat.storage.core.Storage;
 
 public class CpuStatDAOTest {
+    
+    @Test
+    public void testStatementDescriptorsAreSane() {
+        String addCpuStat = "ADD cpu-stats SET 'agentId' = ?s , " +
+                "'perProcessorUsage' = ?d[ , " +
+                "'timeStamp' = ?l";
+        assertEquals(addCpuStat, CpuStatDAOImpl.DESC_ADD_CPU_STAT);
+    }
 
     @Test
     public void testCategory() {
@@ -149,20 +156,30 @@
         verifyNoMoreInteractions(stmt);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutCpuStat() {
+    public void testPutCpuStat() throws DescriptorParsingException,
+            StatementExecutionException {
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<CpuStat> add = mock(Add.class);
-        when(storage.createAdd(eq(CpuStatDAO.cpuStatCategory))).thenReturn(add);
+        PreparedStatement<CpuStat> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
         
         CpuStat stat = new CpuStat("foo", 1,  new double[] {5.0, 10.0, 15.0});
         CpuStatDAO dao = new CpuStatDAOImpl(storage);
         dao.putCpuStat(stat);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(CpuStatDAOImpl.DESC_ADD_CPU_STAT, desc.getDescriptor());
 
-        verify(storage).createAdd(CpuStatDAO.cpuStatCategory);
-        verify(add).setPojo(stat);
-        verify(add).apply();
+        verify(add).setString(0, stat.getAgentId());
+        verify(add).setDoubleList(1, stat.getPerProcessorUsage());
+        verify(add).setLong(2, stat.getTimeStamp());
+        verify(add).execute();
+        verifyNoMoreInteractions(add);
     }
 }
 
--- a/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -37,16 +37,44 @@
 package com.redhat.thermostat.host.memory.common.internal;
 
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
+import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.host.memory.common.MemoryStatDAO;
 import com.redhat.thermostat.host.memory.common.model.MemoryStat;
-import com.redhat.thermostat.storage.core.Add;
+import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostLatestPojoListGetter;
 import com.redhat.thermostat.storage.core.HostRef;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.PreparedStatement;
+import com.redhat.thermostat.storage.core.StatementDescriptor;
+import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 
 public class MemoryStatDAOImpl implements MemoryStatDAO {
 
+    private static final Logger logger = LoggingUtils.getLogger(MemoryStatDAOImpl.class);
+    // ADD memory-stats SET 'agentId' = ?s , \
+    //                      'timeStamp' = ?l , \
+    //                      'total' = ?l , \
+    //                      'free' = ?l , \
+    //                      'buffers' = ?l , \
+    //                      'cached' = ?l , \
+    //                      'swapTotal' = ?l , \
+    //                      'swapFree' = ?l , \
+    //                      'commitLimit' = ?l
+    static final String DESC_ADD_MEMORY_STAT = "ADD " + memoryStatCategory.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + memoryTotalKey.getName() + "' = ?l , " +
+                 "'" + memoryFreeKey.getName() + "' = ?l , " +
+                 "'" + memoryBuffersKey.getName() + "' = ?l , " +
+                 "'" + memoryCachedKey.getName() + "' = ?l , " +
+                 "'" + memorySwapTotalKey.getName() + "' = ?l , " +
+                 "'" + memorySwapFreeKey.getName() + "' = ?l , " +
+                 "'" + memoryCommitLimitKey.getName() + "' = ?l";
+    
     private final Storage storage;
 
     private final HostLatestPojoListGetter<MemoryStat> getter;
@@ -64,9 +92,25 @@
 
     @Override
     public void putMemoryStat(MemoryStat stat) {
-        Add<MemoryStat> add = storage.createAdd(memoryStatCategory);
-        add.setPojo(stat);
-        add.apply();
+        StatementDescriptor<MemoryStat> desc = new StatementDescriptor<>(memoryStatCategory, DESC_ADD_MEMORY_STAT);
+        PreparedStatement<MemoryStat> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, stat.getAgentId());
+            prepared.setLong(1, stat.getTimeStamp());
+            prepared.setLong(2, stat.getTotal());
+            prepared.setLong(3, stat.getFree());
+            prepared.setLong(4, stat.getBuffers());
+            prepared.setLong(5, stat.getCached());
+            prepared.setLong(6, stat.getSwapTotal());
+            prepared.setLong(7, stat.getSwapFree());
+            prepared.setLong(8, stat.getCommitLimit());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
 }
--- a/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -38,7 +38,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -49,10 +48,10 @@
 import java.util.List;
 
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.host.memory.common.MemoryStatDAO;
 import com.redhat.thermostat.host.memory.common.model.MemoryStat;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -72,6 +71,20 @@
     private static long SWAP_TOTAL = 6;
     private static long SWAP_FREE = 7;
     private static long COMMIT_LIMIT = 8;
+    
+    @Test
+    public void testDescriptorsAreSane() {
+        String addMemoryStat = "ADD memory-stats SET 'agentId' = ?s , " +
+                "'timeStamp' = ?l , " +
+                "'total' = ?l , " +
+                "'free' = ?l , " +
+                "'buffers' = ?l , " +
+                "'cached' = ?l , " +
+                "'swapTotal' = ?l , " +
+                "'swapFree' = ?l , " +
+                "'commitLimit' = ?l";
+        assertEquals(addMemoryStat, MemoryStatDAOImpl.DESC_ADD_MEMORY_STAT);
+    }
 
     @Test
     public void testCategory() {
@@ -136,20 +149,34 @@
         return (StatementDescriptor<MemoryStat>) any(StatementDescriptor.class);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutMemoryStat() {
+    public void testPutMemoryStat() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<MemoryStat> add = mock(Add.class);
-        when(storage.createAdd(eq(MemoryStatDAO.memoryStatCategory))).thenReturn(add);
+        PreparedStatement<MemoryStat> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
         MemoryStat stat = new MemoryStat("foo", TIMESTAMP, TOTAL, FREE, BUFFERS, CACHED, SWAP_TOTAL, SWAP_FREE, COMMIT_LIMIT);
         MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
         dao.putMemoryStat(stat);
 
-        verify(storage).createAdd(MemoryStatDAO.memoryStatCategory);
-        verify(add).setPojo(stat);
-        verify(add).apply();
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(MemoryStatDAOImpl.DESC_ADD_MEMORY_STAT, desc.getDescriptor());
+        verify(add).setString(0, stat.getAgentId());
+        verify(add).setLong(1, stat.getTimeStamp());
+        verify(add).setLong(2, stat.getTotal());
+        verify(add).setLong(3, stat.getFree());
+        verify(add).setLong(4, stat.getBuffers());
+        verify(add).setLong(5, stat.getCached());
+        verify(add).setLong(6, stat.getSwapTotal());
+        verify(add).setLong(7, stat.getSwapFree());
+        verify(add).setLong(8, stat.getCommitLimit());
+        verify(add).execute();
+        verifyNoMoreInteractions(add);
     }
     
 }
--- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java	Mon Sep 16 15:28:13 2013 +0200
@@ -48,7 +48,7 @@
     
     static final Category<NumaStat> numaStatCategory = new Category<>("numa-stat", NumaStat.class, Key.AGENT_ID, Key.TIMESTAMP, nodeStats);
 
-    static final Key<Integer> hostNumNumaNodes = new Key<>("hostNumNumaNodes");
+    static final Key<Integer> hostNumNumaNodes = new Key<>("numNumaNodes");
 
     static final Category<NumaHostInfo> numaHostCategory = new Category<>("numa-host-info", NumaHostInfo.class, Key.AGENT_ID, hostNumNumaNodes);
 
--- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -44,7 +44,6 @@
 import com.redhat.thermostat.numa.common.NumaDAO;
 import com.redhat.thermostat.numa.common.NumaHostInfo;
 import com.redhat.thermostat.numa.common.NumaStat;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostLatestPojoListGetter;
@@ -61,6 +60,18 @@
     static final String QUERY_NUMA_INFO = "QUERY "
             + numaHostCategory.getName() + " WHERE '" 
             + Key.AGENT_ID.getName() + "' = ?s LIMIT 1";
+    // ADD numa-stat SET 'agentId' = ?s , \
+    //                   'timeStamp' = ?l , \
+    //                   'nodeStats' = ?p[
+    static final String DESC_ADD_NUMA_STAT = "ADD " + numaStatCategory.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + nodeStats.getName() + "' = ?p[";
+    // ADD numa-host-info SET 'agentId' = ?s , \
+    //                        'numNumaNodes' = ?i
+    static final String DESC_ADD_NUMA_HOST_INFO = "ADD " + numaHostCategory.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + hostNumNumaNodes.getName() + "' = ?i";
     
     private final Storage storage;
     private final HostLatestPojoListGetter<NumaStat> getter;
@@ -74,9 +85,19 @@
 
     @Override
     public void putNumaStat(NumaStat stat) {
-        Add<NumaStat> add = storage.createAdd(numaStatCategory);
-        add.setPojo(stat);
-        add.apply();
+        StatementDescriptor<NumaStat> desc = new StatementDescriptor<>(numaStatCategory, DESC_ADD_NUMA_STAT);
+        PreparedStatement<NumaStat> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, stat.getAgentId());
+            prepared.setLong(1, stat.getTimeStamp());
+            prepared.setPojoList(2, stat.getNodeStats());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
@@ -86,9 +107,18 @@
 
     @Override
     public void putNumberOfNumaNodes(NumaHostInfo numaHostInfo) {
-        Add<NumaHostInfo> replace = storage.createAdd(numaHostCategory);
-        replace.setPojo(numaHostInfo);
-        replace.apply();
+        StatementDescriptor<NumaHostInfo> desc = new StatementDescriptor<>(numaHostCategory, DESC_ADD_NUMA_HOST_INFO);
+        PreparedStatement<NumaHostInfo> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, numaHostInfo.getAgentId());
+            prepared.setInt(1, numaHostInfo.getNumNumaNodes());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
--- a/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -38,7 +38,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -47,12 +46,13 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
 
 import com.redhat.thermostat.numa.common.NumaDAO;
 import com.redhat.thermostat.numa.common.NumaHostInfo;
 import com.redhat.thermostat.numa.common.NumaNodeStat;
 import com.redhat.thermostat.numa.common.NumaStat;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -82,6 +82,13 @@
     public void preparedQueryDescriptorsAreSane() {
         String expectedQueryNumaInfo = "QUERY numa-host-info WHERE 'agentId' = ?s LIMIT 1";
         assertEquals(expectedQueryNumaInfo, NumaDAOImpl.QUERY_NUMA_INFO);
+        String addNumaStat = "ADD numa-stat SET 'agentId' = ?s , " +
+                                "'timeStamp' = ?l , " +
+                                "'nodeStats' = ?p[";
+        assertEquals(addNumaStat, NumaDAOImpl.DESC_ADD_NUMA_STAT);
+        String addNumaHostInfo = "ADD numa-host-info SET 'agentId' = ?s , " +
+                                                    "'numNumaNodes' = ?i";
+        assertEquals(addNumaHostInfo, NumaDAOImpl.DESC_ADD_NUMA_HOST_INFO);
     }
 
     @Test
@@ -89,12 +96,13 @@
         verify(storage).registerCategory(NumaDAO.numaStatCategory);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutNumaStat() {
+    public void testPutNumaStat() throws DescriptorParsingException,
+            StatementExecutionException {
 
-        @SuppressWarnings("unchecked")
-        Add<NumaStat> add = mock(Add.class);
-        when(storage.createAdd(NumaDAO.numaStatCategory)).thenReturn(add);
+        PreparedStatement<NumaStat> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
         NumaNodeStat stat = new NumaNodeStat();
         stat.setNodeId(1);
@@ -108,24 +116,35 @@
         NumaStat numaStat = new NumaStat("agentId");
         numaStat.setTimeStamp(12345);
         numaStat.setNodeStats(new NumaNodeStat[] { stat });
+        
         numaDAO.putNumaStat(numaStat);
 
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(NumaDAOImpl.DESC_ADD_NUMA_STAT, desc.getDescriptor());
+        
         verify(storage).registerCategory(NumaDAO.numaStatCategory);
         verify(storage).registerCategory(NumaDAO.numaHostCategory);
-        verify(storage).createAdd(NumaDAO.numaStatCategory);
         verifyNoMoreInteractions(storage);
-        verify(add).setPojo(numaStat);
-        verify(add).apply();
+        
+        verify(add).setString(0, numaStat.getAgentId());
+        verify(add).setLong(1, numaStat.getTimeStamp());
+        verify(add).setPojoList(2, numaStat.getNodeStats());
+        verify(add).execute();
         verifyNoMoreInteractions(add);
         assertEquals("agentId", numaStat.getAgentId());
     }
     
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutNumberOfNumaNodes() {
+    public void testPutNumberOfNumaNodes() throws DescriptorParsingException,
+            StatementExecutionException {
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<NumaHostInfo> add = mock(Add.class);
-        when(storage.createAdd(eq(NumaDAO.numaHostCategory))).thenReturn(add);
+        PreparedStatement<NumaStat> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
         NumaDAOImpl dao = new NumaDAOImpl(storage);
 
@@ -133,9 +152,17 @@
         info.setNumNumaNodes(4);
         dao.putNumberOfNumaNodes(info);
 
-        verify(storage).createAdd(NumaDAO.numaHostCategory);
-        verify(add).setPojo(info);
-        verify(add).apply();
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(NumaDAOImpl.DESC_ADD_NUMA_HOST_INFO, desc.getDescriptor());
+        
+        verify(add).setString(0, info.getAgentId());
+        verify(add).setInt(1, info.getNumNumaNodes());
+        verify(add).execute();
+        Mockito.verifyNoMoreInteractions(add);
     }
     
     @Test
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -50,16 +50,12 @@
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Update;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.AggregateCount;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class AgentInfoDAOImpl extends BaseCountable implements AgentInfoDAO {
 
@@ -86,14 +82,29 @@
     //                     'configListenAddress' = ?s
     static final String DESC_ADD_AGENT_INFO = "ADD " + CATEGORY.getName() + " SET " +
             "'" + Key.AGENT_ID.getName() + "' = ?s , " +
-            "'" + AgentInfoDAOImpl.START_TIME_KEY.getName() + "' = ?l , " +
-            "'" + AgentInfoDAOImpl.STOP_TIME_KEY.getName() + "' = ?l , " +
-            "'" + AgentInfoDAOImpl.ALIVE_KEY.getName() + "' = ?b , " +
-            "'" + AgentInfoDAOImpl.CONFIG_LISTEN_ADDRESS.getName() + "' = ?s";
+            "'" + START_TIME_KEY.getName() + "' = ?l , " +
+            "'" + STOP_TIME_KEY.getName() + "' = ?l , " +
+            "'" + ALIVE_KEY.getName() + "' = ?b , " +
+            "'" + CONFIG_LISTEN_ADDRESS.getName() + "' = ?s";
+    // REMOVE agent-config WHERE 'agentId' = ?s
+    static final String DESC_REMOVE_AGENT_INFO = "REMOVE " + CATEGORY.getName() +
+            " WHERE '" + Key.AGENT_ID.getName() + "' = ?s";
+    // UPDATE agent-config SET
+    //                       'startTime' = ?l , \
+    //                       'stopTime' = ?l , \
+    //                       'alive' = ?b , \
+    //                       'configListenAddress' = ?s
+    //                     WHERE 'agentId' = ?s
+    static final String DESC_UPDATE_AGENT_INFO = "UPDATE " + CATEGORY.getName() + " SET " +
+            "'" + START_TIME_KEY.getName() + "' = ?l , " +
+            "'" + STOP_TIME_KEY.getName() + "' = ?l , " +
+            "'" + ALIVE_KEY.getName() + "' = ?b , " +
+            "'" + CONFIG_LISTEN_ADDRESS.getName() + "' = ?s " +
+            "WHERE '" + Key.AGENT_ID.getName() + "' = ?s";
+                             
     
     private final Storage storage;
     private final Category<AggregateCount> aggregateCategory;
-    private final ExpressionFactory factory;
 
     public AgentInfoDAOImpl(Storage storage) {
         this.storage = storage;
@@ -102,7 +113,6 @@
         this.aggregateCategory = adapter.getAdapted(AggregateCount.class);
         storage.registerCategory(CATEGORY);
         storage.registerCategory(aggregateCategory);
-        this.factory = new ExpressionFactory();
     }
 
     @Override
@@ -213,22 +223,36 @@
 
     @Override
     public void removeAgentInformation(AgentInformation agentInfo) {
-        Expression expr = factory.equalTo(Key.AGENT_ID, agentInfo.getAgentId());
-        Remove<AgentInformation> remove = storage.createRemove(CATEGORY);
-        remove.where(expr);
-        remove.apply();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, DESC_REMOVE_AGENT_INFO);
+        PreparedStatement<AgentInformation> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, agentInfo.getAgentId());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
     public void updateAgentInformation(AgentInformation agentInfo) {
-        Update<AgentInformation> update = storage.createUpdate(CATEGORY);
-        Expression expr = factory.equalTo(Key.AGENT_ID, agentInfo.getAgentId());
-        update.where(expr);
-        update.set(START_TIME_KEY, agentInfo.getStartTime());
-        update.set(STOP_TIME_KEY, agentInfo.getStopTime());
-        update.set(ALIVE_KEY, agentInfo.isAlive());
-        update.set(CONFIG_LISTEN_ADDRESS, agentInfo.getConfigListenAddress());
-        update.apply();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, DESC_UPDATE_AGENT_INFO);
+        PreparedStatement<AgentInformation> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setLong(0, agentInfo.getStartTime());
+            prepared.setLong(1, agentInfo.getStopTime());
+            prepared.setBoolean(2, agentInfo.isAlive());
+            prepared.setString(3, agentInfo.getConfigListenAddress());
+            prepared.setString(4, agentInfo.getAgentId());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -44,20 +44,16 @@
 
 import com.redhat.thermostat.common.OrderedComparator;
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.model.BackendInformation;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class BackendInfoDAOImpl implements BackendInfoDAO {
     
@@ -65,14 +61,31 @@
     static final String QUERY_BACKEND_INFO = "QUERY "
             + CATEGORY.getName() + " WHERE '" 
             + Key.AGENT_ID.getName() + "' = ?s";
+    // ADD backend-info SET \
+    //                   'agentId' = ?s , \
+    //                   'name' = ?s , \
+    //                   'description' = ?s , \
+    //                   'observeNewJvm' = ?b , \
+    //                   'pids' = ?i[ , \
+    //                   'active' = ?b , \
+    //                   'orderValue' = ?i
+    static final String DESC_ADD_BACKEND_INFO = "ADD " + CATEGORY.getName() + " SET " +
+            "'" + Key.AGENT_ID.getName() + "' = ?s , " +
+            "'" + BACKEND_NAME.getName() + "' = ?s , " +
+            "'" + BACKEND_DESCRIPTION.getName() + "' = ?s , " +
+            "'" + SHOULD_MONITOR_NEW_PROCESSES.getName() + "' = ?b , " +
+            "'" + PIDS_TO_MONITOR.getName() + "' = ?i[ , " +
+            "'" + IS_ACTIVE.getName() + "' = ?b , " +
+            "'" + ORDER_VALUE.getName() + "' = ?i";
+    // REMOVE backend-info WHERE 'name' = ?s
+    static final String DESC_REMOVE_BACKEND_INFO = "REMOVE " + CATEGORY.getName() +
+            " WHERE '" + BACKEND_NAME.getName() + "' = ?s";
 
     private final Storage storage;
-    private final ExpressionFactory factory;
 
     public BackendInfoDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(CATEGORY);
-        factory = new ExpressionFactory();
     }
 
     @Override
@@ -108,17 +121,38 @@
 
     @Override
     public void addBackendInformation(BackendInformation info) {
-        Add<BackendInformation> add = storage.createAdd(BackendInfoDAO.CATEGORY);
-        add.setPojo(info);
-        add.apply();
+        StatementDescriptor<BackendInformation> desc = new StatementDescriptor<>(CATEGORY, DESC_ADD_BACKEND_INFO);
+        PreparedStatement<BackendInformation> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, info.getAgentId());
+            prepared.setString(1, info.getName());
+            prepared.setString(2, info.getDescription());
+            prepared.setBoolean(3, info.isObserveNewJvm());
+            prepared.setIntList(4, info.getPids());
+            prepared.setBoolean(5, info.isActive());
+            prepared.setInt(6, info.getOrderValue());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
     public void removeBackendInformation(BackendInformation info) {
-        Expression expr = factory.equalTo(BACKEND_NAME, info.getName());
-        Remove<BackendInformation> remove = storage.createRemove(CATEGORY);
-        remove.where(expr);
-        remove.apply();
+        StatementDescriptor<BackendInformation> desc = new StatementDescriptor<>(CATEGORY, DESC_REMOVE_BACKEND_INFO);
+        PreparedStatement<BackendInformation> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, info.getName());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
     
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -44,7 +44,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.CategoryAdapter;
 import com.redhat.thermostat.storage.core.Cursor;
@@ -72,6 +71,21 @@
     // only changes the data class. When executed we use the adapted
     // aggregate category.
     static final String AGGREGATE_COUNT_ALL_HOSTS = "QUERY-COUNT " + hostInfoCategory.getName();
+    // ADD host-info SET 'agentId' = ?s , \
+    //                   'hostname' = ?s , \
+    //                   'osName' = ?s , \
+    //                   'osKernel' = ?s , \
+    //                   'cpuModel' = ?s , \
+    //                   'cpuCount' = ?i , \
+    //                   'totalMemory' = ?l
+    static final String DESC_ADD_HOST_INFO = "ADD " + hostInfoCategory.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + hostNameKey.getName() + "' = ?s , " +
+                 "'" + osNameKey.getName() + "' = ?s , " +
+                 "'" + osKernelKey.getName() + "' = ?s , " +
+                 "'" + cpuModelKey.getName() + "' = ?s , " +
+                 "'" + cpuCountKey.getName() + "' = ?i , " +
+                 "'" + hostMemoryTotalKey.getName() + "' = ?l";
 
     private final Storage storage;
     private final AgentInfoDAO agentInfoDao;
@@ -120,9 +134,23 @@
 
     @Override
     public void putHostInfo(HostInfo info) {
-        Add<HostInfo> add = storage.createAdd(hostInfoCategory);
-        add.setPojo(info);
-        add.apply();
+        StatementDescriptor<HostInfo> desc = new StatementDescriptor<>(hostInfoCategory, DESC_ADD_HOST_INFO);
+        PreparedStatement<HostInfo> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, info.getAgentId());
+            prepared.setString(1, info.getHostname());
+            prepared.setString(2, info.getOsName());
+            prepared.setString(3, info.getOsKernel());
+            prepared.setString(4, info.getCpuModel());
+            prepared.setInt(5, info.getCpuCount());
+            prepared.setLong(6, info.getTotalMemory());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -48,14 +48,11 @@
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class NetworkInterfaceInfoDAOImpl implements NetworkInterfaceInfoDAO {
 
@@ -63,6 +60,21 @@
     static final String QUERY_NETWORK_INFO = "QUERY "
             + networkInfoCategory.getName() + " WHERE '"
             + Key.AGENT_ID.getName() + "' = ?s";
+    // REPLACE network-info SET 'agentId' = ?s , \
+    //                          'interfaceName' = ?s , \
+    //                          'ip4Addr' = ?s , \
+    //                          'ip6Addr' = ?s
+    //                      WHERE 'agentId' = ?s AND 'interfaceName' = ?s
+    static final String DESC_REPLACE_NETWORK_INFO = "REPLACE " +
+                            networkInfoCategory.getName() +
+                 " SET " +
+                    "'" + Key.AGENT_ID.getName() + "' = ?s , " +
+                    "'" + ifaceKey.getName() + "' = ?s , " +
+                    "'" + ip4AddrKey.getName() + "' = ?s , " +
+                    "'" + ip6AddrKey.getName() + "' = ?s " +
+                 "WHERE '" + Key.AGENT_ID.getName() + "' = ?s AND " +
+                       "'" + ifaceKey.getName() + "' = ?s"; 
+                                
 
     private final Storage storage;
 
@@ -100,15 +112,24 @@
 
     @Override
     public void putNetworkInterfaceInfo(NetworkInterfaceInfo info) {
-        Replace<NetworkInterfaceInfo> replace = storage.createReplace(networkInfoCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        String agentId = info.getAgentId();
-        Expression left = factory.equalTo(Key.AGENT_ID, agentId);
-        Expression right = factory.equalTo(NetworkInterfaceInfoDAO.ifaceKey, info.getInterfaceName());
-        Expression expression = factory.and(left, right); 
-        replace.setPojo(info);
-        replace.where(expression);
-        replace.apply();
+        StatementDescriptor<NetworkInterfaceInfo> desc = new StatementDescriptor<>(networkInfoCategory, DESC_REPLACE_NETWORK_INFO);
+        PreparedStatement<NetworkInterfaceInfo> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            // SET params.
+            prepared.setString(0, info.getAgentId());
+            prepared.setString(1, info.getInterfaceName());
+            prepared.setString(2, info.getIp4Addr());
+            prepared.setString(3, info.getIp6Addr());
+            // WHERE params.
+            prepared.setString(4, info.getAgentId());
+            prepared.setString(5, info.getInterfaceName());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -44,7 +44,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.CategoryAdapter;
 import com.redhat.thermostat.storage.core.Cursor;
@@ -55,14 +54,11 @@
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Update;
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.DAOException;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.AggregateCount;
 import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class VmInfoDAOImpl extends BaseCountable implements VmInfoDAO {
     
@@ -76,9 +72,52 @@
             + Key.AGENT_ID.getName() + "' = ?s";
     static final String QUERY_ALL_VMS = "QUERY " + vmInfoCategory.getName();
     static final String AGGREGATE_COUNT_ALL_VMS = "QUERY-COUNT " + vmInfoCategory.getName();
+    // ADD vm-info SET 'agentId' = ?s , \
+    //                 'vmId' = ?s , \
+    //                 'vmPid' = ?i , \
+    //                 'startTimeStamp' = ?l , \
+    //                 'stopTimeStamp' = ?l , \
+    //                 'javaVersion' = ?s , \
+    //                 'javaHome' = ?s , \
+    //                 'mainClass' = ?s , \
+    //                 'javaCommandLine' = ?s , \
+    //                 'vmName' = ?s , \
+    //                 'vmArguments' = ?s , \
+    //                 'vmInfo' = ?s , \
+    //                 'vmVersion' = ?s , \
+    //                 'propertiesAsArray' = ?p[ , \
+    //                 'environmentAsArray' = ?p[ , \
+    //                 'loadedNativeLibraries' = ?s[ , \
+    //                 'uid' = ?l , \
+    //                 'username' = ?s
+    static final String DESC_ADD_VM_INFO = "ADD " + vmInfoCategory.getName() + " SET " +
+                        "'" + Key.AGENT_ID.getName() + "' = ?s , " +
+                        "'" + Key.VM_ID.getName() + "' = ?s , " +
+                        "'" + vmPidKey.getName() + "' = ?i , " +
+                        "'" + startTimeKey.getName() + "' = ?l , " +
+                        "'" + stopTimeKey.getName() + "' = ?l , " +
+                        "'" + runtimeVersionKey.getName() + "' = ?s , " +
+                        "'" + javaHomeKey.getName() + "' = ?s , " +
+                        "'" + mainClassKey.getName() + "' = ?s , " +
+                        "'" + commandLineKey.getName() + "' = ?s , " +
+                        "'" + vmNameKey.getName() + "' = ?s , " +
+                        "'" + vmArgumentsKey.getName() + "' = ?s , " +
+                        "'" + vmInfoKey.getName() + "' = ?s , " +
+                        "'" + vmVersionKey.getName() + "' = ?s , " +
+                        // The following two get persisted as pojo arrays.
+                        // There is no direct key representation for what gets
+                        // persisted.
+                        "'propertiesAsArray' = ?p[ , " +
+                        "'environmentAsArray' = ?p[ , " +
+                        "'" + librariesKey.getName() + "' = ?s[ , " +
+                        "'" + uidKey.getName() + "' = ?l , " +
+                        "'" + usernameKey.getName() + "' = ?s";
+    // UPDATE vm-info SET 'stopTimeStamp' = ?l WHERE 'vmId' = ?s
+    static final String DESC_UPDATE_VM_STOP_TIME = "UPDATE " + vmInfoCategory.getName() +
+            " SET '" + VmInfoDAO.stopTimeKey.getName() + "' = ?l" +
+            " WHERE '" + Key.VM_ID.getName() + "' = ?s";
     
     private final Storage storage;
-    private final ExpressionFactory factory;
     private final Category<AggregateCount> aggregateCategory;
 
     public VmInfoDAOImpl(Storage storage) {
@@ -88,7 +127,6 @@
         this.aggregateCategory = adapter.getAdapted(AggregateCount.class);
         storage.registerCategory(vmInfoCategory);
         storage.registerCategory(aggregateCategory);
-        factory = new ExpressionFactory();
     }
 
     @Override
@@ -173,18 +211,50 @@
 
     @Override
     public void putVmInfo(VmInfo info) {
-        Add<VmInfo> replace = storage.createAdd(vmInfoCategory);
-        replace.setPojo(info);
-        replace.apply();
+        StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(vmInfoCategory, DESC_ADD_VM_INFO);
+        PreparedStatement<VmInfo> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, info.getAgentId());
+            prepared.setString(1, info.getVmId());
+            prepared.setInt(2, info.getVmPid());
+            prepared.setLong(3, info.getStartTimeStamp());
+            prepared.setLong(4, info.getStopTimeStamp());
+            prepared.setString(5, info.getJavaVersion());
+            prepared.setString(6, info.getJavaHome());
+            prepared.setString(7, info.getMainClass());
+            prepared.setString(8, info.getJavaCommandLine());
+            prepared.setString(9, info.getVmName());
+            prepared.setString(10, info.getVmArguments());
+            prepared.setString(11, info.getVmInfo());
+            prepared.setString(12, info.getVmVersion());
+            prepared.setPojoList(13, info.getPropertiesAsArray());
+            prepared.setPojoList(14, info.getEnvironmentAsArray());
+            prepared.setStringList(15, info.getLoadedNativeLibraries());
+            prepared.setLong(16, info.getUid());
+            prepared.setString(17, info.getUsername());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
     public void putVmStoppedTime(String vmId, long timestamp) {
-        Update<VmInfo> update = storage.createUpdate(vmInfoCategory);
-        Expression expr = factory.equalTo(Key.VM_ID, vmId);
-        update.where(expr);
-        update.set(VmInfoDAO.stopTimeKey, timestamp);
-        update.apply();
+        StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(vmInfoCategory, DESC_UPDATE_VM_STOP_TIME);
+        PreparedStatement<VmInfo> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setLong(0, timestamp);
+            prepared.setString(1, vmId);
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
 }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -40,7 +40,6 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -60,22 +59,17 @@
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Update;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.AggregateCount;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class AgentInfoDAOTest {
 
     private AgentInformation agentInfo1;
     private AgentInformation agent1;
-    private ExpressionFactory factory;
 
     @Before
     public void setUp() {
@@ -90,7 +84,6 @@
         agent1.setConfigListenAddress("foobar:666");
         agent1.setStartTime(100);
         agent1.setStopTime(10);
-        factory = new ExpressionFactory();
     }
 
     @Test
@@ -109,6 +102,14 @@
                                                    "'alive' = ?b , " +
                                                    "'configListenAddress' = ?s";
         assertEquals(addAgentInfo, AgentInfoDAOImpl.DESC_ADD_AGENT_INFO);
+        String removeAgentInfo = "REMOVE agent-config WHERE 'agentId' = ?s";
+        assertEquals(removeAgentInfo, AgentInfoDAOImpl.DESC_REMOVE_AGENT_INFO);
+        String updateAgentInfo = "UPDATE agent-config SET 'startTime' = ?l , " +
+                                                         "'stopTime' = ?l , " +
+                                                         "'alive' = ?b , " +
+                                                         "'configListenAddress' = ?s " +
+                                                      "WHERE 'agentId' = ?s";
+        assertEquals(updateAgentInfo, AgentInfoDAOImpl.DESC_UPDATE_AGENT_INFO);
     }
     
     @Test
@@ -289,42 +290,45 @@
         Mockito.verifyNoMoreInteractions(add);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void verifyUpdateAgentInformation() {
-
-        @SuppressWarnings("unchecked")
-        Update<AgentInformation> mockUpdate = mock(Update.class);
+    public void verifyUpdateAgentInformation() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        when(storage.createUpdate(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockUpdate);
+        PreparedStatement<AgentInformation> update = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(update);
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
 
         dao.updateAgentInformation(agentInfo1);
 
-        verify(storage).createUpdate(AgentInfoDAO.CATEGORY);
-        Expression expr = factory.equalTo(Key.AGENT_ID, "1234");
-        verify(mockUpdate).where(eq(expr));
-        verify(mockUpdate).set(AgentInfoDAO.START_TIME_KEY, 100L);
-        verify(mockUpdate).set(AgentInfoDAO.STOP_TIME_KEY, 10L);
-        verify(mockUpdate).set(AgentInfoDAO.CONFIG_LISTEN_ADDRESS, "foobar:666");
-        verify(mockUpdate).set(AgentInfoDAO.ALIVE_KEY, true);
-        verify(mockUpdate).apply();
-        verifyNoMoreInteractions(mockUpdate);
-
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        verify(storage).prepareStatement(captor.capture());
+        
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(AgentInfoDAO.CATEGORY, desc.getCategory());
+        assertEquals(AgentInfoDAOImpl.DESC_UPDATE_AGENT_INFO, desc.getDescriptor());
+        verify(update).setLong(0, agentInfo1.getStartTime());
+        verify(update).setLong(1, agentInfo1.getStopTime());
+        verify(update).setBoolean(2, agentInfo1.isAlive());
+        verify(update).setString(3, agentInfo1.getConfigListenAddress());
+        verify(update).setString(4, agentInfo1.getAgentId());
+        verify(update).execute();
+        verifyNoMoreInteractions(update);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void verifyRemoveAgentInformation() {
-        @SuppressWarnings("unchecked")
-        Remove<AgentInformation> mockRemove = mock(Remove.class);
+    public void verifyRemoveAgentInformation() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        when(storage.createRemove(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockRemove);
+        PreparedStatement<AgentInformation> remove = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(remove);
+        
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
 
         dao.removeAgentInformation(agentInfo1);
 
-        verify(mockRemove).apply();
-        Expression expr = factory.equalTo(Key.AGENT_ID, "1234");
-        verify(mockRemove).where(eq(expr));
+        verify(remove).setString(0, agentInfo1.getAgentId());
+        verify(remove).execute();
     }
 
 }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -39,8 +39,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -52,29 +50,24 @@
 
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.InOrder;
+import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.model.BackendInformation;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class BackendInfoDAOTest {
 
     private BackendInformation backendInfo1;
     private BackendInformation backend1;
-    private ExpressionFactory factory;
 
     @Before
     public void setUp() {
@@ -95,14 +88,21 @@
         backend1.setObserveNewJvm(true);
         backend1.setPids(new int[] { -1, 0, 1});
         backend1.setOrderValue(100);
-        
-        factory = new ExpressionFactory();
     }
     
     @Test
     public void preparedQueryDescriptorsAreSane() {
         String expectedBackendInfo = "QUERY backend-info WHERE 'agentId' = ?s";
         assertEquals(expectedBackendInfo, BackendInfoDAOImpl.QUERY_BACKEND_INFO);
+        String addBackendInfo = "ADD backend-info SET " +
+                                        "'agentId' = ?s , " +
+                                        "'name' = ?s , " +
+                                        "'description' = ?s , " +
+                                        "'observeNewJvm' = ?b , " +
+                                        "'pids' = ?i[ , " +
+                                        "'active' = ?b , " +
+                                        "'orderValue' = ?i";
+        assertEquals(addBackendInfo, BackendInfoDAOImpl.DESC_ADD_BACKEND_INFO);
     }
 
     @Test
@@ -125,20 +125,34 @@
         assertTrue(keys.contains(BackendInfoDAO.ORDER_VALUE));
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void verifyAddBackendInformation() {
+    public void verifyAddBackendInformation()
+            throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<BackendInformation> add = mock(Add.class);
-        when(storage.createAdd(eq(BackendInfoDAO.CATEGORY))).thenReturn(add);
+        PreparedStatement<BackendInformation> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
         BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
 
         dao.addBackendInformation(backendInfo1);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(BackendInfoDAOImpl.DESC_ADD_BACKEND_INFO, desc.getDescriptor());
 
-        verify(storage).createAdd(BackendInfoDAO.CATEGORY);
-        verify(add).setPojo(backendInfo1);
-        verify(add).apply();
+        verify(add).setString(0, backendInfo1.getAgentId());
+        verify(add).setString(1, backendInfo1.getName());
+        verify(add).setString(2, backendInfo1.getDescription());
+        verify(add).setBoolean(3, backendInfo1.isObserveNewJvm());
+        verify(add).setIntList(4, backendInfo1.getPids());
+        verify(add).setBoolean(5, backendInfo1.isActive());
+        verify(add).setInt(6, backendInfo1.getOrderValue());
+        verify(add).execute();
+        verifyNoMoreInteractions(add);
     }
 
     @Test
@@ -175,20 +189,28 @@
         return (StatementDescriptor<BackendInformation>) any(StatementDescriptor.class);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void verifyRemoveBackendInformation() {
-        @SuppressWarnings("unchecked")
-        Remove<BackendInformation> remove = mock(Remove.class);
+    public void verifyRemoveBackendInformation()
+            throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        when(storage.createRemove(eq(BackendInfoDAO.CATEGORY))).thenReturn(remove);
+        PreparedStatement<BackendInformation> remove = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(remove);
+        
         BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
 
         dao.removeBackendInformation(backendInfo1);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(BackendInfoDAOImpl.DESC_REMOVE_BACKEND_INFO, desc.getDescriptor());
 
-        InOrder inOrder = inOrder(remove);
-        Expression expr = factory.equalTo(BackendInfoDAO.BACKEND_NAME, "backend-name");
-        inOrder.verify(remove).where(eq(expr));
-        inOrder.verify(remove).apply();
+        verify(remove).setString(0, backendInfo1.getName());
+        verify(remove).execute();
+        verifyNoMoreInteractions(remove);
     }
 
 }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -40,7 +40,6 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -50,8 +49,9 @@
 import java.util.Collection;
 
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
 
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -96,6 +96,14 @@
         assertEquals(expectedAllHosts, HostInfoDAOImpl.QUERY_ALL_HOSTS);
         String aggregateAllHosts = "QUERY-COUNT host-info";
         assertEquals(aggregateAllHosts, HostInfoDAOImpl.AGGREGATE_COUNT_ALL_HOSTS);
+        String addHostInfo = "ADD host-info SET 'agentId' = ?s , " +
+                                                  "'hostname' = ?s , " +
+                                                  "'osName' = ?s , " +
+                                                  "'osKernel' = ?s , " +
+                                                  "'cpuModel' = ?s , " +
+                                                  "'cpuCount' = ?i , " +
+                                                  "'totalMemory' = ?l";
+        assertEquals(addHostInfo, HostInfoDAOImpl.DESC_ADD_HOST_INFO);
     }
     
     @Test
@@ -205,22 +213,36 @@
         return storage;
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutHostInfo() {
+    public void testPutHostInfo() throws DescriptorParsingException,
+            StatementExecutionException {
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<HostInfo> add = mock(Add.class);
-        when(storage.createAdd(eq(HostInfoDAO.hostInfoCategory))).thenReturn(add);
+        PreparedStatement<HostInfo> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
         AgentInfoDAO agentInfo = mock(AgentInfoDAO.class);
 
         HostInfo info = new HostInfo("foo-agent", HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
         HostInfoDAO dao = new HostInfoDAOImpl(storage, agentInfo);
         dao.putHostInfo(info);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
 
-        verify(storage).createAdd(HostInfoDAO.hostInfoCategory);
-        verify(add).setPojo(info);
-        verify(add).apply();
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(HostInfoDAOImpl.DESC_ADD_HOST_INFO, desc.getDescriptor());
+        
+        verify(add).setString(0, info.getAgentId());
+        verify(add).setString(1, info.getHostname());
+        verify(add).setString(2, info.getOsName());
+        verify(add).setString(3, info.getOsKernel());
+        verify(add).setString(4, info.getCpuModel());
+        verify(add).setInt(5, info.getCpuCount());
+        verify(add).setLong(6, info.getTotalMemory());
+        verify(add).execute();
+        Mockito.verifyNoMoreInteractions(add);
     }
 
     @Test
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -39,7 +39,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -49,20 +48,18 @@
 import java.util.List;
 
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class NetworkInterfaceInfoDAOTest {
 
@@ -87,6 +84,12 @@
     public void preparedQueryDescriptorsAreSane() {
         String expectedNetworkInfo = "QUERY network-info WHERE 'agentId' = ?s";
         assertEquals(expectedNetworkInfo, NetworkInterfaceInfoDAOImpl.QUERY_NETWORK_INFO);
+        String replaceNetworkInfo = "REPLACE network-info SET 'agentId' = ?s , " +
+            "'interfaceName' = ?s , " +
+            "'ip4Addr' = ?s , " +
+            "'ip6Addr' = ?s WHERE " +
+            "'agentId' = ?s AND 'interfaceName' = ?s";
+        assertEquals(replaceNetworkInfo, NetworkInterfaceInfoDAOImpl.DESC_REPLACE_NETWORK_INFO);
     }
 
     @Test
@@ -132,29 +135,38 @@
         return (StatementDescriptor<NetworkInterfaceInfo>) any(StatementDescriptor.class);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutNetworkInterfaceInfo() {
+    public void testPutNetworkInterfaceInfo()
+            throws DescriptorParsingException, StatementExecutionException {
         String agentId = "fooAgent";
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Replace<NetworkInterfaceInfo> replace = mock(Replace.class);
-        when(storage.createReplace(eq(NetworkInterfaceInfoDAO.networkInfoCategory))).thenReturn(replace);
+        PreparedStatement<NetworkInterfaceInfo> replace = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(replace);
 
-        NetworkInterfaceInfo info = new NetworkInterfaceInfo("foo-agent", INTERFACE_NAME);
+        NetworkInterfaceInfo info = new NetworkInterfaceInfo(agentId, INTERFACE_NAME);
         info.setIp4Addr(IPV4_ADDR);
         info.setIp6Addr(IPV6_ADDR);
-        info.setAgentId(agentId);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression left = factory.equalTo(Key.AGENT_ID, agentId);
-        Expression right = factory.equalTo(NetworkInterfaceInfoDAO.ifaceKey, INTERFACE_NAME);
-        Expression expected = factory.and(left, right);
+        
         NetworkInterfaceInfoDAO dao = new NetworkInterfaceInfoDAOImpl(storage);
         dao.putNetworkInterfaceInfo(info);
 
-        verify(storage).createReplace(NetworkInterfaceInfoDAO.networkInfoCategory);
-        verify(replace).setPojo(info);
-        verify(replace).where(expected);
-        verify(replace).apply();
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(NetworkInterfaceInfoDAOImpl.DESC_REPLACE_NETWORK_INFO, desc.getDescriptor());
+        
+        verify(replace).setString(0, info.getAgentId());
+        verify(replace).setString(1, info.getInterfaceName());
+        verify(replace).setString(2, info.getIp4Addr());
+        verify(replace).setString(3, info.getIp6Addr());
+        verify(replace).setString(4, info.getAgentId());
+        verify(replace).setString(5, info.getInterfaceName());
+        verify(replace).execute();
+        verifyNoMoreInteractions(replace);
     }
     
 }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -40,7 +40,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -53,8 +52,8 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -63,13 +62,11 @@
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Update;
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.DAOException;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.AggregateCount;
 import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class VmInfoDAOTest {
 
@@ -122,6 +119,27 @@
         assertEquals(expectedAllVms, VmInfoDAOImpl.QUERY_ALL_VMS);
         String aggregateAllVms = "QUERY-COUNT vm-info";
         assertEquals(aggregateAllVms, VmInfoDAOImpl.AGGREGATE_COUNT_ALL_VMS);
+        String addVmInfo = "ADD vm-info SET 'agentId' = ?s , " +
+                                            "'vmId' = ?s , " +
+                                            "'vmPid' = ?i , " +
+                                            "'startTimeStamp' = ?l , " +
+                                            "'stopTimeStamp' = ?l , " +
+                                            "'javaVersion' = ?s , " +
+                                            "'javaHome' = ?s , " +
+                                            "'mainClass' = ?s , " +
+                                            "'javaCommandLine' = ?s , " +
+                                            "'vmName' = ?s , " +
+                                            "'vmArguments' = ?s , " +
+                                            "'vmInfo' = ?s , " +
+                                            "'vmVersion' = ?s , " +
+                                            "'propertiesAsArray' = ?p[ , " +
+                                            "'environmentAsArray' = ?p[ , " +
+                                            "'loadedNativeLibraries' = ?s[ , " +
+                                            "'uid' = ?l , " +
+                                            "'username' = ?s";
+        assertEquals(addVmInfo, VmInfoDAOImpl.DESC_ADD_VM_INFO);
+        String updateVmStopTime = "UPDATE vm-info SET 'stopTimeStamp' = ?l WHERE 'vmId' = ?s";
+        assertEquals(updateVmStopTime, VmInfoDAOImpl.DESC_UPDATE_VM_STOP_TIME);
     }
 
     @Test
@@ -311,41 +329,70 @@
         assertEquals(2, dao.getCount());
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutVmInfo() {
-
+    public void testPutVmInfo() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<VmInfo> add = mock(Add.class);
-        when(storage.createAdd(eq(VmInfoDAO.vmInfoCategory))).thenReturn(add);
-
+        PreparedStatement<VmInfo> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
+        
         VmInfo info = new VmInfo("foo-agent", vmId, vmPid, startTime, stopTime, jVersion, jHome,
                 mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs,
                 props, env, libs, uid, username);
         VmInfoDAO dao = new VmInfoDAOImpl(storage);
         dao.putVmInfo(info);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(VmInfoDAOImpl.DESC_ADD_VM_INFO, desc.getDescriptor());
 
-        verify(storage).createAdd(VmInfoDAO.vmInfoCategory);
-        verify(add).setPojo(info);
-        verify(add).apply();
+        verify(add).setString(0, info.getAgentId());
+        verify(add).setString(1, info.getVmId());
+        verify(add).setInt(2, info.getVmPid());
+        verify(add).setLong(3, info.getStartTimeStamp());
+        verify(add).setLong(4, info.getStopTimeStamp());
+        verify(add).setString(5, info.getJavaVersion());
+        verify(add).setString(6, info.getJavaHome());
+        verify(add).setString(7, info.getMainClass());
+        verify(add).setString(8, info.getJavaCommandLine());
+        verify(add).setString(9, info.getVmName());
+        verify(add).setString(10, info.getVmArguments());
+        verify(add).setString(11, info.getVmInfo());
+        verify(add).setString(12, info.getVmVersion());
+        verify(add).setPojoList(13, info.getPropertiesAsArray());
+        verify(add).setPojoList(14, info.getEnvironmentAsArray());
+        verify(add).setStringList(15, info.getLoadedNativeLibraries());
+        verify(add).setLong(16, info.getUid());
+        verify(add).setString(17, info.getUsername());
+        verify(add).execute();
+        verifyNoMoreInteractions(add);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutVmStoppedTime() {
-        @SuppressWarnings("unchecked")
-        Update<VmInfo> mockUpdate = mock(Update.class);
+    public void testPutVmStoppedTime() throws DescriptorParsingException,
+            StatementExecutionException {
         Storage storage = mock(Storage.class);
-        when(storage.createUpdate(eq(VmInfoDAO.vmInfoCategory))).thenReturn(mockUpdate);
+        PreparedStatement<VmInfo> update = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(update);
 
         VmInfoDAO dao = new VmInfoDAOImpl(storage);
         dao.putVmStoppedTime(vmId, stopTime);
 
-        verify(storage).createUpdate(VmInfoDAO.vmInfoCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        verify(mockUpdate).where(factory.equalTo(Key.VM_ID, "vmId"));
-        verify(mockUpdate).set(VmInfoDAO.stopTimeKey, 3L);
-        verify(mockUpdate).apply();
-        verifyNoMoreInteractions(mockUpdate);
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(VmInfoDAOImpl.DESC_UPDATE_VM_STOP_TIME, desc.getDescriptor());
+        
+        verify(update).setLong(0, stopTime);
+        verify(update).setString(1, vmId);
+        verify(update).execute();
+        verifyNoMoreInteractions(update);
     }
 }
 
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java	Mon Sep 16 15:28:13 2013 +0200
@@ -53,11 +53,10 @@
     static final String CPU_TIME = "thread-cpu-time";
     static final String CONTENTION_MONITOR = "thread-contention-monitor";
     static final String THREAD_ALLOCATED_MEMORY = "thread-allocated-memory";
+    
     static final String SUPPORTED_FEATURES_LIST = "supportedFeaturesList";
 
-    static final Key<Boolean> CPU_TIME_KEY = new Key<Boolean>(CPU_TIME);
-    static final Key<Boolean> CONTENTION_MONITOR_KEY = new Key<Boolean>(CONTENTION_MONITOR);
-    static final Key<Boolean> THREAD_ALLOCATED_MEMORY_KEY = new Key<Boolean>(THREAD_ALLOCATED_MEMORY);
+    static final Key<Long> THREAD_ALLOCATED_BYTES_KEY = new Key<Long>("allocatedBytes");
     static final Key<List<String>> SUPPORTED_FEATURES_LIST_KEY = new Key<List<String>>(SUPPORTED_FEATURES_LIST);
 
     static final Category<VMThreadCapabilities> THREAD_CAPABILITIES =
@@ -83,7 +82,7 @@
     List<ThreadSummary> loadSummary(VmRef ref, long since);
 
     static final String HARVESTING_DATA = "harvesting";
-    static final Key<String> HARVESTING_STATUS_KEY = new Key<String> (HARVESTING_DATA);
+    static final Key<Boolean> HARVESTING_STATUS_KEY = new Key<Boolean>(HARVESTING_DATA);
     static final Category<ThreadHarvestingStatus> THREAD_HARVESTING_STATUS =
             new Category<>("vm-thread-harvesting", ThreadHarvestingStatus.class,
                     Key.AGENT_ID,
@@ -114,13 +113,14 @@
                          Key.TIMESTAMP, THREAD_NAME_KEY, THREAD_ID_KEY,
                          THREAD_STATE_KEY,
                          THREAD_CPU_TIME_KEY,
+                         THREAD_ALLOCATED_BYTES_KEY,
                          THREAD_USER_TIME_KEY, THREAD_BLOCKED_COUNT_KEY,
                          THREAD_WAIT_COUNT_KEY);
     
     void saveThreadInfo(ThreadInfoData info);
     List<ThreadInfoData> loadThreadInfo(VmRef ref, long since);
 
-    static final String DEADLOCK_DESCRIPTION = "description";
+    static final String DEADLOCK_DESCRIPTION = "deadLockDescription";
     static final Key<String> DEADLOCK_DESCRIPTION_KEY = new Key<>(DEADLOCK_DESCRIPTION);
     static final Category<VmDeadLockData> DEADLOCK_INFO = new Category<>("vm-deadlock-data", VmDeadLockData.class,
             Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP,
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -43,20 +43,16 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
 import com.redhat.thermostat.thread.model.ThreadInfoData;
@@ -69,6 +65,7 @@
     private static final Logger logger = LoggingUtils.getLogger(ThreadDaoImpl.class);
     
     // Queries
+    
     static final String QUERY_THREAD_CAPS = "QUERY "
             + THREAD_CAPABILITIES.getName() + " WHERE '"
             + Key.AGENT_ID.getName() + "' = ?s AND '" 
@@ -101,6 +98,71 @@
             + Key.VM_ID.getName() + "' = ?s SORT '" 
             + Key.TIMESTAMP.getName() + "' DSC LIMIT 1";
     
+    // Data modifying descriptors
+    
+    // ADD vm-thread-summary SET 'agentId' = ?s , \
+    //                           'vmId' = ?s , \
+    //                           'currentLiveThreads' = ?l , \
+    //                           'currentDaemonThreads' = ?l , \
+    //                           'timeStamp' = ?l
+    static final String DESC_ADD_THREAD_SUMMARY = "ADD " + THREAD_SUMMARY.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + LIVE_THREADS_KEY.getName() + "' = ?l , " +
+                 "'" + DAEMON_THREADS_KEY.getName() + "' = ?l , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l";
+    // ADD vm-thread-harvesting SET 'agentId' = ?s , \
+    //                              'vmId' = ?s , \
+    //                              'timeStamp' = ?l , \
+    //                              'harvesting' = ?b
+    static final String DESC_ADD_THREAD_HARVESTING_STATUS = "ADD " + THREAD_HARVESTING_STATUS.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + HARVESTING_STATUS_KEY.getName() + "' = ?b";
+    // ADD vm-thread-info SET 'agentId' = ?s , \
+    //                        'vmId' = ?s , \
+    //                        'threadName' = ?s , \
+    //                        'threadId' = ?l , \
+    //                        'threadState' = ?s , \
+    //                        'allocatedBytes' = ?l , \
+    //                        'timeStamp' = ?l , \
+    //                        'threadCpuTime' = ?l , \
+    //                        'threadUserTime' = ?l , \
+    //                        'threadBlockedCount' = ?l , \
+    //                        'threadWaitCount' = ?l
+    static final String DESC_ADD_THREAD_INFO = "ADD " + THREAD_INFO.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + THREAD_NAME_KEY.getName() + "' = ?s , " +
+                 "'" + THREAD_ID_KEY.getName() + "' = ?l , " +
+                 "'" + THREAD_STATE_KEY.getName() + "' = ?s , " +
+                 "'" + THREAD_ALLOCATED_BYTES_KEY.getName() + "' = ?l , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + THREAD_CPU_TIME_KEY.getName() + "' = ?l , " +
+                 "'" + THREAD_USER_TIME_KEY.getName() + "' = ?l , " +
+                 "'" + THREAD_BLOCKED_COUNT_KEY.getName() + "' = ?l , " +
+                 "'" + THREAD_WAIT_COUNT_KEY.getName() + "' = ?l";
+    // ADD vm-deadlock-data SET 'agentId' = ?s , \
+    //                          'vmId' = ?s , \
+    //                          'timeStamp' = ?l , \
+    //                          'deadLockDescription' = ?s
+    static final String DESC_ADD_THREAD_DEADLOCK_DATA = "ADD " + DEADLOCK_INFO.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + DEADLOCK_DESCRIPTION_KEY.getName() + "' = ?s";
+    // REPLACE vm-thread-capabilities SET 'agentId' = ?s , \
+    //                                    'vmId' = ?s , \
+    //                                    'supportedFeaturesList' = ?s[
+    //                                WHERE 'agentId' = ?s AND 'vmId' = ?s
+    static final String DESC_REPLACE_THREAD_CAPS = "REPLACE " + THREAD_CAPABILITIES.getName() + 
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + SUPPORTED_FEATURES_LIST_KEY.getName() + "' = ?s[" +
+            " WHERE '" + Key.AGENT_ID.getName() + "' = ?s AND " +
+                   "'" + Key.VM_ID.getName() + "' = ?s";
+    
     private Storage storage;
     
     public ThreadDaoImpl(Storage storage) {
@@ -138,24 +200,40 @@
     
     @Override
     public void saveCapabilities(VMThreadCapabilities caps) {
-        @SuppressWarnings("unchecked")
-        Replace<VMThreadCapabilities> replace = storage.createReplace(THREAD_CAPABILITIES);
-        ExpressionFactory factory = new ExpressionFactory();
-        String agentId = caps.getAgentId();
-        Expression agentKey = factory.equalTo(Key.AGENT_ID, agentId);
-        Expression vmKey = factory.equalTo(Key.VM_ID, caps.getVmId());
-        Expression and = factory.and(agentKey, vmKey);
-        replace.setPojo(caps);
-        replace.where(and);
-        replace.apply();
+        StatementDescriptor<VMThreadCapabilities> desc = new StatementDescriptor<>(THREAD_CAPABILITIES, DESC_REPLACE_THREAD_CAPS);
+        PreparedStatement<VMThreadCapabilities> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, caps.getAgentId());
+            prepared.setString(1, caps.getVmId());
+            prepared.setStringList(2, caps.getSupportedFeaturesList());
+            prepared.setString(3, caps.getAgentId());
+            prepared.setString(4, caps.getVmId());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
     
     @Override
     public void saveSummary(ThreadSummary summary) {
-        @SuppressWarnings("unchecked")
-        Add<ThreadSummary> add = storage.createAdd(THREAD_SUMMARY);
-        add.setPojo(summary);
-        add.apply();
+        StatementDescriptor<ThreadSummary> desc = new StatementDescriptor<>(THREAD_SUMMARY, DESC_ADD_THREAD_SUMMARY);
+        PreparedStatement<ThreadSummary> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, summary.getAgentId());
+            prepared.setString(1, summary.getVmId());
+            prepared.setLong(2, summary.getCurrentLiveThreads());
+            prepared.setLong(3, summary.getCurrentDaemonThreads());
+            prepared.setLong(4, summary.getTimeStamp());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
     
     @Override
@@ -209,10 +287,20 @@
 
     @Override
     public void saveHarvestingStatus(ThreadHarvestingStatus status) {
-        @SuppressWarnings("unchecked")
-        Add<ThreadHarvestingStatus> add = storage.createAdd(THREAD_HARVESTING_STATUS);
-        add.setPojo(status);
-        add.apply();
+        StatementDescriptor<ThreadHarvestingStatus> desc = new StatementDescriptor<>(THREAD_HARVESTING_STATUS, DESC_ADD_THREAD_HARVESTING_STATUS);
+        PreparedStatement<ThreadHarvestingStatus> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, status.getAgentId());
+            prepared.setString(1, status.getVmId());
+            prepared.setLong(2, status.getTimeStamp());
+            prepared.setBoolean(3, status.isHarvesting());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
@@ -241,10 +329,27 @@
 
     @Override
     public void saveThreadInfo(ThreadInfoData info) {
-        @SuppressWarnings("unchecked")
-        Add<ThreadInfoData> add = storage.createAdd(THREAD_INFO);
-        add.setPojo(info);
-        add.apply();
+        StatementDescriptor<ThreadInfoData> desc = new StatementDescriptor<>(THREAD_INFO, DESC_ADD_THREAD_INFO);
+        PreparedStatement<ThreadInfoData> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, info.getAgentId());
+            prepared.setString(1, info.getVmId());
+            prepared.setString(2, info.getThreadName());
+            prepared.setLong(3, info.getThreadId());
+            prepared.setString(4, info.getThreadState());
+            prepared.setLong(5, info.getAllocatedBytes());
+            prepared.setLong(6, info.getTimeStamp());
+            prepared.setLong(7, info.getThreadCpuTime());
+            prepared.setLong(8, info.getThreadUserTime());
+            prepared.setLong(9, info.getThreadBlockedCount());
+            prepared.setLong(10, info.getThreadWaitCount());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
@@ -298,10 +403,20 @@
 
     @Override
     public void saveDeadLockStatus(VmDeadLockData deadLockInfo) {
-        @SuppressWarnings("unchecked")
-        Add<VmDeadLockData> add = storage.createAdd(DEADLOCK_INFO);
-        add.setPojo(deadLockInfo);
-        add.apply();
+        StatementDescriptor<VmDeadLockData> desc = new StatementDescriptor<>(DEADLOCK_INFO, DESC_ADD_THREAD_DEADLOCK_DATA);
+        PreparedStatement<VmDeadLockData> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, deadLockInfo.getAgentId());
+            prepared.setString(1, deadLockInfo.getVmId());
+            prepared.setLong(2, deadLockInfo.getTimeStamp());
+            prepared.setString(3, deadLockInfo.getDeadLockDescription());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
     
     private <T extends Pojo> PreparedStatement<T> prepareQuery(Category<T> category, String query, VmRef ref) {
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -41,7 +41,6 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -50,21 +49,19 @@
 import java.util.NoSuchElementException;
 
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
 
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
-import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.VmRef;
+import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
 import com.redhat.thermostat.thread.model.VMThreadCapabilities;
@@ -86,6 +83,39 @@
         assertEquals(expectedQueryThreadInfo, ThreadDaoImpl.QUERY_THREAD_INFO);
         String expectedQueryThreadLatestDeadlockInfo = "QUERY vm-deadlock-data WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1";
         assertEquals(expectedQueryThreadLatestDeadlockInfo, ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO);
+        String addThreadSummary = "ADD vm-thread-summary SET 'agentId' = ?s , " +
+                                            "'vmId' = ?s , " +
+                                            "'currentLiveThreads' = ?l , " +
+                                            "'currentDaemonThreads' = ?l , " +
+                                            "'timeStamp' = ?l";
+        assertEquals(addThreadSummary, ThreadDaoImpl.DESC_ADD_THREAD_SUMMARY);
+        String addThreadHarvesting = "ADD vm-thread-harvesting SET 'agentId' = ?s , " +
+                                                    "'vmId' = ?s , " +
+                                                    "'timeStamp' = ?l , " +
+                                                    "'harvesting' = ?b";
+        assertEquals(addThreadHarvesting, ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS);
+        String addThreadInfo = "ADD vm-thread-info SET 'agentId' = ?s , " +
+                                    "'vmId' = ?s , " +
+                                    "'threadName' = ?s , " +
+                                    "'threadId' = ?l , " +
+                                    "'threadState' = ?s , " +
+                                    "'allocatedBytes' = ?l , " +
+                                    "'timeStamp' = ?l , " +
+                                    "'threadCpuTime' = ?l , " +
+                                    "'threadUserTime' = ?l , " +
+                                    "'threadBlockedCount' = ?l , " +
+                                    "'threadWaitCount' = ?l";
+        assertEquals(addThreadInfo, ThreadDaoImpl.DESC_ADD_THREAD_INFO);
+        String addDeadlockData = "ADD vm-deadlock-data SET 'agentId' = ?s , " +
+                                    "'vmId' = ?s , " +
+                                    "'timeStamp' = ?l , " +
+                                    "'deadLockDescription' = ?s";
+        assertEquals(addDeadlockData, ThreadDaoImpl.DESC_ADD_THREAD_DEADLOCK_DATA);
+        String replaceThreadCaps = "REPLACE vm-thread-capabilities SET 'agentId' = ?s , "+
+                                        "'vmId' = ?s , " +
+                                        "'supportedFeaturesList' = ?s[" +
+                                    " WHERE 'agentId' = ?s AND 'vmId' = ?s";
+        assertEquals(replaceThreadCaps, ThreadDaoImpl.DESC_REPLACE_THREAD_CAPS);
     }
     
     @Test
@@ -178,18 +208,13 @@
         assertEquals(null, caps);
     }
 
-    /*
-     * Tests saving of VMCapabilities when agentId has been explicitly set
-     * in thread capabilities model class. Every model class is required
-     * to set this explicitly.
-     */
+    @SuppressWarnings("unchecked")
     @Test
-    public void testSaveVMCapabilities() {
+    public void testSaveVMCapabilities() throws DescriptorParsingException, StatementExecutionException {
         String agentId = "fooAgent";
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Replace<VMThreadCapabilities> replace = mock(Replace.class);
-        when(storage.createReplace(eq(ThreadDao.THREAD_CAPABILITIES))).thenReturn(replace);
+        PreparedStatement<AgentInformation> replace = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(replace);
         
         String vmId = "VM42";
         VMThreadCapabilities caps = new VMThreadCapabilities(agentId);
@@ -203,19 +228,24 @@
         assertTrue(caps.supportCPUTime());
         assertTrue(caps.supportThreadAllocatedMemory());
         caps.setVmId(vmId);
+        
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         dao.saveCapabilities(caps);
         
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression agentExpr = factory.equalTo(Key.AGENT_ID, agentId);
-        Expression vmExpr = factory.equalTo(Key.VM_ID, vmId);
-        Expression expected = factory.and(agentExpr, vmExpr);
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(ThreadDaoImpl.DESC_REPLACE_THREAD_CAPS, desc.getDescriptor());
         
-        verify(storage).createReplace(ThreadDao.THREAD_CAPABILITIES);
-        verify(replace).setPojo(caps);
-        verify(replace).where(expected);
-        verify(replace).apply();
-        assertEquals(agentId, caps.getAgentId());
+        verify(replace).setString(0, caps.getAgentId());
+        verify(replace).setString(1, caps.getVmId());
+        verify(replace).setStringList(2, caps.getSupportedFeaturesList());
+        verify(replace).setString(3, caps.getAgentId());
+        verify(replace).setString(4, caps.getVmId());
+        verify(replace).execute();
+        verifyNoMoreInteractions(replace);
     }
 
     @Test
@@ -251,24 +281,36 @@
         verifyNoMoreInteractions(stmt);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testSaveDeadLockStatus() {
+    public void testSaveDeadLockStatus() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<VmDeadLockData> add = mock(Add.class);
-        when(storage.createAdd(ThreadDaoImpl.DEADLOCK_INFO)).thenReturn(add);
+        PreparedStatement<VmDeadLockData> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
         VmDeadLockData status = mock(VmDeadLockData.class);
 
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         dao.saveDeadLockStatus(status);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<VmDeadLockData> desc = captor.getValue();
+        assertEquals(ThreadDaoImpl.DESC_ADD_THREAD_DEADLOCK_DATA, desc.getDescriptor());
 
-        verify(add).setPojo(status);
-        verify(add).apply();
+        verify(add).setString(0, status.getAgentId());
+        verify(add).setString(1, status.getVmId());
+        verify(add).setLong(2, status.getTimeStamp());
+        verify(add).setString(3, status.getDeadLockDescription());
+        verify(add).execute();
+        Mockito.verifyNoMoreInteractions(add);
     }
 
     @Test
-    public void testGetLatestHarvestingStatus() throws DescriptorParsingException, StatementExecutionException {
+    public void testGetLatestHarvestingStatus()
+            throws DescriptorParsingException, StatementExecutionException {
         VmRef vm = mock(VmRef.class);
         when(vm.getVmId()).thenReturn("VM42");
 
@@ -300,20 +342,31 @@
         assertSame(status, result);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testSetHarvestingStatus() {
+    public void testAddHarvestingStatus() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<ThreadHarvestingStatus> add = mock(Add.class);
-        when(storage.createAdd(ThreadDaoImpl.THREAD_HARVESTING_STATUS)).thenReturn(add);
+        PreparedStatement<ThreadHarvestingStatus> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
         ThreadHarvestingStatus status = mock(ThreadHarvestingStatus.class);
 
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         dao.saveHarvestingStatus(status);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<VmDeadLockData> desc = captor.getValue();
+        assertEquals(ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS, desc.getDescriptor());
 
-        verify(add).setPojo(status);
-        verify(add).apply();
+        verify(add).setString(0, status.getAgentId());
+        verify(add).setString(1, status.getVmId());
+        verify(add).setLong(2, status.getTimeStamp());
+        verify(add).setBoolean(3, status.isHarvesting());
+        verify(add).execute();
+        verifyNoMoreInteractions(add);
     }
 }
 
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -37,8 +37,15 @@
 package com.redhat.thermostat.vm.classstat.common.internal;
 
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
-import com.redhat.thermostat.storage.core.Add;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.DescriptorParsingException;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.PreparedStatement;
+import com.redhat.thermostat.storage.core.StatementDescriptor;
+import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.VmLatestPojoListGetter;
 import com.redhat.thermostat.storage.core.VmRef;
@@ -46,6 +53,17 @@
 import com.redhat.thermostat.vm.classstat.common.model.VmClassStat;
 
 class VmClassStatDAOImpl implements VmClassStatDAO {
+    
+    private static final Logger logger = LoggingUtils.getLogger(VmClassStatDAOImpl.class);
+    // ADD vm-class-stats SET 'agentId' = ?s , \
+    //                        'vmId' = ?s , \
+    //                        'timeStamp' = ?l , \ 
+    //                        'loadedClasses' = ?l
+    static final String DESC_ADD_VM_CLASS_STAT = "ADD " + vmClassStatsCategory.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + loadedClassesKey.getName() + "' = ?l";
 
     private final Storage storage;
     private final VmLatestPojoListGetter<VmClassStat> getter;
@@ -63,9 +81,20 @@
 
     @Override
     public void putVmClassStat(VmClassStat stat) {
-        Add<VmClassStat> add = storage.createAdd(vmClassStatsCategory);
-        add.setPojo(stat);
-        add.apply();
+        StatementDescriptor<VmClassStat> desc = new StatementDescriptor<>(vmClassStatsCategory, DESC_ADD_VM_CLASS_STAT);
+        PreparedStatement<VmClassStat> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, stat.getAgentId());
+            prepared.setString(1, stat.getVmId());
+            prepared.setLong(2, stat.getTimeStamp());
+            prepared.setLong(3, stat.getLoadedClasses());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 }
 
--- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -39,7 +39,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -49,8 +48,8 @@
 import java.util.List;
 
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -70,6 +69,15 @@
     private static final Long LOADED_CLASSES = 12345L;
 
     @Test
+    public void testStatementDescriptorsAreSane() {
+        String addVmClassStat = "ADD vm-class-stats SET 'agentId' = ?s , " +
+                                                "'vmId' = ?s , " +
+                                                "'timeStamp' = ?l , " +
+                                                "'loadedClasses' = ?l";
+        assertEquals(addVmClassStat, VmClassStatDAOImpl.DESC_ADD_VM_CLASS_STAT);
+    }
+    
+    @Test
     public void testCategory() {
         assertEquals("vm-class-stats", VmClassStatDAO.vmClassStatsCategory.getName());
         Collection<Key<?>> keys = VmClassStatDAO.vmClassStatsCategory.getKeys();
@@ -129,21 +137,31 @@
         return new VmClassStat("foo-agent", VM_ID, TIMESTAMP, LOADED_CLASSES);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutVmClassStat() {
+    public void testPutVmClassStat() throws DescriptorParsingException, StatementExecutionException {
 
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<VmClassStat> add = mock(Add.class);
-        when(storage.createAdd(eq(VmClassStatDAO.vmClassStatsCategory))).thenReturn(add);
+        PreparedStatement<VmClassStat> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
         VmClassStat stat = new VmClassStat("foo-agent", VM_ID, TIMESTAMP, LOADED_CLASSES);
         VmClassStatDAO dao = new VmClassStatDAOImpl(storage);
         dao.putVmClassStat(stat);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(VmClassStatDAOImpl.DESC_ADD_VM_CLASS_STAT, desc.getDescriptor());
 
-        verify(storage).createAdd(VmClassStatDAO.vmClassStatsCategory);
-        verify(add).setPojo(stat);
-        verify(add).apply();
+        verify(add).setString(0, stat.getAgentId());
+        verify(add).setString(1, stat.getVmId());
+        verify(add).setLong(2, stat.getTimeStamp());
+        verify(add).setLong(3, stat.getLoadedClasses());
+        verify(add).execute();
+        verifyNoMoreInteractions(add);
     }
 }
 
--- a/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -37,8 +37,15 @@
 package com.redhat.thermostat.vm.cpu.common.internal;
 
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
-import com.redhat.thermostat.storage.core.Add;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.DescriptorParsingException;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.PreparedStatement;
+import com.redhat.thermostat.storage.core.StatementDescriptor;
+import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.VmLatestPojoListGetter;
 import com.redhat.thermostat.storage.core.VmRef;
@@ -46,7 +53,19 @@
 import com.redhat.thermostat.vm.cpu.common.model.VmCpuStat;
 
 public class VmCpuStatDAOImpl implements VmCpuStatDAO {
-
+    
+    private static final Logger logger = LoggingUtils.getLogger(VmCpuStatDAOImpl.class);
+    // ADD vm-cpu-stats SET 'agentId' = ?s , \
+    //                      'vmId' = ?s , \
+    //                      'timeStamp' = ?l , \
+    //                      'cpuLoad' = ?d
+    static final String DESC_ADD_VM_CPU_STAT = "ADD " + vmCpuStatCategory.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + vmCpuLoadKey.getName() + "' = ?d";
+    
+    
     private final Storage storage;
     private final VmLatestPojoListGetter<VmCpuStat> getter;
 
@@ -63,9 +82,20 @@
 
     @Override
     public void putVmCpuStat(VmCpuStat stat) {
-        Add<VmCpuStat> add = storage.createAdd(vmCpuStatCategory);
-        add.setPojo(stat);
-        add.apply();
+        StatementDescriptor<VmCpuStat> desc = new StatementDescriptor<>(vmCpuStatCategory, DESC_ADD_VM_CPU_STAT);
+        PreparedStatement<VmCpuStat> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, stat.getAgentId());
+            prepared.setString(1, stat.getVmId());
+            prepared.setLong(2, stat.getTimeStamp());
+            prepared.setDouble(3, stat.getCpuLoad());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 }
 
--- a/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -39,7 +39,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -50,8 +49,8 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -76,6 +75,15 @@
     public void setUp() {
         cpuStat = new VmCpuStat("foo-agent", TIMESTAMP, VM_ID, CPU_LOAD);
     }
+    
+    @Test
+    public void verifyDescriptorsAreSane() {
+        String addCpuStat = "ADD vm-cpu-stats SET 'agentId' = ?s , " +
+                                                "'vmId' = ?s , " +
+                                                "'timeStamp' = ?l , " +
+                                                "'cpuLoad' = ?d";
+        assertEquals(addCpuStat, VmCpuStatDAOImpl.DESC_ADD_VM_CPU_STAT);
+    }
 
     @Test
     public void testCategory() {
@@ -131,21 +139,30 @@
         return (StatementDescriptor<VmCpuStat>) any(StatementDescriptor.class);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutVmCpuStat() {
+    public void testPutVmCpuStat() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<VmCpuStat> add = mock(Add.class);
-        when(storage.createAdd(eq(VmCpuStatDAO.vmCpuStatCategory))).thenReturn(add);
+        PreparedStatement<VmCpuStat> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
         
         VmCpuStat stat = new VmCpuStat("foo-agent", TIMESTAMP, VM_ID, CPU_LOAD);
         VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage);
         dao.putVmCpuStat(stat);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(VmCpuStatDAOImpl.DESC_ADD_VM_CPU_STAT, desc.getDescriptor());
 
-        verify(storage).createAdd(VmCpuStatDAO.vmCpuStatCategory);
-        verify(add).setPojo(stat);
-        verify(add).apply();
-
+        verify(add).setString(0, stat.getAgentId());
+        verify(add).setString(1, stat.getVmId());
+        verify(add).setLong(2, stat.getTimeStamp());
+        verify(add).setDouble(3, stat.getCpuLoad());
+        verify(add).execute();
+        verifyNoMoreInteractions(add);
     }
 }
 
--- a/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -37,8 +37,15 @@
 package com.redhat.thermostat.vm.gc.common.internal;
 
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
-import com.redhat.thermostat.storage.core.Add;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.DescriptorParsingException;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.PreparedStatement;
+import com.redhat.thermostat.storage.core.StatementDescriptor;
+import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.VmLatestPojoListGetter;
 import com.redhat.thermostat.storage.core.VmRef;
@@ -46,6 +53,21 @@
 import com.redhat.thermostat.vm.gc.common.model.VmGcStat;
 
 public class VmGcStatDAOImpl implements VmGcStatDAO {
+    
+    private static Logger logger = LoggingUtils.getLogger(VmGcStatDAOImpl.class);
+    // ADD vm-gc-stats SET 'agentId' = ?s , \
+    //                     'vmId' = ?s , \
+    //                     'timeStamp' = ?l , \
+    //                     'collectorName' = ?s , \
+    //                     'runCount' = ?l , \
+    //                     'wallTime' = ?l
+    static final String DESC_ADD_VM_GC_STAT = "ADD " + vmGcStatCategory.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + collectorKey.getName() + "' = ?s , " +
+                 "'" + runCountKey.getName() + "' = ?l , " +
+                 "'" + wallTimeKey.getName() + "' = ?l";
 
     private final Storage storage;
     private final VmLatestPojoListGetter<VmGcStat> getter;
@@ -63,9 +85,22 @@
 
     @Override
     public void putVmGcStat(VmGcStat stat) {
-        Add add = storage.createAdd(vmGcStatCategory);
-        add.setPojo(stat);
-        add.apply();
+        StatementDescriptor<VmGcStat> desc = new StatementDescriptor<>(vmGcStatCategory, DESC_ADD_VM_GC_STAT);
+        PreparedStatement<VmGcStat> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, stat.getAgentId());
+            prepared.setString(1, stat.getVmId());
+            prepared.setLong(2, stat.getTimeStamp());
+            prepared.setString(3, stat.getCollectorName());
+            prepared.setLong(4, stat.getRunCount());
+            prepared.setLong(5, stat.getWallTime());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
 }
--- a/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -48,9 +48,8 @@
 import java.util.List;
 
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -70,6 +69,17 @@
     private static final String COLLECTOR = "collector1";
     private static final Long RUN_COUNT = 10L;
     private static final Long WALL_TIME = 9L;
+    
+    @Test
+    public void verifyDescriptorsAreSane() {
+        String addVmGcStat = "ADD vm-gc-stats SET 'agentId' = ?s , " +
+                                    "'vmId' = ?s , " +
+                                    "'timeStamp' = ?l , " +
+                                    "'collectorName' = ?s , " +
+                                    "'runCount' = ?l , " +
+                                    "'wallTime' = ?l";
+        assertEquals(addVmGcStat, VmGcStatDAOImpl.DESC_ADD_VM_GC_STAT);
+    }
 
     @Test
     public void testCategory() {
@@ -131,19 +141,33 @@
         return (StatementDescriptor<VmGcStat>) any(StatementDescriptor.class);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutVmGcStat() {
+    public void testPutVmGcStat() throws DescriptorParsingException,
+            StatementExecutionException {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        PreparedStatement<VmGcStat> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
         
         VmGcStat stat = new VmGcStat("foo-agent", VM_ID, TIMESTAMP, COLLECTOR, RUN_COUNT, WALL_TIME);
         VmGcStatDAO dao = new VmGcStatDAOImpl(storage);
         dao.putVmGcStat(stat);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(VmGcStatDAOImpl.DESC_ADD_VM_GC_STAT, desc.getDescriptor());
 
-        verify(storage).createAdd(VmGcStatDAO.vmGcStatCategory);
-        verify(add).setPojo(stat);
-        verify(add).apply();
+        verify(add).setString(0, stat.getAgentId());
+        verify(add).setString(1, stat.getVmId());
+        verify(add).setLong(2, stat.getTimeStamp());
+        verify(add).setString(3, stat.getCollectorName());
+        verify(add).setLong(4, stat.getRunCount());
+        verify(add).setLong(5, stat.getWallTime());
+        verify(add).execute();
+        verifyNoMoreInteractions(add);
     }
 }
 
--- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -51,7 +51,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.Key;
@@ -68,6 +67,9 @@
 public class HeapDAOImpl implements HeapDAO {
 
     private static final Logger log = LoggingUtils.getLogger(HeapDAOImpl.class);
+    
+    // Query descriptors
+    
     static final String QUERY_ALL_HEAPS = "QUERY "
             + heapInfoCategory.getName() + " WHERE '" 
             + Key.AGENT_ID.getName() + "' = ?s AND '" 
@@ -76,6 +78,22 @@
             + heapInfoCategory.getName() + " WHERE '" 
             + heapIdKey.getName() + "' = ?s LIMIT 1";
 
+    // Write descriptors
+    
+    // ADD vm-heap-info SET 'agentId' = ?s , \
+    //                      'vmId' = ?s , \
+    //                      'timeStamp' = ?l , \
+    //                      'heapId' = ?s , \
+    //                      'heapDumpId' = ?s , \
+    //                      'histogramId' = ?s
+    static final String DESC_ADD_VM_HEAP_INFO = "ADD " + heapInfoCategory.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + heapIdKey.getName() + "' = ?s , " +
+                 "'" + heapDumpIdKey.getName() + "' = ?s , " +
+                 "'" + histogramIdKey.getName() + "' = ?s";
+    
     private final Storage storage;
 
     HeapDAOImpl(Storage storage) {
@@ -96,9 +114,7 @@
         if (histogramData != null) {
             heapInfo.setHistogramId(histogramId);
         }
-        Add<HeapInfo> add = storage.createAdd(heapInfoCategory);
-        add.setPojo(heapInfo);
-        add.apply();
+        addHeapInfo(heapInfo);
 
         if (heapDumpData != null) {
             storage.saveFile(heapDumpId, new FileInputStream(heapDumpData));
@@ -117,6 +133,25 @@
         }
     }
 
+    private void addHeapInfo(HeapInfo heapInfo) {
+        StatementDescriptor<HeapInfo> desc = new StatementDescriptor<>(heapInfoCategory, DESC_ADD_VM_HEAP_INFO);
+        PreparedStatement<HeapInfo> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, heapInfo.getAgentId());
+            prepared.setString(1, heapInfo.getVmId());
+            prepared.setLong(2, heapInfo.getTimeStamp());
+            prepared.setString(3, heapInfo.getHeapId());
+            prepared.setString(4, heapInfo.getHeapDumpId());
+            prepared.setString(5, heapInfo.getHistogramId());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            log.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            log.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
+    }
+
     @Override
     public Collection<HeapInfo> getAllHeapInfo(VmRef vm) {
         StatementDescriptor<HeapInfo> desc = new StatementDescriptor<>(heapInfoCategory, QUERY_ALL_HEAPS);
--- a/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -62,7 +62,6 @@
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
@@ -85,23 +84,14 @@
 
     private HeapDAO dao;
     private Storage storage;
-    private Add<HeapInfo> add;
     private HeapInfo heapInfo;
     private File heapDumpData;
     private ObjectHistogram histogram;
     private InputStream histogramData;
 
-    private PreparedStatement<HeapInfo> stmt;
-
-    @SuppressWarnings("unchecked")
     @Before
     public void setUp() throws IOException, DescriptorParsingException, StatementExecutionException {
         storage = mock(Storage.class);
-        add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
-
-        stmt = (PreparedStatement<HeapInfo>) mock(PreparedStatement.class); 
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
 
         dao = new HeapDAOImpl(storage);
         
@@ -114,7 +104,14 @@
         out.close();
         histogramData = createHistogramData();
 
-        Cursor<HeapInfo> cursor = (Cursor<HeapInfo>) mock(Cursor.class);
+        // Setup for reading heapdump data.
+        when(storage.loadFile("test-heap")).thenReturn(new ByteArrayInputStream(data));
+        when(storage.loadFile("test-histo")).thenReturn(histogramData);
+    }
+
+    private Cursor<HeapInfo> getMockCursor(String writerId) {
+        @SuppressWarnings("unchecked")
+        Cursor<HeapInfo> cursor = mock(Cursor.class);
         HeapInfo info1 = new HeapInfo(writerId, "vm2", 12345L);
         info1.setAgentId("123");
         info1.setHeapId("testheap1");
@@ -129,14 +126,7 @@
 
         when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(info1).thenReturn(info2).thenReturn(null);
-        when(stmt.executeQuery()).thenReturn(cursor);
-
-        // Setup for reading heapdump data.
-        when(storage.loadFile("test-heap")).thenReturn(new ByteArrayInputStream(data));
-        when(storage.loadFile("test-histo")).thenReturn(histogramData);
-
-        // We dont check for AGENT_ID. That's enforced/added/checked by Storage
-
+        return cursor;
     }
 
     @SuppressWarnings("unchecked")
@@ -173,7 +163,6 @@
 
     @After
     public void tearDown() {
-        stmt = null;
         histogramData = null;
         histogram = null;
         heapDumpData.delete();
@@ -181,7 +170,6 @@
         heapInfo = null;
         dao = null;
         storage = null;
-        add = null;
     }
     
     @Test
@@ -190,6 +178,14 @@
         assertEquals(expectedQueryHeapInfo, HeapDAOImpl.QUERY_HEAP_INFO);
         String expectedQueryAllHeaps = "QUERY vm-heap-info WHERE 'agentId' = ?s AND 'vmId' = ?s";
         assertEquals(expectedQueryAllHeaps, HeapDAOImpl.QUERY_ALL_HEAPS);
+        
+        String addHeapInfo = "ADD vm-heap-info SET 'agentId' = ?s , " +
+                                                "'vmId' = ?s , " +
+                                                "'timeStamp' = ?l , " +
+                                                "'heapId' = ?s , " +
+                                                "'heapDumpId' = ?s , " +
+                                                "'histogramId' = ?s";
+        assertEquals(addHeapInfo, HeapDAOImpl.DESC_ADD_VM_HEAP_INFO);
     }
 
     @Test
@@ -206,14 +202,38 @@
         assertTrue(keys.contains(new Key<>("heapDumpId")));
         assertTrue(keys.contains(new Key<>("histogramId")));
     }
+    
+    @SuppressWarnings("unchecked")
+    private void doAddHeapInfoVerifications(Storage storage,
+            PreparedStatement<?> add, HeapInfo info)
+            throws StatementExecutionException, DescriptorParsingException {
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(HeapDAOImpl.DESC_ADD_VM_HEAP_INFO, desc.getDescriptor());
+        
+        verify(add).setString(0, info.getAgentId());
+        verify(add).setString(1, info.getVmId());
+        verify(add).setLong(2, info.getTimeStamp());
+        verify(add).setString(3, info.getHeapId());
+        verify(add).setString(4, info.getHeapDumpId());
+        verify(add).setString(5, info.getHistogramId());
+        verify(add).execute();
+        verifyNoMoreInteractions(add);
+    }
 
     @Test
-    public void testPutHeapInfo() throws IOException {
+    public void testPutHeapInfo() throws IOException,
+            StatementExecutionException, DescriptorParsingException {
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HeapInfo> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(add);
+        
         dao.putHeapInfo(heapInfo, heapDumpData, histogram);
 
-        verify(storage).createAdd(HeapDAO.heapInfoCategory);
-        verify(add).setPojo(heapInfo);
-        verify(add).apply();
+        doAddHeapInfoVerifications(storage, add, heapInfo);
 
         ArgumentCaptor<InputStream> data = ArgumentCaptor.forClass(InputStream.class);
         verify(storage).saveFile(eq("heapdump-test-vm1-12345"), data.capture());
@@ -236,12 +256,15 @@
     }
 
     @Test
-    public void testPutHeapInfoWithoutDump() throws IOException {
+    public void testPutHeapInfoWithoutDump() throws IOException,
+            StatementExecutionException, DescriptorParsingException {
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HeapInfo> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(add);
+        
         dao.putHeapInfo(heapInfo, null, null);
 
-        verify(storage).createAdd(HeapDAO.heapInfoCategory);
-        verify(add).setPojo(heapInfo);
-        verify(add).apply();
+        doAddHeapInfoVerifications(storage, add, heapInfo);
 
         verify(storage, never()).saveFile(anyString(), any(InputStream.class));
         assertEquals("test-vm1-12345", heapInfo.getHeapId());
@@ -255,6 +278,14 @@
         
         HostRef host = new HostRef("123", "test-host");
         VmRef vm = new VmRef(host, "vm2", 234, "test-vm");
+        
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HeapInfo> stmt = mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        
+        Cursor<HeapInfo> cursor = getMockCursor("foo-agent");
+        when(stmt.executeQuery()).thenReturn(cursor);
+        
         Collection<HeapInfo> heapInfos = dao.getAllHeapInfo(vm);
 
         verify(storage).prepareStatement(anyDescriptor());
@@ -282,6 +313,13 @@
     public void testGetHeapInfo() throws DescriptorParsingException, StatementExecutionException {
         final String heapId = "testheap1";
         
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HeapInfo> stmt = mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        
+        Cursor<HeapInfo> cursor = getMockCursor("foo-agent");
+        when(stmt.executeQuery()).thenReturn(cursor);
+        
         HeapInfo result = dao.getHeapInfo(heapId);
         
         verify(storage).prepareStatement(anyDescriptor());
@@ -318,7 +356,11 @@
     }
 
     @Test
-    public void testInvalidHeapId() throws IOException, StatementExecutionException {
+    public void testInvalidHeapId() throws IOException,
+            StatementExecutionException, DescriptorParsingException {
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HeapInfo> stmt = mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
         when(stmt.executeQuery()).thenThrow(new IllegalArgumentException("invalid ObjectId"));
         dao = new HeapDAOImpl(storage);
         heapInfo = dao.getHeapInfo("some-random-heap-id");
--- a/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -43,7 +43,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
@@ -59,7 +58,7 @@
 
 public class JmxNotificationDAOImpl implements JmxNotificationDAO {
 
-    private static final Key<Boolean> NOTIFICATIONS_ENABLED = new Key<>("notififcationsEnabled");
+    private static final Key<Boolean> NOTIFICATIONS_ENABLED = new Key<>("enabled");
     private static final Logger logger = LoggingUtils.getLogger(JmxNotificationDAOImpl.class);
 
     static final Category<JmxNotificationStatus> NOTIFICATION_STATUS =
@@ -74,7 +73,9 @@
             new Category<>("vm-jmx-notification", JmxNotification.class,
                     Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP,
                     SOURCE_BACKEND, SOURCE_DETAILS, CONTENTS);
-
+    
+    // Query descriptors
+            
     static final String QUERY_LATEST_NOTIFICATION_STATUS = "QUERY "
             + NOTIFICATION_STATUS.getName() + " WHERE '"
             + Key.AGENT_ID.getName() + "' = ?s AND '" 
@@ -86,6 +87,31 @@
             + Key.VM_ID.getName() + "' = ?s AND '"
             + Key.TIMESTAMP.getName() + "' > ?l";
     
+    // Write descriptors
+    
+    // ADD vm-jmx-notification-status SET 'agentId' = ?s , \
+    //                                    'vmId' = ?s , \
+    //                                    'timeStamp' = ?l , \
+    //                                    'enabled' = ?b
+    static final String DESC_ADD_NOTIFICATION_STATUS = "ADD " + NOTIFICATION_STATUS.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + NOTIFICATIONS_ENABLED.getName() + "' = ?b";
+    // ADD vm-jmx-notification SET 'agentId' = ?s , \
+    //                             'vmId' = ?s , \
+    //                             'timeStamp' = ?l , \
+    //                             'contents' = ?s , \
+    //                             'sourceDetails' = ?s , \
+    //                             'sourceBackend' = ?s
+    static final String DESC_ADD_NOTIFICATION = "ADD " + NOTIFICATIONS.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + CONTENTS.getName() + "' = ?s , " +
+                 "'" + SOURCE_DETAILS.getName() + "' = ?s , " +
+                 "'" + SOURCE_BACKEND.getName() + "' = ?s";
+    
     private Storage storage;
 
     public JmxNotificationDAOImpl(Storage storage) {
@@ -96,9 +122,20 @@
 
     @Override
     public void addNotificationStatus(JmxNotificationStatus status) {
-        Add<JmxNotificationStatus> add = storage.createAdd(NOTIFICATION_STATUS);
-        add.setPojo(status);
-        add.apply();
+        StatementDescriptor<JmxNotificationStatus> desc = new StatementDescriptor<>(NOTIFICATION_STATUS, DESC_ADD_NOTIFICATION_STATUS);
+        PreparedStatement<JmxNotificationStatus> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, status.getAgentId());
+            prepared.setString(1, status.getVmId());
+            prepared.setLong(2, status.getTimeStamp());
+            prepared.setBoolean(3, status.isEnabled());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
@@ -132,9 +169,22 @@
 
     @Override
     public void addNotification(JmxNotification notification) {
-        Add<JmxNotification> add = storage.createAdd(NOTIFICATIONS);
-        add.setPojo(notification);
-        add.apply();
+        StatementDescriptor<JmxNotification> desc = new StatementDescriptor<>(NOTIFICATIONS, DESC_ADD_NOTIFICATION);
+        PreparedStatement<JmxNotification> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, notification.getAgentId());
+            prepared.setString(1, notification.getVmId());
+            prepared.setLong(2, notification.getTimeStamp());
+            prepared.setString(3, notification.getContents());
+            prepared.setString(4, notification.getSourceDetails());
+            prepared.setString(5, notification.getSourceBackend());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
--- a/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -49,8 +49,8 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -94,20 +94,46 @@
         assertEquals(expectedQueryLatestNotificationStatus, JmxNotificationDAOImpl.QUERY_LATEST_NOTIFICATION_STATUS);
         String expectedQueryNotifications = "QUERY vm-jmx-notification WHERE 'agentId' = ?s AND 'vmId' = ?s AND 'timeStamp' > ?l";
         assertEquals(expectedQueryNotifications, JmxNotificationDAOImpl.QUERY_NOTIFICATIONS);
+        String addNotificationStatus = "ADD vm-jmx-notification-status SET 'agentId' = ?s , " +
+                                            "'vmId' = ?s , " +
+                                            "'timeStamp' = ?l , " +
+                                            "'enabled' = ?b";
+        assertEquals(addNotificationStatus, JmxNotificationDAOImpl.DESC_ADD_NOTIFICATION_STATUS);
+        String addNotificationDesc = "ADD vm-jmx-notification SET 'agentId' = ?s , " +
+                                            "'vmId' = ?s , " +
+                                            "'timeStamp' = ?l , " +
+                                            "'contents' = ?s , " +
+                                            "'sourceDetails' = ?s , " +
+                                            "'sourceBackend' = ?s";
+        assertEquals(addNotificationDesc, JmxNotificationDAOImpl.DESC_ADD_NOTIFICATION);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void verifyAddNotificationStatus() {
-        @SuppressWarnings("unchecked")
-        Add<JmxNotificationStatus> add = mock(Add.class);
-        when(storage.createAdd(JmxNotificationDAOImpl.NOTIFICATION_STATUS)).thenReturn(add);
+    public void verifyAddNotificationStatus()
+            throws DescriptorParsingException, StatementExecutionException {
+        PreparedStatement<JmxNotificationStatus> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
-        JmxNotificationStatus data = mock(JmxNotificationStatus.class);
+        JmxNotificationStatus data = new JmxNotificationStatus("foo-agent");
+        data.setVmId("foo-vmId");
+        data.setEnabled(true);
+        data.setTimeStamp(System.currentTimeMillis());
 
         dao.addNotificationStatus(data);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(JmxNotificationDAOImpl.DESC_ADD_NOTIFICATION_STATUS, desc.getDescriptor());
 
-        verify(add).setPojo(data);
-        verify(add).apply();
+        verify(add).setString(0, data.getAgentId());
+        verify(add).setString(1, data.getVmId());
+        verify(add).setLong(2, data.getTimeStamp());
+        verify(add).setBoolean(3, data.isEnabled());
+        verify(add).execute();
         verifyNoMoreInteractions(add);
     }
 
@@ -142,18 +168,36 @@
         return (StatementDescriptor<T>) any(StatementDescriptor.class);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void verfiyAddNotification() {
-        @SuppressWarnings("unchecked")
-        Add<JmxNotification> add = mock(Add.class);
-        when(storage.createAdd(JmxNotificationDAOImpl.NOTIFICATIONS)).thenReturn(add);
+    public void verfiyAddNotification() throws DescriptorParsingException,
+            StatementExecutionException {
+        PreparedStatement<JmxNotificationStatus> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
 
-        JmxNotification data = mock(JmxNotification.class);
+        JmxNotification data = new JmxNotification("foo-agent");
+        data.setVmId("foo-vmId");
+        data.setContents("something-content");
+        data.setTimeStamp(System.currentTimeMillis());
+        data.setSourceBackend("foo-source-backend");
+        data.setSourceDetails("foo-source-details");
 
         dao.addNotification(data);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(JmxNotificationDAOImpl.DESC_ADD_NOTIFICATION, desc.getDescriptor());
 
-        verify(add).setPojo(data);
-        verify(add).apply();
+        verify(add).setString(0, data.getAgentId());
+        verify(add).setString(1, data.getVmId());
+        verify(add).setLong(2, data.getTimeStamp());
+        verify(add).setString(3, data.getContents());
+        verify(add).setString(4, data.getSourceDetails());
+        verify(add).setString(5, data.getSourceBackend());
+        verify(add).execute();
         verifyNoMoreInteractions(add);
     }
 
--- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Mon Sep 16 15:28:13 2013 +0200
@@ -41,7 +41,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.Key;
@@ -62,6 +61,15 @@
             + Key.AGENT_ID.getName() + "' = ?s AND '" 
             + Key.VM_ID.getName() + "' = ?s SORT '" 
             + Key.TIMESTAMP.getName() + "' DSC LIMIT 1";
+    // ADD vm-memory-stats SET 'agentId' = ?s , \
+    //                         'vmId' = ?s , \
+    //                         'timeStamp' = ?s , \
+    //                         'generations' = ?p[
+    static final String DESC_ADD_VM_MEMORY_STAT = "ADD " + vmMemoryStatsCategory.getName() +
+            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
+                 "'" + Key.VM_ID.getName() + "' = ?s , " +
+                 "'" + Key.TIMESTAMP.getName() + "' = ?l , " +
+                 "'" + generationsKey.getName() + "' = ?p[";
     
     private final Storage storage;
     private final VmLatestPojoListGetter<VmMemoryStat> getter;
@@ -101,9 +109,20 @@
 
     @Override
     public void putVmMemoryStat(VmMemoryStat stat) {
-        Add<VmMemoryStat> add = storage.createAdd(vmMemoryStatsCategory);
-        add.setPojo(stat);
-        add.apply();
+        StatementDescriptor<VmMemoryStat> desc = new StatementDescriptor<>(vmMemoryStatsCategory, DESC_ADD_VM_MEMORY_STAT);
+        PreparedStatement<VmMemoryStat> prepared;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, stat.getAgentId());
+            prepared.setString(1, stat.getVmId());
+            prepared.setLong(2, stat.getTimeStamp());
+            prepared.setPojoList(3, stat.getGenerations());
+            prepared.execute();
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
+        }
     }
 
     @Override
--- a/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Wed Sep 18 18:15:22 2013 +0200
+++ b/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Mon Sep 16 15:28:13 2013 +0200
@@ -39,7 +39,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -52,8 +51,9 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
 
-import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -116,6 +116,11 @@
     public void preparedQueryDescriptorsAreSane() {
         String expectedQueryThreadCaps = "QUERY vm-memory-stats WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1";
         assertEquals(expectedQueryThreadCaps, VmMemoryStatDAOImpl.QUERY_LATEST);
+        String addVmMemoryStat = "ADD vm-memory-stats SET 'agentId' = ?s , " +
+                                        "'vmId' = ?s , " +
+                                        "'timeStamp' = ?l , " +
+                                        "'generations' = ?p[";
+        assertEquals(addVmMemoryStat, VmMemoryStatDAOImpl.DESC_ADD_VM_MEMORY_STAT);
     }
 
     @Test
@@ -171,8 +176,10 @@
         assertTrue(latest == null);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
-    public void testPutVmMemoryStat() {
+    public void testPutVmMemoryStat() throws DescriptorParsingException,
+            StatementExecutionException {
 
         List<Generation> generations = new ArrayList<Generation>();
 
@@ -205,16 +212,25 @@
         VmMemoryStat stat = new VmMemoryStat("foo-agent", 1, "vmId", generations.toArray(new Generation[generations.size()]));
 
         Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Add<VmMemoryStat> add = mock(Add.class);
-        when(storage.createAdd(eq(VmMemoryStatDAO.vmMemoryStatsCategory))).thenReturn(add);
+        PreparedStatement<VmMemoryStat> add = mock(PreparedStatement.class);
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
         
         VmMemoryStatDAO dao = new VmMemoryStatDAOImpl(storage);
         dao.putVmMemoryStat(stat);
+        
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
+        
+        verify(storage).prepareStatement(captor.capture());
+        StatementDescriptor<?> desc = captor.getValue();
+        assertEquals(VmMemoryStatDAOImpl.DESC_ADD_VM_MEMORY_STAT, desc.getDescriptor());
 
-        verify(storage).createAdd(VmMemoryStatDAO.vmMemoryStatsCategory);
-        verify(add).setPojo(stat);
-        verify(add).apply();
+        verify(add).setString(0, stat.getAgentId());
+        verify(add).setString(1, stat.getVmId());
+        verify(add).setLong(2, stat.getTimeStamp());
+        verify(add).setPojoList(3, stat.getGenerations());
+        verify(add).execute();
+        Mockito.verifyNoMoreInteractions(add);
     }
     
 }