changeset 902:4de458324cf9

Un-fluentize Storage.find(). Reviewed-by: vanaltj, jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/005064.html
author Roman Kennke <rkennke@redhat.com>
date Thu, 10 Jan 2013 15:09:23 +0100
parents eef06eccb01b
children d8f4cdaed16e 6e38be537e2a
files common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java common/core/src/main/java/com/redhat/thermostat/test/MockQuery.java common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/QueryTestHelper.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java 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 storage/core/src/main/java/com/redhat/thermostat/storage/core/AbstractQuery.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Query.java storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoQuery.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoQueryTest.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.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-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 web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java web/common/src/main/java/com/redhat/thermostat/web/common/WebQuery.java web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryTest.java web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java
diffstat 42 files changed, 487 insertions(+), 811 deletions(-) [+]
line wrap: on
line diff
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
@@ -65,8 +65,8 @@
 
     @Override
     public List<AgentInformation> getAllAgentInformation() {
-        Query query = storage.createQuery().from(CATEGORY);
-        Cursor<AgentInformation> agentCursor = storage.findAllPojos(query, AgentInformation.class);
+        Query<AgentInformation> query = storage.createQuery(CATEGORY, AgentInformation.class);
+        Cursor<AgentInformation> agentCursor = query.execute();
 
         List<AgentInformation> results = new ArrayList<>();
 
@@ -79,11 +79,10 @@
 
     @Override
     public List<AgentInformation> getAliveAgents() {
-        Query query = storage.createQuery()
-                .from(CATEGORY)
-                .where(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true);
+        Query<AgentInformation> query = storage.createQuery(CATEGORY, AgentInformation.class);
+        query.where(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true);
 
-        Cursor<AgentInformation> agentCursor = storage.findAllPojos(query, AgentInformation.class);
+        Cursor<AgentInformation> agentCursor = query.execute();
 
         List<AgentInformation> results = new ArrayList<>();
 
@@ -96,11 +95,10 @@
 
     @Override
     public AgentInformation getAgentInformation(HostRef agentRef) {
-        Query query = storage.createQuery()
-                .from(CATEGORY)
-                .where(Key.AGENT_ID, Criteria.EQUALS, agentRef.getAgentId());
-
-        return storage.findPojo(query, AgentInformation.class);
+        Query<AgentInformation> query = storage.createQuery(CATEGORY, AgentInformation.class);
+        query.where(Key.AGENT_ID, Criteria.EQUALS, agentRef.getAgentId());
+        query.limit(1);
+        return query.execute().next();
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
@@ -62,12 +62,11 @@
     @Override
     public List<BackendInformation> getBackendInformation(HostRef host) {
         // Sort by order value
-        Query query = storage.createQuery()
-                .from(CATEGORY)
-                .where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId());
+        Query<BackendInformation> query = storage.createQuery(CATEGORY, BackendInformation.class);
+        query.where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId());
 
         List<BackendInformation> results = new ArrayList<>();
-        Cursor<BackendInformation> cursor = storage.findAllPojos(query, BackendInformation.class);
+        Cursor<BackendInformation> cursor = query.execute();
         while (cursor.hasNext()) {
             BackendInformation backendInfo = cursor.next();
             results.add(backendInfo);
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
@@ -63,10 +63,10 @@
 
     @Override
     public HostInfo getHostInfo(HostRef ref) {
-        Query query = storage.createQuery()
-                .from(hostInfoCategory)
-                .where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId());
-        HostInfo result = storage.findPojo(query, HostInfo.class);
+        Query<HostInfo> query = storage.createQuery(hostInfoCategory, HostInfo.class);
+        query.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId());
+        query.limit(1);
+        HostInfo result = query.execute().next();
         return result;
     }
 
@@ -79,7 +79,7 @@
 
     @Override
     public Collection<HostRef> getHosts() {
-        Query allHosts = storage.createQuery().from(hostInfoCategory);
+        Query<HostInfo> allHosts = storage.createQuery(hostInfoCategory, HostInfo.class);
         return getHosts(allHosts);
     }
 
@@ -88,10 +88,8 @@
         List<HostRef> hosts = new ArrayList<>();
         List<AgentInformation> agentInfos = agentInfoDao.getAliveAgents();
         for (AgentInformation agentInfo : agentInfos) {
-            Query filter = storage.createQuery()
-                    .from(hostInfoCategory)
-                    .where(Key.AGENT_ID, Criteria.EQUALS, agentInfo.getAgentId());
-
+            Query<HostInfo> filter = storage.createQuery(hostInfoCategory, HostInfo.class);
+            filter.where(Key.AGENT_ID, Criteria.EQUALS, agentInfo.getAgentId());
             hosts.addAll(getHosts(filter));
         }
 
@@ -99,10 +97,10 @@
     }
 
 
