changeset 1169:340d6f755eb7

Convert all queries to prepared statements This commit builds off b6722888e6b3, and converts all queries in Thermostat to use prepared statements. Now the only users of Storage.createQuery are the prepared statement code and storage implementations themselves. As a next step, we should block access to createQuery outside of these remaining cases. Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-July/007303.html
author Elliott Baron <ebaron@redhat.com>
date Mon, 15 Jul 2013 12:52:59 -0400
parents b6722888e6b3
children 0a210b878276
files host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.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/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/core/HostLatestPojoListGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatement.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.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/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java storage/core/src/test/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetterTest.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/impl/ThreadDaoImpl.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.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/agent/src/main/java/com/redhat/thermostat/vm/jmx/agent/internal/JmxBackend.java vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/JmxNotificationDAO.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 33 files changed, 1155 insertions(+), 648 deletions(-) [+]
line wrap: on
line diff
--- a/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -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;
@@ -58,12 +57,13 @@
 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.Query;
+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.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class CpuStatDAOTest {
 
@@ -79,12 +79,13 @@
     }
 
     @Test
-    public void testGetLatestCpuStats() {
+    public void testGetLatestCpuStats() throws DescriptorParsingException, StatementExecutionException {
 
         @SuppressWarnings("unchecked")
-        Cursor<CpuStat> cursor = mock(Cursor.class);
+        Cursor<CpuStat> cursor = (Cursor<CpuStat>) mock(Cursor.class);
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<CpuStat> stmt = (PreparedStatement<CpuStat>) mock(PreparedStatement.class);
         HostRef hostRef = mock(HostRef.class);
         CpuStatDAO dao = new CpuStatDAOImpl(storage);
 
@@ -94,17 +95,17 @@
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(cpuStat);
 
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
         when(hostRef.getAgentId()).thenReturn("system");
 
         List<CpuStat> cpuStats = dao.getLatestCpuStats(hostRef, Long.MIN_VALUE);
 
-        Expression expr = createWhereExpression();
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "system");
+        verify(stmt).setLong(1, Long.MIN_VALUE);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertEquals(1, cpuStats.size());
         CpuStat stat = cpuStats.get(0);
@@ -113,19 +114,18 @@
 
     }
 
