changeset 1195:1925258e6309

Merge
author Elliott Baron <ebaron@redhat.com>
date Wed, 31 Jul 2013 18:58:17 -0400
parents b525881b4f8a (diff) 56e89524791c (current diff)
children dd3c6928c4e6
files storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java
diffstat 20 files changed, 395 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Wed Jul 31 18:58:17 2013 -0400
@@ -57,6 +57,7 @@
 import com.redhat.thermostat.host.cpu.common.model.CpuStat;
 import com.redhat.thermostat.storage.config.StartupConfiguration;
 import com.redhat.thermostat.storage.core.Add;
+import com.redhat.thermostat.storage.core.BackingStorage;
 import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
 import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
 import com.redhat.thermostat.storage.core.Cursor;
@@ -131,7 +132,7 @@
      * Make a connection to mongo storage (returning the Storage object). Before
      * initiating the connection, add the ConnectionListener to Storage.
      */
-    private static Storage getAndConnectStorage(ConnectionListener listener) {
+    private static BackingStorage getAndConnectStorage(ConnectionListener listener) {
         final String url = "mongodb://127.0.0.1:27518";
         StartupConfiguration config = new StartupConfiguration() {
 
@@ -141,7 +142,7 @@
             }
             
         };
-        Storage storage = new MongoStorage(config);
+        BackingStorage storage = new MongoStorage(config);
         if (listener != null) {
             storage.getConnection().addListener(listener);
         }
@@ -241,7 +242,7 @@
     public void canQueryNoWhere() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -258,7 +259,7 @@
     public void canQueryEqualTo() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -277,7 +278,7 @@
     public void canQueryNotEqualTo() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -296,7 +297,7 @@
     public void canQueryGreaterThan() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -315,7 +316,7 @@
     public void canQueryGreaterThanOrEqualTo() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -334,7 +335,7 @@
     public void canQueryLessThan() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -353,7 +354,7 @@
     public void canQueryLessThanOrEqualTo() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -372,7 +373,7 @@
     public void canQueryIn() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -392,7 +393,7 @@
     public void canQueryNotIn() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -411,7 +412,7 @@
     public void canQueryNot() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -430,7 +431,7 @@
     public void canQueryAnd() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -450,7 +451,7 @@
     public void canQueryOr() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         mongoStorage.registerCategory(CpuStatDAO.cpuStatCategory);
@@ -504,7 +505,7 @@
     public void setDefaultAgentID() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
-        Storage mongoStorage = getAndConnectStorage(listener);
+        BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         UUID uuid = new UUID(42, 24);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/BackingStorage.java	Wed Jul 31 18:58:17 2013 -0400
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012, 2013 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.storage.core;
+
+import com.redhat.thermostat.storage.model.Pojo;
+
+/**
+ * This subclass of {@link Storage} should be implemented by classes that
+ * interact directly with a form of storage (e.g. a database).
+ * 
+ * This interface contains methods which provide capabilities we do not want to
+ * expose directly to clients. Clients should instead prepare statements using
+ * {@link Storage#prepareStatement(StatementDescriptor)}. The methods in this
+ * interface then provide the mechanisms to execute the prepared statement, and
+ * should only be used by the prepared statement implementations.
+ */
+public interface BackingStorage extends Storage {
+    
+    <T extends Pojo> Query<T> createQuery(Category<T> category);
+    
+    // TODO Move createUpdate and createRemove here
+
+}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameters.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameters.java	Wed Jul 31 18:58:17 2013 -0400
@@ -49,6 +49,11 @@
         params = new PreparedParameter[numParams];
     }
     