-    private Collection<HostRef> getHosts(Query filter) {
+    private Collection<HostRef> getHosts(Query<HostInfo> filter) {
         Collection<HostRef> hosts = new ArrayList<HostRef>();
         
-        Cursor<HostInfo> hostsCursor = storage.findAllPojos(filter, HostInfo.class);
+        Cursor<HostInfo> hostsCursor = filter.execute();
         while(hostsCursor.hasNext()) {
             HostInfo host = hostsCursor.next();
             String agentId = host.getAgentId();
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java	Thu Jan 10 15:09:23 2013 +0100
@@ -60,12 +60,12 @@
     }
 
     public List<T> getLatest(HostRef hostRef, long since) {
-        Query query = buildQuery(hostRef, since);
+        Query<T> query = buildQuery(hostRef, since);
         return getLatest(query);
     }
 
-    private List<T> getLatest(Query query) {
-        Cursor<T> cursor = storage.findAllPojos(query, resultClass);
+    private List<T> getLatest(Query<T> query) {
+        Cursor<T> cursor = query.execute();
         List<T> result = new ArrayList<>();
         while (cursor.hasNext()) {
             T pojo = cursor.next();
@@ -74,13 +74,11 @@
         return result;
     }
 
-    protected Query buildQuery(HostRef hostRef, long since) {
-        Query query = storage.createQuery()
-                .from(cat)
-                .where(Key.AGENT_ID, Criteria.EQUALS, hostRef.getAgentId())
-                .where(Key.TIMESTAMP, Criteria.GREATER_THAN, since)
-                .sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
-        
+    protected Query<T> buildQuery(HostRef hostRef, long since) {
+        Query<T> query = storage.createQuery(cat, resultClass);
+        query.where(Key.AGENT_ID, Criteria.EQUALS, hostRef.getAgentId());
+        query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since);
+        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
         return query;
     }
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
@@ -58,11 +58,10 @@
 
     @Override
     public List<NetworkInterfaceInfo> getNetworkInterfaces(HostRef ref) {
-        Query allHostNetworkInterfaces = storage.createQuery()
-                .from(networkInfoCategory)
-                .where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId());
+        Query<NetworkInterfaceInfo> allHostNetworkInterfaces = storage.createQuery(networkInfoCategory, NetworkInterfaceInfo.class);
+        allHostNetworkInterfaces.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId());
 
-        Cursor<NetworkInterfaceInfo> cursor = storage.findAllPojos(allHostNetworkInterfaces, NetworkInterfaceInfo.class);
+        Cursor<NetworkInterfaceInfo> cursor = allHostNetworkInterfaces.execute();
         List<NetworkInterfaceInfo> result = new ArrayList<>();
         while (cursor.hasNext()) {
             NetworkInterfaceInfo stat = cursor.next();
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
@@ -60,11 +60,11 @@
 
     @Override
     public VmInfo getVmInfo(VmRef ref) {
-        Query findMatchingVm = storage.createQuery()
-                .from(vmInfoCategory)
-                .where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId())
-                .where(Key.VM_ID, Criteria.EQUALS, ref.getId());
-        VmInfo result = storage.findPojo(findMatchingVm, VmInfo.class);
+        Query<VmInfo> findMatchingVm = storage.createQuery(vmInfoCategory, VmInfo.class);
+        findMatchingVm.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId());
+        findMatchingVm.where(Key.VM_ID, Criteria.EQUALS, ref.getId());
+        findMatchingVm.limit(1);
+        VmInfo result = findMatchingVm.execute().next();
         if (result == null) {
             throw new DAOException("Unknown VM: host:" + ref.getAgent().getAgentId() + ";vm:" + ref.getId());
         }
@@ -74,15 +74,14 @@
     @Override
     public Collection<VmRef> getVMs(HostRef host) {
 
-        Query query = buildQuery(host);
-        Cursor<VmInfo> cursor = storage.findAllPojos(query, VmInfo.class);
+        Query<VmInfo> query = buildQuery(host);
+        Cursor<VmInfo> cursor = query.execute();
         return buildVMsFromQuery(cursor, host);
     }
 
-    private Query buildQuery(HostRef host) {
-        Query query = storage.createQuery()
-                .from(vmInfoCategory)
-                .where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId());
+    private Query<VmInfo> buildQuery(HostRef host) {
+        Query<VmInfo> query = storage.createQuery(vmInfoCategory, VmInfo.class);
+        query.where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId());
         return query;
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java	Thu Jan 10 15:09:23 2013 +0100
@@ -60,12 +60,12 @@
     }
 
     public List<T> getLatest(VmRef vmRef, long since) {
-        Query query = buildQuery(vmRef, since);
+        Query<T> query = buildQuery(vmRef, since);
         return getLatest(query);
     }
 
-    private List<T> getLatest(Query query) {
-        Cursor<T> cursor = storage.findAllPojos(query, resultClass);
+    private List<T> getLatest(Query<T> query) {
+        Cursor<T> cursor = query.execute();
         List<T> result = new ArrayList<>();
         while (cursor.hasNext()) {
             T pojo = cursor.next();
@@ -74,13 +74,12 @@
         return result;
     }
 
-    protected Query buildQuery(VmRef vmRef, long since) {
-        Query query = storage.createQuery()
-                .from(cat)
-                .where(Key.AGENT_ID, Criteria.EQUALS, vmRef.getAgent().getAgentId())
-                .where(Key.VM_ID, Criteria.EQUALS, vmRef.getId())
-                .where(Key.TIMESTAMP, Criteria.GREATER_THAN, since)
-                .sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+    protected Query<T> buildQuery(VmRef vmRef, long since) {
+        Query<T> query = storage.createQuery(cat, resultClass);
+        query.where(Key.AGENT_ID, Criteria.EQUALS, vmRef.getAgent().getAgentId());
+        query.where(Key.VM_ID, Criteria.EQUALS, vmRef.getId());
+        query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since);
+        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
         return query;
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/test/MockQuery.java	Thu Jan 10 15:02:44 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.test;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import com.redhat.thermostat.storage.core.AbstractQuery;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Key;
-
-public class MockQuery extends AbstractQuery {
-
-    public static class WhereClause <T> {
-        public final Key<T> key;
-        public final Criteria criteria;
-        public final T value;
-
-        public WhereClause(Key<T> key, Criteria criteria, T value) {
-            this.key = key;
-            this.criteria = criteria;
-            this.value = value;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj == null) {
-                return false;
-            }
-            if (obj == this) {
-                return true;
-            }
-            if (!(obj instanceof WhereClause)) {
-                return false;
-            }
-            WhereClause<?> other = (WhereClause<?>) obj;
-            return Objects.equals(key, other.key) && Objects.equals(criteria, other.criteria) && Objects.equals(value, other.value);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(key, criteria, value);
-        }
-    }
-
-    private final List<WhereClause<?>> whereClauses = new ArrayList<>();
-    private Category category;
-
-    @Override
-    public MockQuery from(Category category) {
-        setCategory(category);
-        return this;
-    }
-
-    public Category getCategory() {
-        return category;
-    }
-
-    public void setCategory(Category category) {
-        this.category = category;
-    }
-
-    @Override
-    public <T> MockQuery where(Key<T> key, Criteria criteria, T value) {
-        whereClauses.add(new WhereClause<>(key, criteria, value));
-        return this;
-    }
-
-    public List<WhereClause<?>> getWhereClauses() {
-        return whereClauses;
-    }
-
-    public int getWhereClausesCount() {
-        return whereClauses.size();
-    }
-
-    public <T> boolean hasWhereClause(Key<T> key, Criteria criteria, T value) {
-        for (WhereClause<?> whereClause: whereClauses) {
-            if (whereClause.equals(new WhereClause<T>(key, criteria, value))) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean hasWhereClauseFor(Key<?> key) {
-        for (WhereClause<?> where : whereClauses) {
-            if (where.key.equals(key)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (obj == this) {
-            return true;
-        }
-        if (!(obj instanceof MockQuery)) {
-            return false;
-        }
-        MockQuery other = (MockQuery) obj;
-        return Objects.equals(getCategory(), other.getCategory()) && Objects.equals(whereClauses, other.whereClauses);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(getCategory(), whereClauses);
-    }
-
-    public boolean hasSort(Key<?> key, SortDirection direction) {
-        
-        return getSorts().contains(new Sort(key, direction));
-    }
-
-}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -62,7 +62,6 @@
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.Update;
 import com.redhat.thermostat.storage.model.AgentInformation;
-import com.redhat.thermostat.test.MockQuery;
 
 public class AgentInfoDAOTest {
 
@@ -120,9 +119,9 @@
         when(agentCursor.next()).thenReturn(agent1).thenReturn(null);
 
         Storage storage = mock(Storage.class);
-        when(storage.findAllPojos(any(Query.class), same(AgentInformation.class))).thenReturn(agentCursor);
-        MockQuery query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
+        Query query = mock(Query.class);
+        when(query.execute()).thenReturn(agentCursor);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
         AgentInfoDAOImpl dao = new AgentInfoDAOImpl(storage);
 
         List<AgentInformation> allAgentInfo = dao.getAllAgentInformation();
@@ -141,16 +140,18 @@
         when(agentCursor.hasNext()).thenReturn(true).thenReturn(false);
         when(agentCursor.next()).thenReturn(agent1).thenReturn(null);
 
-        MockQuery query = new MockQuery();
+        Query query = mock(Query.class);
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(query);
-        when(storage.findAllPojos(query, AgentInformation.class)).thenReturn(agentCursor);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(agentCursor);
 
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
         List<AgentInformation> aliveAgents = dao.getAliveAgents();
 
-        assertEquals(AgentInfoDAO.CATEGORY, query.getCategory());
-        assertTrue(query.hasWhereClause(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true));
+        verify(storage).createQuery(AgentInfoDAO.CATEGORY, AgentInformation.class);
+        verify(query).where(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
 
         assertEquals(1, aliveAgents.size());
 
@@ -163,9 +164,14 @@
     public void verifyGetAgentInformationWhenStorageCantFindIt() {
         HostRef agentRef = mock(HostRef.class);
 
-        MockQuery query = new MockQuery();
+        Query query = mock(Query.class);
+        Cursor cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(false);
+        when(cursor.next()).thenReturn(null);
+        when(query.execute()).thenReturn(cursor);
+
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(query);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
 
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
 
@@ -180,16 +186,21 @@
         when(agentRef.getAgentId()).thenReturn(agentInfo1.getAgentId());
 
         Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
-        when(storage.findPojo(query, AgentInformation.class)).thenReturn(agentInfo1);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        Cursor cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(agentInfo1).thenReturn(null);
+        when(query.execute()).thenReturn(cursor);
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
 
         AgentInformation computed = dao.getAgentInformation(agentRef);
 
-        assertEquals(AgentInfoDAO.CATEGORY, query.getCategory());
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, agentInfo1.getAgentId()));
-
+        verify(storage).createQuery(AgentInfoDAO.CATEGORY, AgentInformation.class);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, agentInfo1.getAgentId());
+        verify(query).limit(1);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
         AgentInformation expected = agentInfo1;
         assertSame(expected, computed);
     }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -42,6 +42,7 @@
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
@@ -56,11 +57,11 @@
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.BackendInformation;
-import com.redhat.thermostat.test.MockQuery;
 
 public class BackendInfoDAOTest {
 
@@ -134,17 +135,19 @@
         when(backendCursor.hasNext()).thenReturn(true).thenReturn(false);
         when(backendCursor.next()).thenReturn(backend1).thenReturn(null);
 
-        MockQuery query = new MockQuery();
+        Query query = mock(Query.class);
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(query);
-        when(storage.findAllPojos(query, BackendInformation.class)).thenReturn(backendCursor);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(backendCursor);
 
         BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
 
         List<BackendInformation> result = dao.getBackendInformation(agentref);
 
-        assertEquals(BackendInfoDAO.CATEGORY, query.getCategory());
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
+        verify(storage).createQuery(BackendInfoDAO.CATEGORY, BackendInformation.class);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
 
         assertEquals(Arrays.asList(backendInfo1), result);
     }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -40,9 +40,8 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -50,8 +49,6 @@
 import java.util.Collection;
 
 import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Category;
@@ -61,7 +58,7 @@
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.HostInfo;
-import com.redhat.thermostat.test.MockQuery;
+
 
 public class HostInfoDAOTest {
 
@@ -100,9 +97,13 @@
     public void testGetHostInfo() {
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(new MockQuery());
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
         HostInfo info = new HostInfo(HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
-        when(storage.findPojo(any(Query.class), same(HostInfo.class))).thenReturn(info);
+        Cursor cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(info).thenReturn(null);
+        when(query.execute()).thenReturn(cursor);
         AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
 
         HostInfo result = new HostInfoDAOImpl(storage, agentInfoDao).getHostInfo(new HostRef("some uid", HOST_NAME));
@@ -133,13 +134,9 @@
         when(cursor.next()).thenReturn(hostConfig);
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(HostInfo.class))).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
         
         return storage;
     }
@@ -175,13 +172,9 @@
         when(cursor.next()).thenReturn(hostConfig1).thenReturn(hostConfig2).thenReturn(hostConfig3);
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(HostInfo.class))).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
         
         return storage;
     }
@@ -225,7 +218,7 @@
 
         assertEquals(1, hosts.size());
         assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
-        verify(storage, times(1)).findAllPojos(any(Query.class), same(HostInfo.class));
+        verify(storage).createQuery(HostInfoDAO.hostInfoCategory, HostInfo.class);
     }
     
     private Pair<Storage, AgentInfoDAO> setupForSingleAliveHost() {
@@ -260,13 +253,10 @@
         // storage
         
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(HostInfo.class))).thenReturn(cursor1);
+        Query query = mock(Query.class);
+        
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor1);
 
         AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
         when(agentDao.getAliveAgents()).thenReturn(Arrays.asList(agentInfo1));
@@ -288,7 +278,7 @@
         assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
         assertTrue(hosts.contains(new HostRef("456", "fluffhost2")));
         assertTrue(hosts.contains(new HostRef("678", "fluffhost3")));
-        verify(storage, times(3)).findAllPojos(any(Query.class), same(HostInfo.class));
+        verify(storage, atLeast(3)).createQuery(HostInfoDAO.hostInfoCategory, HostInfo.class);
     }
     
     private Pair<Storage, AgentInfoDAO> setupForAliveHost3() {
@@ -338,15 +328,9 @@
         // storage
         
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(HostInfo.class))).thenReturn(cursor1).
-                                                                           thenReturn(cursor2).
-                                                                           thenReturn(cursor3);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor1).thenReturn(cursor2).thenReturn(cursor3);
         
         AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
         when(agentDao.getAliveAgents()).thenReturn(Arrays.asList(agentInfo1, agentInfo2, agentInfo3));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -39,8 +39,11 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.List;