-    private Expression createWhereExpression() {
-        ExpressionFactory factory = new ExpressionFactory();
-        return factory.and(factory.equalTo(Key.AGENT_ID, "system"),
-                factory.greaterThan(Key.TIMESTAMP, Long.MIN_VALUE));
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<CpuStat> anyDescriptor() {
+        return (StatementDescriptor<CpuStat>) any(StatementDescriptor.class);
     }
 
     @Test
-    public void testGetLatestCpuStatsTwice() {
-
+    public void testGetLatestCpuStatsTwice() throws DescriptorParsingException, StatementExecutionException {
         @SuppressWarnings("unchecked")
-        Cursor<CpuStat> cursor = mock(Cursor.class);
+        Cursor<CpuStat> cursor = (Cursor<CpuStat>) mock(Cursor.class);
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<CpuStat> stmt = (PreparedStatement<CpuStat>) mock(PreparedStatement.class);
         HostRef hostRef = mock(HostRef.class);
 
         CpuStatDAO dao = new CpuStatDAOImpl(storage);
@@ -135,16 +135,18 @@
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(cpuStat);
 
-        when(storage.createQuery(CpuStatDAO.cpuStatCategory)).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
         when(hostRef.getAgentId()).thenReturn("system");
 
         dao.getLatestCpuStats(hostRef, Long.MIN_VALUE);
         dao.getLatestCpuStats(hostRef, Long.MIN_VALUE);
 
-        Expression expr = createWhereExpression();
-        verify(query, times(2)).execute();
-        verify(query, atLeastOnce()).where(eq(expr));
+        verify(storage, atLeastOnce()).prepareStatement(anyDescriptor());
+        verify(stmt, times(2)).setString(0, "system");
+        verify(stmt, times(2)).setLong(1, Long.MIN_VALUE);
+        verify(stmt, times(2)).executeQuery();
+        verifyNoMoreInteractions(stmt);
     }
 
     @Test
--- a/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -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;
@@ -55,12 +54,13 @@
 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.Query;
+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.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class MemoryStatDAOTest {
 
@@ -90,7 +90,7 @@
     }
 
     @Test
-    public void testGetLatestMemoryStats() {
+    public void testGetLatestMemoryStats() throws DescriptorParsingException, StatementExecutionException {
 
         MemoryStat memStat1 = new MemoryStat(TIMESTAMP, TOTAL, FREE, BUFFERS, CACHED, SWAP_TOTAL, SWAP_FREE, COMMIT_LIMIT);
 
@@ -100,9 +100,10 @@
         when(cursor.next()).thenReturn(memStat1);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<MemoryStat> stmt = (PreparedStatement<MemoryStat>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -110,13 +111,11 @@
         MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
         List<MemoryStat> memoryStats = dao.getLatestMemoryStats(hostRef, Long.MIN_VALUE);
 
-        verify(storage).createQuery(MemoryStatDAO.memoryStatCategory);
-        
-        Expression expr = createWhereExpression();
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "system");
+        verify(stmt).setLong(1, Long.MIN_VALUE);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertEquals(1, memoryStats.size());
         MemoryStat stat = memoryStats.get(0);
@@ -131,6 +130,11 @@
         assertEquals(COMMIT_LIMIT, stat.getCommitLimit());
     }
 
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<MemoryStat> anyDescriptor() {
+        return (StatementDescriptor<MemoryStat>) any(StatementDescriptor.class);
+    }
+
     @Test
     public void testPutMemoryStat() {
         Storage storage = mock(Storage.class);
@@ -155,10 +159,5 @@
         assertEquals((Long) 5L, count);
     }
     
-    private Expression createWhereExpression() {
-        ExpressionFactory factory = new ExpressionFactory();
-        return factory.and(factory.equalTo(Key.AGENT_ID, "system"),
-                factory.greaterThan(Key.TIMESTAMP, Long.MIN_VALUE));
-    }
 }
 
--- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -37,27 +37,35 @@
 package com.redhat.thermostat.numa.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.numa.common.NumaDAO;
 import com.redhat.thermostat.numa.common.NumaHostInfo;
 import com.redhat.thermostat.numa.common.NumaStat;
 import com.redhat.thermostat.storage.core.Cursor;
+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.Put;
-import com.redhat.thermostat.storage.core.Query;
 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.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class NumaDAOImpl implements NumaDAO {
 
+    private static final Logger logger = LoggingUtils.getLogger(NumaDAOImpl.class);
+    private static final String QUERY_NUMA_INFO = "QUERY "
+            + numaHostCategory.getName() + " WHERE " 
+            + Key.AGENT_ID.getName() + " = ?s LIMIT 1";
+    
     private final Storage storage;
     private final HostLatestPojoListGetter<NumaStat> getter;
 
-
     NumaDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(numaStatCategory);
@@ -88,14 +96,25 @@
 
     @Override
     public int getNumberOfNumaNodes(HostRef ref) {
-        Query<NumaHostInfo> query = storage.createQuery(numaHostCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.equalTo(Key.AGENT_ID, ref.getAgentId());
-        query.where(expr);
-        query.limit(1);
-        Cursor<NumaHostInfo> numaHostInfo = query.execute();
-        if (numaHostInfo.hasNext()) {
-            return numaHostInfo.next().getNumNumaNodes();
+        StatementDescriptor<NumaHostInfo> desc = new StatementDescriptor<>(numaHostCategory, QUERY_NUMA_INFO);
+        PreparedStatement<NumaHostInfo> stmt;
+        Cursor<NumaHostInfo> cursor;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, ref.getAgentId());
+            cursor = stmt.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return 0;
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return 0;
+        }
+        
+        if (cursor.hasNext()) {
+            return cursor.next().getNumNumaNodes();
         } else {
             return 0;
         }
--- a/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -34,9 +34,10 @@
  * to do so, delete this exception statement from your version.
  */
 
-
 package com.redhat.thermostat.numa.common.internal;
 
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -47,9 +48,17 @@
 import org.junit.Test;
 
 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;
+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 NumaDAOImplTest {
@@ -102,5 +111,36 @@
         verify(add).apply();
         verifyNoMoreInteractions(add);
     }
+    
+    @Test
+    public void testGetNumberOfNumaNodes() throws DescriptorParsingException, StatementExecutionException {
+        NumaHostInfo info = mock(NumaHostInfo.class);
+        when(info.getNumNumaNodes()).thenReturn(2);
+        
+        @SuppressWarnings("unchecked")
+        PreparedStatement<NumaHostInfo> stmt = (PreparedStatement<NumaHostInfo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        @SuppressWarnings("unchecked")
+        Cursor<NumaHostInfo> cursor = (Cursor<NumaHostInfo>) mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(info).thenReturn(null);
+        when(stmt.executeQuery()).thenReturn(cursor);
+        
+        final String agentId = "system";
+        HostRef hostRef = mock(HostRef.class);
+        when(hostRef.getAgentId()).thenReturn(agentId);
+        int result = numaDAO.getNumberOfNumaNodes(hostRef);
+        assertEquals(2, result);
+        
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, agentId);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
+    }
+
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<NumaHostInfo> anyDescriptor() {
+        return (StatementDescriptor<NumaHostInfo>) any(StatementDescriptor.class);
+    }
 }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetter.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetter.java	Mon Jul 15 12:52:59 2013 -0400
@@ -37,29 +37,48 @@
 package com.redhat.thermostat.storage.core;
 
 import java.util.ArrayList;
+import java.util.Collections;
 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.storage.model.TimeStampedPojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class HostLatestPojoListGetter<T extends TimeStampedPojo> {
 
+    private static final Logger logger = LoggingUtils.getLogger(HostLatestPojoListGetter.class);
+    
     private final Storage storage;
     private final Category<T> cat;
+    private final String queryLatest;
 
     public HostLatestPojoListGetter(Storage storage, Category<T> cat) {
         this.storage = storage;
         this.cat = cat;
+        this.queryLatest = "QUERY " + cat.getName() + " WHERE "
+                + Key.AGENT_ID.getName() + " = ?s AND "
+                + Key.TIMESTAMP.getName() + " > ?l SORT "
+                + Key.TIMESTAMP.getName() + " DSC";
     }
 
     public List<T> getLatest(HostRef hostRef, long since) {
-        Query<T> query = buildQuery(hostRef, since);
+        PreparedStatement<T> query = buildQuery(hostRef, since);
+        if (query == null) {
+            return Collections.emptyList();
+        }
         return getLatest(query);
     }
 
-    private List<T> getLatest(Query<T> query) {
-        Cursor<T> cursor = query.execute();
+    private List<T> getLatest(PreparedStatement<T> query) {
+        Cursor<T> cursor;
+        try {
+            cursor = query.executeQuery();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + query + "' failed!", e);
+            return Collections.emptyList();
+        }
         List<T> result = new ArrayList<>();
         while (cursor.hasNext()) {
             T pojo = cursor.next();
@@ -68,15 +87,18 @@
         return result;
     }
 
-    protected Query<T> buildQuery(HostRef hostRef, long since) {
-        Query<T> query = storage.createQuery(cat);
-        // AGENT_ID == hostRef.getAgentId() && TIMESTAMP > since
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(factory.equalTo(Key.AGENT_ID, hostRef.getAgentId()), 
-                factory.greaterThan(Key.TIMESTAMP, since));
-        query.where(expr);
-        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        return query;
+    PreparedStatement<T> buildQuery(HostRef hostRef, long since) {
+        StatementDescriptor<T> desc = new StatementDescriptor<>(cat, queryLatest);
+        PreparedStatement<T> stmt = null;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, hostRef.getAgentId());
+            stmt.setLong(1, since);
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+        }
+        return stmt;
     }
 }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatement.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatement.java	Mon Jul 15 12:52:59 2013 -0400
@@ -50,8 +50,4 @@
      */
     int getId();
     
-    /**
-     * @return the {@link StatementDescriptor} that describes this statement.
-     */
-    StatementDescriptor<T> getDescriptor();
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java	Mon Jul 15 12:52:59 2013 -0400
@@ -37,29 +37,50 @@
 package com.redhat.thermostat.storage.core;
 
 import java.util.ArrayList;
+import java.util.Collections;
 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.storage.model.TimeStampedPojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class VmLatestPojoListGetter<T extends TimeStampedPojo> {
+    
+    private static final Logger logger = LoggingUtils.getLogger(VmLatestPojoListGetter.class);
 
     private final Storage storage;
     private final Category<T> cat;
+    private final String queryLatest;
 
     public VmLatestPojoListGetter(Storage storage, Category<T> cat) {
         this.storage = storage;
         this.cat = cat;
+        this.queryLatest = "QUERY " + cat.getName() + " WHERE "
+                + Key.AGENT_ID.getName() + " = ?s AND "
+                + Key.VM_ID.getName() + " = ?i AND " 
+                + Key.TIMESTAMP.getName() + " > ?l SORT "
+                + Key.TIMESTAMP.getName() + " DSC";
     }
 
     public List<T> getLatest(VmRef vmRef, long since) {
-        Query<T> query = buildQuery(vmRef, since);
+        PreparedStatement<T> query = buildQuery(vmRef, since);
+        if (query == null) {
+            return Collections.emptyList();
+        }
         return getLatest(query);
     }
 
-    private List<T> getLatest(Query<T> query) {
-        Cursor<T> cursor = query.execute();
+    private List<T> getLatest(PreparedStatement<T> query) {
+        Cursor<T> cursor;
+        try {
+            cursor = query.executeQuery();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + query + "' failed!", e);
+            return Collections.emptyList();
+        }
+        
         List<T> result = new ArrayList<>();
         while (cursor.hasNext()) {
             T pojo = cursor.next();
@@ -68,16 +89,19 @@
         return result;
     }
 
-    protected Query<T> buildQuery(VmRef vmRef, long since) {
-        Query<T> query = storage.createQuery(cat);
-        // AGENT_ID == getAgentId() && VM_ID == getId() && TIMESTAMP > since
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(factory.equalTo(Key.AGENT_ID, vmRef.getAgent().getAgentId()),
-                factory.and(factory.equalTo(Key.VM_ID, vmRef.getId()),
-                        factory.greaterThan(Key.TIMESTAMP, since)));
-        query.where(expr);
-        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        return query;
+    protected PreparedStatement<T> buildQuery(VmRef vmRef, long since) {
+        StatementDescriptor<T> desc = new StatementDescriptor<>(cat, queryLatest);
+        PreparedStatement<T> stmt = null;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, vmRef.getAgent().getAgentId());
+            stmt.setInt(1, vmRef.getId());
+            stmt.setLong(2, since);
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+        }
+        return stmt;
     }
 
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -62,6 +62,15 @@
 public class AgentInfoDAOImpl implements AgentInfoDAO {
 
     private static final Logger logger = LoggingUtils.getLogger(AgentInfoDAOImpl.class);
+    private static final String QUERY_AGENT_INFO = "QUERY "
+            + CATEGORY.getName() + " WHERE " 
+            + Key.AGENT_ID.getName() + " = ?s";
+    private static final String QUERY_ALL_AGENTS = "QUERY "
+            + CATEGORY.getName();
+    private static final String QUERY_ALIVE_AGENTS = "QUERY "
+            + CATEGORY.getName() + " WHERE " 
+            + ALIVE_KEY.getName() + " = ?b";
+    
     private final Storage storage;
     private final ExpressionFactory factory;
 
@@ -78,8 +87,7 @@
 
     @Override
     public List<AgentInformation> getAllAgentInformation() {
-        String allAgentsQuery = "QUERY " + CATEGORY.getName();
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, allAgentsQuery);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, QUERY_ALL_AGENTS);
         PreparedStatement<AgentInformation> prepared = null;
         Cursor<AgentInformation> agentCursor = null;
         try {
@@ -105,15 +113,12 @@
 
     @Override
     public List<AgentInformation> getAliveAgents() {
-        // QUERY agent-config WHERE ? = true
-        String allAgentsQuery = "QUERY " + CATEGORY.getName() + " WHERE ?s = ?b";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, allAgentsQuery);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, QUERY_ALIVE_AGENTS);
         PreparedStatement<AgentInformation> prepared = null;
         Cursor<AgentInformation> agentCursor = null;
         try {
             prepared = storage.prepareStatement(desc);
-            prepared.setString(0, ALIVE_KEY.getName());
-            prepared.setBoolean(1, true);
+            prepared.setBoolean(0, true);
             agentCursor = prepared.executeQuery();
         } catch (DescriptorParsingException e) {
             // should not happen, but if it *does* happen, at least log it
@@ -135,14 +140,12 @@
 
     @Override
     public AgentInformation getAgentInformation(HostRef agentRef) {
-        String query = "QUERY " + CATEGORY.getName() + " WHERE ?s = ?s";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, query);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, QUERY_AGENT_INFO);
         PreparedStatement<AgentInformation> prepared;
         Cursor<AgentInformation> agentCursor;
         try {
             prepared = storage.prepareStatement(desc);
-            prepared.setString(0, Key.AGENT_ID.getName());
-            prepared.setString(1, agentRef.getAgentId());
+            prepared.setString(0, agentRef.getAgentId());
             agentCursor = prepared.executeQuery();
         } catch (DescriptorParsingException e) {
             // should not happen, but if it *does* happen, at least log it
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -39,14 +39,20 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.OrderedComparator;
+import com.redhat.thermostat.common.utils.LoggingUtils;
 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.Put;
-import com.redhat.thermostat.storage.core.Query;
 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;
@@ -54,6 +60,11 @@
 import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class BackendInfoDAOImpl implements BackendInfoDAO {
+    
+    private static final Logger logger = LoggingUtils.getLogger(BackendInfoDAOImpl.class);
+    private static final String QUERY_BACKEND_INFO = "QUERY "
+            + CATEGORY.getName() + " WHERE " 
+            + Key.AGENT_ID.getName() + " = ?s";
 
     private final Storage storage;
     private final ExpressionFactory factory;
@@ -66,13 +77,24 @@
 
     @Override
     public List<BackendInformation> getBackendInformation(HostRef host) {
-        // Sort by order value
-        Query<BackendInformation> query = storage.createQuery(CATEGORY);
-        Expression expr = factory.equalTo(Key.AGENT_ID, host.getAgentId());
-        query.where(expr);
-
+        StatementDescriptor<BackendInformation> desc = new StatementDescriptor<>(CATEGORY, QUERY_BACKEND_INFO);
+        PreparedStatement<BackendInformation> prepared;
+        Cursor<BackendInformation> cursor;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, host.getAgentId());
+            cursor = prepared.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        }
+        
         List<BackendInformation> results = new ArrayList<>();
-        Cursor<BackendInformation> cursor = query.execute();
         while (cursor.hasNext()) {
             BackendInformation backendInfo = cursor.next();
             results.add(backendInfo);
@@ -97,6 +119,6 @@
         Remove remove = storage.createRemove().from(CATEGORY).where(expr);
         storage.removePojo(remove);
     }
-
+    
 }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -38,22 +38,33 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 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.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.Put;
-import com.redhat.thermostat.storage.core.Query;
+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.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.HostInfo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class HostInfoDAOImpl implements HostInfoDAO {
+    
+    private static final Logger logger = LoggingUtils.getLogger(HostInfoDAOImpl.class);
+    private static final String QUERY_HOST_INFO = "QUERY "
+            + hostInfoCategory.getName() + " WHERE " 
+            + Key.AGENT_ID.getName() + " = ?s LIMIT 1";
+    private static final String QUERY_ALL_HOSTS = "QUERY " + hostInfoCategory.getName();
 
     private final Storage storage;
     private final AgentInfoDAO agentInfoDao;
@@ -67,12 +78,31 @@
 
     @Override
     public HostInfo getHostInfo(HostRef ref) {
-        Query<HostInfo> query = storage.createQuery(hostInfoCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.equalTo(Key.AGENT_ID, ref.getAgentId());
-        query.where(expr);
-        query.limit(1);
-        HostInfo result = query.execute().next();
+        return getHostInfo(ref.getAgentId());
+    }
+
+    private HostInfo getHostInfo(String agentId) {
+        StatementDescriptor<HostInfo> desc = new StatementDescriptor<>(hostInfoCategory, QUERY_HOST_INFO);
+        PreparedStatement<HostInfo> prepared;
+        Cursor<HostInfo> cursor;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, agentId);
+            cursor = prepared.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return null;
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return null;
+        }
+        
+        HostInfo result = null;
+        if (cursor.hasNext()) {
+            result = cursor.next();
+        }
         return result;
     }
 
@@ -85,8 +115,28 @@
 
     @Override
     public Collection<HostRef> getHosts() {
-        Query<HostInfo> allHosts = storage.createQuery(hostInfoCategory);
-        return getHosts(allHosts);
+        StatementDescriptor<HostInfo> desc = new StatementDescriptor<>(hostInfoCategory, QUERY_ALL_HOSTS);
+        PreparedStatement<HostInfo> prepared;
+        Cursor<HostInfo> cursor;
+        try {
+            prepared = storage.prepareStatement(desc);
+            cursor = prepared.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        }
+        
+        List<HostRef> result = new ArrayList<>();
+        while (cursor.hasNext()) {
+            HostInfo hostInfo = cursor.next();
+            result.add(toHostRef(hostInfo));
+        }
+        return result;
     }
 
     @Override
@@ -94,33 +144,24 @@
         List<HostRef> hosts = new ArrayList<>();
         List<AgentInformation> agentInfos = agentInfoDao.getAliveAgents();
         for (AgentInformation agentInfo : agentInfos) {
-            Query<HostInfo> filter = storage.createQuery(hostInfoCategory);
-            ExpressionFactory factory = new ExpressionFactory();
-            Expression expr = factory.equalTo(Key.AGENT_ID, agentInfo.getAgentId());
-            filter.where(expr);
-            hosts.addAll(getHosts(filter));
+            HostInfo hostInfo = getHostInfo(agentInfo.getAgentId());
+            hosts.add(toHostRef(hostInfo));
         }
 
         return hosts;
     }
 
 
-    private Collection<HostRef> getHosts(Query<HostInfo> filter) {
-        Collection<HostRef> hosts = new ArrayList<HostRef>();
-        
-        Cursor<HostInfo> hostsCursor = filter.execute();
-        while(hostsCursor.hasNext()) {
-            HostInfo host = hostsCursor.next();
-            String agentId = host.getAgentId();
-            String hostName = host.getHostname();
-            hosts.add(new HostRef(agentId, hostName));
-        }
-        return hosts;
+    private HostRef toHostRef(HostInfo hostInfo) {
+        String agentId = hostInfo.getAgentId();
+        String hostName = hostInfo.getHostname();
+        return new HostRef(agentId, hostName);
     }
 
     @Override
     public long getCount() {
         return storage.getCount(hostInfoCategory);
     }
+    
 }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -37,21 +37,31 @@
 package com.redhat.thermostat.storage.internal.dao;
 
 import java.util.ArrayList;
+import java.util.Collections;
 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.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.Put;
-import com.redhat.thermostat.storage.core.Query;
+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 {
 
+    private static final Logger logger = LoggingUtils.getLogger(NetworkInterfaceInfoDAOImpl.class);
+    private static final String QUERY_NETWORK_INFO = "QUERY "
+            + networkInfoCategory.getName() + " WHERE "
+            + Key.AGENT_ID.getName() + " = ?s";
+
     private Storage storage;
 
     public NetworkInterfaceInfoDAOImpl(Storage storage) {
@@ -61,12 +71,23 @@
 
     @Override
     public List<NetworkInterfaceInfo> getNetworkInterfaces(HostRef ref) {
-        Query<NetworkInterfaceInfo> allHostNetworkInterfaces = storage.createQuery(networkInfoCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.equalTo(Key.AGENT_ID, ref.getAgentId());
-        allHostNetworkInterfaces.where(expr);
+        StatementDescriptor<NetworkInterfaceInfo> desc = new StatementDescriptor<>(networkInfoCategory, QUERY_NETWORK_INFO);
+        PreparedStatement<NetworkInterfaceInfo> stmt;
+        Cursor<NetworkInterfaceInfo> cursor;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, ref.getAgentId());
+            cursor = stmt.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        }
 
-        Cursor<NetworkInterfaceInfo> cursor = allHostNetworkInterfaces.execute();
         List<NetworkInterfaceInfo> result = new ArrayList<>();
         while (cursor.hasNext()) {
             NetworkInterfaceInfo stat = cursor.next();
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -38,13 +38,20 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 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.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.Put;
-import com.redhat.thermostat.storage.core.Query;
+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;
@@ -55,7 +62,16 @@
 import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class VmInfoDAOImpl implements VmInfoDAO {
-
+    
+    private final Logger logger = LoggingUtils.getLogger(VmInfoDAOImpl.class);
+    private final String QUERY_VM_INFO = "QUERY " 
+            + vmInfoCategory.getName() + " WHERE " 
+            + Key.AGENT_ID.getName() + " = ?s AND "
+            + Key.VM_ID.getName() + " = ?i LIMIT 1";
+    private final String QUERY_ALL_VMS = "QUERY " 
+            + vmInfoCategory.getName() + " WHERE " 
+            + Key.AGENT_ID.getName() + " = ?s";
+    
     private final Storage storage;
     private final ExpressionFactory factory;
 
@@ -67,16 +83,30 @@
 
     @Override
     public VmInfo getVmInfo(VmRef ref) {
-        Query<VmInfo> findMatchingVm = storage.createQuery(vmInfoCategory);
-        // AGENT_ID == getAgentId() && VM_ID == getId()
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(
-                factory.equalTo(Key.AGENT_ID, ref.getAgent().getAgentId()),
-                factory.equalTo(Key.VM_ID, ref.getId()));
-        findMatchingVm.where(expr);
-        findMatchingVm.limit(1);
-        VmInfo result = findMatchingVm.execute().next();
-        if (result == null) {
+        StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(vmInfoCategory, QUERY_VM_INFO);
+        PreparedStatement<VmInfo> stmt;
+        Cursor<VmInfo> cursor;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, ref.getAgent().getAgentId());
+            stmt.setInt(1, ref.getId());
+            cursor = stmt.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return null;
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return null;
+        }
+        
+        VmInfo result;
+        if (cursor.hasNext()) {
+            result = cursor.next();
+        }
+        else {
+            // FIXME this is inconsistent with null returned elsewhere
             throw new DAOException("Unknown VM: host:" + ref.getAgent().getAgentId() + ";vm:" + ref.getId());
         }
         return result;
@@ -84,19 +114,25 @@
 
     @Override
     public Collection<VmRef> getVMs(HostRef host) {
-
-        Query<VmInfo> query = buildQuery(host);
-        Cursor<VmInfo> cursor = query.execute();
+        StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(vmInfoCategory, QUERY_ALL_VMS);
+        PreparedStatement<VmInfo> stmt;
+        Cursor<VmInfo> cursor;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, host.getAgentId());
+            cursor = stmt.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        }
         return buildVMsFromQuery(cursor, host);
     }
 
-    private Query<VmInfo> buildQuery(HostRef host) {
-        Query<VmInfo> query = storage.createQuery(vmInfoCategory);
-        Expression expr = factory.equalTo(Key.AGENT_ID, host.getAgentId());
-        query.where(expr);
-        return query;
-    }
-
     private Collection<VmRef> buildVMsFromQuery(Cursor<VmInfo> cursor, HostRef host) {
         List<VmRef> vmRefs = new ArrayList<VmRef>();
         while (cursor.hasNext()) {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -156,7 +156,7 @@
     }
 
     @Override
-    public StatementDescriptor<T> getDescriptor() {
-        return desc;
+    public String toString() {
+        return desc.getQueryDescriptor();
     }
 }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetterTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetterTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -40,7 +40,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -54,8 +53,6 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class HostLatestPojoListGetterTest {
     private static final String AGENT_ID = "agentid";
@@ -102,28 +99,34 @@
     }
 
     @Test
-    public void testBuildQuery() {
+    public void testBuildQuery() throws DescriptorParsingException {
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when (storage.createQuery(any(Category.class))).thenReturn(query);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
 
         HostLatestPojoListGetter<TestPojo> getter = new HostLatestPojoListGetter<>(storage, cat);
         query = getter.buildQuery(ref, 123);
 
         assertNotNull(query);
-        verify(storage).createQuery(cat);
-        Expression expr = createWhereExpression(123l);
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(query).setString(0, ref.getAgentId());
+        verify(query).setLong(1, 123L);
         verifyNoMoreInteractions(query);
     }
 
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<TestPojo> anyDescriptor() {
+        return (StatementDescriptor<TestPojo>) any(StatementDescriptor.class);
+    }
+
     @Test
-    public void testBuildQueryPopulatesUpdateTimes() {
+    public void testBuildQueryPopulatesUpdateTimes() throws DescriptorParsingException {
         Storage storage = mock(Storage.class);
-        Query ignored = mock(Query.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(ignored).thenReturn(query);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<TestPojo> ignored = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(ignored).thenReturn(query);
 
         HostLatestPojoListGetter<TestPojo> getter = new HostLatestPojoListGetter<>(storage, cat);
         ignored = getter.buildQuery(ref,Long.MIN_VALUE); // Ignore first return value.
@@ -131,32 +134,29 @@
         query = getter.buildQuery(ref, Long.MIN_VALUE);
 
         assertNotNull(query);
-        verify(storage, times(2)).createQuery(cat);
-        Expression expr = createWhereExpression(Long.MIN_VALUE);
-        verify(query).where(expr);
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(storage, times(2)).prepareStatement(anyDescriptor());
+        verify(query).setString(0, ref.getAgentId());
+        verify(query).setLong(1, Long.MIN_VALUE);
         verifyNoMoreInteractions(query);
     }
 
     @Test
-    public void testGetLatest() {
+    public void testGetLatest() throws DescriptorParsingException, StatementExecutionException {
         @SuppressWarnings("unchecked")
         Cursor<TestPojo> cursor = mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
+        when(query.executeQuery()).thenReturn(cursor);
 
         HostLatestPojoListGetter<TestPojo> getter = new HostLatestPojoListGetter<>(storage, cat);
 
         List<TestPojo> stats = getter.getLatest(ref, Long.MIN_VALUE);
 
-        Expression expr = createWhereExpression(Long.MIN_VALUE);
-        verify(query).where(expr);
-
         assertNotNull(stats);
         assertEquals(2, stats.size());
         TestPojo stat1 = stats.get(0);
@@ -167,11 +167,6 @@
         assertArrayEquals(new double[] {load5_2, load10_2, load15_2}, stat2.getData(), 0.001);
     }
 
-    private Expression createWhereExpression(long time) {
-        ExpressionFactory factory = new ExpressionFactory();
-        return factory.and(factory.equalTo(Key.AGENT_ID, AGENT_ID), factory.greaterThan(Key.TIMESTAMP, time));
-    }
-
     @After
     public void tearDown() {
         ref = null;
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetterTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetterTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -39,7 +39,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -52,8 +51,6 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 
 public class VmLatestPojoListGetterTest {
     private static final String AGENT_ID = "agentid";
@@ -81,9 +78,6 @@
     public void setUp() {
         hostRef = new HostRef(AGENT_ID, HOSTNAME);
         vmRef = new VmRef(hostRef, VM_PID, MAIN_CLASS);
-        //result1 = new VmClassStat(VM_PID, t1, lc1);
-        //result2 = new VmClassStat(VM_PID, t2, lc2);
-        //result3 = new VmClassStat(VM_PID, t3, lc3);
         result1 = mock(TestPojo.class);
         when(result1.getTimeStamp()).thenReturn(t1);
         when(result1.getData()).thenReturn(lc1);
@@ -96,70 +90,71 @@
     }
 
     @Test
-    public void testBuildQuery() {
+    public void testBuildQuery() throws DescriptorParsingException {
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
 
         VmLatestPojoListGetter<TestPojo> getter = new VmLatestPojoListGetter<>(storage, cat);
         query = getter.buildQuery(vmRef, 123l);
 
         assertNotNull(query);
-        verify(storage).createQuery(cat);
-        Expression expr = createWhereExpression(123l);
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(query).setString(0, AGENT_ID);
+        verify(query).setInt(1, VM_PID);
+        verify(query).setLong(2, 123l);
         verifyNoMoreInteractions(query);
     }
 
-    private Expression createWhereExpression(long time) {
-        ExpressionFactory factory = new ExpressionFactory();
-        return factory.and(
-                factory.equalTo(Key.AGENT_ID, AGENT_ID),
-                factory.and(factory.equalTo(Key.VM_ID, VM_PID),
-                        factory.greaterThan(Key.TIMESTAMP, time)));
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<TestPojo> anyDescriptor() {
+        return (StatementDescriptor<TestPojo>) any(StatementDescriptor.class);
     }
 
     @Test
-    public void testBuildQueryPopulatesUpdateTimes() {
+    public void testBuildQueryPopulatesUpdateTimes() throws DescriptorParsingException {
         Storage storage = mock(Storage.class);
-        Query ignored = mock(Query.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(ignored).thenReturn(query);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<TestPojo> ignored = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(ignored).thenReturn(query);
 
         VmLatestPojoListGetter<TestPojo> getter = new VmLatestPojoListGetter<>(storage, cat);
         getter.buildQuery(vmRef, Long.MIN_VALUE); // Ignore first return value.
         query = getter.buildQuery(vmRef, Long.MIN_VALUE);
 
         assertNotNull(query);
-        verify(storage, times(2)).createQuery(cat);
-        Expression expr = createWhereExpression(Long.MIN_VALUE);
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(storage, times(2)).prepareStatement(anyDescriptor());
+        verify(query).setString(0, AGENT_ID);
+        verify(query).setInt(1, VM_PID);
+        verify(query).setLong(2, Long.MIN_VALUE);
         verifyNoMoreInteractions(query);
     }
 
     @Test
-    public void testGetLatest() {
+    public void testGetLatest() throws DescriptorParsingException, StatementExecutionException {
         @SuppressWarnings("unchecked")
         Cursor<TestPojo> cursor = mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
+        when(query.executeQuery()).thenReturn(cursor);
 
         VmLatestPojoListGetter<TestPojo> getter = new VmLatestPojoListGetter<>(storage, cat);
 
         List<TestPojo> stats = getter.getLatest(vmRef, t2);
 
-        verify(storage).createQuery(cat);
-        Expression expr = createWhereExpression(t2);
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        verify(query).execute();
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(query).setString(0, AGENT_ID);
+        verify(query).setInt(1, VM_PID);
+        verify(query).setLong(2, t2);
+        verify(query).executeQuery();
         verifyNoMoreInteractions(query);
 
         assertNotNull(stats);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -166,8 +166,7 @@
 
         verify(storage).prepareStatement(anyDescriptor());
         verify(stmt).executeQuery();
-        verify(stmt).setString(eq(0), eq(AgentInfoDAOImpl.ALIVE_KEY.getName()));
-        verify(stmt).setBoolean(eq(1), eq(true));
+        verify(stmt).setBoolean(0, true);
         verifyNoMoreInteractions(stmt);
 
         assertEquals(1, aliveAgents.size());
@@ -217,8 +216,7 @@
         AgentInformation computed = dao.getAgentInformation(agentRef);
 
         verify(storage).prepareStatement(anyDescriptor());
-        verify(stmt).setString(0, Key.AGENT_ID.getName());
-        verify(stmt).setString(1, agentInfo1.getAgentId());
+        verify(stmt).setString(0, agentInfo1.getAgentId());
         verify(stmt).executeQuery();
         verifyNoMoreInteractions(stmt);
         AgentInformation expected = agentInfo1;
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -57,18 +57,18 @@
 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.Query;
+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.BinaryComparisonExpression;
-import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
 import com.redhat.thermostat.storage.query.Expression;
 import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.storage.query.LiteralExpression;
 
 public class BackendInfoDAOTest {
 
@@ -101,13 +101,13 @@
 
     @Test
     public void verifyCategoryName() {
-        Category c = BackendInfoDAO.CATEGORY;
+        Category<BackendInformation> c = BackendInfoDAO.CATEGORY;
         assertEquals("backend-info", c.getName());
     }
 
     @Test
     public void verifyCategoryHasAllKeys() {
-        Category c = BackendInfoDAO.CATEGORY;
+        Category<BackendInformation> c = BackendInfoDAO.CATEGORY;
         Collection<Key<?>> keys = c.getKeys();
 
         assertTrue(keys.contains(Key.AGENT_ID));
@@ -135,34 +135,39 @@
     }
 
     @Test
-    public void verifyGetBackendInformation() {
+    public void verifyGetBackendInformation() throws DescriptorParsingException, StatementExecutionException {
         final String AGENT_ID = "agent-id";
         HostRef agentref = mock(HostRef.class);
         when(agentref.getAgentId()).thenReturn(AGENT_ID);
 
         @SuppressWarnings("unchecked")
-        Cursor<BackendInformation> backendCursor = mock(Cursor.class);
+        Cursor<BackendInformation> backendCursor = (Cursor<BackendInformation>) mock(Cursor.class);
         when(backendCursor.hasNext()).thenReturn(true).thenReturn(false);
         when(backendCursor.next()).thenReturn(backend1).thenReturn(null);
 
-        Query query = mock(Query.class);
         Storage storage = mock(Storage.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(backendCursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<BackendInformation> stmt = (PreparedStatement<BackendInformation>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(backendCursor);
 
         BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
 
         List<BackendInformation> result = dao.getBackendInformation(agentref);
 
-        verify(storage).createQuery(BackendInfoDAO.CATEGORY);
-        Expression expr = factory.equalTo(Key.AGENT_ID, AGENT_ID);
-        verify(query).where(eq(expr));
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, AGENT_ID);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertEquals(Arrays.asList(backendInfo1), result);
     }
 
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<BackendInformation> anyDescriptor() {
+        return (StatementDescriptor<BackendInformation>) any(StatementDescriptor.class);
+    }
+
     @Test
     public void verifyRemoveBackendInformation() {
         Remove remove = QueryTestHelper.createMockRemove();
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -53,9 +53,12 @@
 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.Query;
+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.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
@@ -65,13 +68,15 @@
 
 public class HostInfoDAOTest {
 
-    static class Pair<T,U> {
-        final T first;
-        final U second;
+    static class Triple<S, T, U> {
+        final S first;
+        final T second;
+        final U third;
 
-        public Pair(T first, U second) {
+        public Triple(S first, T second, U third) {
             this.first = first;
             this.second = second;
+            this.third = third;
         }
     }
 
@@ -97,24 +102,35 @@
     }
 
     @Test
-    public void testGetHostInfo() {
-
+    public void testGetHostInfo() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HostInfo> prepared = (PreparedStatement<HostInfo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(prepared);
+
         HostInfo info = new HostInfo(HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
-        Cursor cursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        Cursor<HostInfo> cursor = (Cursor<HostInfo>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(info).thenReturn(null);
-        when(query.execute()).thenReturn(cursor);
+        when(prepared.executeQuery()).thenReturn(cursor);
         AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
 
         HostInfo result = new HostInfoDAOImpl(storage, agentInfoDao).getHostInfo(new HostRef("some uid", HOST_NAME));
+        
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(prepared).setString(0, "some uid");
+        verify(prepared).executeQuery();
         assertSame(result, info);
     }
+    
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<HostInfo> anyDescriptor() {
+        return (StatementDescriptor<HostInfo>) any(StatementDescriptor.class);
+    }
 
     @Test
-    public void testGetHostsSingleHost() {
+    public void testGetHostsSingleHost() throws DescriptorParsingException, StatementExecutionException {
 
         Storage storage = setupStorageForSingleHost();
         AgentInfoDAO agentInfo = mock(AgentInfoDAO.class);
@@ -126,26 +142,25 @@
         assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
     }
 
-    private Storage setupStorageForSingleHost() {
-
+    private Storage setupStorageForSingleHost() throws DescriptorParsingException, StatementExecutionException {
         HostInfo hostConfig = new HostInfo("fluffhost1", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
         hostConfig.setAgentId("123");
 
         @SuppressWarnings("unchecked")
-        Cursor<HostInfo> cursor = mock(Cursor.class);
+        Cursor<HostInfo> cursor = (Cursor<HostInfo>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(hostConfig);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
-        
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HostInfo> stmt = (PreparedStatement<HostInfo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
         return storage;
     }
 
     @Test
-    public void testGetHosts3Hosts() {
+    public void testGetHosts3Hosts() throws DescriptorParsingException, StatementExecutionException {
 
         Storage storage = setupStorageFor3Hosts();
         AgentInfoDAO agentInfo = mock(AgentInfoDAO.class);
@@ -159,7 +174,7 @@
         assertTrue(hosts.contains(new HostRef("789", "fluffhost3")));
     }
 
-    private Storage setupStorageFor3Hosts() {
+    private Storage setupStorageFor3Hosts() throws DescriptorParsingException, StatementExecutionException {
 
         HostInfo hostConfig1 = new HostInfo("fluffhost1", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
         hostConfig1.setAgentId("123");
@@ -170,14 +185,15 @@
 
 
         @SuppressWarnings("unchecked")
-        Cursor<HostInfo> cursor = mock(Cursor.class);
+        Cursor<HostInfo> cursor = (Cursor<HostInfo>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(hostConfig1).thenReturn(hostConfig2).thenReturn(hostConfig3);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HostInfo> stmt = (PreparedStatement<HostInfo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
         
         return storage;
     }
@@ -211,20 +227,24 @@
     }
     
     @Test
-    public void getAliveHostSingle() {
-        Pair<Storage, AgentInfoDAO> setup = setupForSingleAliveHost();
+    public void getAliveHostSingle() throws DescriptorParsingException, StatementExecutionException {
+        Triple<Storage, AgentInfoDAO, PreparedStatement<HostInfo>> setup = setupForSingleAliveHost();
         Storage storage = setup.first;
         AgentInfoDAO agentInfoDao = setup.second;
+        PreparedStatement<HostInfo> stmt = setup.third;
 
         HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage, agentInfoDao);
         Collection<HostRef> hosts = hostsDAO.getAliveHosts();
 
         assertEquals(1, hosts.size());
         assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
-        verify(storage).createQuery(HostInfoDAO.hostInfoCategory);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "123");
+        verify(stmt).executeQuery();
     }
     
-    private Pair<Storage, AgentInfoDAO> setupForSingleAliveHost() {
+    private Triple<Storage, AgentInfoDAO, PreparedStatement<HostInfo>> setupForSingleAliveHost()
+            throws DescriptorParsingException, StatementExecutionException {
         
         // agents
         
@@ -256,22 +276,23 @@
         // storage
         
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor1);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HostInfo> stmt = (PreparedStatement<HostInfo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor1);
 
         AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
         when(agentDao.getAliveAgents()).thenReturn(Arrays.asList(agentInfo1));
 
-        return new Pair<>(storage, agentDao);
+        return new Triple<>(storage, agentDao, stmt);
     }
 
     @Test
-    public void getAliveHost3() {
-        Pair<Storage, AgentInfoDAO> setup = setupForAliveHost3();
+    public void getAliveHost3() throws DescriptorParsingException, StatementExecutionException {
+        Triple<Storage, AgentInfoDAO, PreparedStatement<HostInfo>> setup = setupForAliveHost3();
         Storage storage = setup.first;
         AgentInfoDAO agentInfoDao = setup.second;
+        PreparedStatement<HostInfo> stmt = setup.third;
 
         HostInfoDAO hostsDAO = new HostInfoDAOImpl(storage, agentInfoDao);
         Collection<HostRef> hosts = hostsDAO.getAliveHosts();
@@ -281,10 +302,15 @@
         assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
         assertTrue(hosts.contains(new HostRef("456", "fluffhost2")));
         assertTrue(hosts.contains(new HostRef("678", "fluffhost3")));
-        verify(storage, atLeast(3)).createQuery(HostInfoDAO.hostInfoCategory);
+        verify(storage, atLeast(3)).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "123");
+        verify(stmt).setString(0, "456");
+        verify(stmt).setString(0, "678");
+        verify(stmt, atLeast(3)).executeQuery();
     }
     
-    private Pair<Storage, AgentInfoDAO> setupForAliveHost3() {
+    private Triple<Storage, AgentInfoDAO, PreparedStatement<HostInfo>> setupForAliveHost3()
+            throws DescriptorParsingException, StatementExecutionException {
         
         // agents
         AgentInformation agentInfo1 = new AgentInformation();
@@ -331,14 +357,15 @@
         // storage
         
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor1).thenReturn(cursor2).thenReturn(cursor3);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<HostInfo> stmt = (PreparedStatement<HostInfo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor1).thenReturn(cursor2).thenReturn(cursor3);
         
         AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
         when(agentDao.getAliveAgents()).thenReturn(Arrays.asList(agentInfo1, agentInfo2, agentInfo3));
 
-        return new Pair<>(storage, agentDao);
+        return new Triple<>(storage, agentDao, stmt);
     }
 }
 
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -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,18 +51,16 @@
 
 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.Query;
+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.BinaryComparisonExpression;
-import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.storage.query.LiteralExpression;
 
 public class NetworkInterfaceInfoDAOTest {
 
@@ -85,21 +82,22 @@
     }
 
     @Test
-    public void testGetNetworkInterfaces() {
+    public void testGetNetworkInterfaces() throws DescriptorParsingException, StatementExecutionException {
 
         NetworkInterfaceInfo niInfo = new NetworkInterfaceInfo(INTERFACE_NAME);
         niInfo.setIp4Addr(IPV4_ADDR);
         niInfo.setIp6Addr(IPV6_ADDR);
 
         @SuppressWarnings("unchecked")
-        Cursor<NetworkInterfaceInfo> cursor = mock(Cursor.class);
+        Cursor<NetworkInterfaceInfo> cursor = (Cursor<NetworkInterfaceInfo>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(niInfo);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<NetworkInterfaceInfo> stmt = (PreparedStatement<NetworkInterfaceInfo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -107,11 +105,10 @@
         NetworkInterfaceInfoDAO dao = new NetworkInterfaceInfoDAOImpl(storage);
         List<NetworkInterfaceInfo> netInfo = dao.getNetworkInterfaces(hostRef);
 
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.equalTo(Key.AGENT_ID, "system");
-        verify(query).where(eq(expr));
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "system");
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertEquals(1, netInfo.size());
 
@@ -122,6 +119,11 @@
         assertEquals(IPV6_ADDR, info.getIp6Addr());
     }
 
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<NetworkInterfaceInfo> anyDescriptor() {
+        return (StatementDescriptor<NetworkInterfaceInfo>) any(StatementDescriptor.class);
+    }
+
     @Test
     public void testPutNetworkInterfaceInfo() {
         Storage storage = mock(Storage.class);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -55,10 +55,13 @@
 
 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.Query;
+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.Update;
 import com.redhat.thermostat.storage.core.VmRef;
@@ -132,16 +135,17 @@
     }
 
     @Test
-    public void testGetVmInfo() {
-
+    public void testGetVmInfo() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<VmInfo> stmt = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
         VmInfo expected = new VmInfo(vmId, startTime, stopTime, jVersion, jHome, mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs, props, env, libs, uid, username);
-        Cursor cursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        Cursor<VmInfo> cursor = (Cursor<VmInfo>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(expected).thenReturn(null);
-        when(query.execute()).thenReturn(cursor);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -153,16 +157,27 @@
         VmInfoDAO dao = new VmInfoDAOImpl(storage);
         VmInfo info = dao.getVmInfo(vmRef);
         assertEquals(expected, info);
+        
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "system");
+        verify(stmt).setInt(1, 321);
+        verify(stmt).executeQuery();
+    }
+
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<VmInfo> anyDescriptor() {
+        return (StatementDescriptor<VmInfo>) any(StatementDescriptor.class);
     }
 
     @Test
-    public void testGetVmInfoUnknownVM() {
-
+    public void testGetVmInfoUnknownVM() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        Cursor cursor = mock(Cursor.class);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<VmInfo> stmt = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        @SuppressWarnings("unchecked")
+        Cursor<VmInfo> cursor = (Cursor<VmInfo>) mock(Cursor.class);
+        when(stmt.executeQuery()).thenReturn(cursor);
         
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -179,10 +194,14 @@
             assertEquals("Unknown VM: host:system;vm:321", ex.getMessage());
         }
 
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "system");
+        verify(stmt).setInt(1, 321);
+        verify(stmt).executeQuery();
     }
 
     @Test
-    public void testSingleVM() {
+    public void testSingleVM() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = setupStorageForSingleVM();
         VmInfoDAO dao = new VmInfoDAOImpl(storage);
         HostRef host = new HostRef("123", "fluffhost");
@@ -192,26 +211,27 @@
         assertCollection(vms, new VmRef(host, 123, "mainClass1"));
     }
 
-    private Storage setupStorageForSingleVM() {
+    private Storage setupStorageForSingleVM() throws DescriptorParsingException, StatementExecutionException {
 
       VmInfo vm1 = new VmInfo();
       vm1.setVmPid(123);
       vm1.setMainClass("mainClass1");
 
       @SuppressWarnings("unchecked")
-      Cursor<VmInfo> singleVMCursor = mock(Cursor.class);
+      Cursor<VmInfo> singleVMCursor = (Cursor<VmInfo>) mock(Cursor.class);
       when(singleVMCursor.hasNext()).thenReturn(true).thenReturn(false);
       when(singleVMCursor.next()).thenReturn(vm1);
 
       Storage storage = mock(Storage.class);
-      Query query = mock(Query.class);
-      when(storage.createQuery(any(Category.class))).thenReturn(query);
-      when(query.execute()).thenReturn(singleVMCursor);
+      @SuppressWarnings("unchecked")
+      PreparedStatement<VmInfo> stmt = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
+      when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+      when(stmt.executeQuery()).thenReturn(singleVMCursor);
       return storage;
   }
 
     @Test
-    public void testMultiVMs() {
+    public void testMultiVMs() throws DescriptorParsingException, StatementExecutionException {
         Storage storage = setupStorageForMultiVM();
         VmInfoDAO dao = new VmInfoDAOImpl(storage);
 
@@ -222,8 +242,7 @@
         assertCollection(vms, new VmRef(host, 123, "mainClass1"), new VmRef(host, 456, "mainClass2"));
     }
 
-    private Storage setupStorageForMultiVM() {
-
+    private Storage setupStorageForMultiVM() throws DescriptorParsingException, StatementExecutionException {
       VmInfo vm1 = new VmInfo();
       vm1.setVmPid(123);
       vm1.setMainClass("mainClass1");
@@ -238,9 +257,10 @@
       when(multiVMsCursor.next()).thenReturn(vm1).thenReturn(vm2);
 
       Storage storage = mock(Storage.class);
-      Query query = mock(Query.class);
-      when(storage.createQuery(any(Category.class))).thenReturn(query);
-      when(query.execute()).thenReturn(multiVMsCursor);
+      @SuppressWarnings("unchecked")
+      PreparedStatement<VmInfo> stmt = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
+      when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+      when(stmt.executeQuery()).thenReturn(multiVMsCursor);
       return storage;
   }
 
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -37,28 +37,69 @@
 package com.redhat.thermostat.thread.dao.impl;
 
 import java.util.ArrayList;
+import java.util.Collections;
 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.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.Put;
-import com.redhat.thermostat.storage.core.Query;
+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.VmDeadLockData;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
 import com.redhat.thermostat.thread.model.ThreadInfoData;
 import com.redhat.thermostat.thread.model.ThreadSummary;
 import com.redhat.thermostat.thread.model.VMThreadCapabilities;
+import com.redhat.thermostat.thread.model.VmDeadLockData;
 
 public class ThreadDaoImpl implements ThreadDao {
-
+    
+    private static final Logger logger = LoggingUtils.getLogger(ThreadDaoImpl.class);
+    
+    // Queries
+    private static final String QUERY_THREAD_CAPS = "QUERY "
+            + THREAD_CAPABILITIES.getName() + " WHERE "
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i LIMIT 1";
+    private static final String QUERY_LATEST_SUMMARY = "QUERY "
+            + THREAD_SUMMARY.getName() + " WHERE "
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i SORT " 
+            + Key.TIMESTAMP.getName() + "DSC LIMIT 1";
+    private static final String QUERY_SUMMARY_SINCE = "QUERY "
+            + THREAD_SUMMARY.getName() + " WHERE "
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i AND "
+            + Key.TIMESTAMP.getName() + " > ?l SORT "
+            + Key.TIMESTAMP.getName() + "DSC";
+    private static final String QUERY_LATEST_HARVESTING_STATUS = "QUERY "
+            + THREAD_HARVESTING_STATUS.getName() + " WHERE "
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i SORT " 
+            + Key.TIMESTAMP.getName() + "DSC LIMIT 1";
+    private static final String QUERY_THREAD_INFO = "QUERY "
+            + THREAD_INFO.getName() + " WHERE "
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i AND "
+            + Key.TIMESTAMP.getName() + " > ?l SORT "
+            + Key.TIMESTAMP.getName() + "DSC";
+    private static final String QUERY_LATEST_DEADLOCK_INFO = "QUERY "
+            + DEADLOCK_INFO.getName() + " WHERE "
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i SORT " 
+            + Key.TIMESTAMP.getName() + "DSC LIMIT 1";
+    
     private Storage storage;
+    
     public ThreadDaoImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(THREAD_CAPABILITIES);
@@ -70,18 +111,25 @@
 
     @Override
     public VMThreadCapabilities loadCapabilities(VmRef vm) {
-        Query<VMThreadCapabilities> query = storage.createQuery(THREAD_CAPABILITIES);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(
-                factory.equalTo(Key.AGENT_ID, vm.getAgent().getAgentId()),
-                factory.equalTo(Key.VM_ID, vm.getId()));
-        query.where(expr);
-        query.limit(1);
-        Cursor<VMThreadCapabilities> cursor = query.execute();
-        if (!cursor.hasNext()) {
+        PreparedStatement<VMThreadCapabilities> stmt = prepareQuery(THREAD_CAPABILITIES, QUERY_THREAD_CAPS, vm);
+        if (stmt == null) {
             return null;
         }
-        VMThreadCapabilities caps = cursor.next();
+        
+        Cursor<VMThreadCapabilities> cursor;
+        try {
+            cursor = stmt.executeQuery();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + stmt + "' failed!", e);
+            return null;
+        }
+        
+        VMThreadCapabilities caps = null;
+        if (cursor.hasNext()) {
+            caps = cursor.next();
+        }
+        
         return caps;
     }
     
@@ -101,12 +149,21 @@
     
     @Override
     public ThreadSummary loadLastestSummary(VmRef ref) {
+        PreparedStatement<ThreadSummary> stmt = prepareQuery(THREAD_SUMMARY, QUERY_LATEST_SUMMARY, ref);
+        if (stmt == null) {
+            return null;
+        }
+        
+        Cursor<ThreadSummary> cursor;
+        try {
+            cursor = stmt.executeQuery();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + stmt + "' failed!", e);
+            return null;
+        }
+        
         ThreadSummary summary = null;
-
-        Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ref);
-        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        query.limit(1);
-        Cursor<ThreadSummary> cursor = query.execute();
         if (cursor.hasNext()) {
             summary = cursor.next();
         }
@@ -116,13 +173,21 @@
     
     @Override
     public List<ThreadSummary> loadSummary(VmRef ref, long since) {
+        PreparedStatement<ThreadSummary> stmt = prepareQuery(THREAD_SUMMARY, QUERY_SUMMARY_SINCE, ref, since);
+        if (stmt == null) {
+            return Collections.emptyList();
+        }
+
+        Cursor<ThreadSummary> cursor;
+        try {
+            cursor = stmt.executeQuery();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + stmt + "' failed!", e);
+            return Collections.emptyList();
+        }
         
         List<ThreadSummary> result = new ArrayList<>();
-        
-        Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ref, since);
-        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-
-        Cursor<ThreadSummary> cursor = query.execute();
         while (cursor.hasNext()) {
             ThreadSummary summary = cursor.next();
             result.add(summary);
@@ -140,15 +205,26 @@
 
     @Override
     public ThreadHarvestingStatus getLatestHarvestingStatus(VmRef vm) {
-        Query<ThreadHarvestingStatus> query = prepareQuery(THREAD_HARVESTING_STATUS, vm);
-        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        query.limit(1);
-
-        Cursor<ThreadHarvestingStatus> cursor = query.execute();
+        PreparedStatement<ThreadHarvestingStatus> stmt = prepareQuery(THREAD_HARVESTING_STATUS, 
+                QUERY_LATEST_HARVESTING_STATUS, vm);
+        if (stmt == null) {
+            return null;
+        }
+        
+        Cursor<ThreadHarvestingStatus> cursor;
+        try {
+            cursor = stmt.executeQuery();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + stmt + "' failed!", e);
+            return null;
+        }
+        
+        ThreadHarvestingStatus result = null;
         if (cursor.hasNext()) {
-            return cursor.next();
+            result = cursor.next();
         }
-        return null;
+        return result;
     }
 
     @Override
@@ -160,12 +236,21 @@
 
     @Override
     public List<ThreadInfoData> loadThreadInfo(VmRef ref, long since) {
-        List<ThreadInfoData> result = new ArrayList<>();
+        PreparedStatement<ThreadInfoData> stmt = prepareQuery(THREAD_INFO, QUERY_THREAD_INFO, ref, since);
+        if (stmt == null) {
+            return Collections.emptyList();
+        }
         
-        Query<ThreadInfoData> query = prepareQuery(THREAD_INFO, ref, since);
-        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        Cursor<ThreadInfoData> cursor;
+        try {
+            cursor = stmt.executeQuery();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + stmt + "' failed!", e);
+            return Collections.emptyList();
+        }
         
-        Cursor<ThreadInfoData> cursor = query.execute();
+        List<ThreadInfoData> result = new ArrayList<>();
         while (cursor.hasNext()) {
             ThreadInfoData info = cursor.next();
             result.add(info);
@@ -176,17 +261,26 @@
 
     @Override
     public VmDeadLockData loadLatestDeadLockStatus(VmRef ref) {
-        Query<VmDeadLockData> query = prepareQuery(DEADLOCK_INFO, ref);
-        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        query.limit(1);
-
-        Cursor<VmDeadLockData> cursor = query.execute();
+        PreparedStatement<VmDeadLockData> stmt = prepareQuery(DEADLOCK_INFO, QUERY_LATEST_DEADLOCK_INFO, ref);
+        if (stmt == null) {
+            return null;
+        }
+        
+        Cursor<VmDeadLockData> cursor;
+        try {
+            cursor = stmt.executeQuery();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + stmt + "' failed!", e);
+            return null;
+        }
+        
+        VmDeadLockData result = null;
         if (cursor.hasNext()) {
-            VmDeadLockData data = cursor.next();
-            return data;
+            result = cursor.next();
         }
 
-        return null;
+        return result;
     }
 
     @Override
@@ -196,23 +290,25 @@
         add.apply();
     }
     
-    private <T extends Pojo> Query<T> prepareQuery(Category<T> category, VmRef vm) {
-        return prepareQuery(category, vm.getId(), vm.getAgent().getAgentId(), null);
+    private <T extends Pojo> PreparedStatement<T> prepareQuery(Category<T> category, String query, VmRef ref) {
+        return prepareQuery(category, query, ref, null);
     }
     
-    private <T extends Pojo> Query<T> prepareQuery(Category<T> category, VmRef vm, Long since) {
-        return prepareQuery(category, vm.getId(), vm.getAgent().getAgentId(), since);
-    }
-
-    private <T extends Pojo> Query<T> prepareQuery(Category<T> category, Integer vmId, String agentId, Long since) {
-        Query<T> query = storage.createQuery(category);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(factory.equalTo(Key.AGENT_ID, agentId), factory.equalTo(Key.VM_ID, vmId));
-        if (since != null) {
-            expr = factory.and(expr, factory.greaterThan(Key.TIMESTAMP, since));
+    private <T extends Pojo> PreparedStatement<T> prepareQuery(Category<T> category, String query, VmRef ref, Long since) {
+        StatementDescriptor<T> desc = new StatementDescriptor<>(category, query);
+        PreparedStatement<T> stmt = null;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, ref.getAgent().getAgentId());
+            stmt.setInt(1, ref.getId());
+            if (since != null) {
+                stmt.setLong(2, since);
+            }
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
         }
-        query.where(expr);
-        return query;
+        return stmt;
     }
     
     @Override
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -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;
@@ -54,15 +53,15 @@
 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.Query;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
+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.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
 import com.redhat.thermostat.thread.model.VMThreadCapabilities;
@@ -84,10 +83,11 @@
     }
     
     @Test
-    public void testLoadVMCapabilities() {
-        Query query = mock(Query.class);
+    public void testLoadVMCapabilities() throws DescriptorParsingException, StatementExecutionException {
+        @SuppressWarnings("unchecked")
+        PreparedStatement<VMThreadCapabilities> stmt = (PreparedStatement<VMThreadCapabilities>) mock(PreparedStatement.class);
         Storage storage = mock(Storage.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
+        when(storage.prepareStatement(anyDescriptor(VMThreadCapabilities.class))).thenReturn(stmt);
         VmRef ref = mock(VmRef.class);
         when(ref.getId()).thenReturn(42);
         
@@ -98,35 +98,37 @@
 
         VMThreadCapabilities expected = new VMThreadCapabilities();
         expected.setSupportedFeaturesList(new String[] { ThreadDao.CPU_TIME, ThreadDao.THREAD_ALLOCATED_MEMORY });
-        Cursor cursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        Cursor<VMThreadCapabilities> cursor = (Cursor<VMThreadCapabilities>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(expected).thenReturn(null);
-        when(query.execute()).thenReturn(cursor);
+        when(stmt.executeQuery()).thenReturn(cursor);
         
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         VMThreadCapabilities caps = dao.loadCapabilities(ref);
 
-        Expression expr = createWhereExpression();
-        verify(query).where(eq(expr));
-        verify(query).limit(1);
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor(VMThreadCapabilities.class));
+        verify(stmt).setString(0, "0xcafe");
+        verify(stmt).setInt(1, 42);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertFalse(caps.supportContentionMonitor());
         assertTrue(caps.supportCPUTime());
         assertTrue(caps.supportThreadAllocatedMemory());
     }
 
-    private Expression createWhereExpression() {
-        ExpressionFactory factory = new ExpressionFactory();
-        return factory.and(factory.equalTo(Key.AGENT_ID, "0xcafe"), factory.equalTo(Key.VM_ID, 42));
+    @SuppressWarnings("unchecked")
+    private <T extends Pojo> StatementDescriptor<T> anyDescriptor(Class<T> type) {
+        return (StatementDescriptor<T>) any(StatementDescriptor.class);
     }
-    
+
     @Test
-    public void testLoadVMCapabilitiesWithoutAnyDataInStorage() {
-        Query query = mock(Query.class);
+    public void testLoadVMCapabilitiesWithoutAnyDataInStorage() throws DescriptorParsingException, StatementExecutionException {
+        @SuppressWarnings("unchecked")
+        PreparedStatement<VMThreadCapabilities> stmt = (PreparedStatement<VMThreadCapabilities>) mock(PreparedStatement.class);
         Storage storage = mock(Storage.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
+        when(storage.prepareStatement(anyDescriptor(VMThreadCapabilities.class))).thenReturn(stmt);
         VmRef ref = mock(VmRef.class);
         when(ref.getId()).thenReturn(42);
 
@@ -137,19 +139,20 @@
 
         VMThreadCapabilities expected = new VMThreadCapabilities();
         expected.setSupportedFeaturesList(new String[] { ThreadDao.CPU_TIME, ThreadDao.THREAD_ALLOCATED_MEMORY });
-        Cursor cursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        Cursor<VMThreadCapabilities> cursor = (Cursor<VMThreadCapabilities>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(false);
         when(cursor.next()).thenThrow(new NoSuchElementException());
-        when(query.execute()).thenReturn(cursor);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         VMThreadCapabilities caps = dao.loadCapabilities(ref);
 
-        Expression expr = createWhereExpression();
-        verify(query).where(eq(expr));
-        verify(query).limit(1);
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor(VMThreadCapabilities.class));
+        verify(stmt).setString(0, "0xcafe");
+        verify(stmt).setInt(1, 42);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertEquals(null, caps);
     }
@@ -174,7 +177,7 @@
     }
 
     @Test
-    public void testLoadLatestDeadLockStatus() {
+    public void testLoadLatestDeadLockStatus() throws DescriptorParsingException, StatementExecutionException {
         VmRef vm = mock(VmRef.class);
         when(vm.getId()).thenReturn(42);
         when(vm.getIdString()).thenReturn("42");
@@ -184,27 +187,27 @@
         when(vm.getAgent()).thenReturn(agent);
 
         Storage storage = mock(Storage.class);
-        Query<VmDeadLockData> query = mock(Query.class);
-        Cursor<VmDeadLockData> cursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<VmDeadLockData> stmt = (PreparedStatement<VmDeadLockData>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor(VmDeadLockData.class))).thenReturn(stmt);
+        @SuppressWarnings("unchecked")
+        Cursor<VmDeadLockData> cursor = (Cursor<VmDeadLockData>) mock(Cursor.class);
         VmDeadLockData data = mock(VmDeadLockData.class);
 
         when(cursor.hasNext()).thenReturn(true);
         when(cursor.next()).thenReturn(data);
-        when(query.execute()).thenReturn(cursor);
-
-        when(storage.createQuery(ThreadDaoImpl.DEADLOCK_INFO)).thenReturn(query);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         VmDeadLockData result = dao.loadLatestDeadLockStatus(vm);
 
         assertSame(data, result);
 
-        Expression expr = createWhereExpression();
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, SortDirection.DESCENDING);
-        verify(query).execute();
-        verify(query).limit(1);
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor(VmDeadLockData.class));
+        verify(stmt).setString(0, "0xcafe");
+        verify(stmt).setInt(1, 42);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
     }
 
     @Test
@@ -223,7 +226,7 @@
     }
 
     @Test
-    public void testGetLatestHarvestingStatus() {
+    public void testGetLatestHarvestingStatus() throws DescriptorParsingException, StatementExecutionException {
         VmRef vm = mock(VmRef.class);
         when(vm.getId()).thenReturn(42);
         when(vm.getIdString()).thenReturn("42");
@@ -233,25 +236,25 @@
         when(vm.getAgent()).thenReturn(agent);
 
         Storage storage = mock(Storage.class);
-        Query<ThreadHarvestingStatus> query = mock(Query.class);
-        Cursor<ThreadHarvestingStatus> cursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<ThreadHarvestingStatus> stmt = (PreparedStatement<ThreadHarvestingStatus>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor(ThreadHarvestingStatus.class))).thenReturn(stmt);
+        @SuppressWarnings("unchecked")
+        Cursor<ThreadHarvestingStatus> cursor = (Cursor<ThreadHarvestingStatus>) mock(Cursor.class);
         ThreadHarvestingStatus status = mock(ThreadHarvestingStatus.class);
 
         when(cursor.hasNext()).thenReturn(true);
         when(cursor.next()).thenReturn(status);
-        when(query.execute()).thenReturn(cursor);
-
-        when(storage.createQuery(ThreadDaoImpl.THREAD_HARVESTING_STATUS)).thenReturn(query);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         ThreadHarvestingStatus result = dao.getLatestHarvestingStatus(vm);
 
-        Expression expr = createWhereExpression();
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, SortDirection.DESCENDING);
-        verify(query).execute();
-        verify(query).limit(1);
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor(ThreadHarvestingStatus.class));
+        verify(stmt).setString(0, "0xcafe");
+        verify(stmt).setInt(1, 42);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertSame(status, result);
     }
--- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -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;
@@ -53,13 +52,14 @@
 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.Query;
+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.VmRef;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO;
 import com.redhat.thermostat.vm.classstat.common.model.VmClassStat;
 
@@ -81,7 +81,7 @@
     }
 
     @Test
-    public void testGetLatestClassStatsBasic() {
+    public void testGetLatestClassStatsBasic() throws DescriptorParsingException, StatementExecutionException {
 
         VmClassStat vmClassStat = getClassStat();
 
@@ -91,9 +91,10 @@
         when(cursor.next()).thenReturn(vmClassStat);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<VmClassStat> stmt = (PreparedStatement<VmClassStat>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -105,15 +106,12 @@
         VmClassStatDAO dao = new VmClassStatDAOImpl(storage);
         List<VmClassStat> vmClassStats = dao.getLatestClassStats(vmRef, Long.MIN_VALUE);
 
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(
-                factory.equalTo(Key.AGENT_ID, "system"),
-                factory.and(factory.equalTo(Key.VM_ID, 321),
-                        factory.greaterThan(Key.TIMESTAMP, Long.MIN_VALUE)));
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "system");
+        verify(stmt).setInt(1, 321);
+        verify(stmt).setLong(2, Long.MIN_VALUE);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertEquals(1, vmClassStats.size());
         VmClassStat stat = vmClassStats.get(0);
@@ -122,6 +120,11 @@
         assertEquals(VM_ID, (Integer) stat.getVmId());
     }
 
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<VmClassStat> anyDescriptor() {
+        return (StatementDescriptor<VmClassStat>) any(StatementDescriptor.class);
+    }
+
     private VmClassStat getClassStat() {
         return new VmClassStat(VM_ID, TIMESTAMP, LOADED_CLASSES);
     }
--- a/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -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;
@@ -54,13 +53,14 @@
 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.Query;
+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.VmRef;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO;
 import com.redhat.thermostat.vm.cpu.common.model.VmCpuStat;
 
@@ -89,17 +89,18 @@
     }
 
     @Test
-    public void testGetLatestCpuStatsBasic() {
+    public void testGetLatestCpuStatsBasic() throws DescriptorParsingException, StatementExecutionException {
 
         @SuppressWarnings("unchecked")
-        Cursor<VmCpuStat> cursor = mock(Cursor.class);
+        Cursor<VmCpuStat> cursor = (Cursor<VmCpuStat>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(cpuStat);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<VmCpuStat> stmt = (PreparedStatement<VmCpuStat>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -108,20 +109,15 @@
         when(vmRef.getAgent()).thenReturn(hostRef);
         when(vmRef.getId()).thenReturn(VM_ID);
 
-
         VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage);
         List<VmCpuStat> vmCpuStats = dao.getLatestVmCpuStats(vmRef, Long.MIN_VALUE);
 
-        verify(storage).createQuery(VmCpuStatDAO.vmCpuStatCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(
-                factory.equalTo(Key.AGENT_ID, vmRef.getAgent().getAgentId()),
-                factory.and(factory.equalTo(Key.VM_ID, vmRef.getId()),
-                        factory.greaterThan(Key.TIMESTAMP, Long.MIN_VALUE)));
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "system");
+        verify(stmt).setInt(1, VM_ID);
+        verify(stmt).setLong(2, Long.MIN_VALUE);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertEquals(1, vmCpuStats.size());
         VmCpuStat stat = vmCpuStats.get(0);
@@ -130,6 +126,11 @@
         assertEquals(VM_ID, (Integer) stat.getVmId());
     }
 
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<VmCpuStat> anyDescriptor() {
+        return (StatementDescriptor<VmCpuStat>) any(StatementDescriptor.class);
+    }
+
     @Test
     public void testPutVmCpuStat() {
         Storage storage = mock(Storage.class);
--- a/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -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;
@@ -53,13 +52,14 @@
 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.Query;
+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.VmRef;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 import com.redhat.thermostat.vm.gc.common.model.VmGcStat;
 
@@ -85,19 +85,20 @@
     }
 
     @Test
-    public void testGetLatestVmGcStatsBasic() {
+    public void testGetLatestVmGcStatsBasic() throws DescriptorParsingException, StatementExecutionException {
 
         VmGcStat vmGcStat = new VmGcStat(VM_ID, TIMESTAMP, COLLECTOR, RUN_COUNT, WALL_TIME);
 
         @SuppressWarnings("unchecked")
-        Cursor<VmGcStat> cursor = mock(Cursor.class);
+        Cursor<VmGcStat> cursor = (Cursor<VmGcStat>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(vmGcStat);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<VmGcStat> stmt = (PreparedStatement<VmGcStat>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -106,20 +107,15 @@
         when(vmRef.getAgent()).thenReturn(hostRef);
         when(vmRef.getId()).thenReturn(321);
 
-
         VmGcStatDAO dao = new VmGcStatDAOImpl(storage);
         List<VmGcStat> vmGcStats = dao.getLatestVmGcStats(vmRef, Long.MIN_VALUE);
 
-        verify(storage).createQuery(VmGcStatDAO.vmGcStatCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(
-                factory.equalTo(Key.AGENT_ID, vmRef.getAgent().getAgentId()),
-                factory.and(factory.equalTo(Key.VM_ID, vmRef.getId()),
-                        factory.greaterThan(Key.TIMESTAMP, Long.MIN_VALUE)));
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "system");
+        verify(stmt).setInt(1, 321);
+        verify(stmt).setLong(2, Long.MIN_VALUE);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
 
         assertEquals(1, vmGcStats.size());
         VmGcStat stat = vmGcStats.get(0);
@@ -130,6 +126,11 @@
         assertEquals(WALL_TIME, (Long) stat.getWallTime());
     }
 
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<VmGcStat> anyDescriptor() {
+        return (StatementDescriptor<VmGcStat>) any(StatementDescriptor.class);
+    }
+
     @Test
     public void testPutVmGcStat() {
         Storage storage = mock(Storage.class);
--- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -46,18 +46,20 @@
 import java.io.ObjectOutputStream;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
 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.Put;
-import com.redhat.thermostat.storage.core.Query;
+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.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
 import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
@@ -66,6 +68,13 @@
 public class HeapDAOImpl implements HeapDAO {
 
     private static final Logger log = LoggingUtils.getLogger(HeapDAOImpl.class);
+    private static final String QUERY_ALL_HEAPS = "QUERY "
+            + heapInfoCategory.getName() + " WHERE " 
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i";
+    private static final String QUERY_HEAP_INFO = "QUERY "
+            + heapInfoCategory.getName() + " WHERE " 
+            + heapIdKey.getName() + " = ?s LIMIT 1";
 
     private final Storage storage;
 
@@ -111,13 +120,24 @@
 
     @Override
     public Collection<HeapInfo> getAllHeapInfo(VmRef vm) {
-        Query<HeapInfo> query = storage.createQuery(heapInfoCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(
-                factory.equalTo(Key.AGENT_ID, vm.getAgent().getAgentId()),
-                factory.equalTo(Key.VM_ID, vm.getId()));
-        query.where(expr);
-        Cursor<HeapInfo> cursor = query.execute();
+        StatementDescriptor<HeapInfo> desc = new StatementDescriptor<>(heapInfoCategory, QUERY_ALL_HEAPS);
+        PreparedStatement<HeapInfo> stmt;
+        Cursor<HeapInfo> cursor;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, vm.getAgent().getAgentId());
+            stmt.setInt(1, vm.getId());
+            cursor = stmt.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            log.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            log.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        }
+        
         Collection<HeapInfo> heapInfos = new ArrayList<>();
         while (cursor.hasNext()) {
             heapInfos.add(cursor.next());
@@ -144,14 +164,13 @@
 
     @Override
     public HeapInfo getHeapInfo(String heapId) {
-        Query<HeapInfo> query = storage.createQuery(heapInfoCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.equalTo(heapIdKey, heapId);
-        query.where(expr);
-        query.limit(1);
-        HeapInfo found = null;
+        StatementDescriptor<HeapInfo> desc = new StatementDescriptor<>(heapInfoCategory, QUERY_HEAP_INFO);
+        PreparedStatement<HeapInfo> stmt; 
+        Cursor<HeapInfo> cursor;
         try {
-            found = query.execute().next();
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, heapId);
+            cursor = stmt.executeQuery();
         } catch (IllegalArgumentException iae) {
             /*
              * if the heap id is not found, we get a nice
@@ -159,10 +178,25 @@
              * exception is caused by that before propagating it.
              */
             if (!iae.getMessage().contains("invalid ObjectId")) {
+                // FIXME Is this needed?
                 throw iae;
             }
+            return null;
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            log.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return null;
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            log.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return null;
         }
-        return found;
+        
+        HeapInfo result = null;
+        if (cursor.hasNext()) {
+            result = cursor.next();
+        }
+        return result;
     }
 
     @Override
--- a/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -45,6 +45,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.io.ByteArrayInputStream;
@@ -64,9 +65,12 @@
 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.Query;
+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.VmRef;
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
@@ -87,17 +91,18 @@
     private ObjectHistogram histogram;
     private InputStream histogramData;
 
-    private Query query;
+    private PreparedStatement<HeapInfo> stmt;
 
+    @SuppressWarnings("unchecked")
     @Before
-    public void setUp() throws IOException {
+    public void setUp() throws IOException, DescriptorParsingException, StatementExecutionException {
         storage = mock(Storage.class);
         add = mock(Add.class);
         when(storage.createAdd(any(Category.class))).thenReturn(add);
 
         when(storage.getAgentId()).thenReturn("test");
-        query = mock(Query.class); 
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
+        stmt = (PreparedStatement<HeapInfo>) mock(PreparedStatement.class); 
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
 
         dao = new HeapDAOImpl(storage);
         
@@ -109,21 +114,22 @@
         out.close();
         histogramData = createHistogramData();
 
-        @SuppressWarnings("unchecked")
-        Cursor<HeapInfo> cursor = mock(Cursor.class);
+        Cursor<HeapInfo> cursor = (Cursor<HeapInfo>) mock(Cursor.class);
         HeapInfo info1 = new HeapInfo(234, 12345L);
         info1.setAgentId("123");
+        info1.setHeapId("testheap1");
         info1.setHeapDumpId("test1");
         info1.setHistogramId("histotest1");
 
         HeapInfo info2 = new HeapInfo(234, 23456L);
         info2.setAgentId("123");
+        info2.setHeapId("testheap2");
         info2.setHeapDumpId("test2");
         info2.setHistogramId("histotest2");
 
         when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(info1).thenReturn(info2).thenReturn(null);
-        when(query.execute()).thenReturn(cursor);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         // Setup for reading heapdump data.
         when(storage.loadFile("test-heap")).thenReturn(new ByteArrayInputStream(data));
@@ -133,6 +139,11 @@
 
     }
 
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<HeapInfo> anyDescriptor() {
+        return (StatementDescriptor<HeapInfo>) any(StatementDescriptor.class);
+    }
+
     private InputStream createHistogramData() throws IOException {
         histogram = new ObjectHistogram();
 
@@ -162,7 +173,7 @@
 
     @After
     public void tearDown() {
-        query = null;
+        stmt = null;
         histogramData = null;
         histogram = null;
         heapDumpData.delete();
@@ -175,7 +186,7 @@
 
     @Test
     public void testCategory() {
-        Category category = HeapDAO.heapInfoCategory;
+        Category<HeapInfo> category = HeapDAO.heapInfoCategory;
         assertNotNull(category);
         assertEquals("vm-heap-info", category.getName());
         Collection<Key<?>> keys = category.getKeys();
@@ -229,8 +240,7 @@
     }
 
     @Test
-    public void testGetAllHeapInfo() {
-        
+    public void testGetAllHeapInfo() throws DescriptorParsingException, StatementExecutionException {
         // verify a connection key has been created before requesting the
         // heap dumps
         verify(storage).registerCategory(HeapDAO.heapInfoCategory);
@@ -238,22 +248,49 @@
         HostRef host = new HostRef("123", "test-host");
         VmRef vm = new VmRef(host, 234, "test-vm");
         Collection<HeapInfo> heapInfos = dao.getAllHeapInfo(vm);
+
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, "123");
+        verify(stmt).setInt(1, 234);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
         
         HeapInfo info1 = new HeapInfo(234, 12345);
         info1.setHeapDumpId("test1");
+        info1.setHeapId("testheap1");
         info1.setHistogramId("histotest1");
         
         HeapInfo info2 = new HeapInfo(234, 23456);
         info2.setHeapDumpId("test2");
+        info2.setHeapId("testheap2");
         info2.setHistogramId("histotest2");
         
         assertEquals(2, heapInfos.size());
         assertTrue(heapInfos.contains(info1));
         assertTrue(heapInfos.contains(info2));
     }
+    
+    @Test
+    public void testGetHeapInfo() throws DescriptorParsingException, StatementExecutionException {
+        final String heapId = "testheap1";
+        
+        HeapInfo result = dao.getHeapInfo(heapId);
+        
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, heapId);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
+        
+        HeapInfo info = new HeapInfo(234, 12345);
+        info.setHeapDumpId("test1");
+        info.setHeapId("testheap1");
+        info.setHistogramId("histotest1");
+        
+        assertEquals(info, result);
+    }
 
     @Test
-    public void testGetHeapDump() throws IOException {
+    public void testGetHeapDump() throws IOException, DescriptorParsingException, StatementExecutionException {
         heapInfo.setHeapDumpId("test-heap");
         InputStream in = dao.getHeapDumpData(heapInfo);
         assertEquals(1, in.read());
@@ -273,8 +310,8 @@
     }
 
     @Test
-    public void testInvalidHeapId() throws IOException {
-        when(query.execute()).thenThrow(new IllegalArgumentException("invalid ObjectId"));
+    public void testInvalidHeapId() throws IOException, StatementExecutionException {
+        when(stmt.executeQuery()).thenThrow(new IllegalArgumentException("invalid ObjectId"));
         dao = new HeapDAOImpl(storage);
         heapInfo = dao.getHeapInfo("some-random-heap-id");
         assertTrue(heapInfo == null);
--- a/vm-jmx/agent/src/main/java/com/redhat/thermostat/vm/jmx/agent/internal/JmxBackend.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-jmx/agent/src/main/java/com/redhat/thermostat/vm/jmx/agent/internal/JmxBackend.java	Mon Jul 15 12:52:59 2013 -0400
@@ -153,7 +153,7 @@
             update.setVmId(pid);
             update.setEnabled(true);
             update.setTimeStamp(clock.getRealTimeMillis());
-            dao.addNotifcationStatus(update);
+            dao.addNotificationStatus(update);
         } catch (Exception e) {
             logger.log(Level.WARNING, "Unable to connect to the mx bean connector", e);
         }
@@ -168,7 +168,7 @@
         update.setVmId(pid);
         update.setEnabled(false);
         update.setTimeStamp(clock.getRealTimeMillis());
-        dao.addNotifcationStatus(update);
+        dao.addNotificationStatus(update);
 
         try {
             pool.release(pid, connection);
--- a/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/JmxNotificationDAO.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/JmxNotificationDAO.java	Mon Jul 15 12:52:59 2013 -0400
@@ -42,7 +42,7 @@
 
 public interface JmxNotificationDAO {
 
-    void addNotifcationStatus(JmxNotificationStatus notificationsStatus);
+    void addNotificationStatus(JmxNotificationStatus notificationsStatus);
 
     JmxNotificationStatus getLatestNotificationStatus(VmRef statusFor);
 
--- a/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -37,18 +37,22 @@
 package com.redhat.thermostat.vm.jmx.common.internal;
 
 import java.util.ArrayList;
+import java.util.Collections;
 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.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.Query;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
+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.VmRef;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.vm.jmx.common.JmxNotification;
 import com.redhat.thermostat.vm.jmx.common.JmxNotificationDAO;
 import com.redhat.thermostat.vm.jmx.common.JmxNotificationStatus;
@@ -56,6 +60,7 @@
 public class JmxNotificationDAOImpl implements JmxNotificationDAO {
 
     private static final Key<Boolean> NOTIFICATIONS_ENABLED = new Key<>("notififcationsEnabled", false);
+    private static final Logger logger = LoggingUtils.getLogger(JmxNotificationDAOImpl.class);
 
     static final Category<JmxNotificationStatus> NOTIFICATION_STATUS =
             new Category<>("vm-jmx-notification-status", JmxNotificationStatus.class,
@@ -73,6 +78,17 @@
                     Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP,
                     SOURCE_BACKEND, SOURCE_DESCRPTION, CONTENTS);
 
+    private static final String QUERY_LATEST_NOTIFICATION_STATUS = "QUERY "
+            + NOTIFICATION_STATUS.getName() + " WHERE "
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i SORT " 
+            + Key.TIMESTAMP.getName() + " DSC LIMIT 1";
+    private static final String QUERY_NOTIFICATIONS = "QUERY "
+            + NOTIFICATIONS.getName() + " WHERE " 
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i AND "
+            + Key.TIMESTAMP.getName() + " > ?l";
+    
     private Storage storage;
 
     public JmxNotificationDAOImpl(Storage storage) {
@@ -82,7 +98,7 @@
     }
 
     @Override
-    public void addNotifcationStatus(JmxNotificationStatus status) {
+    public void addNotificationStatus(JmxNotificationStatus status) {
         Add add = storage.createAdd(NOTIFICATION_STATUS);
         add.setPojo(status);
         add.apply();
@@ -90,21 +106,31 @@
 
     @Override
     public JmxNotificationStatus getLatestNotificationStatus(VmRef statusFor) {
-        Query<JmxNotificationStatus> query = storage.createQuery(NOTIFICATION_STATUS);
+        StatementDescriptor<JmxNotificationStatus> desc = new StatementDescriptor<>(NOTIFICATION_STATUS, 
+                QUERY_LATEST_NOTIFICATION_STATUS);
+        PreparedStatement<JmxNotificationStatus> stmt;
+        Cursor<JmxNotificationStatus> cursor;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, statusFor.getAgent().getAgentId());
+            stmt.setInt(1, statusFor.getId());
+            cursor = stmt.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return null;
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return null;
+        }
         
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(factory.equalTo(Key.AGENT_ID, statusFor
-                .getAgent().getAgentId()), factory.equalTo(Key.VM_ID,
-                statusFor.getId()));
-        query.where(expr);
-
-        query.sort(Key.TIMESTAMP, SortDirection.DESCENDING);
-        Cursor<JmxNotificationStatus> results = query.execute();
-        if (results.hasNext()) {
-            return results.next();
+        JmxNotificationStatus result = null;
+        if (cursor.hasNext()) {
+            result = cursor.next();
         }
 
-        return null;
+        return result;
     }
 
     @Override
@@ -116,16 +142,26 @@
 
     @Override
     public List<JmxNotification> getNotifications(VmRef notificationsFor, long timeStampSince) {
-        Query<JmxNotification> query = storage.createQuery(NOTIFICATIONS);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(factory.equalTo(Key.AGENT_ID,
-                notificationsFor.getAgent().getAgentId()), factory.and(
-                factory.equalTo(Key.VM_ID, notificationsFor.getId()),
-                factory.greaterThan(Key.TIMESTAMP, timeStampSince)));
-        query.where(expr);
+        StatementDescriptor<JmxNotification> desc = new StatementDescriptor<>(NOTIFICATIONS, QUERY_NOTIFICATIONS);
+        PreparedStatement<JmxNotification> stmt;
+        Cursor<JmxNotification> cursor;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, notificationsFor.getAgent().getAgentId());
+            stmt.setInt(1, notificationsFor.getId());
+            stmt.setLong(2, timeStampSince);
+            cursor = stmt.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return Collections.emptyList();
+        }
 
         List<JmxNotification> results = new ArrayList<>();
-        Cursor<JmxNotification> cursor = query.execute();
         while (cursor.hasNext()) {
             results.add(cursor.next());
         }
--- a/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -39,7 +39,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
 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;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -52,14 +52,14 @@
 
 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.Query;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
+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.VmRef;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.vm.jmx.common.JmxNotification;
 import com.redhat.thermostat.vm.jmx.common.JmxNotificationStatus;
 
@@ -95,7 +95,7 @@
 
         JmxNotificationStatus data = mock(JmxNotificationStatus.class);
 
-        dao.addNotifcationStatus(data);
+        dao.addNotificationStatus(data);
 
         verify(add).setPojo(data);
         verify(add).apply();
@@ -103,29 +103,36 @@
     }
 
     @Test
-    public void verifyGetLatestNotificationStatus() {
+    public void verifyGetLatestNotificationStatus() throws DescriptorParsingException, StatementExecutionException {
         JmxNotificationStatus data = new JmxNotificationStatus();
 
-        Query<JmxNotificationStatus> query = mock(Query.class);
-        when(storage.createQuery(JmxNotificationDAOImpl.NOTIFICATION_STATUS)).thenReturn(query);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<JmxNotificationStatus> stmt = (PreparedStatement<JmxNotificationStatus>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor(JmxNotificationStatus.class))).thenReturn(stmt);
 
-        Cursor<JmxNotificationStatus> cursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        Cursor<JmxNotificationStatus> cursor = (Cursor<JmxNotificationStatus>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(data).thenThrow(new AssertionError("should not be called"));
 
-        when(query.execute()).thenReturn(cursor);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         JmxNotificationStatus result = dao.getLatestNotificationStatus(vm);
 
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(factory.equalTo(Key.AGENT_ID, AGENT_ID),
-                factory.equalTo(Key.VM_ID, VM_ID));
-        verify(query).where(expr);
-        verify(query).sort(Key.TIMESTAMP, SortDirection.DESCENDING);
+        verify(storage).prepareStatement(anyDescriptor(JmxNotificationStatus.class));
+        verify(stmt).setString(0, AGENT_ID);
+        verify(stmt).setInt(1, VM_ID);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
         
         assertTrue(result == data);
     }
 
+    @SuppressWarnings("unchecked")
+    private <T extends Pojo> StatementDescriptor<T> anyDescriptor(Class<T> type) {
+        return (StatementDescriptor<T>) any(StatementDescriptor.class);
+    }
+
     @Test
     public void verfiyAddNotification() {
         Add add = mock(Add.class);
@@ -141,29 +148,31 @@
     }
 
     @Test
-    public void verifyGetNotificationsForVmSince() {
+    public void verifyGetNotificationsForVmSince() throws DescriptorParsingException, StatementExecutionException {
         long timeStamp = 10;
 
         JmxNotification data = mock(JmxNotification.class);
 
-        Query<JmxNotification> query = mock(Query.class);
-        when(storage.createQuery(JmxNotificationDAOImpl.NOTIFICATIONS)).thenReturn(query);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<JmxNotification> stmt = (PreparedStatement<JmxNotification>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor(JmxNotification.class))).thenReturn(stmt);
 
-        Cursor<JmxNotification> cursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        Cursor<JmxNotification> cursor = (Cursor<JmxNotification>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(data).thenThrow(new AssertionError("not supposed to be called again"));
 
-        when(query.execute()).thenReturn(cursor);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         List<JmxNotification> result = dao.getNotifications(vm, timeStamp);
 
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(
-                factory.equalTo(Key.AGENT_ID, AGENT_ID),
-                factory.and(factory.equalTo(Key.VM_ID, VM_ID),
-                        factory.greaterThan(Key.TIMESTAMP, timeStamp)));
-        verify(query).where(eq(expr));
-
+        verify(storage).prepareStatement(anyDescriptor(JmxNotification.class));
+        verify(stmt).setString(0, AGENT_ID);
+        verify(stmt).setInt(1, VM_ID);
+        verify(stmt).setLong(2, timeStamp);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
+        
         assertEquals(1, result.size());
         assertSame(data, result.get(0));
     }
--- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Mon Jul 15 12:52:59 2013 -0400
@@ -37,21 +37,32 @@
 package com.redhat.thermostat.vm.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.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.Put;
-import com.redhat.thermostat.storage.core.Query;
+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;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat;
 
 class VmMemoryStatDAOImpl implements VmMemoryStatDAO {
 
+    private static final Logger logger = LoggingUtils.getLogger(VmMemoryStatDAOImpl.class);
+    private static final String QUERY_LATEST = "QUERY "
+            + vmMemoryStatsCategory.getName() + " WHERE "
+            + Key.AGENT_ID.getName() + " = ?s AND " 
+            + Key.VM_ID.getName() + " = ?i SORT " 
+            + Key.TIMESTAMP.getName() + " DSC LIMIT 1";
+    
     private final Storage storage;
     private final VmLatestPojoListGetter<VmMemoryStat> getter;
 
@@ -63,19 +74,29 @@
 
     @Override
     public VmMemoryStat getLatestMemoryStat(VmRef ref) {
-        Query<VmMemoryStat> query = storage.createQuery(vmMemoryStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(
-                factory.equalTo(Key.AGENT_ID, ref.getAgent().getAgentId()),
-                factory.equalTo(Key.VM_ID, ref.getId()));
-        query.where(expr);
-        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        query.limit(1);
-        Cursor<VmMemoryStat> cursor = query.execute();
+        StatementDescriptor<VmMemoryStat> desc = new StatementDescriptor<>(vmMemoryStatsCategory, QUERY_LATEST);
+        PreparedStatement<VmMemoryStat> stmt;
+        Cursor<VmMemoryStat> cursor;
+        try {
+            stmt = storage.prepareStatement(desc);
+            stmt.setString(0, ref.getAgent().getAgentId());
+            stmt.setInt(1, ref.getId());
+            cursor = stmt.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return null;
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return null;
+        }
+        
+        VmMemoryStat result = null;
         if (cursor.hasNext()) {
-            return cursor.next();
+            result = cursor.next();
         }
-        return null;
+        return result;
     }
 
     @Override
--- a/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
+++ b/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Mon Jul 15 12:52:59 2013 -0400
@@ -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;
@@ -56,13 +55,14 @@
 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.Query;
+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.VmRef;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat.Generation;
@@ -76,14 +76,12 @@
     private Storage storage;
     private VmRef vmRef;
 
-    private Query query;
+    private PreparedStatement<VmMemoryStat> stmt;
     private Cursor<VmMemoryStat> cursor;
 
     @SuppressWarnings("unchecked")
     @Before
-    public void setUp() {
-        
-
+    public void setUp() throws DescriptorParsingException, StatementExecutionException {
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn(AGENT_ID);
 
@@ -92,19 +90,23 @@
         when(vmRef.getId()).thenReturn(VM_ID);
 
         storage = mock(Storage.class);
-        query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
+        stmt = (PreparedStatement<VmMemoryStat>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
 
-        cursor = mock(Cursor.class);
-        when(query.execute()).thenReturn(cursor);
+        cursor = (Cursor<VmMemoryStat>) mock(Cursor.class);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         when(cursor.hasNext()).thenReturn(false);
+    }
 
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<VmMemoryStat> anyDescriptor() {
+        return (StatementDescriptor<VmMemoryStat>) any(StatementDescriptor.class);
     }
 
     @After
     public void tearDown() {
-        query = null;
+        stmt = null;
         vmRef = null;
         cursor = null;
         storage = null;
@@ -124,42 +126,39 @@
     }
 
     @Test
-    public void testGetLatest() {
+    public void testGetLatest() throws DescriptorParsingException, StatementExecutionException {
         VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage);
         impl.getLatestMemoryStat(vmRef);
 
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(factory.equalTo(Key.AGENT_ID, AGENT_ID),
-                factory.equalTo(Key.VM_ID, VM_ID));
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, vmRef.getAgent().getAgentId());
+        verify(stmt).setInt(1, vmRef.getId());
+        verify(stmt).executeQuery();
     }
 
     @Test
-    public void testGetLatestSince() {
+    public void testGetLatestSince() throws DescriptorParsingException, StatementExecutionException {
         VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage);
-        impl.getLatestVmMemoryStats(vmRef, 123);
+        impl.getLatestVmMemoryStats(vmRef, 123L);
 
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(
-                factory.equalTo(Key.AGENT_ID, AGENT_ID),
-                factory.and(factory.equalTo(Key.VM_ID, VM_ID),
-                        factory.greaterThan(Key.TIMESTAMP, 123l)));
-        verify(query).where(eq(expr));
-        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, vmRef.getAgent().getAgentId());
+        verify(stmt).setInt(1, vmRef.getId());
+        verify(stmt).setLong(2, 123L);
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
     }
 
     @Test
-    public void testGetLatestReturnsNullWhenStorageEmpty() {
+    public void testGetLatestReturnsNullWhenStorageEmpty() throws DescriptorParsingException, StatementExecutionException {
         when(cursor.hasNext()).thenReturn(false);
         when(cursor.next()).thenReturn(null);
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(cursor);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<VmMemoryStat> stmt = (PreparedStatement<VmMemoryStat>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage);
         VmMemoryStat latest = impl.getLatestMemoryStat(vmRef);