+    @SuppressWarnings("unused")
+    private PreparedParameters() {
+        // nothing. Exists for serialization purposes.
+    }
+    
     @Override
     public void setLong(int paramIndex, long paramValue) {
         setType(paramIndex, paramValue, Long.class);
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatementFactory.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatementFactory.java	Wed Jul 31 18:58:17 2013 -0400
@@ -9,7 +9,7 @@
  */
 public class PreparedStatementFactory {
 
-    public static <T extends Pojo> PreparedStatement<T> getInstance(Storage storage,
+    public static <T extends Pojo> PreparedStatement<T> getInstance(BackingStorage storage,
             StatementDescriptor<T> desc) throws DescriptorParsingException {
         // This is the sole method in order to avoid leaking impl details of
         // this OSGi module. Storage implementations will have to use this
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedBackingStorage.java	Wed Jul 31 18:58:17 2013 -0400
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012, 2013 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.storage.core;
+
+import java.util.concurrent.ExecutorService;
+
+import com.redhat.thermostat.storage.model.Pojo;
+
+public class QueuedBackingStorage extends QueuedStorage implements
+        BackingStorage {
+    
+    public QueuedBackingStorage(BackingStorage delegate) {
+        super(delegate);
+    }
+
+    QueuedBackingStorage(BackingStorage delegate, ExecutorService executor,
+            ExecutorService fileExecutor) {
+        super(delegate, executor, fileExecutor);
+    }
+
+    @Override
+    public <T extends Pojo> Query<T> createQuery(Category<T> category) {
+        return ((BackingStorage) delegate).createQuery(category);
+    }
+    
+    @Override
+    public <T extends Pojo> PreparedStatement<T> prepareStatement(
+            StatementDescriptor<T> desc) throws DescriptorParsingException {
+        // FIXME: Use some kind of cache in order to avoid parsing of
+        // descriptors each time this is called. At least if the descriptor
+        // class is the same we should be able to do something here.
+        
+        // Don't just defer to the delegate, since we want statements
+        // prepared by this method to create queries using the
+        // createQuery method in this class.
+        return PreparedStatementFactory.getInstance(this, desc);
+    }
+
+}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Wed Jul 31 18:58:17 2013 -0400
@@ -229,11 +229,6 @@
     }
 
     @Override
-    public <T extends Pojo> Query<T> createQuery(Category<T> category) {
-        return delegate.createQuery(category);
-    }
-
-    @Override
     public Update createUpdate(Category<?> category) {
         QueuedUpdate update = new QueuedUpdate(delegate.createUpdate(category));
         return update;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Wed Jul 31 18:58:17 2013 -0400
@@ -96,8 +96,6 @@
 
     InputStream loadFile(String filename);
 
-    <T extends Pojo> Query<T> createQuery(Category<T> category);
-
     Update createUpdate(Category<?> category);
     Remove createRemove();
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java	Wed Jul 31 18:58:17 2013 -0400
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.storage.internal.statement;
 
+import com.redhat.thermostat.storage.core.BackingStorage;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DataModifyingStatement;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
@@ -48,7 +49,6 @@
 import com.redhat.thermostat.storage.core.Statement;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.Pojo;
 
 /**
@@ -63,7 +63,7 @@
     private final PreparedParameters params;
     private final ParsedStatementImpl<T> parsedStatement;
     
-    public PreparedStatementImpl(Storage storage, StatementDescriptor<T> desc) throws DescriptorParsingException {
+    public PreparedStatementImpl(BackingStorage storage, StatementDescriptor<T> desc) throws DescriptorParsingException {
         this.desc = desc;
         StatementDescriptorParser<T> parser = new StatementDescriptorParser<>(storage, desc);
         this.parsedStatement = (ParsedStatementImpl<T>)parser.parse();
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java	Wed Jul 31 18:58:17 2013 -0400
@@ -40,6 +40,7 @@
 import java.util.List;
 import java.util.StringTokenizer;
 
+import com.redhat.thermostat.storage.core.BackingStorage;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.Key;
@@ -47,7 +48,6 @@
 import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Query.SortDirection;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
 import com.redhat.thermostat.storage.query.BinaryLogicalOperator;
@@ -117,14 +117,14 @@
     
     private final String[] tokens;
     private final StatementDescriptor<T> desc;
-    private final Storage storage;
+    private final BackingStorage storage;
     private int currTokenIndex;
     private int placeHolderCount;
     // the parsed statement
     private ParsedStatementImpl<T> parsedStatement;
     private SuffixExpression tree;
     
-    StatementDescriptorParser(Storage storage, StatementDescriptor<T> desc) {
+    StatementDescriptorParser(BackingStorage storage, StatementDescriptor<T> desc) {
         this.tokens = getTokens(desc.getQueryDescriptor());
         this.currTokenIndex = 0;
         this.placeHolderCount = 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedBackingStorageTest.java	Wed Jul 31 18:58:17 2013 -0400
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2012, 2013 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.storage.core;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+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;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.model.Pojo;
+
+
+public class QueuedBackingStorageTest {
+
+    private static class TestExecutor implements ExecutorService {
+
+        private Runnable task;
+        private boolean shutdown;
+
+        @Override
+        public void execute(Runnable task) {
+            this.task = task;
+        }
+
+        Runnable getTask() {
+            return task;
+        }
+
+        @Override
+        public void shutdown() {
+            shutdown = true;
+        }
+
+        @Override
+        public List<Runnable> shutdownNow() {
+            // Not used.
+            shutdown = true;
+            return null;
+        }
+
+        @Override
+        public boolean isShutdown() {
+            return shutdown;
+        }
+
+        @Override
+        public boolean isTerminated() {
+            // Not used.
+            return shutdown;
+        }
+
+        @Override
+        public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+            return true;
+        }
+
+        @Override
+        public <T> Future<T> submit(Callable<T> task) {
+            // Not used.
+            return null;
+        }
+
+        @Override
+        public <T> Future<T> submit(Runnable task, T result) {
+            // Not used.
+            return null;
+        }
+
+        @Override
+        public Future<?> submit(Runnable task) {
+            // Not used.
+            return null;
+        }
+
+        @Override
+        public <T> List<Future<T>> invokeAll(
+                Collection<? extends Callable<T>> tasks)
+                throws InterruptedException {
+            // Not used.
+            return null;
+        }
+
+        @Override
+        public <T> List<Future<T>> invokeAll(
+                Collection<? extends Callable<T>> tasks, long timeout,
+                TimeUnit unit) throws InterruptedException {
+            // Not used.
+            return null;
+        }
+
+        @Override
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+                throws InterruptedException, ExecutionException {
+            // Not used.
+            return null;
+        }
+
+        @Override
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                long timeout, TimeUnit unit) throws InterruptedException,
+                ExecutionException, TimeoutException {
+            // Not used.
+            return null;
+        }
+
+    }
+    
+    private QueuedBackingStorage queuedStorage;
+    private BackingStorage delegateStorage;
+    private Query<TestPojo> delegateQuery;
+
+    private TestExecutor executor;
+    private TestExecutor fileExecutor;
+
+    private Cursor<TestPojo> expectedResults;
+
+    @SuppressWarnings("unchecked")
+    @Before
+    public void setUp() {
+        executor = new TestExecutor();
+        fileExecutor = new TestExecutor();
+        delegateStorage = mock(BackingStorage.class);
+
+        delegateQuery = (Query<TestPojo>) mock(Query.class);
+        expectedResults = (Cursor<TestPojo>) mock(Cursor.class);
+        when(delegateStorage.createQuery(any(Category.class))).thenReturn(delegateQuery);
+        when(delegateQuery.execute()).thenReturn(expectedResults);
+        
+        queuedStorage = new QueuedBackingStorage(delegateStorage, executor, fileExecutor);
+    }
+
+    @After
+    public void tearDown() {
+        expectedResults = null;
+        queuedStorage = null;
+        delegateStorage = null;
+        fileExecutor = null;
+        executor = null;
+        delegateQuery = null;
+    }
+    
+    @Test
+    public void testCreateQuery() {
+        @SuppressWarnings("unchecked")
+        Category<TestPojo> category = (Category<TestPojo>) mock(Category.class);
+        Query<TestPojo> query = queuedStorage.createQuery(category);
+        verify(delegateStorage).createQuery(category);
+        verifyNoMoreInteractions(delegateStorage);
+
+        Cursor<TestPojo> result = query.execute();
+        verify(delegateQuery).execute();
+        assertSame(expectedResults, result);
+
+        assertNull(executor.getTask());
+        assertNull(fileExecutor.getTask());
+    }
+    
+    private static class TestPojo implements Pojo {
+        
+    }
+
+}
+
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Wed Jul 31 18:58:17 2013 -0400
@@ -194,24 +194,16 @@
         }
     }
 
-    private static class TestPojo implements Pojo {
-        
-    }
-
     private QueuedStorage queuedStorage;
     private Storage delegateStorage;
     private Add delegateAdd;
     private Replace delegateReplace;
-    private Query<?> delegateQuery;
 
     private TestExecutor executor;
     private TestExecutor fileExecutor;
 
-    @SuppressWarnings("rawtypes")
-    private Cursor expectedResults;
     private InputStream expectedFile;
 
-    @SuppressWarnings("unchecked")
     @Before
     public void setUp() {
         executor = new TestExecutor();
@@ -222,30 +214,23 @@
         delegateReplace = mock(Replace.class);
 
         Remove remove = mock(Remove.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(any(Category.class))).thenReturn(delegateQuery);
-        expectedResults = mock(Cursor.class);
-        when(delegateQuery.execute()).thenReturn(expectedResults);
         when(delegateStorage.getCount(any(Category.class))).thenReturn(42l);
         expectedFile = mock(InputStream.class);
         when(delegateStorage.loadFile(anyString())).thenReturn(expectedFile);
         when(delegateStorage.getAgentId()).thenReturn("huzzah");
         queuedStorage = new QueuedStorage(delegateStorage, executor, fileExecutor);
-        
     }
 
     @After
     public void tearDown() {
         expectedFile = null;
-        expectedResults = null;
         queuedStorage = null;
         delegateStorage = null;
         fileExecutor = null;
         executor = null;
-        delegateQuery = null;
     }
 
     @Test
@@ -329,22 +314,6 @@
     }
 
     @Test
-    public void testFindAllPojos() {
-        @SuppressWarnings("unchecked")
-        Category<TestPojo> category = mock(Category.class);
-        Query<TestPojo> query = queuedStorage.createQuery(category);
-        verify(delegateStorage).createQuery(category);
-        verifyNoMoreInteractions(delegateStorage);
-
-        Cursor<TestPojo> result = query.execute();
-        verify(delegateQuery).execute();
-        assertSame(expectedResults, result);
-
-        assertNull(executor.getTask());
-        assertNull(fileExecutor.getTask());
-    }
-
-    @Test
     public void testGetCount() {
         Category<?> category = mock(Category.class);
 
@@ -535,12 +504,6 @@
         }
 
         @Override
-        public <T extends Pojo> Query<T> createQuery(Category<T> category) {
-            // not implemented
-            throw new AssertionError();
-        }
-
-        @Override
         public Update createUpdate(Category<?> category) {
             // not implemented
             throw new AssertionError();
@@ -564,7 +527,7 @@
         }
 
         @Override
-        public PreparedStatement prepareStatement(StatementDescriptor desc)
+        public <T extends Pojo> PreparedStatement<T> prepareStatement(StatementDescriptor<T> desc)
                 throws DescriptorParsingException {
             // not implemented
             return null;
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImplTest.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImplTest.java	Wed Jul 31 18:58:17 2013 -0400
@@ -44,13 +44,13 @@
 
 import org.junit.Test;
 
+import com.redhat.thermostat.storage.core.BackingStorage;
 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.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.BinaryComparisonExpression;
 import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
@@ -100,7 +100,7 @@
         Category<Pojo> mockCategory = (Category<Pojo>) mock(Category.class);
         when(desc.getCategory()).thenReturn(mockCategory);
         when(mockCategory.getName()).thenReturn("foo");
-        Storage storage = mock(Storage.class);
+        BackingStorage storage = mock(BackingStorage.class);
         StubQuery stmt = new StubQuery();
         when(storage.createQuery(mockCategory)).thenReturn(stmt);
         PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(storage, desc);
@@ -124,7 +124,7 @@
         Category<Pojo> mockCategory = (Category<Pojo>) mock(Category.class);
         when(desc.getCategory()).thenReturn(mockCategory);
         when(mockCategory.getName()).thenReturn("foo");
-        Storage storage = mock(Storage.class);
+        BackingStorage storage = mock(BackingStorage.class);
         StubQuery stmt = new StubQuery();
         when(storage.createQuery(mockCategory)).thenReturn(stmt);
         PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(storage, desc);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParserTest.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParserTest.java	Wed Jul 31 18:58:17 2013 -0400
@@ -51,12 +51,12 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import com.redhat.thermostat.storage.core.BackingStorage;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Query.SortDirection;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.internal.statement.BinaryExpressionNode;
@@ -77,14 +77,14 @@
 
 public class StatementDescriptorParserTest {
 
-    private Storage storage;
+    private BackingStorage storage;
     private Query<AgentInformation> mockQuery;
     private StatementDescriptorParser<AgentInformation> parser;
     
     @SuppressWarnings("unchecked")
     @Before
     public void setup() {
-        storage = mock(Storage.class);
+        storage = mock(BackingStorage.class);
         mockQuery = mock(Query.class);
         when(storage.createQuery(any(AgentInfoDAO.CATEGORY.getClass()))).thenReturn(mockQuery);
     }
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/MongoStorageProvider.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/MongoStorageProvider.java	Wed Jul 31 18:58:17 2013 -0400
@@ -37,7 +37,7 @@
 package com.redhat.thermostat.storage.mongodb;
 
 import com.redhat.thermostat.storage.config.StartupConfiguration;
-import com.redhat.thermostat.storage.core.QueuedStorage;
+import com.redhat.thermostat.storage.core.QueuedBackingStorage;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.StorageProvider;
 import com.redhat.thermostat.storage.mongodb.internal.MongoStorage;
@@ -53,7 +53,7 @@
     @Override
     public Storage createStorage() {
         MongoStorage storage = new MongoStorage(configuration);
-        return new QueuedStorage(storage);
+        return new QueuedBackingStorage(storage);
     }
 
     @Override
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Wed Jul 31 18:58:17 2013 -0400
@@ -55,6 +55,7 @@
 import com.redhat.thermostat.storage.config.StartupConfiguration;
 import com.redhat.thermostat.storage.core.AbstractQuery.Sort;
 import com.redhat.thermostat.storage.core.Add;
+import com.redhat.thermostat.storage.core.BackingStorage;
 import com.redhat.thermostat.storage.core.BasePut;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Connection;
@@ -69,7 +70,6 @@
 import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.Update;
 import com.redhat.thermostat.storage.model.Pojo;
 
@@ -78,7 +78,7 @@
  *
  * In this implementation, each CATEGORY is given a distinct collection.
  */
-public class MongoStorage implements Storage {
+public class MongoStorage implements BackingStorage {
 
     private class MongoAdd extends BasePut implements Add {
 
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageProviderTest.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageProviderTest.java	Wed Jul 31 18:58:17 2013 -0400
@@ -36,14 +36,15 @@
 
 package com.redhat.thermostat.storage.mongodb.internal;
 
-import org.junit.Test;
-
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import org.junit.Test;
+
 import com.redhat.thermostat.storage.config.StartupConfiguration;
+import com.redhat.thermostat.storage.core.BackingStorage;
 import com.redhat.thermostat.storage.core.QueuedStorage;
 import com.redhat.thermostat.storage.core.SecureStorage;
 import com.redhat.thermostat.storage.core.Storage;
@@ -59,6 +60,7 @@
         provider.setConfig(config);
         Storage result = provider.createStorage();
         assertTrue(result instanceof QueuedStorage);
+        assertTrue(result instanceof BackingStorage);
         assertFalse(result instanceof SecureStorage);
     }
 }
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Wed Jul 31 18:58:17 2013 -0400
@@ -101,7 +101,6 @@
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedParameter;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.SecureStorage;
@@ -513,14 +512,6 @@
     }
 
     @Override
-    public <T extends Pojo> Query<T> createQuery(Category<T> category) {
-        // There isn't going to be a query end-point on server side.
-        String msg = "createQuery() not supported for Web storage. " +
-                "Please use prepareStatement() instead.";
-        throw new IllegalStateException(msg);
-    }
-
-    @Override
     public Remove createRemove() {
         return new WebRemove(categoryIds);
     }
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageProviderTest.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageProviderTest.java	Wed Jul 31 18:58:17 2013 -0400
@@ -36,16 +36,18 @@
 
 package com.redhat.thermostat.web.client.internal;
 
-import org.junit.Test;
-import org.mockito.Mockito;
-
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import org.junit.Test;
+import org.mockito.Mockito;
+
 import com.redhat.thermostat.storage.config.AuthenticationConfiguration;
 import com.redhat.thermostat.storage.config.StartupConfiguration;
+import com.redhat.thermostat.storage.core.BackingStorage;
 import com.redhat.thermostat.storage.core.QueuedStorage;
 import com.redhat.thermostat.storage.core.SecureStorage;
 import com.redhat.thermostat.storage.core.Storage;
@@ -61,6 +63,7 @@
         Storage storage = provider.createStorage();
         assertTrue(storage instanceof SecureStorage);
         assertTrue(storage instanceof QueuedStorage);
+        assertFalse(storage instanceof BackingStorage);
         verify(config, Mockito.atLeastOnce()).getUsername();
         verify(config, Mockito.atLeastOnce()).getPassword();
     }
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Wed Jul 31 18:58:17 2013 -0400
@@ -391,17 +391,6 @@
     }
 
     @Test
-    public void createQueryFailsCorrectly() throws UnsupportedEncodingException, IOException {
-        try {
-            storage.createQuery(category);
-            fail("createQuery() should fail for WebStorage.");
-        } catch (IllegalStateException e) {
-            // pass
-            assertTrue(e.getMessage().contains("createQuery() not supported"));
-        }
-    }
-
-    @Test
     public void testPut() throws IOException, JsonSyntaxException, ClassNotFoundException {
 
         TestObj obj = new TestObj();
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Wed Jul 31 15:30:51 2013 -0400
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Wed Jul 31 18:58:17 2013 -0400
@@ -92,6 +92,7 @@
 import com.google.gson.GsonBuilder;
 import com.google.gson.reflect.TypeToken;
 import com.redhat.thermostat.storage.core.Add;
+import com.redhat.thermostat.storage.core.BackingStorage;
 import com.redhat.thermostat.storage.core.Categories;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
@@ -164,7 +165,7 @@
 
     private Server server;
     private int port;
-    private Storage mockStorage;
+    private BackingStorage mockStorage;
     private Integer categoryId;
 
     private static Key<String> key1;
@@ -197,7 +198,7 @@
         assertTrue(fakeHome.canRead());
         System.setProperty("THERMOSTAT_HOME", fakeHome.getAbsolutePath());
         
-        mockStorage = mock(Storage.class);
+        mockStorage = mock(BackingStorage.class);
         StorageWrapper.setStorage(mockStorage);
         
         factory = new ExpressionFactory();