@@ -52,10 +55,10 @@
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Query.Criteria;
+import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.CpuStat;
-import com.redhat.thermostat.test.MockQuery;
 
 public class HostLatestPojoListGetterTest {
     private static final String AGENT_ID = "agentid";
@@ -95,36 +98,38 @@
     @Test
     public void testBuildQuery() {
         Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
-        when (storage.createQuery()).thenReturn(query);
+        Query query = mock(Query.class);
+        when (storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
 
         HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, CpuStat.class);
-        query = (MockQuery) getter.buildQuery(ref, 123);
+        query = getter.buildQuery(ref, 123);
 
         assertNotNull(query);
-        assertEquals(cat, query.getCategory());
-        assertEquals(2, query.getWhereClausesCount());
-        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l));
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
+        verify(storage).createQuery(cat, CpuStat.class);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verifyNoMoreInteractions(query);
     }
 
     @Test
     public void testBuildQueryPopulatesUpdateTimes() {
         Storage storage = mock(Storage.class);
-        MockQuery ignored = new MockQuery();
-        MockQuery query = new MockQuery();
-        when(storage.createQuery()).thenReturn(ignored).thenReturn(query);
+        Query ignored = mock(Query.class);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(ignored).thenReturn(query);
 
         HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, CpuStat.class);
-        ignored = (MockQuery) getter.buildQuery(ref,Long.MIN_VALUE); // Ignore first return value.
+        ignored = getter.buildQuery(ref,Long.MIN_VALUE); // Ignore first return value.
 
-        query = (MockQuery) getter.buildQuery(ref, Long.MIN_VALUE);
+        query = getter.buildQuery(ref, Long.MIN_VALUE);
 
         assertNotNull(query);
-        assertEquals(cat, query.getCategory());
-        assertEquals(2, query.getWhereClausesCount());
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
-        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
+        verify(storage, times(2)).createQuery(cat, CpuStat.class);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verifyNoMoreInteractions(query);
     }
 
     @Test
@@ -135,16 +140,16 @@
         when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
 
         Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
-        when(storage.findAllPojos(query, CpuStat.class)).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
 
         HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, CpuStat.class);
 
         List<CpuStat> stats = getter.getLatest(ref, Long.MIN_VALUE);
 
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
-        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
 
         assertNotNull(stats);
         assertEquals(2, stats.size());
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -37,11 +37,11 @@
 package com.redhat.thermostat.common.dao;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.Collection;
@@ -52,10 +52,11 @@
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
-import com.redhat.thermostat.test.MockQuery;
 
 public class NetworkInterfaceInfoDAOTest {
 
@@ -89,9 +90,9 @@
         when(cursor.next()).thenReturn(niInfo);
 
         Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
-        when(storage.findAllPojos(query, NetworkInterfaceInfo.class)).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -99,7 +100,9 @@
         NetworkInterfaceInfoDAO dao = new NetworkInterfaceInfoDAOImpl(storage);
         List<NetworkInterfaceInfo> netInfo = dao.getNetworkInterfaces(hostRef);
 
-        assertFalse(query.hasWhereClauseFor(Key.TIMESTAMP));
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system");
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
 
         assertEquals(1, netInfo.size());
 
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/QueryTestHelper.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/QueryTestHelper.java	Thu Jan 10 15:09:23 2013 +0100
@@ -43,8 +43,6 @@
 
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Remove;
 
 public class QueryTestHelper {
@@ -57,11 +55,4 @@
         return mockRemove;
     }
 
-    @SuppressWarnings("unchecked")
-    public static Query createMockQuery() {
-        Query mockQuery = mock(Query.class);
-        when(mockQuery.from(any(Category.class))).thenReturn(mockQuery);
-        when(mockQuery.where(any(Key.class), any(Criteria.class), any())).thenReturn(mockQuery);
-        return mockQuery;
-    }
 }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -57,12 +57,10 @@
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.Update;
 import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.test.MockQuery;
 
 public class VmInfoDAOTest {
 
@@ -126,10 +124,13 @@
     public void testGetVmInfo() {
 
         Storage storage = mock(Storage.class);
-        Query query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
         VmInfo expected = new VmInfo(vmId, startTime, stopTime, jVersion, jHome, mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs, props, env, libs);
-        when(storage.findPojo(query, VmInfo.class)).thenReturn(expected);
+        Cursor cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(expected).thenReturn(null);
+        when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -147,9 +148,11 @@
     public void testGetVmInfoUnknownVM() {
 
         Storage storage = mock(Storage.class);
-        Query query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
-
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        Cursor cursor = mock(Cursor.class);
+        when(query.execute()).thenReturn(cursor);
+        
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
 
@@ -179,9 +182,6 @@
     }
 
     private Storage setupStorageForSingleVM() {
-      Query expectedQuery = new MockQuery()
-          .from(VmInfoDAO.vmInfoCategory)
-          .where(Key.AGENT_ID, Criteria.EQUALS, "123");
 
       VmInfo vm1 = new VmInfo();
       vm1.setVmPid(123);
@@ -193,8 +193,9 @@
       when(singleVMCursor.next()).thenReturn(vm1);
 
       Storage storage = mock(Storage.class);
-      when(storage.createQuery()).thenReturn(new MockQuery());
-      when(storage.findAllPojos(expectedQuery, VmInfo.class)).thenReturn(singleVMCursor);
+      Query query = mock(Query.class);
+      when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+      when(query.execute()).thenReturn(singleVMCursor);
       return storage;
   }
 
@@ -211,9 +212,6 @@
     }
 
     private Storage setupStorageForMultiVM() {
-      Query expectedQuery = new MockQuery()
-          .from(VmInfoDAO.vmInfoCategory)
-          .where(Key.AGENT_ID, Criteria.EQUALS, "456");
 
       VmInfo vm1 = new VmInfo();
       vm1.setVmPid(123);
@@ -229,8 +227,9 @@
       when(multiVMsCursor.next()).thenReturn(vm1).thenReturn(vm2);
 
       Storage storage = mock(Storage.class);
-      when(storage.createQuery()).thenReturn(new MockQuery());
-      when(storage.findAllPojos(expectedQuery, VmInfo.class)).thenReturn(multiVMsCursor);
+      Query query = mock(Query.class);
+      when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+      when(query.execute()).thenReturn(multiVMsCursor);
       return storage;
   }
 
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -38,11 +38,11 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.List;
@@ -54,10 +54,9 @@
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query;
+import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.model.VmClassStat;
-import com.redhat.thermostat.test.MockQuery;
 
 public class VmLatestPojoListGetterTest {
     private static final String AGENT_ID = "agentid";
@@ -93,37 +92,39 @@
     @Test
     public void testBuildQuery() {
         Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
 
         VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, VmClassStat.class);
-        query = (MockQuery) getter.buildQuery(vmRef, 123l);
+        query = getter.buildQuery(vmRef, 123l);
 
         assertNotNull(query);
-        assertEquals(cat, query.getCategory());
-        assertEquals(3, query.getWhereClausesCount());
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
-        assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, VM_PID));
-        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l));
+        verify(storage).createQuery(cat, VmClassStat.class);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
+        verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_PID);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l);
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verifyNoMoreInteractions(query);
     }
 
     @Test
     public void testBuildQueryPopulatesUpdateTimes() {
         Storage storage = mock(Storage.class);
-        MockQuery ignored = new MockQuery();
-        MockQuery query = new MockQuery();
-        when(storage.createQuery()).thenReturn(ignored).thenReturn(query);
+        Query ignored = mock(Query.class);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(ignored).thenReturn(query);
 
         VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, VmClassStat.class);
         getter.buildQuery(vmRef, Long.MIN_VALUE); // Ignore first return value.
-        query = (MockQuery) getter.buildQuery(vmRef, Long.MIN_VALUE);
+        query = getter.buildQuery(vmRef, Long.MIN_VALUE);
 
         assertNotNull(query);
-        assertEquals(cat, query.getCategory());
-        assertEquals(3, query.getWhereClausesCount());
-        assertTrue(query.hasWhereClauseFor(Key.AGENT_ID));
-        assertTrue(query.hasWhereClauseFor(Key.VM_ID));
-        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
+        verify(storage, times(2)).createQuery(cat, VmClassStat.class);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
+        verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_PID);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verifyNoMoreInteractions(query);
     }
 
     @Test
@@ -134,19 +135,21 @@
         when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
 
         Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
-        when(storage.findAllPojos(any(Query.class), same(VmClassStat.class))).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
 
         VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, VmClassStat.class);
 
         List<VmClassStat> stats = getter.getLatest(vmRef, t2);
 
-        verify(storage).findAllPojos(any(Query.class), same(VmClassStat.class));
-
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
-        assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, VM_PID));
-        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, t2));
+        verify(storage).createQuery(cat, VmClassStat.class);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
+        verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_PID);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, t2);
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
 
         assertNotNull(stats);
         assertEquals(2, stats.size());
--- a/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -41,9 +41,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.Collection;
@@ -61,7 +63,6 @@
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.CpuStat;
-import com.redhat.thermostat.test.MockQuery;
 
 public class CpuStatDAOTest {
 
@@ -82,7 +83,7 @@
         @SuppressWarnings("unchecked")
         Cursor<CpuStat> cursor = mock(Cursor.class);
         Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
+        Query query = mock(Query.class);
         HostRef hostRef = mock(HostRef.class);
         CpuStatDAO dao = new CpuStatDAOImpl(storage);
 
@@ -92,13 +93,17 @@
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(cpuStat);
 
-        when(storage.createQuery()).thenReturn(query);
-        when(storage.findAllPojos(query, CpuStat.class)).thenReturn(cursor);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
         when(hostRef.getAgentId()).thenReturn("system");
 
         List<CpuStat> cpuStats = dao.getLatestCpuStats(hostRef, Long.MIN_VALUE);
 
-        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system");
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
 
         assertEquals(1, cpuStats.size());
         CpuStat stat = cpuStats.get(0);
@@ -113,7 +118,7 @@
         @SuppressWarnings("unchecked")
         Cursor<CpuStat> cursor = mock(Cursor.class);
         Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
+        Query query = mock(Query.class);
         HostRef hostRef = mock(HostRef.class);
 
         CpuStatDAO dao = new CpuStatDAOImpl(storage);
@@ -123,16 +128,16 @@
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(cpuStat);
 
-        when(storage.createQuery()).thenReturn(query);
-        when(storage.findAllPojos(any(Query.class), same(CpuStat.class))).thenReturn(cursor);
+        when(storage.createQuery(CpuStatDAO.cpuStatCategory, CpuStat.class)).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
         when(hostRef.getAgentId()).thenReturn("system");
 
         dao.getLatestCpuStats(hostRef, Long.MIN_VALUE);
         dao.getLatestCpuStats(hostRef, Long.MIN_VALUE);
 
-        verify(storage, times(2)).findAllPojos(query, CpuStat.class);
-
-        query.hasWhereClauseFor(Key.TIMESTAMP);
+        verify(query, times(2)).execute();
+        verify(query, atLeastOnce()).where(same(Key.AGENT_ID), same(Criteria.EQUALS), any());
+        verify(query, atLeastOnce()).where(same(Key.TIMESTAMP), any(Criteria.class), any());
     }
 
     @Test
--- a/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -42,6 +42,7 @@
 import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.Collection;
@@ -62,7 +63,6 @@
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.MemoryStat;
-import com.redhat.thermostat.test.MockQuery;
 
 public class MemoryStatDAOTest {
 
@@ -102,13 +102,9 @@
         when(cursor.next()).thenReturn(memStat1);
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(MemoryStat.class))).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -116,9 +112,12 @@
         MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
         List<MemoryStat> memoryStats = dao.getLatestMemoryStats(hostRef, Long.MIN_VALUE);
 
-        ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
-        verify(storage).findAllPojos(arg.capture(), same(MemoryStat.class));
-        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
+        verify(storage).createQuery(MemoryStatDAO.memoryStatCategory, MemoryStat.class);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system");
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
 
         assertEquals(1, memoryStats.size());
         MemoryStat stat = memoryStats.get(0);
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/AbstractQuery.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/AbstractQuery.java	Thu Jan 10 15:09:23 2013 +0100
@@ -41,7 +41,9 @@
 import java.util.List;
 import java.util.Objects;
 
-public abstract class AbstractQuery implements Query {
+import com.redhat.thermostat.storage.model.Pojo;
+
+public abstract class AbstractQuery<T extends Pojo> implements Query<T> {
 
     public static class Sort {
         private Key<?> key;
@@ -93,9 +95,8 @@
     }
 
     @Override
-    public <T> Query sort(Key<T> key, SortDirection direction) {
+    public void sort(Key<?> key, SortDirection direction) {
         sorts.add(new Sort(key, direction));
-        return this;
     }
 
     public List<Sort> getSorts() {
@@ -107,9 +108,8 @@
     }
 
     @Override
-    public Query limit(int limit) {
+    public void limit(int limit) {
         this.limit  = limit;
-        return this;
     }
 
     public int getLimit() {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Query.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Query.java	Thu Jan 10 15:09:23 2013 +0100
@@ -36,10 +36,12 @@
 
 package com.redhat.thermostat.storage.core;
 
+import com.redhat.thermostat.storage.model.Pojo;
+
 /**
  * Describes what data should be fetched.
  */
-public interface Query {
+public interface Query<T extends Pojo> {
 
     enum Criteria {
         EQUALS,
@@ -65,11 +67,12 @@
         }
     }
 
-    Query from(Category category);
+    <S> void where(Key<S> key, Criteria criteria, S value);
 
-    <T> Query where(Key<T> key, Criteria criteria, T value);
+    void sort(Key<?> key, SortDirection direction);
 
-    <T> Query sort(Key<T> key, SortDirection direction);
+    void limit(int n);
 
-    Query limit(int n);
+    Cursor<T> execute();
+
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Thu Jan 10 15:09:23 2013 +0100
@@ -199,14 +199,8 @@
 
     }
 
-    @Override
-    public <T extends Pojo> Cursor<T> findAllPojos(Query query, Class<T> resultClass) {
-        return delegate.findAllPojos(query, resultClass);
-    }
-
-    @Override
-    public <T extends Pojo> T findPojo(Query query, Class<T> resultClass) {
-        return delegate.findPojo(query, resultClass);
+    <T extends Pojo> Cursor<T> findAllPojos(Query query, Class<T> resultClass) {
+        return query.execute();
     }
 
     @Override
@@ -234,8 +228,8 @@
     }
 
     @Override
-    public Query createQuery() {
-        return delegate.createQuery();
+    public <T extends Pojo> Query<T> createQuery(Category category, Class<T> resultClass) {
+        return delegate.createQuery(category, resultClass);
     }
 
     @Override
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Thu Jan 10 15:09:23 2013 +0100
@@ -56,8 +56,6 @@
 
     Connection getConnection();
 
-    // TODO why does putPojo have an agent id param but not updatePojo and removePojo?
-
     Add createAdd(Category category);
     Replace createReplace(Category category);
 
@@ -68,17 +66,14 @@
      */
     void purge();
 
-    <T extends Pojo> Cursor<T> findAllPojos(Query query, Class<T> resultClass);
-
-    <T extends Pojo> T findPojo(Query query, Class<T> resultClass);
-
     long getCount(Category category);
 
     void saveFile(String filename, InputStream data);
 
     InputStream loadFile(String filename);
 
-    Query createQuery();
+    <T extends Pojo> Query<T> createQuery(Category category, Class<T> resultClass);
+
     Update createUpdate(Category category);
     Remove createRemove();
 
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -175,6 +175,7 @@
     private Storage delegateStorage;
     private Add delegateAdd;
     private Replace delegateReplace;
+    private Query delegateQuery;
 
     private TestExecutor executor;
     private TestExecutor fileExecutor;
@@ -195,15 +196,14 @@
         delegateReplace = mock(Replace.class);
 
         Remove remove = mock(Remove.class);
-        Query query = mock(Query.class);
+        delegateQuery = mock(Query.class);
         when(delegateStorage.createAdd(any(Category.class))).thenReturn(delegateAdd);
         when(delegateStorage.createReplace(any(Category.class))).thenReturn(delegateReplace);
         when(delegateStorage.createRemove()).thenReturn(remove);
-        when(delegateStorage.createQuery()).thenReturn(query);
+        when(delegateStorage.createQuery(any(Category.class), any(Class.class))).thenReturn(delegateQuery);
         expectedResults = mock(Cursor.class);
-        when(delegateStorage.findAllPojos(query, TestPojo.class)).thenReturn(expectedResults);
+        when(delegateQuery.execute()).thenReturn(expectedResults);
         expectedResult = new TestPojo();
-        when(delegateStorage.findPojo(query, TestPojo.class)).thenReturn(expectedResult);
         when(delegateStorage.getCount(any(Category.class))).thenReturn(42l);
         expectedFile = mock(InputStream.class);
         when(delegateStorage.loadFile(anyString())).thenReturn(expectedFile);
@@ -221,6 +221,7 @@
         delegateStorage = null;
         fileExecutor = null;
         executor = null;
+        delegateQuery = null;
     }
 
     @Test
@@ -305,12 +306,13 @@
 
     @Test
     public void testFindAllPojos() {
-        Query query = queuedStorage.createQuery();
-        verify(delegateStorage).createQuery();
+        Category category = mock(Category.class);
+        Query query = queuedStorage.createQuery(category, TestPojo.class);
+        verify(delegateStorage).createQuery(category, TestPojo.class);
         verifyNoMoreInteractions(delegateStorage);
 
-        Cursor<TestPojo> result = queuedStorage.findAllPojos(query, TestPojo.class);
-        verify(delegateStorage).findAllPojos(query, TestPojo.class);
+        Cursor<TestPojo> result = query.execute();
+        verify(delegateQuery).execute();
         assertSame(expectedResults, result);
 
         assertNull(executor.getTask());
@@ -318,20 +320,6 @@
     }
 
     @Test
-    public void testFindPojo() {
-        Query query = queuedStorage.createQuery();
-        verify(delegateStorage).createQuery();
-        verifyNoMoreInteractions(delegateStorage);
-
-        TestPojo result = queuedStorage.findPojo(query, TestPojo.class);
-        verify(delegateStorage).findPojo(query, TestPojo.class);
-        assertSame(expectedResult, result);
-
-        assertNull(executor.getTask());
-        assertNull(fileExecutor.getTask());
-    }
-
-    @Test
     public void testGetCount() {
         Category category = mock(Category.class);
 
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoQuery.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoQuery.java	Thu Jan 10 15:09:23 2013 +0100
@@ -42,18 +42,22 @@
 import com.mongodb.DBObject;
 import com.redhat.thermostat.storage.core.AbstractQuery;
 import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.model.Pojo;
 
-public class MongoQuery extends AbstractQuery {
+public class MongoQuery<T extends Pojo> extends AbstractQuery<T> {
 
+    private MongoStorage storage;
     private BasicDBObject query = new BasicDBObject();
     private boolean hasClauses = false;
     private Category category;
+    private Class<T> resultClass;
 
-    @Override
-    public MongoQuery from(Category category) {
-        setCategory(category);
-        return this;
+    MongoQuery(MongoStorage storage, Category category, Class<T> resultClass) {
+        this.storage = storage;
+        this.category = category;
+        this.resultClass = resultClass;
     }
 
     public Category getCategory() {
@@ -65,11 +69,11 @@
     }
 
     @Override
-    public <T> MongoQuery where(Key<T> key, Criteria operator, T value) {
-        return where(key.getName(), operator, value);
+    public <S> void where(Key<S> key, Criteria operator, S value) {
+        where(key.getName(), operator, value);
     }
 
-    public MongoQuery where(String key, Criteria operator, Object value) {
+    public void where(String key, Criteria operator, Object value) {
         switch (operator) {
         case EQUALS:
             query.put(key, value);
@@ -97,7 +101,6 @@
             throw new IllegalArgumentException("MongoQuery can not handle " + operator);
         }
         hasClauses = true;
-        return this;
     }
 
     DBObject getGeneratedQuery() {
@@ -115,7 +118,7 @@
         if (!(obj instanceof MongoQuery)) {
             return false;
         }
-        MongoQuery other = (MongoQuery) obj;
+        MongoQuery<?> other = (MongoQuery<?>) obj;
         return Objects.equals(getCategory(), other.getCategory()) && Objects.equals(this.query, other.query);
     }
 
@@ -128,4 +131,8 @@
         return hasClauses ;
     }
 
+    @Override
+    public Cursor<T> execute() {
+        return storage.findAllPojos(this, resultClass);
+    }
 }
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Thu Jan 10 15:09:23 2013 +0100
@@ -236,8 +236,8 @@
     }
 
     @Override
-    public Query createQuery() {
-        return new MongoQuery();
+    public <T extends Pojo> Query<T> createQuery(Category category, Class<T> resultClass) {
+        return new MongoQuery(this, category, resultClass);
     }
 
     @Override
@@ -250,8 +250,7 @@
         return new MongoRemove();
     }
 
-    @Override
-    public <T extends Pojo> Cursor<T> findAllPojos(Query query, Class<T> resultClass) {
+    <T extends Pojo> Cursor<T> findAllPojos(Query<T> query, Class<T> resultClass) {
         MongoQuery mongoQuery =  checkAndCastQuery(query);
         DBCollection coll = getCachedCollection(mongoQuery.getCategory());
         DBCursor dbCursor;
@@ -279,15 +278,6 @@
     }
 
 
-    @Override
-    public <T extends Pojo> T findPojo(Query query, Class<T> resultClass) {
-        MongoQuery mongoQuery = checkAndCastQuery(query);
-        DBCollection coll = getCachedCollection(mongoQuery.getCategory());
-        DBObject dbResult = coll.findOne(mongoQuery.getGeneratedQuery());
-        MongoPojoConverter conv = new MongoPojoConverter();
-        return conv.convertMongoToPojo(dbResult, resultClass);
-    }
-
     private MongoQuery checkAndCastQuery(Query query) {
         if (!(query instanceof MongoQuery)) {
             throw new IllegalArgumentException("MongoStorage can only handle MongoQuery");
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoQueryTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoQueryTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -38,28 +38,45 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
 
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.mongodb.BasicDBObject;
 import com.mongodb.DBObject;
 import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Query.Criteria;
-import com.redhat.thermostat.storage.mongodb.internal.MongoQuery;
 
 public class MongoQueryTest {
 
+    private static MongoStorage storage;
+    private static Category category;
+
+    @BeforeClass
+    public static void setUp() {
+        storage = mock(MongoStorage.class);
+        category = new Category("some-collection");
+    }
+
+    @AfterClass
+    public static void tearDown() {
+        storage = null;
+        category = null;
+    }
+
     @Test
     public void testEmptyQuery() {
-        MongoQuery query = new MongoQuery();
+        
+        MongoQuery query = new MongoQuery(storage, category, String.class);
         DBObject mongoQuery = query.getGeneratedQuery();
         assertTrue(mongoQuery.keySet().isEmpty());
     }
 
     @Test
     public void testCollectionName() {
-        MongoQuery query = new MongoQuery().from(new Category("some-collection"));
+        MongoQuery query = new MongoQuery(storage, category, String.class);
         assertEquals("some-collection", query.getCategory().getName());
     }
 
@@ -100,7 +117,8 @@
     }
 
     private DBObject generateSimpleWhereQuery(String key, Criteria criteria, Object value) {
-        MongoQuery query = new MongoQuery().where(key, criteria, value);
+        MongoQuery query = new MongoQuery(storage, category, String.class);
+        query.where(key, criteria, value);
         return query.getGeneratedQuery();
     }
 
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -203,57 +203,26 @@
         cursor = null;
     }
 
-    @Test (expected=IllegalArgumentException.class)
-    public void verifyFindOnlyAcceptsMongoQuery() {
-        MongoStorage storage = makeStorage();
-        Query query = mock(Query.class);
-        storage.findPojo(query, TestClass.class);
-    }
-
-    @Test (expected=IllegalArgumentException.class)
-    public void verifyFindAllOnlyAcceptsMongoQuery() {
-        MongoStorage storage = makeStorage();
-        Query query = mock(Query.class);
-        storage.findAllPojos(query, TestClass.class);
-    }
-
     @Test
     public void verifyFindAllReturnsCursor() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
-        Query query = storage.createQuery().from(testCategory);
-        Cursor<TestClass> cursor = storage.findAllPojos(query, TestClass.class);
+        Query query = storage.createQuery(testCategory, TestClass.class);
+        Cursor<TestClass> cursor = query.execute();
         assertNotNull(cursor);
     }
 
     @Test
-    public void verifyFindReturnsChunk() throws Exception {
-        PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
-        MongoStorage storage = makeStorage();
-        Query query = storage.createQuery().from(testCategory).where(key1, Criteria.EQUALS, "test1");
-        TestClass result = storage.findPojo(query, TestClass.class);
-        assertNotNull(result);
-    }
-
-    @Test
     public void verifyFindAllCallsDBCollectionFind() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
-        Query query = storage.createQuery().from(testCategory).where(key1, Criteria.EQUALS, "fluff");
-        storage.findAllPojos(query, TestClass.class);
+        Query query = storage.createQuery(testCategory, TestClass.class);
+        query.where(key1, Criteria.EQUALS, "fluff");
+        query.execute();
         verify(testCollection).find(any(DBObject.class));
     }
 
     @Test
-    public void verifyFindCallsDBCollectionFindOne() throws Exception {
-        PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
-        MongoStorage storage = makeStorage();
-        Query query = storage.createQuery().from(testCategory);
-        storage.findPojo(query, TestClass.class);
-        verify(testCollection).findOne(any(DBObject.class));
-    }
-
-    @Test
     public void verifyFindAllCallsDBCollectionFindWithCorrectQuery() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
@@ -263,45 +232,10 @@
         DBObject generatedQuery = mock(DBObject.class);
         when(query.getGeneratedQuery()).thenReturn(generatedQuery);
         when(query.getCategory()).thenReturn(testCategory);
-        ArgumentCaptor<DBObject> findArg = ArgumentCaptor.forClass(DBObject.class);
 
         storage.findAllPojos(query, TestClass.class);
 
-        verify(testCollection).find(findArg.capture());
-        assertSame(generatedQuery, findArg.getValue());
-    }
-
-    @Test
-    public void verifyFindCallsDBCollectionFindOneWithCorrectQuery() throws Exception {
-        PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
-        MongoStorage storage = makeStorage();
-
-        MongoQuery query = mock(MongoQuery.class);
-        DBObject generatedQuery = mock(DBObject.class);
-        when(query.getGeneratedQuery()).thenReturn(generatedQuery);
-        when(query.getCategory()).thenReturn(testCategory);
-
-        ArgumentCaptor<DBObject> findArg = ArgumentCaptor.forClass(DBObject.class);
-
-        storage.findPojo(query, TestClass.class);
-
-        verify(testCollection).findOne(findArg.capture());
-        assertSame(generatedQuery, findArg.getValue());
-    }
-
-    @Test
-    public void verifyFindReturnsCorrectChunk() throws Exception {
-        PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
-        MongoStorage storage = makeStorage();
-        // TODO find a way to test this that isn't just testing mock and converters
-        // Because we mock the DBCollection, the contents of this query don't actually determine the result.
-        MongoQuery query = new MongoQuery().from(testCategory);
-
-        TestClass result = storage.findPojo(query, TestClass.class);
-
-        assertNotNull(result);
-        assertEquals("test1", result.getKey1());
-        assertEquals("test2", result.getKey2());
+        verify(testCollection).find(same(generatedQuery));
     }
 
     @Test
@@ -310,9 +244,8 @@
         MongoStorage storage = makeStorage();
         // TODO find a way to test this that isn't just testing MongoCursor
         // Because we mock the DBCollection, the contents of this query don't actually determine the result.
-        MongoQuery query = new MongoQuery().from(testCategory);
-
-        Cursor<TestClass> cursor = storage.findAllPojos(query, TestClass.class);
+        Query query = storage.createQuery(testCategory, TestClass.class);
+        Cursor<TestClass> cursor = query.execute();
 
         verifyDefaultCursor(cursor);
     }
@@ -323,9 +256,11 @@
         MongoStorage storage = makeStorage();
         // TODO find a way to test this that isn't just testing MongoCursor
         // Because we mock the DBCollection, the contents of this query don't actually determine the result.
-        MongoQuery query = (MongoQuery) new MongoQuery().from(testCategory).sort(key1, Query.SortDirection.ASCENDING).limit(3);
+        Query query = storage.createQuery(testCategory, TestClass.class);
+        query.sort(key1, Query.SortDirection.ASCENDING);
+        query.limit(3);
 
-        Cursor<TestClass> cursor = storage.findAllPojos(query, TestClass.class);
+        Cursor<TestClass> cursor = query.execute();
 
         verifyDefaultCursor(cursor);
         ArgumentCaptor<DBObject> orderBy = ArgumentCaptor.forClass(DBObject.class);
@@ -339,8 +274,8 @@
     public void verifyFindAllFromCategoryCallsDBCollectionFindAll() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
-        Query query = storage.createQuery().from(testCategory);
-        storage.findAllPojos(query, TestClass.class);
+        Query query = storage.createQuery(testCategory, TestClass.class);
+        query.execute();
         verify(testCollection).find();
     }
 
@@ -348,8 +283,8 @@
     public void verifyFindAllFromCategoryReturnsCorrectCursor() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
-        Query query = storage.createQuery().from(testCategory);
-        Cursor<TestClass> cursor = storage.findAllPojos(query, TestClass.class);
+        Query query = storage.createQuery(testCategory, TestClass.class);
+        Cursor<TestClass> cursor = query.execute();
 
         verifyDefaultCursor(cursor);
     }
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Thu Jan 10 15:09:23 2013 +0100
@@ -47,6 +47,7 @@
 import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadInfoData;
 import com.redhat.thermostat.thread.model.ThreadSummary;
@@ -64,19 +65,12 @@
 
     @Override
     public VMThreadCapabilities loadCapabilities(VmRef vm) {
-        try {
-        Query query = storage.createQuery()
-                .from(THREAD_CAPABILITIES)
-                .where(Key.VM_ID, Query.Criteria.EQUALS, vm.getId())
-                .where(Key.AGENT_ID, Query.Criteria.EQUALS, vm.getAgent().getAgentId());
-        
-        VMThreadCapabilities caps = storage.findPojo(query, VMThreadCapabilities.class);
+        Query<VMThreadCapabilities> query = storage.createQuery(THREAD_CAPABILITIES, VMThreadCapabilities.class);
+        query.where(Key.VM_ID, Query.Criteria.EQUALS, vm.getId());
+        query.where(Key.AGENT_ID, Query.Criteria.EQUALS, vm.getAgent().getAgentId());
+        query.limit(1);
+        VMThreadCapabilities caps = query.execute().next();
         return caps;
-        } catch (Throwable t) {
-            t.printStackTrace();
-            System.exit(0);
-            return null;
-        }
     }
     
     @Override
@@ -97,8 +91,10 @@
     public ThreadSummary loadLastestSummary(VmRef ref) {
         ThreadSummary summary = null;
 
-        Query query = prepareQuery(THREAD_SUMMARY, ref).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING).limit(1);
-        Cursor<ThreadSummary> cursor = storage.findAllPojos(query, ThreadSummary.class);
+        Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ThreadSummary.class, ref);
+        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        query.limit(1);
+        Cursor<ThreadSummary> cursor = query.execute();
         if (cursor.hasNext()) {
             summary = cursor.next();
         }
@@ -111,10 +107,11 @@
         
         List<ThreadSummary> result = new ArrayList<>();
         
-        Query query = prepareQuery(THREAD_SUMMARY, ref).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ThreadSummary.class, ref);
+        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
         query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since);
 
-        Cursor<ThreadSummary> cursor = storage.findAllPojos(query, ThreadSummary.class);
+        Cursor<ThreadSummary> cursor = query.execute();
         while (cursor.hasNext()) {
             ThreadSummary summary = cursor.next();
             result.add(summary);
@@ -134,11 +131,11 @@
     public List<ThreadInfoData> loadThreadInfo(VmRef ref, long since) {
         List<ThreadInfoData> result = new ArrayList<>();
         
-        Query query = prepareQuery(THREAD_INFO, ref)
-                .where(Key.TIMESTAMP, Criteria.GREATER_THAN, since)
-                .sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        Query<ThreadInfoData> query = prepareQuery(THREAD_INFO, ThreadInfoData.class, ref);
+        query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since);
+        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
         
-        Cursor<ThreadInfoData> cursor = storage.findAllPojos(query, ThreadInfoData.class);
+        Cursor<ThreadInfoData> cursor = query.execute();
         while (cursor.hasNext()) {
             ThreadInfoData info = cursor.next();
             result.add(info);
@@ -147,15 +144,14 @@
         return result;
     }
     
-    private Query prepareQuery(Category category, VmRef vm) {
-        return prepareQuery(category, vm.getIdString(), vm.getAgent().getAgentId());
+    private <T extends Pojo> Query<T> prepareQuery(Category category, Class<T> resultClass, VmRef vm) {
+        return prepareQuery(category, resultClass, vm.getIdString(), vm.getAgent().getAgentId());
     }
 
-    private Query prepareQuery(Category category, String vmId, String agentId) {
-        Query query = storage.createQuery()
-                .from(category)
-                .where(Key.AGENT_ID, Query.Criteria.EQUALS, agentId)
-                .where(Key.VM_ID, Query.Criteria.EQUALS, Integer.valueOf(vmId));
+    private <T extends Pojo> Query<T> prepareQuery(Category category, Class<T> resultClass, String vmId, String agentId) {
+        Query<T> query = storage.createQuery(category, resultClass);
+        query.where(Key.AGENT_ID, Query.Criteria.EQUALS, agentId);
+        query.where(Key.VM_ID, Query.Criteria.EQUALS, Integer.valueOf(vmId));
         return query;
     }
     
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -41,6 +41,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import org.junit.Test;
@@ -48,11 +49,12 @@
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.test.MockQuery;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.VMThreadCapabilities;
 
@@ -72,9 +74,9 @@
     
     @Test
     public void testLoadVMCapabilities() {
-        MockQuery query = new MockQuery();
+        Query query = mock(Query.class);
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(query);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
         VmRef ref = mock(VmRef.class);
         when(ref.getId()).thenReturn(42);
         
@@ -85,14 +87,20 @@
 
         VMThreadCapabilities expected = new VMThreadCapabilities();
         expected.setSupportedFeaturesList(new String[] { ThreadDao.CPU_TIME, ThreadDao.THREAD_ALLOCATED_MEMORY });
-        when(storage.findPojo(query, VMThreadCapabilities.class)).thenReturn(expected);
+        Cursor cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(expected).thenReturn(null);
+        when(query.execute()).thenReturn(cursor);
         
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         VMThreadCapabilities caps = dao.loadCapabilities(ref);
 
-        assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, 42));
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, "0xcafe"));
-        
+        verify(query).where(Key.VM_ID, Criteria.EQUALS, 42);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "0xcafe");
+        verify(query).limit(1);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
+
         assertFalse(caps.supportContentionMonitor());
         assertTrue(caps.supportCPUTime());
         assertTrue(caps.supportThreadAllocatedMemory());
--- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -39,18 +39,15 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.Collection;
 import java.util.List;
 
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
@@ -62,7 +59,6 @@
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.VmClassStat;
-import com.redhat.thermostat.test.MockQuery;
 import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO;
 
 public class VmClassStatDAOTest {
@@ -93,13 +89,9 @@
         when(cursor.next()).thenReturn(vmClassStat);
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(VmClassStat.class))).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -111,9 +103,12 @@
         VmClassStatDAO dao = new VmClassStatDAOImpl(storage);
         List<VmClassStat> vmClassStats = dao.getLatestClassStats(vmRef, Long.MIN_VALUE);
 
-        ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
-        verify(storage).findAllPojos(arg.capture(), same(VmClassStat.class));
-        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system");
+        verify(query).where(Key.VM_ID, Criteria.EQUALS, 321);
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
 
         assertEquals(1, vmClassStats.size());
         VmClassStat stat = vmClassStats.get(0);
--- a/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -39,9 +39,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.Collection;
@@ -49,9 +49,6 @@
 
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
@@ -63,7 +60,6 @@
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.VmCpuStat;
-import com.redhat.thermostat.test.MockQuery;
 import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO;
 
 public class VmCpuStatDAOTest {
@@ -99,13 +95,9 @@
         when(cursor.next()).thenReturn(cpuStat);
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(VmCpuStat.class))).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -118,9 +110,13 @@
         VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage);
         List<VmCpuStat> vmCpuStats = dao.getLatestVmCpuStats(vmRef, Long.MIN_VALUE);
 
-        ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
-        verify(storage).findAllPojos(arg.capture(), same(VmCpuStat.class));
-        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
+        verify(storage).createQuery(VmCpuStatDAO.vmCpuStatCategory, VmCpuStat.class);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, vmRef.getAgent().getAgentId());
+        verify(query).where(Key.VM_ID, Criteria.EQUALS, vmRef.getId());
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
 
         assertEquals(1, vmCpuStats.size());
         VmCpuStat stat = vmCpuStats.get(0);
--- a/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -39,16 +39,15 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.Collection;
 import java.util.List;
 
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
@@ -60,7 +59,6 @@
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.VmGcStat;
-import com.redhat.thermostat.test.MockQuery;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 
 public class VmGcStatDAOTest {
@@ -95,8 +93,9 @@
         when(cursor.next()).thenReturn(vmGcStat);
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(new MockQuery());
-        when(storage.findAllPojos(any(Query.class), same(VmGcStat.class))).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
         when(hostRef.getAgentId()).thenReturn("system");
@@ -109,9 +108,14 @@
         VmGcStatDAO dao = new VmGcStatDAOImpl(storage);
         List<VmGcStat> vmGcStats = dao.getLatestVmGcStats(vmRef, Long.MIN_VALUE);
 
-        ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
-        verify(storage).findAllPojos(arg.capture(), same(VmGcStat.class));
-        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
+        verify(storage).createQuery(VmGcStatDAO.vmGcStatCategory, VmGcStat.class);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system");
+        verify(query).where(Key.VM_ID, Criteria.EQUALS, 321);
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
 
         assertEquals(1, vmGcStats.size());
         VmGcStat stat = vmGcStats.get(0);
--- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
@@ -110,11 +110,10 @@
 
     @Override
     public Collection<HeapInfo> getAllHeapInfo(VmRef vm) {
-        Query query = storage.createQuery()
-                .from(heapInfoCategory)
-                .where(Key.AGENT_ID, Criteria.EQUALS, vm.getAgent().getAgentId())
-                .where(Key.VM_ID, Criteria.EQUALS, vm.getId());
-        Cursor<HeapInfo> cursor = storage.findAllPojos(query, HeapInfo.class);
+        Query<HeapInfo> query = storage.createQuery(heapInfoCategory, HeapInfo.class);
+        query.where(Key.AGENT_ID, Criteria.EQUALS, vm.getAgent().getAgentId());
+        query.where(Key.VM_ID, Criteria.EQUALS, vm.getId());
+        Cursor<HeapInfo> cursor = query.execute();
         Collection<HeapInfo> heapInfos = new ArrayList<>();
         while (cursor.hasNext()) {
             heapInfos.add(cursor.next());
@@ -141,12 +140,12 @@
 
     @Override
     public HeapInfo getHeapInfo(String heapId) {
-        Query query = storage.createQuery()
-                .from(heapInfoCategory)
-                .where(heapIdKey, Criteria.EQUALS, heapId);
+        Query<HeapInfo> query = storage.createQuery(heapInfoCategory, HeapInfo.class);
+        query.where(heapIdKey, Criteria.EQUALS, heapId);
+        query.limit(1);
         HeapInfo found = null;
         try {
-            found = storage.findPojo(query, HeapInfo.class);
+            found = query.execute().next();
         } catch (IllegalArgumentException iae) {
             /*
              * if the heap id is not found, we get a nice
--- a/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -42,7 +42,6 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -61,8 +60,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
@@ -71,10 +68,8 @@
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.test.MockQuery;
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
 import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord;
 import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
@@ -92,6 +87,8 @@
     private ObjectHistogram histogram;
     private InputStream histogramData;
 
+    private Query query;
+
     @Before
     public void setUp() throws IOException {
         storage = mock(Storage.class);
@@ -99,12 +96,8 @@
         when(storage.createAdd(any(Category.class))).thenReturn(add);
 
         when(storage.getAgentId()).thenReturn("test");
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
+        query = mock(Query.class); 
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
 
         dao = new HeapDAOImpl(storage);
         
@@ -116,12 +109,6 @@
         out.close();
         histogramData = createHistogramData();
 
-        // Setup for reading data from DB.
-        MockQuery findAllQuery = new MockQuery()
-            .from(HeapDAO.heapInfoCategory)
-            .where(Key.AGENT_ID, Criteria.EQUALS, "123")
-            .where(Key.VM_ID, Criteria.EQUALS, 234);
-
         @SuppressWarnings("unchecked")
         Cursor<HeapInfo> cursor = mock(Cursor.class);
         HeapInfo info1 = new HeapInfo(234, 12345L);
@@ -136,7 +123,7 @@
 
         when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(info1).thenReturn(info2).thenReturn(null);
-        when(storage.findAllPojos(findAllQuery, HeapInfo.class)).thenReturn(cursor);
+        when(query.execute()).thenReturn(cursor);
 
         // Setup for reading heapdump data.
         when(storage.loadFile("test-heap")).thenReturn(new ByteArrayInputStream(data));
@@ -175,6 +162,7 @@
 
     @After
     public void tearDown() {
+        query = null;
         histogramData = null;
         histogram = null;
         heapDumpData.delete();
@@ -286,9 +274,7 @@
 
     @Test
     public void testInvalidHeapId() throws IOException {
-        storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(new MockQuery());
-        when(storage.findPojo(any(Query.class), same(HeapInfo.class))).thenThrow(new IllegalArgumentException("invalid ObjectId"));
+        when(query.execute()).thenThrow(new IllegalArgumentException("invalid ObjectId"));
         dao = new HeapDAOImpl(storage);
         heapInfo = dao.getHeapInfo("some-random-heap-id");
         assertTrue(heapInfo == null);
--- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
@@ -62,13 +62,12 @@
 
     @Override
     public VmMemoryStat getLatestMemoryStat(VmRef ref) {
-        Query query = storage.createQuery()
-                .from(vmMemoryStatsCategory)
-                .where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId())
-                .where(Key.VM_ID, Criteria.EQUALS, ref.getId())
-                .sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING)
-                .limit(1);
-        Cursor<VmMemoryStat> cursor = storage.findAllPojos(query, VmMemoryStat.class);
+        Query<VmMemoryStat> query = storage.createQuery(vmMemoryStatsCategory, VmMemoryStat.class);
+        query.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId());
+        query.where(Key.VM_ID, Criteria.EQUALS, ref.getId());
+        query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
+        query.limit(1);
+        Cursor<VmMemoryStat> cursor = query.execute();
         if (cursor.hasNext()) {
             return cursor.next();
         }
--- a/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -39,9 +39,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
@@ -64,7 +64,6 @@
 import com.redhat.thermostat.storage.model.VmMemoryStat;
 import com.redhat.thermostat.storage.model.VmMemoryStat.Generation;
 import com.redhat.thermostat.storage.model.VmMemoryStat.Space;
-import com.redhat.thermostat.test.MockQuery;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 
 public class VmMemoryStatDAOTest {
@@ -75,7 +74,7 @@
     private Storage storage;
     private VmRef vmRef;
 
-    private MockQuery query;
+    private Query query;
     private Cursor<VmMemoryStat> cursor;
 
     @SuppressWarnings("unchecked")
@@ -91,11 +90,11 @@
         when(vmRef.getId()).thenReturn(VM_ID);
 
         storage = mock(Storage.class);
-        query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
+        query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
 
         cursor = mock(Cursor.class);
-        when(storage.findAllPojos(any(Query.class), same(VmMemoryStat.class))).thenReturn(cursor);
+        when(query.execute()).thenReturn(cursor);
 
         when(cursor.hasNext()).thenReturn(false);
 
@@ -137,14 +136,16 @@
 
         verifyQuery();
 
-        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l));
+        verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l);
+        verify(query).execute();
+        verifyNoMoreInteractions(query);
     }
 
     private void verifyQuery() {
 
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
-        assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, VM_ID));
-        assertTrue(query.hasSort(Key.TIMESTAMP, Query.SortDirection.DESCENDING));
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
+        verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_ID);
+        verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
     }
 
     @Test
@@ -153,8 +154,9 @@
         when(cursor.next()).thenReturn(null);
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(new MockQuery());
-        when(storage.findAllPojos(any(Query.class), same(VmMemoryStat.class))).thenReturn(cursor);
+        Query query = mock(Query.class);
+        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(query.execute()).thenReturn(cursor);
 
         VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage);
         VmMemoryStat latest = impl.getLatestMemoryStat(vmRef);
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Thu Jan 10 15:09:23 2013 +0100
@@ -304,6 +304,18 @@
         }
     }
 
+    private class WebQueryImpl<T extends Pojo> extends WebQuery<T> {
+
+        WebQueryImpl(int categoryId, Class<T> resultClass) {
+            super(categoryId, resultClass);
+        }
+
+        @Override
+        public Cursor<T> execute() {
+            return findAllPojos(this, getResultClass());
+        }
+    }
+
     private String endpoint;
     private UUID agentId;
 
@@ -433,8 +445,8 @@
     }
 
     @Override
-    public Query createQuery() {
-        return new WebQuery(categoryIds);
+    public <T extends Pojo> Query<T> createQuery(Category category, Class<T> resultClass) {
+        return new WebQueryImpl(categoryIds.get(category), resultClass);
     }
 
     @Override
@@ -450,8 +462,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    @Override
-    public <T extends Pojo> Cursor<T> findAllPojos(Query query,
+    private <T extends Pojo> Cursor<T> findAllPojos(Query query,
             Class<T> resultClass) throws StorageException {
         ((WebQuery) query).setResultClassName(resultClass.getName());
         NameValuePair queryParam = new BasicNameValuePair("query",
@@ -467,21 +478,6 @@
     }
 
     @Override
-    public <T extends Pojo> T findPojo(Query query, Class<T> resultClass)
-            throws StorageException {
-        ((WebQuery) query).setResultClassName(resultClass.getName());
-        NameValuePair queryParam = new BasicNameValuePair("query",
-                gson.toJson(query));
-        List<NameValuePair> formparams = Arrays.asList(queryParam);
-        try (CloseableHttpEntity entity = post(endpoint + "/find-pojo",
-                formparams)) {
-            Reader reader = getContentAsReader(entity);
-            T result = gson.fromJson(reader, resultClass);
-            return result;
-        }
-    }
-
-    @Override
     public String getAgentId() {
         return agentId.toString();
     }
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -221,35 +221,6 @@
     }
 
     @Test
-    public void testFindPojo() throws UnsupportedEncodingException, IOException {
-
-        TestObj obj = new TestObj();
-        obj.setProperty1("fluffor");
-        Gson gson = new Gson();
-        responseBody = gson.toJson(obj);
-
-        Query query = storage.createQuery().from(category).where(key1, Criteria.EQUALS, "fluff");
-
-        TestObj result = storage.findPojo(query, TestObj.class);
-        StringReader reader = new StringReader(requestBody);
-        BufferedReader bufRead = new BufferedReader(reader);
-        String line = URLDecoder.decode(bufRead.readLine(), "UTF-8");
-        String[] parts = line.split("=");
-        assertEquals("query", parts[0]);
-        WebQuery restQuery = gson.fromJson(parts[1], WebQuery.class);
-
-        assertEquals(42, restQuery.getCategoryId());
-        List<Qualifier<?>> qualifiers = restQuery.getQualifiers();
-        assertEquals(1, qualifiers.size());
-        Qualifier<?> qual = qualifiers.get(0);
-        assertEquals(new Key<String>("property1", true), qual.getKey());
-        assertEquals(Criteria.EQUALS, qual.getCriteria());
-        assertEquals("fluff", qual.getValue());
-
-        assertEquals("fluffor", result.getProperty1());
-    }
-
-    @Test
     public void testFindAllPojos() throws UnsupportedEncodingException, IOException {
 
         TestObj obj1 = new TestObj();
@@ -260,9 +231,10 @@
         responseBody = gson.toJson(Arrays.asList(obj1, obj2));
 
         Key<String> key1 = new Key<>("property1", true);
-        Query query = storage.createQuery().from(category).where(key1, Criteria.EQUALS, "fluff");
+        Query<TestObj> query = storage.createQuery(category, TestObj.class);
+        query.where(key1, Criteria.EQUALS, "fluff");
 
-        Cursor<TestObj> results = storage.findAllPojos(query, TestObj.class);
+        Cursor<TestObj> results = query.execute();
         StringReader reader = new StringReader(requestBody);
         BufferedReader bufRead = new BufferedReader(reader);
         String line = URLDecoder.decode(bufRead.readLine(), "UTF-8");
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebQuery.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebQuery.java	Thu Jan 10 15:09:23 2013 +0100
@@ -43,31 +43,26 @@
 
 import com.redhat.thermostat.storage.core.AbstractQuery;
 import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.Query;
+import com.redhat.thermostat.storage.model.Pojo;
 
-public class WebQuery extends AbstractQuery {
+public class WebQuery<T extends Pojo> extends AbstractQuery<T> {
 
     private List<Qualifier<?>> qualifiers;
     private String resultClassName;
-
-    private transient Map<Category, Integer> categoryIdMap;
+    private transient Class<T> resultClass;
 
     private int categoryId;
 
     public WebQuery() {
-        this(null);
+        this(-1, null);
     }
 
-    public WebQuery(Map<Category, Integer> categoryIdMap) {
+    public WebQuery(int categoryId, Class<T> resultClass) {
         qualifiers = new ArrayList<>();
-        this.categoryIdMap = categoryIdMap;
-    }
-
-    @Override
-    public WebQuery from(Category category) {
-        categoryId = categoryIdMap.get(category);
-        return this;
+        this.categoryId = categoryId;
+        this.resultClass = resultClass;
     }
 
     public int getCategoryId() {
@@ -79,9 +74,8 @@
     }
 
     @Override
-    public <T> WebQuery where(Key<T> key, Criteria criteria, T value) {
+    public <T> void where(Key<T> key, Criteria criteria, T value) {
         qualifiers.add(new Qualifier<>(key, criteria, value));
-        return this;
     }
 
     public List<Qualifier<?>> getQualifiers() {
@@ -100,4 +94,14 @@
         this.resultClassName = resultClassName;
     }
 
+    public Class<T> getResultClass() {
+        return resultClass;
+    }
+
+    @Override
+    public Cursor<T> execute() {
+        // This should only ever be called when created from WebStorage, which provides its own subclass.
+        throw new IllegalStateException();
+    }
+
 }
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -1,6 +1,5 @@
 package com.redhat.thermostat.web.common;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
 
 import java.util.HashMap;
 import java.util.List;
@@ -11,8 +10,6 @@
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query.Criteria;
-import com.redhat.thermostat.web.common.Qualifier;
-import com.redhat.thermostat.web.common.WebQuery;
 
 /*
  * Copyright 2012 Red Hat, Inc.
@@ -58,8 +55,8 @@
         Category category = new Category("test", key1);
         Map<Category,Integer> categoryIdMap = new HashMap<>();
         categoryIdMap.put(category, 42);
-        WebQuery query = new WebQuery(categoryIdMap);
-        query.from(category).where(key1, Criteria.EQUALS, "fluff");
+        WebQuery query = new WebQuery(42, String.class);
+        query.where(key1, Criteria.EQUALS, "fluff");
 
         List<Qualifier<?>> qualifiers = query.getQualifiers();
         assertEquals(1, qualifiers.size());
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Thu Jan 10 15:09:23 2013 +0100
@@ -70,6 +70,7 @@
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.StorageException;
 import com.redhat.thermostat.storage.core.Update;
 import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.web.common.Qualifier;
@@ -126,9 +127,7 @@
         String uri = req.getRequestURI();
         int lastPartIdx = uri.lastIndexOf("/");
         String cmd = uri.substring(lastPartIdx + 1);
-        if (cmd.equals("find-pojo")) {
-            findPojo(req, resp);
-        } else if (cmd.equals("find-all")) {
+        if (cmd.equals("find-all")) {
             findAll(req, resp);
         } else if (cmd.equals("put-pojo")) {
             putPojo(req, resp);
@@ -316,21 +315,6 @@
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    private void findPojo(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        try {
-            String queryParam = req.getParameter("query");
-            WebQuery query = gson.fromJson(queryParam, WebQuery.class);
-            Class resultClass = Class.forName(query.getResultClassName());
-            Query targetQuery = constructTargetQuery(query);
-            Object result = storage.findPojo(targetQuery, resultClass);
-            writeResponse(resp, result);
-        } catch (ClassNotFoundException e) {
-            e.printStackTrace();
-            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "result class not found");
-        }
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
     private void findAll(HttpServletRequest req, HttpServletResponse resp) throws IOException {
         try {
             String queryParam = req.getParameter("query");
@@ -338,7 +322,7 @@
             Class resultClass = Class.forName(query.getResultClassName());
             Query targetQuery = constructTargetQuery(query);
             ArrayList resultList = new ArrayList();
-            Cursor result = storage.findAllPojos(targetQuery, resultClass);
+            Cursor result = targetQuery.execute();
             while (result.hasNext()) {
                 resultList.add(result.next());
             }
@@ -349,20 +333,24 @@
         }
     }
 
-    private Query constructTargetQuery(WebQuery query) {
-        Query targetQuery = storage.createQuery();
+    private Query constructTargetQuery(WebQuery<? extends Pojo> query) {
         int categoryId = query.getCategoryId();
         Category category = getCategoryFromId(categoryId);
-        targetQuery = targetQuery.from(category);
-        List<Qualifier<?>> qualifiers = query.getQualifiers();
-        for (Qualifier q : qualifiers) {
-            targetQuery = targetQuery.where(q.getKey(), q.getCriteria(), q.getValue());
+        try {
+            Class<? extends Pojo> resultClass = (Class<? extends Pojo>) Class.forName(query.getResultClassName());
+            Query targetQuery = storage.createQuery(category, resultClass);
+            List<Qualifier<?>> qualifiers = query.getQualifiers();
+            for (Qualifier q : qualifiers) {
+                targetQuery.where(q.getKey(), q.getCriteria(), q.getValue());
+            }
+            for (Sort s : query.getSorts()) {
+                targetQuery.sort(s.getKey(), s.getDirection());
+            }
+            targetQuery.limit(query.getLimit());
+            return targetQuery;
+        } catch (ClassNotFoundException ex) {
+            throw new StorageException(ex);
         }
-        for (Sort s : query.getSorts()) {
-            targetQuery = targetQuery.sort(s.getKey(), s.getDirection());
-        }
-        targetQuery = targetQuery.limit(query.getLimit());
-        return targetQuery;
     }
 
     private Category getCategoryFromId(int categoryId) {
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Thu Jan 10 15:02:44 2013 +0100
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Thu Jan 10 15:09:23 2013 +0100
@@ -37,11 +37,9 @@
 package com.redhat.thermostat.web.server;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -91,7 +89,6 @@
 import com.redhat.thermostat.storage.model.BasePojo;
 import com.redhat.thermostat.test.FreePortFinder;
 import com.redhat.thermostat.test.FreePortFinder.TryPort;
-import com.redhat.thermostat.test.MockQuery;
 import com.redhat.thermostat.web.common.StorageWrapper;
 import com.redhat.thermostat.web.common.WebInsert;
 import com.redhat.thermostat.web.common.WebQuery;
@@ -201,42 +198,6 @@
     }
 
     @Test
-    public void testFind() throws IOException {
-        // Configure mock storage.
-        TestClass expected = new TestClass();
-        expected.setKey1("fluff");
-        expected.setKey2(42);
-        when(mockStorage.findPojo(any(Query.class), same(TestClass.class))).thenReturn(expected);
-
-        Query mockQuery = new MockQuery();
-        when(mockStorage.createQuery()).thenReturn(mockQuery);
-
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/find-pojo");
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setDoInput(true);
-        conn.setDoOutput(true);
-        Map<Category,Integer> categoryIdMap = new HashMap<>();
-        categoryIdMap.put(category, categoryId);
-        WebQuery query = (WebQuery) new WebQuery(categoryIdMap).from(category).where(key1, Criteria.EQUALS, "fluff");
-        query.setResultClassName(TestClass.class.getName());
-        Gson gson = new Gson();
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        out.write("query=");
-        out.write(URLEncoder.encode(gson.toJson(query), "UTF-8"));
-        out.write("\n");
-        out.flush();
-
-        Reader in = new InputStreamReader(conn.getInputStream());
-        TestClass result = gson.fromJson(in, TestClass.class);
-
-        assertEquals("fluff", result.getKey1());
-        assertEquals(42, result.getKey2());
-        verify(mockStorage).createQuery();
-        verify(mockStorage).findPojo(any(Query.class), same(TestClass.class));
-    }
-
-    @Test
     public void testFindAllPojos() throws IOException {
         TestClass expected1 = new TestClass();
         expected1.setKey1("fluff1");
@@ -249,9 +210,9 @@
         when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(expected1).thenReturn(expected2);
 
-        when(mockStorage.findAllPojos(any(Query.class), same(TestClass.class))).thenReturn(cursor);
-        MockQuery mockQuery = new MockQuery();
-        when(mockStorage.createQuery()).thenReturn(mockQuery);
+        Query mockQuery = mock(Query.class);
+        when(mockStorage.createQuery(any(Category.class), any(Class.class))).thenReturn(mockQuery);
+        when(mockQuery.execute()).thenReturn(cursor);
 
         String endpoint = getEndpoint();
         URL url = new URL(endpoint + "/find-all");
@@ -262,8 +223,10 @@
         conn.setDoOutput(true);
         Map<Category,Integer> categoryIdMap = new HashMap<>();
         categoryIdMap.put(category, categoryId);
-        WebQuery query = (WebQuery) new WebQuery(categoryIdMap).from(category).where(key1, Criteria.EQUALS, "fluff")
-                                                               .sort(key1, SortDirection.DESCENDING).limit(42);
+        WebQuery query = new WebQuery(categoryId, TestClass.class);
+        query.where(key1, Criteria.EQUALS, "fluff");
+        query.sort(key1, SortDirection.DESCENDING);
+        query.limit(42);
         query.setResultClassName(TestClass.class.getName());
         Gson gson = new Gson();
         OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
@@ -279,8 +242,11 @@
         assertEquals("fluff2", results[1].getKey1());
         assertEquals(43, results[1].getKey2());
 
-        assertTrue(mockQuery.hasSort(key1, SortDirection.DESCENDING));
-        assertEquals(42, mockQuery.getLimit());
+        verify(mockQuery).where(key1, Criteria.EQUALS, "fluff");
+        verify(mockQuery).sort(key1, SortDirection.DESCENDING);
+        verify(mockQuery).limit(42);
+        verify(mockQuery).execute();
+        verifyNoMoreInteractions(mockQuery);
     }
 
     @Test